[ox/std] Add HashMap

This commit is contained in:
Gary Talent 2019-02-02 21:06:42 -06:00
parent 8da1b77aa5
commit 87e6b8d19f
7 changed files with 274 additions and 45 deletions

106
deps/ox/src/ox/std/hashmap.hpp vendored Normal file
View 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;
}
}

View File

@ -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"

View File

@ -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;

View File

@ -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;

View File

@ -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")

View File

@ -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) {

View File

@ -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;
} }
}
} }