From 4a86120a8f0140c4261681c6f38d42a992da02b9 Mon Sep 17 00:00:00 2001 From: q66 Date: Tue, 16 Jun 2015 22:19:20 +0100 Subject: [PATCH] add octa::Set (hash table set) --- octa/set.h | 221 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 221 insertions(+) create mode 100644 octa/set.h diff --git a/octa/set.h b/octa/set.h new file mode 100644 index 0000000..140d6d7 --- /dev/null +++ b/octa/set.h @@ -0,0 +1,221 @@ +/* A set container for OctaSTD. Implemented as a hash table. + * + * This file is part of OctaSTD. See COPYING.md for futher information. + */ + +#ifndef OCTA_SET_H +#define OCTA_SET_H + +#include "octa/types.h" +#include "octa/utility.h" +#include "octa/memory.h" +#include "octa/functional.h" +#include "octa/initializer_list.h" + +#include "octa/internal/hashtable.h" + +namespace octa { + +namespace detail { + template struct SetBase { + static inline const T &get_key(const T &e) { + return e; + } + static inline T &get_data(T &e) { + return e; + } + template + static inline void set_key(T &, const U &, A &) {} + static inline void swap_elem(T &a, T &b) { octa::swap(a, b); } + }; +} + +template< + typename T, + typename H = octa::ToHash, + typename C = octa::Equal, + typename A = octa::Allocator +> struct Set { +private: + using Base = octa::detail::Hashtable< + octa::detail::SetBase, T, T, T, H, C, A + >; + Base p_table; + + template + octa::Size estimate_rsize(const R &range, + octa::EnableIf::value, bool> = true + ) { + return range.size(); + } + + template + octa::Size estimate_rsize(const R &, + octa::EnableIf::value, bool> = true + ) { + /* we have no idea how big the range actually is */ + return 16; + } + +public: + + using Key = T; + using Size = octa::Size; + using Difference = octa::Ptrdiff; + using Hasher = H; + using KeyEqual = C; + using Value = T; + using Reference = Value &; + using Pointer = octa::AllocatorPointer; + using ConstPointer = octa::AllocatorConstPointer; + using Range = octa::HashRange; + using ConstRange = octa::HashRange; + using LocalRange = octa::BucketRange; + using ConstLocalRange = octa::BucketRange; + using Allocator = A; + + explicit Set(octa::Size size, const H &hf = H(), + const C &eqf = C(), const A &alloc = A() + ): p_table(size, hf, eqf, alloc) {} + + Set(): Set(0) {} + explicit Set(const A &alloc): Set(0, H(), C(), alloc) {} + + Set(octa::Size size, const A &alloc): Set(size, H(), C(), alloc) {} + Set(octa::Size size, const H &hf, const A &alloc): Set(size, hf, C(), alloc) {} + + Set(const Set &m): p_table(m.p_table, + octa::allocator_container_copy(m.p_table.get_alloc())) {} + + Set(const Set &m, const A &alloc): p_table(m.p_table, alloc) {} + + Set(Set &&m): p_table(octa::move(m.p_table)) {} + Set(Set &&m, const A &alloc): p_table(octa::move(m.p_table), alloc) {} + + template + Set(R range, octa::Size size = 0, const H &hf = H(), + const C &eqf = C(), const A &alloc = A(), + octa::EnableIf< + octa::IsInputRange::value && + octa::IsConvertible, Value>::value, + bool + > = true + ): p_table(size ? size : estimate_rsize(range), hf, eqf, alloc) { + for (; !range.empty(); range.pop_front()) + emplace(range.front()); + p_table.rehash_up(); + } + + template + Set(R range, octa::Size size, const A &alloc) + : Set(range, size, H(), C(), alloc) {} + + template + Set(R range, octa::Size size, const H &hf, const A &alloc) + : Set(range, size, hf, C(), alloc) {} + + Set(octa::InitializerList init, octa::Size size = 0, + const H &hf = H(), const C &eqf = C(), const A &alloc = A() + ): Set(octa::each(init), size, hf, eqf, alloc) {} + + Set(octa::InitializerList init, octa::Size size, const A &alloc) + : Set(octa::each(init), size, H(), C(), alloc) {} + + Set(octa::InitializerList init, octa::Size size, const H &hf, + const A &alloc + ): Set(octa::each(init), size, hf, C(), alloc) {} + + Set &operator=(const Set &m) { + p_table = m.p_table; + return *this; + } + + Set &operator=(Set &&m) { + p_table = octa::move(m.p_table); + return *this; + } + + template + octa::EnableIf< + octa::IsInputRange::value && + octa::IsConvertible, Value>::value, + Set & + > operator=(R range) { + clear(); + p_table.reserve_at_least(estimate_rsize(range)); + for (; !range.empty(); range.pop_front()) + emplace(range.front()); + p_table.rehash_up(); + return *this; + } + + Set &operator=(InitializerList il) { + const Value *beg = il.begin(), *end = il.end(); + clear(); + p_table.reserve_at_least(end - beg); + while (beg != end) + emplace(*beg++); + return *this; + } + + bool empty() const { return p_table.empty(); } + octa::Size size() const { return p_table.size(); } + octa::Size max_size() const { return p_table.max_size(); } + + octa::Size bucket_count() const { return p_table.bucket_count(); } + octa::Size max_bucket_count() const { return p_table.max_bucket_count(); } + + octa::Size bucket(const T &key) const { return p_table.bucket(key); } + octa::Size bucket_size(octa::Size n) const { return p_table.bucket_size(n); } + + void clear() { p_table.clear(); } + + A get_allocator() const { + return p_table.get_alloc(); + } + + template + octa::Pair emplace(Args &&...args) { + return p_table.emplace(octa::forward(args)...); + } + + octa::Size erase(const T &key) { + if (p_table.remove(key)) return 1; + return 0; + } + + octa::Size count(const T &key) { + octa::Size h; + T *v = p_table.access_base(key, h); + if (v) return 1; + return 0; + } + + float load_factor() const { return p_table.load_factor(); } + float max_load_factor() const { return p_table.max_load_factor(); } + void max_load_factor(float lf) { p_table.max_load_factor(lf); } + + void rehash(octa::Size count) { + p_table.rehash(count); + } + + void reserve(octa::Size count) { + p_table.reserve(count); + } + + Range each() { return p_table.each(); } + ConstRange each() const { return p_table.each(); } + ConstRange ceach() const { return p_table.ceach(); } + + LocalRange each(octa::Size n) { return p_table.each(n); } + ConstLocalRange each(octa::Size n) const { return p_table.each(n); } + ConstLocalRange ceach(octa::Size n) const { return p_table.each(n); } + + void swap(Set &v) { + octa::swap(p_table, v.p_table); + } +}; + +} /* namespace detail */ + +#endif \ No newline at end of file