diff --git a/deps/ox/src/ox/std/hashmap.hpp b/deps/ox/src/ox/std/hashmap.hpp new file mode 100644 index 00000000..c7ced32e --- /dev/null +++ b/deps/ox/src/ox/std/hashmap.hpp @@ -0,0 +1,106 @@ +/* + * Copyright 2015 - 2018 gtalent2@gmail.com + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "string.hpp" +#include "vector.hpp" + +namespace ox { + +template +class HashMap { + + private: + struct Pair { + K key; + T value; + }; + Vector m_keys; + Vector m_pairs; + + public: + explicit HashMap(std::size_t size = 100) noexcept; + + HashMap(HashMap &other) noexcept; + + ~HashMap() noexcept; + + HashMap &operator=(HashMap &other) noexcept; + + /** + * K is assumed to be a null terminated string. + */ + T &operator[](K key) noexcept; + + std::size_t size() const noexcept; + + private: + /** + * K is assumed to be a null terminated string. + */ + static std::uint64_t hash(K, int len = 0xFFFF); + +}; + +template +HashMap::HashMap(std::size_t size) noexcept: m_pairs(size) { +} + +template +HashMap::HashMap(HashMap &other) noexcept { + m_pairs = other.m_pairs; +} + +template +HashMap::~HashMap() noexcept { + for (std::size_t i = 0; i < m_pairs.size(); i++) { + delete m_pairs[i]; + } +} + +template +HashMap &HashMap::operator=(HashMap &other) noexcept { + this->~HashMap(); + m_keys = other.m_keys; + m_pairs = other.m_pairs; + return *this; +} + +template +T &HashMap::operator[](K k) noexcept { + auto h = hash(k) % m_pairs.size(); + auto hashStr = reinterpret_cast(&h); + while (1) { + auto &p = m_pairs[h]; + if (p == nullptr) { + p = new Pair; + p->key = k; + m_keys.push_back(k); + return p->value; + } else if (ox_strcmp(p->key, k) == 0) { + return p->value; + } else { + h = hash(hashStr, 8) % m_pairs.size(); + } + } +} + +template +std::size_t HashMap::size() const noexcept { + return m_keys.size(); +}; + +template +std::uint64_t HashMap::hash(K k, int len) { + std::uint64_t sum = 1; + for (int i = 0; i < len && k[i]; i++) { + sum += ((sum + k[i]) * 7) * sum; + } + return sum; +} + +} diff --git a/deps/ox/src/ox/std/std.hpp b/deps/ox/src/ox/std/std.hpp index 1da4226b..1c17dfff 100644 --- a/deps/ox/src/ox/std/std.hpp +++ b/deps/ox/src/ox/std/std.hpp @@ -12,6 +12,7 @@ #include "bitops.hpp" #include "byteswap.hpp" #include "error.hpp" +#include "hashmap.hpp" #include "math.hpp" #include "memops.hpp" #include "new.hpp" diff --git a/deps/ox/src/ox/std/string.hpp b/deps/ox/src/ox/std/string.hpp index 8728cacd..63b5d496 100644 --- a/deps/ox/src/ox/std/string.hpp +++ b/deps/ox/src/ox/std/string.hpp @@ -18,7 +18,7 @@ namespace ox { template class BString { private: - uint8_t m_buff[buffLen + 1]; + char m_buff[buffLen + 1]; public: BString() noexcept; @@ -39,6 +39,10 @@ class BString { bool operator==(const BString &other) noexcept; + char operator[](std::size_t i) const noexcept; + + char &operator[](std::size_t i) noexcept; + char *data() noexcept; const char *c_str() const noexcept; @@ -132,6 +136,16 @@ bool BString::operator==(const BString &other) noexcept { return retval; } +template +char BString::operator[](std::size_t i) const noexcept { + return m_buff[i]; +} + +template +char &BString::operator[](std::size_t i) noexcept { + return m_buff[i]; +} + template char *BString::data() noexcept { return (char*) m_buff; diff --git a/deps/ox/src/ox/std/strops.hpp b/deps/ox/src/ox/std/strops.hpp index 78f7339d..93b5d709 100644 --- a/deps/ox/src/ox/std/strops.hpp +++ b/deps/ox/src/ox/std/strops.hpp @@ -12,7 +12,8 @@ #include "types.hpp" #include "typetraits.hpp" -constexpr char *ox_strncpy(char *dest, const char *src, std::size_t maxLen) noexcept { +template +constexpr char *ox_strncpy(T1 dest, T2 src, std::size_t maxLen) noexcept { for (std::size_t i = 0; i < maxLen && src[i]; i++) { dest[i] = src[i]; } @@ -25,19 +26,15 @@ constexpr int ox_strnlen(const char *str1, int maxLen) noexcept { return len; } -constexpr int ox_strlen(const char *str1) noexcept { +template +constexpr int ox_strlen(T str1) noexcept { int len = 0; for (; str1[len]; len++); return len; } -constexpr int ox_strlen(char *str1) noexcept { - int len = 0; - for (; str1[len]; len++); - return len; -} - -constexpr int ox_strcmp(const char *str1, const char *str2) noexcept { +template +constexpr int ox_strcmp(T1 str1, T2 str2) noexcept { auto retval = 0; auto i = 0; while (str1[i] || str2[i]) { @@ -123,7 +120,8 @@ constexpr int ox_atoi(const char *str) noexcept { return total; } -constexpr char *ox_itoa(int64_t v, char *str) noexcept { +template +constexpr char *ox_itoa(int64_t v, T str) noexcept { if (v) { auto mod = 1000000000000000000; constexpr auto base = 10; diff --git a/deps/ox/src/ox/std/test/CMakeLists.txt b/deps/ox/src/ox/std/test/CMakeLists.txt index 79e18641..a541eaa4 100644 --- a/deps/ox/src/ox/std/test/CMakeLists.txt +++ b/deps/ox/src/ox/std/test/CMakeLists.txt @@ -11,3 +11,5 @@ add_test("Test\\ ox_memcmp\\ ABCDEFG\\ !=\\ HIJKLMN" StdTest "ABCDEFG != HIJKLMN add_test("Test\\ ox_memcmp\\ HIJKLMN\\ !=\\ ABCDEFG" StdTest "HIJKLMN != ABCDEFG") add_test("Test\\ ox_memcmp\\ ABCDEFG\\ ==\\ ABCDEFG" StdTest "ABCDEFG == ABCDEFG") add_test("Test\\ ox_memcmp\\ ABCDEFGHI\\ ==\\ ABCDEFG" StdTest "ABCDEFGHI == ABCDEFG") +add_test("Test\\ Vector" StdTest "Vector") +add_test("Test\\ HashMap" StdTest "HashMap") diff --git a/deps/ox/src/ox/std/test/tests.cpp b/deps/ox/src/ox/std/test/tests.cpp index 7949f5c0..cebc475e 100644 --- a/deps/ox/src/ox/std/test/tests.cpp +++ b/deps/ox/src/ox/std/test/tests.cpp @@ -37,6 +37,34 @@ map> tests = { return !(ox_memcmp("ABCDEFGHI", "ABCDEFG", 7) == 0); } }, + { + "Vector", + [] { + ox::Vector v; + oxAssert(v.size() == 0, "Initial Vector size not 0"); + auto insertTest = [&v](int val, std::size_t size) { + v.push_back(val); + oxAssert(v.size() == size, "Vector size incorrect"); + oxAssert(v[v.size() - 1] == val, "Vector value wrong"); + }; + insertTest(42, 1); + insertTest(100, 2); + insertTest(102, 3); + return 0; + } + }, + { + "HashMap", + [] { + ox::HashMap v; + v["asdf"] = 42; + v["aoeu"] = 100; + std::cout << v["asdf"]; + oxAssert(v["asdf"] == 42, "asdf != 42"); + oxAssert(v["aoeu"] == 100, "aoeu != 100"); + return 0; + } + }, }; int main(int argc, const char **args) { diff --git a/deps/ox/src/ox/std/vector.hpp b/deps/ox/src/ox/std/vector.hpp index 67ea829d..e6b5f0d1 100644 --- a/deps/ox/src/ox/std/vector.hpp +++ b/deps/ox/src/ox/std/vector.hpp @@ -17,58 +17,86 @@ class Vector { private: std::size_t m_size = 0; + std::size_t m_cap = 0; T *m_items = nullptr; public: - Vector() = default; + Vector() noexcept = default; - explicit Vector(std::size_t size); + explicit Vector(std::size_t size) noexcept; - Vector(Vector &other); + Vector(Vector &other) noexcept; - Vector(Vector &&other); + Vector(Vector &&other) noexcept; - ~Vector(); + ~Vector() noexcept; - Vector &operator=(Vector &other); + Vector &operator=(Vector &other) noexcept; - Vector &operator=(Vector &&other); + Vector &operator=(Vector &&other) noexcept; - T &operator[](std::size_t i); + T &operator[](std::size_t i) noexcept; - const T &operator[](std::size_t i) const; + const T &operator[](std::size_t i) const noexcept; - std::size_t size() const; + std::size_t size() const noexcept; - void resize(std::size_t size); + void resize(std::size_t size) noexcept; + + bool contains(T) const noexcept; + + void push_back(const T &item) noexcept; + + /** + * Removes an item from the Vector. + * @param pos position of item to remove + */ + void erase(std::size_t pos) noexcept; + + /** + * Moves the last item in the Vector to position pos and decrements the + * size by 1. + * @param pos position of item to remove + */ + void unordered_erase(std::size_t pos) noexcept; + + private: + void expandCap(std::size_t cap) noexcept; }; template -Vector::Vector(std::size_t size) { +Vector::Vector(std::size_t size) noexcept { m_size = size; - m_items = new T[m_size]; + m_cap = m_size; + m_items = new T[m_cap]; + for (std::size_t i = 0; i < size; i++) { + m_items[i] = {}; + } } template -Vector::Vector(Vector &other) { +Vector::Vector(Vector &other) noexcept { m_size = other.m_size; - m_items = new T[m_size]; + m_cap = other.m_cap; + m_items = new T[m_cap]; for (std::size_t i = 0; i < m_size; i++) { m_items[i] = other.m_items[i]; } } template -Vector::Vector(Vector &&other) { +Vector::Vector(Vector &&other) noexcept { m_size = other.m_size; + m_cap = other.m_cap; m_items = other.m_items; other.m_size = 0; + other.m_cap = 0; other.m_items = nullptr; } template -Vector::~Vector() { +Vector::~Vector() noexcept { if (m_items) { delete[] m_items; m_items = nullptr; @@ -76,10 +104,11 @@ Vector::~Vector() { } template -Vector &Vector::operator=(Vector &other) { - ~Vector(); +Vector &Vector::operator=(Vector &other) noexcept { + this->~Vector(); m_size = other.m_size; - m_items = new T[m_size]; + m_cap = other.m_cap; + m_items = new T[m_cap]; for (std::size_t i = 0; i < m_size; i++) { m_items[i] = other.m_items[i]; } @@ -87,40 +116,91 @@ Vector &Vector::operator=(Vector &other) { } template -Vector &Vector::operator=(Vector &&other) { - ~Vector(); +Vector &Vector::operator=(Vector &&other) noexcept { + this->~Vector(); m_size = other.m_size; + m_cap = other.m_cap; m_items = other.m_items; other.m_size = 0; + other.m_cap = 0; other.m_items = nullptr; return *this; } template -T &Vector::operator[](std::size_t i) { - return *(m_items[i]); +T &Vector::operator[](std::size_t i) noexcept { + return m_items[i]; } template -const T &Vector::operator[](std::size_t i) const { - return *(m_items[i]); +const T &Vector::operator[](std::size_t i) const noexcept { + return m_items[i]; } template -std::size_t Vector::size() const { +std::size_t Vector::size() const noexcept { return m_size; }; template -void Vector::resize(std::size_t size) { - auto oldItems = m_items; - m_items = new T[size]; - const auto itRange = size > m_size ? m_size : size; - for (std::size_t i = 0; i < itRange; i++) { - m_items[i] = oldItems[i]; +void Vector::resize(std::size_t size) noexcept { + if (m_cap < size) { + expandCap(size); + } + for (std::size_t i = m_size; i < size; i++) { + m_items[i] = {}; } m_size = size; - delete[] oldItems; +} + +template +bool Vector::contains(T v) const noexcept { + for (std::size_t i = 0; i < m_size; i++) { + if (m_items[i] == v) { + return true; + } + } + return false; +} + +template +void Vector::push_back(const T &item) noexcept { + if (m_size == m_cap) { + expandCap(m_cap ? m_cap * 2 : 100); + } + m_items[m_size] = item; + ++m_size; +} + +template +void Vector::erase(std::size_t pos) noexcept { + m_size--; + for (auto i = pos; i < m_size; i++) { + m_items[i] = m_items[i + 1]; + } +} + +template +void Vector::unordered_erase(std::size_t pos) noexcept { + m_size--; + m_items[pos] = m_items[m_size]; +} + +template +void Vector::expandCap(std::size_t cap) noexcept { + auto oldItems = m_items; + m_cap = cap; + m_items = new T[m_cap]; + if (oldItems) { // move over old items + const auto itRange = cap > m_size ? m_size : cap; + for (std::size_t i = 0; i < itRange; i++) { + m_items[i] = oldItems[i]; + } + for (std::size_t i = itRange; i < m_cap; i++) { + m_items[i] = {}; + } + delete[] oldItems; + } } }