[ox/std] Add HashMap
This commit is contained in:
parent
8da1b77aa5
commit
87e6b8d19f
106
deps/ox/src/ox/std/hashmap.hpp
vendored
Normal file
106
deps/ox/src/ox/std/hashmap.hpp
vendored
Normal file
@ -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<typename K, typename T>
|
||||||
|
class HashMap {
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Pair {
|
||||||
|
K key;
|
||||||
|
T value;
|
||||||
|
};
|
||||||
|
Vector<K> m_keys;
|
||||||
|
Vector<Pair*> 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<typename K, typename T>
|
||||||
|
HashMap<K, T>::HashMap(std::size_t size) noexcept: m_pairs(size) {
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename K, typename T>
|
||||||
|
HashMap<K, T>::HashMap(HashMap<K, T> &other) noexcept {
|
||||||
|
m_pairs = other.m_pairs;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename K, typename T>
|
||||||
|
HashMap<K, T>::~HashMap() noexcept {
|
||||||
|
for (std::size_t i = 0; i < m_pairs.size(); i++) {
|
||||||
|
delete m_pairs[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename K, typename T>
|
||||||
|
HashMap<K, T> &HashMap<K, T>::operator=(HashMap<K, T> &other) noexcept {
|
||||||
|
this->~HashMap<K, T>();
|
||||||
|
m_keys = other.m_keys;
|
||||||
|
m_pairs = other.m_pairs;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename K, typename T>
|
||||||
|
T &HashMap<K, T>::operator[](K k) noexcept {
|
||||||
|
auto h = hash(k) % m_pairs.size();
|
||||||
|
auto hashStr = reinterpret_cast<char*>(&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<typename K, typename T>
|
||||||
|
std::size_t HashMap<K, T>::size() const noexcept {
|
||||||
|
return m_keys.size();
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename K, typename T>
|
||||||
|
std::uint64_t HashMap<K, T>::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
1
deps/ox/src/ox/std/std.hpp
vendored
1
deps/ox/src/ox/std/std.hpp
vendored
@ -12,6 +12,7 @@
|
|||||||
#include "bitops.hpp"
|
#include "bitops.hpp"
|
||||||
#include "byteswap.hpp"
|
#include "byteswap.hpp"
|
||||||
#include "error.hpp"
|
#include "error.hpp"
|
||||||
|
#include "hashmap.hpp"
|
||||||
#include "math.hpp"
|
#include "math.hpp"
|
||||||
#include "memops.hpp"
|
#include "memops.hpp"
|
||||||
#include "new.hpp"
|
#include "new.hpp"
|
||||||
|
16
deps/ox/src/ox/std/string.hpp
vendored
16
deps/ox/src/ox/std/string.hpp
vendored
@ -18,7 +18,7 @@ namespace ox {
|
|||||||
template<std::size_t buffLen>
|
template<std::size_t buffLen>
|
||||||
class BString {
|
class BString {
|
||||||
private:
|
private:
|
||||||
uint8_t m_buff[buffLen + 1];
|
char m_buff[buffLen + 1];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BString() noexcept;
|
BString() noexcept;
|
||||||
@ -39,6 +39,10 @@ class BString {
|
|||||||
|
|
||||||
bool operator==(const BString &other) noexcept;
|
bool operator==(const BString &other) noexcept;
|
||||||
|
|
||||||
|
char operator[](std::size_t i) const noexcept;
|
||||||
|
|
||||||
|
char &operator[](std::size_t i) noexcept;
|
||||||
|
|
||||||
char *data() noexcept;
|
char *data() noexcept;
|
||||||
|
|
||||||
const char *c_str() const noexcept;
|
const char *c_str() const noexcept;
|
||||||
@ -132,6 +136,16 @@ bool BString<buffLen>::operator==(const BString<buffLen> &other) noexcept {
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<std::size_t buffLen>
|
||||||
|
char BString<buffLen>::operator[](std::size_t i) const noexcept {
|
||||||
|
return m_buff[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t buffLen>
|
||||||
|
char &BString<buffLen>::operator[](std::size_t i) noexcept {
|
||||||
|
return m_buff[i];
|
||||||
|
}
|
||||||
|
|
||||||
template<std::size_t buffLen>
|
template<std::size_t buffLen>
|
||||||
char *BString<buffLen>::data() noexcept {
|
char *BString<buffLen>::data() noexcept {
|
||||||
return (char*) m_buff;
|
return (char*) m_buff;
|
||||||
|
18
deps/ox/src/ox/std/strops.hpp
vendored
18
deps/ox/src/ox/std/strops.hpp
vendored
@ -12,7 +12,8 @@
|
|||||||
#include "types.hpp"
|
#include "types.hpp"
|
||||||
#include "typetraits.hpp"
|
#include "typetraits.hpp"
|
||||||
|
|
||||||
constexpr char *ox_strncpy(char *dest, const char *src, std::size_t maxLen) noexcept {
|
template<typename T1, typename T2>
|
||||||
|
constexpr char *ox_strncpy(T1 dest, T2 src, std::size_t maxLen) noexcept {
|
||||||
for (std::size_t i = 0; i < maxLen && src[i]; i++) {
|
for (std::size_t i = 0; i < maxLen && src[i]; i++) {
|
||||||
dest[i] = src[i];
|
dest[i] = src[i];
|
||||||
}
|
}
|
||||||
@ -25,19 +26,15 @@ constexpr int ox_strnlen(const char *str1, int maxLen) noexcept {
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr int ox_strlen(const char *str1) noexcept {
|
template<typename T>
|
||||||
|
constexpr int ox_strlen(T str1) noexcept {
|
||||||
int len = 0;
|
int len = 0;
|
||||||
for (; str1[len]; len++);
|
for (; str1[len]; len++);
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr int ox_strlen(char *str1) noexcept {
|
template<typename T1, typename T2>
|
||||||
int len = 0;
|
constexpr int ox_strcmp(T1 str1, T2 str2) noexcept {
|
||||||
for (; str1[len]; len++);
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr int ox_strcmp(const char *str1, const char *str2) noexcept {
|
|
||||||
auto retval = 0;
|
auto retval = 0;
|
||||||
auto i = 0;
|
auto i = 0;
|
||||||
while (str1[i] || str2[i]) {
|
while (str1[i] || str2[i]) {
|
||||||
@ -123,7 +120,8 @@ constexpr int ox_atoi(const char *str) noexcept {
|
|||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr char *ox_itoa(int64_t v, char *str) noexcept {
|
template<typename T>
|
||||||
|
constexpr char *ox_itoa(int64_t v, T str) noexcept {
|
||||||
if (v) {
|
if (v) {
|
||||||
auto mod = 1000000000000000000;
|
auto mod = 1000000000000000000;
|
||||||
constexpr auto base = 10;
|
constexpr auto base = 10;
|
||||||
|
2
deps/ox/src/ox/std/test/CMakeLists.txt
vendored
2
deps/ox/src/ox/std/test/CMakeLists.txt
vendored
@ -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\\ HIJKLMN\\ !=\\ ABCDEFG" StdTest "HIJKLMN != ABCDEFG")
|
||||||
add_test("Test\\ ox_memcmp\\ ABCDEFG\\ ==\\ ABCDEFG" StdTest "ABCDEFG == ABCDEFG")
|
add_test("Test\\ ox_memcmp\\ ABCDEFG\\ ==\\ ABCDEFG" StdTest "ABCDEFG == ABCDEFG")
|
||||||
add_test("Test\\ ox_memcmp\\ ABCDEFGHI\\ ==\\ ABCDEFG" StdTest "ABCDEFGHI == ABCDEFG")
|
add_test("Test\\ ox_memcmp\\ ABCDEFGHI\\ ==\\ ABCDEFG" StdTest "ABCDEFGHI == ABCDEFG")
|
||||||
|
add_test("Test\\ Vector" StdTest "Vector")
|
||||||
|
add_test("Test\\ HashMap" StdTest "HashMap")
|
||||||
|
28
deps/ox/src/ox/std/test/tests.cpp
vendored
28
deps/ox/src/ox/std/test/tests.cpp
vendored
@ -37,6 +37,34 @@ map<string, function<int()>> tests = {
|
|||||||
return !(ox_memcmp("ABCDEFGHI", "ABCDEFG", 7) == 0);
|
return !(ox_memcmp("ABCDEFGHI", "ABCDEFG", 7) == 0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"Vector",
|
||||||
|
[] {
|
||||||
|
ox::Vector<int> 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<const char*, int> 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) {
|
int main(int argc, const char **args) {
|
||||||
|
142
deps/ox/src/ox/std/vector.hpp
vendored
142
deps/ox/src/ox/std/vector.hpp
vendored
@ -17,58 +17,86 @@ class Vector {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::size_t m_size = 0;
|
std::size_t m_size = 0;
|
||||||
|
std::size_t m_cap = 0;
|
||||||
T *m_items = nullptr;
|
T *m_items = nullptr;
|
||||||
|
|
||||||
public:
|
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<typename T>
|
template<typename T>
|
||||||
Vector<T>::Vector(std::size_t size) {
|
Vector<T>::Vector(std::size_t size) noexcept {
|
||||||
m_size = size;
|
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<typename T>
|
template<typename T>
|
||||||
Vector<T>::Vector(Vector<T> &other) {
|
Vector<T>::Vector(Vector<T> &other) noexcept {
|
||||||
m_size = other.m_size;
|
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++) {
|
for (std::size_t i = 0; i < m_size; i++) {
|
||||||
m_items[i] = other.m_items[i];
|
m_items[i] = other.m_items[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Vector<T>::Vector(Vector<T> &&other) {
|
Vector<T>::Vector(Vector<T> &&other) noexcept {
|
||||||
m_size = other.m_size;
|
m_size = other.m_size;
|
||||||
|
m_cap = other.m_cap;
|
||||||
m_items = other.m_items;
|
m_items = other.m_items;
|
||||||
other.m_size = 0;
|
other.m_size = 0;
|
||||||
|
other.m_cap = 0;
|
||||||
other.m_items = nullptr;
|
other.m_items = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Vector<T>::~Vector() {
|
Vector<T>::~Vector() noexcept {
|
||||||
if (m_items) {
|
if (m_items) {
|
||||||
delete[] m_items;
|
delete[] m_items;
|
||||||
m_items = nullptr;
|
m_items = nullptr;
|
||||||
@ -76,10 +104,11 @@ Vector<T>::~Vector() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Vector<T> &Vector<T>::operator=(Vector<T> &other) {
|
Vector<T> &Vector<T>::operator=(Vector<T> &other) noexcept {
|
||||||
~Vector<T>();
|
this->~Vector<T>();
|
||||||
m_size = other.m_size;
|
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++) {
|
for (std::size_t i = 0; i < m_size; i++) {
|
||||||
m_items[i] = other.m_items[i];
|
m_items[i] = other.m_items[i];
|
||||||
}
|
}
|
||||||
@ -87,40 +116,91 @@ Vector<T> &Vector<T>::operator=(Vector<T> &other) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Vector<T> &Vector<T>::operator=(Vector<T> &&other) {
|
Vector<T> &Vector<T>::operator=(Vector<T> &&other) noexcept {
|
||||||
~Vector<T>();
|
this->~Vector<T>();
|
||||||
m_size = other.m_size;
|
m_size = other.m_size;
|
||||||
|
m_cap = other.m_cap;
|
||||||
m_items = other.m_items;
|
m_items = other.m_items;
|
||||||
other.m_size = 0;
|
other.m_size = 0;
|
||||||
|
other.m_cap = 0;
|
||||||
other.m_items = nullptr;
|
other.m_items = nullptr;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T &Vector<T>::operator[](std::size_t i) {
|
T &Vector<T>::operator[](std::size_t i) noexcept {
|
||||||
return *(m_items[i]);
|
return m_items[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
const T &Vector<T>::operator[](std::size_t i) const {
|
const T &Vector<T>::operator[](std::size_t i) const noexcept {
|
||||||
return *(m_items[i]);
|
return m_items[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
std::size_t Vector<T>::size() const {
|
std::size_t Vector<T>::size() const noexcept {
|
||||||
return m_size;
|
return m_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void Vector<T>::resize(std::size_t size) {
|
void Vector<T>::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
bool Vector<T>::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<typename T>
|
||||||
|
void Vector<T>::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<typename T>
|
||||||
|
void Vector<T>::erase(std::size_t pos) noexcept {
|
||||||
|
m_size--;
|
||||||
|
for (auto i = pos; i < m_size; i++) {
|
||||||
|
m_items[i] = m_items[i + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void Vector<T>::unordered_erase(std::size_t pos) noexcept {
|
||||||
|
m_size--;
|
||||||
|
m_items[pos] = m_items[m_size];
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void Vector<T>::expandCap(std::size_t cap) noexcept {
|
||||||
auto oldItems = m_items;
|
auto oldItems = m_items;
|
||||||
m_items = new T[size];
|
m_cap = cap;
|
||||||
const auto itRange = size > m_size ? m_size : size;
|
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++) {
|
for (std::size_t i = 0; i < itRange; i++) {
|
||||||
m_items[i] = oldItems[i];
|
m_items[i] = oldItems[i];
|
||||||
}
|
}
|
||||||
m_size = size;
|
for (std::size_t i = itRange; i < m_cap; i++) {
|
||||||
|
m_items[i] = {};
|
||||||
|
}
|
||||||
delete[] oldItems;
|
delete[] oldItems;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user