diff --git a/ostd/internal/hashtable.hh b/ostd/internal/hashtable.hh deleted file mode 100644 index a0d29d7..0000000 --- a/ostd/internal/hashtable.hh +++ /dev/null @@ -1,754 +0,0 @@ -/* Internal hash table implementation. Used as a base for set, map etc. - * - * This file is part of OctaSTD. See COPYING.md for futher information. - */ - -#ifndef OSTD_INTERNAL_HASHTABLE_HH -#define OSTD_INTERNAL_HASHTABLE_HH - -#include -#include - -#include "ostd/types.hh" -#include "ostd/utility.hh" -#include "ostd/memory.hh" -#include "ostd/range.hh" -#include "ostd/initializer_list.hh" - -namespace ostd { - -namespace detail { - template - struct HashChain { - HashChain *prev; - HashChain *next; - T value; - }; - - template - static inline size_t estimate_hrsize( - const R &range, EnableIf, bool> = true - ) { - return range.size(); - } - - template - static inline size_t estimate_hrsize( - const R &, EnableIf, bool> = true - ) { - /* we have no idea how big the range actually is */ - return 16; - } -} - -template -struct HashRange: InputRange, ForwardRangeTag, T> { -private: - template - friend struct HashRange; - - using Chain = detail::HashChain; - Chain *p_node; -public: - HashRange(): p_node(nullptr) {} - HashRange(const HashRange &v): p_node(v.p_node) {} - HashRange(Chain *node): p_node(node) {} - - template - HashRange( - const HashRange &v, EnableIf< - IsSame, RemoveCv> && IsConvertible, bool - > = true - ): - p_node(const_cast(v.p_node)) - {} - - HashRange &operator=(const HashRange &v) { - p_node = v.p_node; - return *this; - } - - bool empty() const { return !p_node; } - - bool pop_front() { - if (!p_node) { - return false; - } - p_node = p_node->next; - return true; - } - - bool equals_front(const HashRange &v) const { - return p_node == v.p_node; - } - - T &front() const { return p_node->value; } -}; - -template -struct BucketRange: InputRange, ForwardRangeTag, T> { -private: - template - friend struct BucketRange; - - using Chain = detail::HashChain; - Chain *p_node, *p_end; -public: - BucketRange(): p_node(nullptr) {} - BucketRange(Chain *node, Chain *end): p_node(node), p_end(end) {} - BucketRange(const BucketRange &v): p_node(v.p_node), p_end(v.p_end) {} - - template - BucketRange( - const BucketRange &v, EnableIf< - IsSame, RemoveCv> && IsConvertible, bool - > = true - ): - p_node(const_cast(v.p_node)), - p_end(const_cast(v.p_end)) - {} - - BucketRange &operator=(const BucketRange &v) { - p_node = v.p_node; - p_end = v.p_end; - return *this; - } - - bool empty() const { return p_node == p_end; } - - bool pop_front() { - if (p_node == p_end) { - return false; - } - p_node = p_node->next; - return true; - } - - bool equals_front(const BucketRange &v) const { - return p_node == v.p_node; - } - - T &front() const { return p_node->value; } -}; - -namespace detail { - /* Use template metaprogramming to figure out a correct number - * of elements to use per chunk for proper cache alignment - * (i.e. sizeof(Chunk) % CacheLineSize == 0). - * - * If this is not possible, use the upper bound and pad the - * structure with some extra bytes. - */ - static constexpr size_t CacheLineSize = 64; - static constexpr size_t ChunkLowerBound = 32; - static constexpr size_t ChunkUpperBound = 128; - - template constexpr size_t HashChainAlign = - (((sizeof(HashChain[N]) + sizeof(void *)) % CacheLineSize) == 0) - ? N : HashChainAlign; - - template - constexpr size_t HashChainAlign = ChunkUpperBound; - - template - struct HashChainPad; - - template - struct HashChainPad {}; - - template - struct HashChainPad { - byte pad[CacheLineSize - (N % CacheLineSize)]; - }; - - template - struct HashPad: HashChainPad {}; - - template< - typename E, size_t V = HashChainAlign, - bool P = (V == ChunkUpperBound) - > - struct HashChunk; - - template - struct HashChunk { - static constexpr size_t num = V; - HashChain chains[num]; - HashChunk *next; - }; - - template - struct HashChunk: HashPad< - sizeof(HashChain[V]) + sizeof(void *) - > { - static constexpr size_t num = V; - HashChain chains[num]; - HashChunk *next; - }; - - template< - typename B, /* contains methods specific to each ht type */ - typename E, /* element type */ - typename K, /* key type */ - typename T, /* value type */ - typename H, /* hash func */ - typename C, /* equality check */ - typename A, /* allocator */ - bool Multihash - > - struct Hashtable { -private: - using Chain = HashChain; - using Chunk = HashChunk; - - size_t p_size; - size_t p_len; - - Chunk *p_chunks; - Chain *p_unused; - - using CPA = AllocatorRebind; - using CHA = AllocatorRebind; - - using CoreAllocPair = detail::CompressedPair; - using AllocPair = detail::CompressedPair; - using FuncPair = detail::CompressedPair; - using FAPair = detail::CompressedPair; - using DataPair = detail::CompressedPair; - - using Range = HashRange; - using ConstRange = HashRange; - using LocalRange = BucketRange; - using ConstLocalRange = BucketRange; - - DataPair p_data; - - float p_maxlf; - - void clear_buckets() { - memset(p_data.first(), 0, (p_size + 1) * sizeof(Chain *)); - } - - void init_buckets() { - p_data.first() = allocator_allocate(get_cpalloc(), p_size + 1); - clear_buckets(); - } - - Chain *find(const K &key, size_t &h) const { - if (!p_size) { - return nullptr; - } - h = bucket(key); - Chain **cp = p_data.first(); - for (Chain *c = cp[h], *e = cp[h + 1]; c != e; c = c->next) { - if (get_eq()(key, B::get_key(c->value))) { - return c; - } - } - return nullptr; - } - - Chain *insert_node(size_t h, Chain *c) { - Chain **cp = p_data.first(); - Chain *it = cp[h + 1]; - c->next = it; - if (it) { - c->prev = it->prev; - it->prev = c; - if (c->prev) { - c->prev->next = c; - } - } else { - size_t nb = h; - while (nb && !cp[nb]) { - --nb; - } - Chain *prev = cp[nb]; - while (prev && prev->next) { - prev = prev->next; - } - c->prev = prev; - if (prev) { - prev->next = c; - } - } - for (; it == cp[h]; --h) { - cp[h] = c; - if (!h) { - break; - } - } - return c; - } - - Chain *request_node() { - if (!p_unused) { - Chunk *chunk = allocator_allocate(get_challoc(), 1); - allocator_construct(get_challoc(), chunk); - chunk->next = p_chunks; - p_chunks = chunk; - for (size_t i = 0; i < (Chunk::num - 1); ++i) { - chunk->chains[i].next = &chunk->chains[i + 1]; - } - chunk->chains[Chunk::num - 1].next = p_unused; - p_unused = chunk->chains; - } - ++p_len; - Chain *c = p_unused; - p_unused = p_unused->next; - return c; - } - - Chain *insert(size_t h) { - return insert_node(h, request_node()); - } - - void delete_chunks(Chunk *chunks) { - for (Chunk *nc; chunks; chunks = nc) { - nc = chunks->next; - allocator_destroy(get_challoc(), chunks); - allocator_deallocate(get_challoc(), chunks, 1); - } - } - - void rehash_ahead(size_t n) { - if (!bucket_count()) { - reserve(n); - } else if ((float(size() + n) / bucket_count()) > max_load_factor()) { - rehash(size_t((size() + 1) / max_load_factor()) * 2); - } - } - -protected: - template - T &insert(size_t h, U &&key) { - Chain *c = insert(h); - B::set_key(c->value, std::forward(key), get_alloc()); - return B::get_data(c->value); - } - - T &access_or_insert(const K &key) { - size_t h = 0; - Chain *c = find(key, h); - if (c) { - return B::get_data(c->value); - } - rehash_ahead(1); - return insert(bucket(key), key); - } - - T &access_or_insert(K &&key) { - size_t h = 0; - Chain *c = find(key, h); - if (c) { - return B::get_data(c->value); - } - rehash_ahead(1); - return insert(bucket(key), std::move(key)); - } - - T *access(const K &key) const { - size_t h; - Chain *c = find(key, h); - if (c) { - return &B::get_data(c->value); - } - return nullptr; - } - - template - void assign_range(R range) { - clear(); - reserve_at_least(detail::estimate_hrsize(range)); - for (; !range.empty(); range.pop_front()) { - emplace(range.front()); - } - rehash_up(); - } - - void assign_init(std::initializer_list il) { - const E *beg = il.begin(), *end = il.end(); - clear(); - reserve_at_least(end - beg); - while (beg != end) { - emplace(*beg++); - } - } - - const H &get_hash() const { return p_data.second().second().first(); } - const C &get_eq() const { return p_data.second().second().second(); } - - A &get_alloc() { return p_data.second().first().first(); } - const A &get_alloc() const { return p_data.second().first().first(); } - - CPA &get_cpalloc() { return p_data.second().first().second().first(); } - const CPA &get_cpalloc() const { - return p_data.second().first().second().first(); - } - - CHA &get_challoc() { return p_data.second().first().second().second(); } - const CHA &get_challoc() const { - return p_data.second().first().second().second(); - } - - Hashtable(size_t size, const H &hf, const C &eqf, const A &alloc): - p_size(size), p_len(0), p_chunks(nullptr), p_unused(nullptr), - p_data(nullptr, FAPair(AllocPair(alloc, CoreAllocPair(alloc, alloc)), - FuncPair(hf, eqf))), - p_maxlf(1.0f) { - if (!size) { - return; - } - init_buckets(); - } - - Hashtable(const Hashtable &ht, const A &alloc): p_size(ht.p_size), - p_len(0), p_chunks(nullptr), p_unused(nullptr), - p_data(nullptr, FAPair(AllocPair(alloc, CoreAllocPair(alloc, alloc)), - FuncPair(ht.get_hash(), ht.get_eq()))), - p_maxlf(ht.p_maxlf) { - if (!p_size) { - return; - } - init_buckets(); - Chain **och = ht.p_data.first(); - for (Chain *oc = *och; oc; oc = oc->next) { - size_t h = bucket(B::get_key(oc->value)); - Chain *nc = insert(h); - allocator_destroy(get_alloc(), &nc->value); - allocator_construct(get_alloc(), &nc->value, oc->value); - } - } - - Hashtable(Hashtable &&ht): p_size(ht.p_size), p_len(ht.p_len), - p_chunks(ht.p_chunks), p_unused(ht.p_unused), - p_data(std::move(ht.p_data)), p_maxlf(ht.p_maxlf) { - ht.p_size = ht.p_len = 0; - ht.p_chunks = nullptr; - ht.p_unused = nullptr; - ht.p_data.first() = nullptr; - } - - Hashtable(Hashtable &&ht, const A &alloc): p_data(nullptr, - FAPair(AllocPair(alloc, CoreAllocPair(alloc, alloc)), - FuncPair(ht.get_hash(), ht.get_eq()))) { - p_size = ht.p_size; - if (alloc == ht.get_alloc()) { - p_len = ht.p_len; - p_chunks = ht.p_chunks; - p_unused = ht.p_unused; - p_data.first() = ht.p_data.first(); - p_maxlf = ht.p_maxlf; - ht.p_size = ht.p_len = 0; - ht.p_chunks = nullptr; - ht.p_unused = nullptr; - ht.p_data.first() = nullptr; - return; - } - p_len = 0; - p_chunks = nullptr; - p_unused = nullptr; - init_buckets(); - Chain **och = ht.p_data.first(); - for (Chain *oc = *och; oc; oc = oc->next) { - size_t h = bucket(B::get_key(oc->value)); - Chain *nc = insert(h); - B::swap_elem(oc->value, nc->value); - } - } - - Hashtable &operator=(const Hashtable &ht) { - clear(); - if (AllocatorPropagateOnContainerCopyAssignment) { - if ((get_cpalloc() != ht.get_cpalloc()) && p_size) { - allocator_deallocate( - get_cpalloc(), p_data.first(), p_size + 1 - ); - init_buckets(); - } - get_alloc() = ht.get_alloc(); - get_cpalloc() = ht.get_cpalloc(); - get_challoc() = ht.get_challoc(); - } - for (ConstRange range = ht.iter(); !range.empty(); range.pop_front()) { - emplace(range.front()); - } - return *this; - } - - Hashtable &operator=(Hashtable &&ht) { - using std::swap; - clear(); - swap(p_size, ht.p_size); - swap(p_len, ht.p_len); - swap(p_chunks, ht.p_chunks); - swap(p_unused, ht.p_unused); - swap(p_data.first(), ht.p_data.first()); - swap(p_data.second().second(), ht.p_data.second().second()); - if (AllocatorPropagateOnContainerMoveAssignment) { - swap(p_data.second().first(), ht.p_data.second().first()); - } - return *this; - } - - void rehash_up() { - if (load_factor() <= max_load_factor()) { - return; - } - rehash(size_t(size() / max_load_factor()) * 2); - } - - void reserve_at_least(size_t count) { - size_t nc = size_t(ceil(count / max_load_factor())); - if (p_size > nc) { - return; - } - rehash(nc); - } - - void swap(Hashtable &ht) { - using std::swap; - swap(p_size, ht.p_size); - swap(p_len, ht.p_len); - swap(p_chunks, ht.p_chunks); - swap(p_unused, ht.p_unused); - swap(p_data.first(), ht.p_data.first()); - swap(p_data.second().second(), ht.p_data.second().second()); - if (AllocatorPropagateOnContainerSwap) { - swap(p_data.second().first(), ht.p_data.second().first()); - } - } - -public: - ~Hashtable() { - if (p_size) { - allocator_deallocate(get_cpalloc(), p_data.first(), p_size + 1); - } - delete_chunks(p_chunks); - } - - A get_allocator() const { - return get_alloc(); - } - - void clear() { - if (!p_len) { - return; - } - clear_buckets(); - p_len = 0; - p_unused = nullptr; - delete_chunks(p_chunks); - } - - bool empty() const { return p_len == 0; } - size_t size() const { return p_len; } - size_t max_size() const { return size_t(~0) / sizeof(E); } - - size_t bucket_count() const { return p_size; } - size_t max_bucket_count() const { return size_t(~0) / sizeof(Chain); } - - size_t bucket(const K &key) const { - return get_hash()(key) & (p_size - 1); - } - - size_t bucket_size(size_t n) const { - size_t ret = 0; - if (n >= p_size) { - return ret; - } - Chain **cp = p_data.first(); - for (Chain *c = cp[n], *e = cp[n + 1]; c != e; c = c->next) { - ++ret; - } - return ret; - } - - template - std::pair emplace(Args &&...args) { - rehash_ahead(1); - E elem(std::forward(args)...); - if (Multihash) { - /* multihash: always insert - * gotta make sure that equal keys always come after - * each other (this is then used by other APIs) - */ - size_t h = bucket(B::get_key(elem)); - Chain *ch = insert(h); - B::swap_elem(ch->value, elem); - return std::make_pair(Range(ch), true); - } - size_t h = bucket(B::get_key(elem)); - Chain *found = nullptr; - bool ins = true; - Chain **cp = p_data.first(); - for (Chain *c = cp[h], *e = cp[h + 1]; c != e; c = c->next) { - if (get_eq()(B::get_key(elem), B::get_key(c->value))) { - found = c; - ins = false; - break; - } - } - if (!found) { - found = insert(h); - B::swap_elem(found->value, elem); - } - return std::make_pair(Range(found), ins); - } - - size_t erase(const K &key) { - size_t h = 0; - Chain *c = find(key, h); - if (!c) { - return 0; - } - Chain **cp = p_data.first(); - size_t olen = p_len; - for (Chain *e = cp[h + 1]; c != e; c = c->next) { - if (!get_eq()(key, B::get_key(c->value))) { - break; - } - --p_len; - size_t hh = h; - Chain *next = c->next; - for (; cp[hh] == c; --hh) { - cp[hh] = next; - if (!hh) { - break; - } - } - if (c->prev) { - c->prev->next = next; - } - if (next) { - next->prev = c->prev; - } - c->next = p_unused; - c->prev = nullptr; - p_unused = c; - allocator_destroy(get_alloc(), &c->value); - allocator_construct(get_alloc(), &c->value); - if (!Multihash) { - return 1; - } - } - return olen - p_len; - } - - size_t count(const K &key) { - size_t h = 0; - Chain *c = find(key, h); - if (!c) { - return 0; - } - size_t ret = 1; - if (!Multihash) { - return ret; - } - for (c = c->next; c; c = c->next) { - if (get_eq()(key, B::get_key(c->value))) { - ++ret; - } - } - return ret; - } - - Range find(const K &key) { - size_t h = 0; - return Range(find(key, h)); - } - - ConstRange find(const K &key) const { - size_t h = 0; - return ConstRange(reinterpret_cast *>( - find(key, h) - )); - } - - float load_factor() const { return float(p_len) / p_size; } - float max_load_factor() const { return p_maxlf; } - void max_load_factor(float lf) { p_maxlf = lf; } - - void rehash(size_t count) { - size_t fbcount = size_t(p_len / max_load_factor()); - if (fbcount > count) { - count = fbcount; - } - - Chain **och = p_data.first(); - size_t osize = p_size; - - p_size = count; - init_buckets(); - - Chain *p = och ? *och : nullptr; - while (p) { - Chain *pp = p->next; - size_t h = bucket(B::get_key(p->value)); - p->prev = p->next = nullptr; - insert_node(h, p); - p = pp; - } - - if (och && osize) { - allocator_deallocate(get_cpalloc(), och, osize + 1); - } - } - - void reserve(size_t count) { - rehash(size_t(ceil(count / max_load_factor()))); - } - - Range iter() { - if (!p_len) { - return Range(); - } - return Range(*p_data.first()); - } - ConstRange iter() const { - using Chain = detail::HashChain; - if (!p_len) { - return ConstRange(); - } - return ConstRange(reinterpret_cast(*p_data.first())); - } - ConstRange citer() const { - using Chain = detail::HashChain; - if (!p_len) { - return ConstRange(); - } - return ConstRange(reinterpret_cast(*p_data.first())); - } - - LocalRange iter(size_t n) { - if (n >= p_size) { - return LocalRange(); - } - return LocalRange(p_data.first()[n], p_data.first()[n + 1]); - } - ConstLocalRange iter(size_t n) const { - using Chain = detail::HashChain; - if (n >= p_size) { - return ConstLocalRange(); - } - return ConstLocalRange( - reinterpret_cast(p_data.first()[n]), - reinterpret_cast(p_data.first()[n + 1]) - ); - } - ConstLocalRange citer(size_t n) const { - using Chain = detail::HashChain; - if (n >= p_size) { - return ConstLocalRange(); - } - return ConstLocalRange( - reinterpret_cast(p_data.first()[n]), - reinterpret_cast(p_data.first()[n + 1]) - ); - } - }; -} /* namespace detail */ - -} /* namespace ostd */ - -#endif diff --git a/ostd/keyset.hh b/ostd/keyset.hh deleted file mode 100644 index 2e2e9af..0000000 --- a/ostd/keyset.hh +++ /dev/null @@ -1,213 +0,0 @@ -/* Keyed set for OctaSTD. Implemented as a hash table. - * - * This file is part of OctaSTD. See COPYING.md for futher information. - */ - -#ifndef OSTD_KEYSET_HH -#define OSTD_KEYSET_HH - -#include "ostd/types.hh" -#include "ostd/utility.hh" -#include "ostd/memory.hh" -#include "ostd/functional.hh" -#include "ostd/initializer_list.hh" -#include "ostd/type_traits.hh" - -#include "ostd/internal/hashtable.hh" - -namespace ostd { - -namespace detail { - template - using KeysetKeyRet = decltype(std::declval().get_key()); - template - using KeysetKey = Decay> const; - - template struct KeysetBase { - using Key = KeysetKey; - - using RetKey = Conditional>, Key &, Key>; - static inline RetKey get_key(T const &e) { - return e.get_key(); - } - static inline T &get_data(T &e) { - return e; - } - template - static inline void set_key(T &, U const &, A &) {} - static inline void swap_elem(T &a, T &b) { - using std::swap; - swap(a, b); - } - }; - - template< - typename T, typename H, typename C, typename A, bool IsMultihash - > - struct KeysetImpl: detail::Hashtable, - T, KeysetKey, T, H, C, A, IsMultihash - > { - private: - using Base = detail::Hashtable, - T, KeysetKey, T, H, C, A, IsMultihash - >; - - public: - using Key = KeysetKey; - using Mapped = T; - using Size = size_t; - using Difference = ptrdiff_t; - using Hasher = H; - using KeyEqual = C; - using Value = T; - using Reference = Value &; - using Pointer = AllocatorPointer; - using ConstPointer = AllocatorConstPointer; - using Range = HashRange; - using ConstRange = HashRange; - using LocalRange = BucketRange; - using ConstLocalRange = BucketRange; - using Allocator = A; - - explicit KeysetImpl( - Size size, H const &hf = H(), C const &eqf = C(), - A const &alloc = A() - ): Base(size, hf, eqf, alloc) {} - - KeysetImpl(): KeysetImpl(0) {} - explicit KeysetImpl(A const &alloc): KeysetImpl(0, H(), C(), alloc) {} - - KeysetImpl(Size size, A const &alloc): - KeysetImpl(size, H(), C(), alloc) - {} - KeysetImpl(Size size, H const &hf, A const &alloc): - KeysetImpl(size, hf, C(), alloc) - {} - - KeysetImpl(KeysetImpl const &m): - Base(m, allocator_container_copy(m.get_alloc())) - {} - - KeysetImpl(KeysetImpl const &m, A const &alloc): Base(m, alloc) {} - - KeysetImpl(KeysetImpl &&m): Base(std::move(m)) {} - KeysetImpl(KeysetImpl &&m, A const &alloc): Base(std::move(m), alloc) {} - - template && IsConvertible, Value> - >> - KeysetImpl( - R range, Size size = 0, H const &hf = H(), - C const &eqf = C(), A const &alloc = A() - ): - Base(size ? size : detail::estimate_hrsize(range), hf, eqf, alloc) - { - for (; !range.empty(); range.pop_front()) { - Base::emplace(range.front()); - } - Base::rehash_up(); - } - - template - KeysetImpl(R range, Size size, A const &alloc): - KeysetImpl(range, size, H(), C(), alloc) - {} - - template - KeysetImpl(R range, Size size, H const &hf, A const &alloc): - KeysetImpl(range, size, hf, C(), alloc) - {} - - KeysetImpl( - std::initializer_list init, Size size = 0, - H const &hf = H(), C const &eqf = C(), A const &alloc = A() - ): - KeysetImpl(iter(init), size, hf, eqf, alloc) - {} - - KeysetImpl(std::initializer_list init, Size size, A const &alloc): - KeysetImpl(iter(init), size, H(), C(), alloc) - {} - - KeysetImpl( - std::initializer_list init, Size size, H const &hf, A const &alloc - ): - KeysetImpl(iter(init), size, hf, C(), alloc) - {} - - KeysetImpl &operator=(KeysetImpl const &m) { - Base::operator=(m); - return *this; - } - - KeysetImpl &operator=(KeysetImpl &&m) { - Base::operator=(std::move(m)); - return *this; - } - - template && IsConvertible, Value> - >> - KeysetImpl &operator=(R range) { - Base::assign_range(range); - return *this; - } - - KeysetImpl &operator=(std::initializer_list il) { - Base::assign_init(il); - return *this; - } - - T *at(Key const &key) { - static_assert(!IsMultihash, "at() only allowed on regular keysets"); - return Base::access(key); - } - T const *at(Key const &key) const { - static_assert(!IsMultihash, "at() only allowed on regular keysets"); - return Base::access(key); - } - - T &operator[](Key const &key) { - static_assert(!IsMultihash, "operator[] only allowed on regular keysets"); - return Base::access_or_insert(key); - } - T &operator[](Key &&key) { - static_assert(!IsMultihash, "operator[] only allowed on regular keysets"); - return Base::access_or_insert(std::move(key)); - } - - void swap(KeysetImpl &v) { - Base::swap(v); - } - }; -} - -template< - typename T, - typename H = std::hash>, - typename C = EqualWithCstr>, - typename A = Allocator -> -using Keyset = detail::KeysetImpl; - -template -inline void swap(Keyset &a, Keyset &b) { - a.swap(b); -} - -template< - typename T, - typename H = std::hash>, - typename C = EqualWithCstr>, - typename A = Allocator -> -using Multikeyset = detail::KeysetImpl; - -template -inline void swap(Multikeyset &a, Multikeyset &b) { - a.swap(b); -} - -} /* namespace ostd */ - -#endif diff --git a/ostd/map.hh b/ostd/map.hh deleted file mode 100644 index 65d9747..0000000 --- a/ostd/map.hh +++ /dev/null @@ -1,215 +0,0 @@ -/* Associative array for OctaSTD. Implemented as a hash table. - * - * This file is part of OctaSTD. See COPYING.md for futher information. - */ - -#ifndef OSTD_MAP_HH -#define OSTD_MAP_HH - -#include - -#include "ostd/types.hh" -#include "ostd/utility.hh" -#include "ostd/memory.hh" -#include "ostd/functional.hh" -#include "ostd/initializer_list.hh" - -#include "ostd/internal/hashtable.hh" - -namespace ostd { - -namespace detail { - template struct MapBase { - using Element = std::pair; - - static inline K const &get_key(Element &e) { - return e.first; - } - static inline T &get_data(Element &e) { - return e.second; - } - template - static inline void set_key(Element &e, U &&key, A &alloc) { - allocator_destroy(alloc, &e); - allocator_construct(alloc, &e, std::forward(key), std::move(T())); - } - static inline void swap_elem(Element &a, Element &b) { - using std::swap; - swap(const_cast(a.first), const_cast(b.first)); - swap(a.second, b.second); - } - }; - - template< - typename K, typename T, typename H, - typename C, typename A, bool IsMultihash - > - struct MapImpl: detail::Hashtable, - std::pair, K, T, H, C, A, IsMultihash - > { - private: - using Base = detail::Hashtable, - std::pair, K, T, H, C, A, IsMultihash - >; - - public: - using Key = K; - using Mapped = T; - using Size = size_t; - using Difference = ptrdiff_t; - using Hasher = H; - using KeyEqual = C; - using Value = std::pair; - using Reference = Value &; - using Pointer = AllocatorPointer; - using ConstPointer = AllocatorConstPointer; - using Range = HashRange>; - using ConstRange = HashRange const>; - using LocalRange = BucketRange>; - using ConstLocalRange = BucketRange const>; - using Allocator = A; - - explicit MapImpl( - Size size, H const &hf = H(), - C const &eqf = C(), A const &alloc = A() - ): - Base(size, hf, eqf, alloc) - {} - - MapImpl(): MapImpl(0) {} - explicit MapImpl(A const &alloc): MapImpl(0, H(), C(), alloc) {} - - MapImpl(Size size, A const &alloc): - MapImpl(size, H(), C(), alloc) - {} - MapImpl(Size size, H const &hf, A const &alloc): - MapImpl(size, hf, C(), alloc) - {} - - MapImpl(MapImpl const &m): - Base(m, allocator_container_copy(m.get_alloc())) - {} - - MapImpl(MapImpl const &m, A const &alloc): Base(m, alloc) {} - - MapImpl(MapImpl &&m): Base(std::move(m)) {} - MapImpl(MapImpl &&m, A const &alloc): Base(std::move(m), alloc) {} - - template && IsConvertible, Value> - >> - MapImpl( - R range, Size size = 0, H const &hf = H(), - C const &eqf = C(), A const &alloc = A() - ): - Base(size ? size : detail::estimate_hrsize(range), hf, eqf, alloc) - { - for (; !range.empty(); range.pop_front()) { - Base::emplace(range.front()); - } - Base::rehash_up(); - } - - template - MapImpl(R range, Size size, A const &alloc): - MapImpl(range, size, H(), C(), alloc) - {} - - template - MapImpl(R range, Size size, H const &hf, A const &alloc): - MapImpl(range, size, hf, C(), alloc) - {} - - MapImpl( - std::initializer_list init, Size size = 0, - H const &hf = H(), C const &eqf = C(), A const &alloc = A() - ): - MapImpl(iter(init), size, hf, eqf, alloc) - {} - - MapImpl(std::initializer_list init, Size size, A const &alloc): - MapImpl(iter(init), size, H(), C(), alloc) - {} - - MapImpl( - std::initializer_list init, Size size, H const &hf, A const &alloc - ): - MapImpl(iter(init), size, hf, C(), alloc) - {} - - MapImpl &operator=(MapImpl const &m) { - Base::operator=(m); - return *this; - } - - MapImpl &operator=(MapImpl &&m) { - Base::operator=(std::move(m)); - return *this; - } - - template && IsConvertible, Value> - >> - MapImpl &operator=(R range) { - Base::assign_range(range); - return *this; - } - - MapImpl &operator=(std::initializer_list il) { - Base::assign_init(il); - return *this; - } - - T *at(K const &key) { - static_assert(!IsMultihash, "at() only allowed on regular maps"); - return Base::access(key); - } - T const *at(K const &key) const { - static_assert(!IsMultihash, "at() only allowed on regular maps"); - return Base::access(key); - } - - T &operator[](K const &key) { - static_assert(!IsMultihash, "operator[] only allowed on regular maps"); - return Base::access_or_insert(key); - } - T &operator[](K &&key) { - static_assert(!IsMultihash, "operator[] only allowed on regular maps"); - return Base::access_or_insert(std::move(key)); - } - - void swap(MapImpl &v) { - Base::swap(v); - } - }; -} - -template< - typename K, typename T, - typename H = std::hash, - typename C = EqualWithCstr, - typename A = Allocator> -> -using Map = detail::MapImpl; - -template -inline void swap(Map &a, Map &b) { - a.swap(b); -} - -template< - typename K, typename T, - typename H = std::hash, - typename C = EqualWithCstr, - typename A = Allocator> -> -using Multimap = detail::MapImpl; - -template -inline void swap(Multimap &a, Multimap &b) { - a.swap(b); -} - -} /* namespace ostd */ - -#endif diff --git a/ostd/set.hh b/ostd/set.hh deleted file mode 100644 index b7f1476..0000000 --- a/ostd/set.hh +++ /dev/null @@ -1,186 +0,0 @@ -/* A set container for OctaSTD. Implemented as a hash table. - * - * This file is part of OctaSTD. See COPYING.md for futher information. - */ - -#ifndef OSTD_SET_HH -#define OSTD_SET_HH - -#include "ostd/types.hh" -#include "ostd/utility.hh" -#include "ostd/memory.hh" -#include "ostd/functional.hh" -#include "ostd/initializer_list.hh" - -#include "ostd/internal/hashtable.hh" - -namespace ostd { - -namespace detail { - template - struct SetBase { - static inline T const &get_key(T const &e) { - return e; - } - static inline T &get_data(T &e) { - return e; - } - template - static inline void set_key(T &, U const &, A &) {} - static inline void swap_elem(T &a, T &b) { - using std::swap; - swap(a, b); - } - }; - - template - struct SetImpl: detail::Hashtable< - detail::SetBase, T, T, T, H, C, A, IsMultihash - > { - private: - using Base = detail::Hashtable< - detail::SetBase, T, T, T, H, C, A, IsMultihash - >; - - public: - using Key = T; - using Size = size_t; - using Difference = ptrdiff_t; - using Hasher = H; - using KeyEqual = C; - using Value = T; - using Reference = Value &; - using Pointer = AllocatorPointer; - using ConstPointer = AllocatorConstPointer; - using Range = HashRange; - using ConstRange = HashRange; - using LocalRange = BucketRange; - using ConstLocalRange = BucketRange; - using Allocator = A; - - explicit SetImpl( - Size size, H const &hf = H(), - C const &eqf = C(), A const &alloc = A() - ): - Base(size, hf, eqf, alloc) - {} - - SetImpl(): SetImpl(0) {} - explicit SetImpl(A const &alloc): SetImpl(0, H(), C(), alloc) {} - - SetImpl(Size size, A const &alloc): - SetImpl(size, H(), C(), alloc) - {} - SetImpl(Size size, H const &hf, A const &alloc): - SetImpl(size, hf, C(), alloc) - {} - - SetImpl(SetImpl const &m): - Base(m, allocator_container_copy(m.get_alloc())) - {} - - SetImpl(SetImpl const &m, A const &alloc): Base(m, alloc) {} - - SetImpl(SetImpl &&m): Base(std::move(m)) {} - SetImpl(SetImpl &&m, A const &alloc): Base(std::move(m), alloc) {} - - template && IsConvertible, Value> - >> - SetImpl( - R range, Size size = 0, H const &hf = H(), - C const &eqf = C(), A const &alloc = A() - ): - Base(size ? size : detail::estimate_hrsize(range), hf, eqf, alloc) - { - for (; !range.empty(); range.pop_front()) { - Base::emplace(range.front()); - } - Base::rehash_up(); - } - - template - SetImpl(R range, Size size, A const &alloc): - SetImpl(range, size, H(), C(), alloc) - {} - - template - SetImpl(R range, Size size, H const &hf, A const &alloc): - SetImpl(range, size, hf, C(), alloc) - {} - - SetImpl( - std::initializer_list init, Size size = 0, - H const &hf = H(), C const &eqf = C(), A const &alloc = A() - ): - SetImpl(iter(init), size, hf, eqf, alloc) - {} - - SetImpl(std::initializer_list init, Size size, A const &alloc): - SetImpl(iter(init), size, H(), C(), alloc) - {} - - SetImpl( - std::initializer_list init, Size size, H const &hf, A const &alloc - ): - SetImpl(iter(init), size, hf, C(), alloc) - {} - - SetImpl &operator=(SetImpl const &m) { - Base::operator=(m); - return *this; - } - - SetImpl &operator=(SetImpl &&m) { - Base::operator=(std::move(m)); - return *this; - } - - template && IsConvertible, Value> - >> - SetImpl &operator=(R range) { - Base::assign_range(range); - return *this; - } - - SetImpl &operator=(std::initializer_list il) { - Base::assign_init(il); - return *this; - } - - void swap(SetImpl &v) { - Base::swap(v); - } - }; -} - -template< - typename T, - typename H = std::hash, - typename C = EqualWithCstr, - typename A = Allocator -> -using Set = detail::SetImpl; - -template -inline void swap(Set &a, Set &b) { - a.swap(b); -} - -template< - typename T, - typename H = std::hash, - typename C = EqualWithCstr, - typename A = Allocator -> -using Multiset = detail::SetImpl; - -template -inline void swap(Multiset &a, Multiset &b) { - a.swap(b); -} - -} /* namespace ostd */ - -#endif