diff --git a/ostd/keyset.hh b/ostd/keyset.hh new file mode 100644 index 0000000..6108f1d --- /dev/null +++ b/ostd/keyset.hh @@ -0,0 +1,178 @@ +/* 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 KeysetKey = const Decay().get_key())>; + + template struct KeysetBase { + using Key = KeysetKey; + static inline const Key &get_key(const T &e) { + return e.get_key(); + } + 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) { swap_adl(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 = ostd::Size; + using Difference = Ptrdiff; + 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, const H &hf = H(), + const C &eqf = C(), const A &alloc = A() + ): Base(size, hf, eqf, alloc) {} + + KeysetImpl(): KeysetImpl(0) {} + explicit KeysetImpl(const A &alloc): KeysetImpl(0, H(), C(), alloc) {} + + KeysetImpl(Size size, const A &alloc): + KeysetImpl(size, H(), C(), alloc) {} + KeysetImpl(Size size, const H &hf, const A &alloc): + KeysetImpl(size, hf, C(), alloc) {} + + KeysetImpl(const KeysetImpl &m): Base(m, + allocator_container_copy(m.get_alloc())) {} + + KeysetImpl(const KeysetImpl &m, const A &alloc): Base(m, alloc) {} + + KeysetImpl(KeysetImpl &&m): Base(move(m)) {} + KeysetImpl(KeysetImpl &&m, const A &alloc): Base(move(m), alloc) {} + + template::value && IsConvertible, + Value>::value + >> KeysetImpl(R range, Size size = 0, const H &hf = H(), + const C &eqf = C(), const A &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, const A &alloc) + : KeysetImpl(range, size, H(), C(), alloc) {} + + template + KeysetImpl(R range, Size size, const H &hf, const A &alloc) + : KeysetImpl(range, size, hf, C(), alloc) {} + + KeysetImpl(InitializerList init, Size size = 0, + const H &hf = H(), const C &eqf = C(), const A &alloc = A() + ): KeysetImpl(iter(init), size, hf, eqf, alloc) {} + + KeysetImpl(InitializerList init, Size size, const A &alloc) + : KeysetImpl(iter(init), size, H(), C(), alloc) {} + + KeysetImpl(InitializerList init, Size size, const H &hf, + const A &alloc + ): KeysetImpl(iter(init), size, hf, C(), alloc) {} + + KeysetImpl &operator=(const KeysetImpl &m) { + Base::operator=(m); + return *this; + } + + KeysetImpl &operator=(KeysetImpl &&m) { + Base::operator=(move(m)); + return *this; + } + + template::value && + IsConvertible, Value>::value + >> KeysetImpl &operator=(R range) { + Base::assign_range(range); + return *this; + } + + KeysetImpl &operator=(InitializerList il) { + Base::assign_init(il); + return *this; + } + + T *at(const Key &key) { + static_assert(!IsMultihash, "at() only allowed on regular keysets"); + return Base::access(key); + } + const T *at(const Key &key) const { + static_assert(!IsMultihash, "at() only allowed on regular keysets"); + return Base::access(key); + } + + T &operator[](const Key &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(move(key)); + } + + void swap(KeysetImpl &v) { + Base::swap(v); + } + }; +} + +template< + typename T, + typename H = ToHash>, + typename C = EqualWithCstr>, + typename A = Allocator +> using Keyset = detail::KeysetImpl; + +template< + typename T, + typename H = ToHash>, + typename C = EqualWithCstr>, + typename A = Allocator +> using Multikeyset = detail::KeysetImpl; + +} /* namespace ostd */ + +#endif \ No newline at end of file