1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
#pragma once
//hashset
//
//search: O(1) average; O(n) worst
//insert: O(1) average; O(n) worst
//remove: O(1) average; O(n) worst
//
//requirements:
// auto T::hash() const -> uint;
// auto T::operator==(const T&) const -> bool;
namespace nall {
template<typename T>
struct hashset {
hashset() = default;
hashset(uint length) : length(bit::round(length)) {}
hashset(const hashset& source) { operator=(source); }
hashset(hashset&& source) { operator=(move(source)); }
~hashset() { reset(); }
auto operator=(const hashset& source) -> hashset& {
reset();
if(source.pool) {
for(uint n : range(source.count)) {
insert(*source.pool[n]);
}
}
return *this;
}
auto operator=(hashset&& source) -> hashset& {
reset();
pool = source.pool;
length = source.length;
count = source.count;
source.pool = nullptr;
source.length = 8;
source.count = 0;
return *this;
}
explicit operator bool() const { return count; }
auto capacity() const -> uint { return length; }
auto size() const -> uint { return count; }
auto reset() -> void {
if(pool) {
for(uint n : range(length)) {
if(pool[n]) {
delete pool[n];
pool[n] = nullptr;
}
}
delete pool;
pool = nullptr;
}
length = 8;
count = 0;
}
auto reserve(uint size) -> void {
//ensure all items will fit into pool (with <= 50% load) and amortize growth
size = bit::round(max(size, count << 1));
T** copy = new T*[size]();
if(pool) {
for(uint n : range(length)) {
if(pool[n]) {
uint hash = (*pool[n]).hash() & (size - 1);
while(copy[hash]) if(++hash >= size) hash = 0;
copy[hash] = pool[n];
pool[n] = nullptr;
}
}
}
delete pool;
pool = copy;
length = size;
}
auto find(const T& value) -> maybe<T&> {
if(!pool) return nothing;
uint hash = value.hash() & (length - 1);
while(pool[hash]) {
if(value == *pool[hash]) return *pool[hash];
if(++hash >= length) hash = 0;
}
return nothing;
}
auto insert(const T& value) -> maybe<T&> {
if(!pool) pool = new T*[length]();
//double pool size when load is >= 50%
if(count >= (length >> 1)) reserve(length << 1);
count++;
uint hash = value.hash() & (length - 1);
while(pool[hash]) if(++hash >= length) hash = 0;
pool[hash] = new T(value);
return *pool[hash];
}
auto remove(const T& value) -> bool {
if(!pool) return false;
uint hash = value.hash() & (length - 1);
while(pool[hash]) {
if(value == *pool[hash]) {
delete pool[hash];
pool[hash] = nullptr;
count--;
return true;
}
if(++hash >= length) hash = 0;
}
return false;
}
protected:
T** pool = nullptr;
uint length = 8; //length of pool
uint count = 0; //number of objects inside of the pool
};
}
|