diff --git a/octa/internal/hashtable.h b/octa/internal/hashtable.h index 5b22368..3cdc22a 100644 --- a/octa/internal/hashtable.h +++ b/octa/internal/hashtable.h @@ -11,9 +11,12 @@ #include "octa/types.h" #include "octa/utility.h" #include "octa/memory.h" +#include "octa/range.h" namespace octa { +template struct HashRange; + namespace detail { template< typename B, /* contains methods specific to each ht type */ @@ -49,6 +52,9 @@ namespace detail { using FAPair = octa::detail::CompressedPair; using DataPair = octa::detail::CompressedPair; + using Range = octa::HashRange; + using ConstRange = octa::HashRange; + DataPair p_data; float p_maxlf; @@ -170,6 +176,16 @@ namespace detail { octa::Size bucket_count() const { return p_size; } octa::Size max_bucket_count() const { return Size(~0) / sizeof(Chain); } + Range each() { + return Range(p_data.first(), bucket_count()); + } + ConstRange each() const { + return ConstRange(p_data.first(), bucket_count()); + } + ConstRange ceach() const { + return ConstRange(p_data.first(), bucket_count()); + } + void swap(Hashtable &h) { octa::swap(p_size, h.p_size); octa::swap(p_len, h.p_len); @@ -180,6 +196,66 @@ namespace detail { }; } /* namespace detail */ +template +struct HashRange: octa::InputRange, octa::ForwardRangeTag, T> { +private: + struct Chain { + T value; + Chain *next; + }; + + Chain **p_chains; + Chain *p_node; + octa::Size p_num; + + void advance() { + while (p_num > 0 && !p_chains[0]) { + --p_num; + ++p_chains; + } + if (p_num > 0) { + p_node = p_chains[0]; + --p_num; + ++p_chains; + } else { + p_node = nullptr; + } + } +public: + HashRange(): p_chains(), p_num(0) {} + HashRange(void *ch, octa::Size n): p_chains((Chain **)ch), p_num(n) { + advance(); + } + HashRange(const HashRange &v): p_chains(v.p_chains), p_node(v.p_node), + p_num(v.p_num) {} + + HashRange &operator=(const HashRange &v) { + p_chains = v.p_chains; + p_node = v.p_node; + p_num = v.p_num; + return *this; + } + + bool empty() const { return !p_node && p_num <= 0; } + + bool pop_front() { + if (empty()) return false; + if (p_node->next) { + p_node = p_node->next; + return true; + } + p_node = nullptr; + advance(); + return true; + } + + bool equals_front(const HashRange &v) const { + return p_node == v.p_node; + } + + T &front() const { return p_node->value; } +}; + } /* namespace octa */ #endif \ No newline at end of file diff --git a/octa/map.h b/octa/map.h index 25f97f9..32b21a2 100644 --- a/octa/map.h +++ b/octa/map.h @@ -17,7 +17,7 @@ namespace octa { namespace detail { template struct MapBase { - typedef octa::Pair Element; + using Element = octa::Pair; static inline const K &get_key(Element &e) { return e.first; @@ -56,6 +56,8 @@ public: using Reference = Value &; using Pointer = octa::AllocatorPointer; using ConstPointer = octa::AllocatorConstPointer; + using Range = octa::HashRange>; + using ConstRange = octa::HashRange>; using Allocator = A; Map(octa::Size size = 1 << 10, const H &hf = H(), const C &eqf = C(), @@ -103,6 +105,10 @@ public: float max_load_factor() const { return p_table.max_load_factor(); } void max_load_factor(float lf) { p_table.max_load_factor(lf); } + Range each() { return p_table.each(); } + ConstRange each() const { return p_table.each(); } + ConstRange ceach() const { return p_table.ceach(); } + void swap(Map &v) { octa::swap(p_table, v.p_table); }