initial range interface for hashtables

master
Daniel Kolesa 2015-06-14 04:32:01 +01:00
parent c9e3ebd773
commit fa7bf1d3db
2 changed files with 83 additions and 1 deletions

View File

@ -11,9 +11,12 @@
#include "octa/types.h"
#include "octa/utility.h"
#include "octa/memory.h"
#include "octa/range.h"
namespace octa {
template<typename T> 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<AllocPair, FuncPair>;
using DataPair = octa::detail::CompressedPair<Chain **, FAPair>;
using Range = octa::HashRange<E>;
using ConstRange = octa::HashRange<const E>;
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<typename T>
struct HashRange: octa::InputRange<HashRange<T>, 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

View File

@ -17,7 +17,7 @@ namespace octa {
namespace detail {
template<typename K, typename T> struct MapBase {
typedef octa::Pair<const K, T> Element;
using Element = octa::Pair<const K, T>;
static inline const K &get_key(Element &e) {
return e.first;
@ -56,6 +56,8 @@ public:
using Reference = Value &;
using Pointer = octa::AllocatorPointer<A>;
using ConstPointer = octa::AllocatorConstPointer<A>;
using Range = octa::HashRange<octa::Pair<const K, T>>;
using ConstRange = octa::HashRange<const octa::Pair<const K, T>>;
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);
}