/* Associative array for OctaSTD. Implemented as a hash table. * * This file is part of OctaSTD. See COPYING.md for futher information. */ #ifndef OCTA_MAP_HH #define OCTA_MAP_HH #include "octa/types.hh" #include "octa/utility.hh" #include "octa/memory.hh" #include "octa/functional.hh" #include "octa/initializer_list.hh" #include "octa/internal/hashtable.hh" namespace octa { namespace detail { template struct MapBase { using Element = octa::Pair; static inline const K &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) { octa::allocator_destroy(alloc, &e); octa::allocator_construct(alloc, &e, octa::forward(key), octa::move(T())); } static inline void swap_elem(Element &a, Element &b) { octa::swap(*((K *)&a.first), *((K *)&b.first)); octa::swap(*((T *)&a.second), *((T *)&b.second)); } }; template< typename K, typename T, typename H, typename C, typename A, bool IsMultihash > struct MapImpl: octa::detail::Hashtable< octa::detail::MapBase, octa::Pair, K, T, H, C, A, IsMultihash > { private: using Base = octa::detail::Hashtable< octa::detail::MapBase, octa::Pair, K, T, H, C, A, IsMultihash >; public: using Key = K; using Mapped = T; using Size = octa::Size; using Difference = octa::Ptrdiff; using Hasher = H; using KeyEqual = C; using Value = octa::Pair; 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 MapImpl(octa::Size size, const H &hf = H(), const C &eqf = C(), const A &alloc = A() ): Base(size, hf, eqf, alloc) {} MapImpl(): MapImpl(0) {} explicit MapImpl(const A &alloc): MapImpl(0, H(), C(), alloc) {} MapImpl(octa::Size size, const A &alloc): MapImpl(size, H(), C(), alloc) {} MapImpl(octa::Size size, const H &hf, const A &alloc): MapImpl(size, hf, C(), alloc) {} MapImpl(const MapImpl &m): Base(m, octa::allocator_container_copy(m.get_alloc())) {} MapImpl(const MapImpl &m, const A &alloc): Base(m, alloc) {} MapImpl(MapImpl &&m): Base(octa::move(m)) {} MapImpl(MapImpl &&m, const A &alloc): Base(octa::move(m), alloc) {} template::value && octa::IsConvertible, Value>::value >> MapImpl(R range, octa::Size size = 0, const H &hf = H(), const C &eqf = C(), const A &alloc = A() ): Base(size ? size : octa::detail::estimate_hrsize(range), hf, eqf, alloc) { for (; !range.empty(); range.pop_front()) Base::emplace(range.front()); Base::rehash_up(); } template MapImpl(R range, octa::Size size, const A &alloc) : MapImpl(range, size, H(), C(), alloc) {} template MapImpl(R range, octa::Size size, const H &hf, const A &alloc) : MapImpl(range, size, hf, C(), alloc) {} MapImpl(octa::InitializerList init, octa::Size size = 0, const H &hf = H(), const C &eqf = C(), const A &alloc = A() ): MapImpl(octa::iter(init), size, hf, eqf, alloc) {} MapImpl(octa::InitializerList init, octa::Size size, const A &alloc) : MapImpl(octa::iter(init), size, H(), C(), alloc) {} MapImpl(octa::InitializerList init, octa::Size size, const H &hf, const A &alloc ): MapImpl(octa::iter(init), size, hf, C(), alloc) {} MapImpl &operator=(const MapImpl &m) { Base::operator=(m); return *this; } MapImpl &operator=(MapImpl &&m) { Base::operator=(octa::move(m)); return *this; } template::value && octa::IsConvertible, Value>::value >> MapImpl &operator=(R range) { Base::assign_range(range); return *this; } MapImpl &operator=(InitializerList il) { Base::assign_init(il); return *this; } T &at(const K &key) { static_assert(!IsMultihash, "at() only allowed on regular maps"); return Base::access(key); } const T &at(const K &key) const { static_assert(!IsMultihash, "at() only allowed on regular maps"); return Base::access(key); } T &operator[](const K &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(octa::move(key)); } void swap(MapImpl &v) { Base::swap(v); } }; } template< typename K, typename T, typename H = octa::ToHash, typename C = octa::Equal, typename A = octa::Allocator> > using Map = octa::detail::MapImpl; template< typename K, typename T, typename H = octa::ToHash, typename C = octa::Equal, typename A = octa::Allocator> > using Multimap = octa::detail::MapImpl; } /* namespace octa */ #endif