Zen C++ Libraries
Zero-dependency re-usable components for C++
Loading...
Searching...
No Matches
hash_index.hpp
1#ifndef ZEN_HASHINDEX_HPP
2#define ZEN_HASHINDEX_HPP
3
4#include <type_traits>
5#include <vector>
6
7#include "zen/config.hpp"
8#include "zen/hash.hpp"
9
10ZEN_NAMESPACE_START
11
12template<typename T, typename KeyT>
13using hash_bucket = std::vector<T>;
14
15template<
16 typename T,
17 typename KeyT,
18 typename ReferenceT,
19 typename BucketT
20>
21class hash_index_iterator {
22
23 BucketT& buckets;
24 std::size_t bucket_index;
25 std::size_t element_index;
26
27public:
28
29 using value_type = T;
30 using reference = ReferenceT;
31 using pointer = value_type*;
32
33 inline hash_index_iterator(
34 BucketT& buckets,
35 std::size_t bucket_index,
36 std::size_t element_index
37 ): buckets(buckets),
38 bucket_index(bucket_index),
39 element_index(element_index) {}
40
41 value_type operator*() {
42 return buckets[bucket_index][element_index];
43 }
44
45 void operator++() {
46 for (;;) {
47 if (bucket_index >= buckets.size()) {
48 break;
49 }
50 if (element_index >= buckets[bucket_index].size()) {
51 ++bucket_index;
52 } else {
53 ++element_index;
54 }
55 if (element_index < buckets[bucket_index].size()) {
56 break;
57 }
58 }
59 }
60
61 void operator--() {
62 for (;;) {
63 if (element_index == 0) {
64 --bucket_index;
65 element_index = buckets[bucket_index].size();
66 } else {
67 --element_index;
68 }
69 if (element_index < buckets[bucket_index].size()) {
70 break;
71 }
72 }
73 }
74
75 bool operator==(const hash_index_iterator& other) const {
76 return bucket_index == other.bucket_index
77 && element_index == other.element_index;
78 }
79
80};
81
82template<
83 typename T,
84 typename KeyT,
85 typename ReferenceT,
86 typename BucketT
87>
88class const_hash_index_iterator : hash_index_iterator<const T, KeyT, const ReferenceT, const BucketT> {
89
90};
91
92template<typename T, typename KeyT = T>
93class hash_index {
94
95 using bucket = hash_bucket<T, KeyT>;
96
97 std::hash<KeyT> hasher;
98
99 std::vector<bucket> buckets;
100
101 const KeyT& get_key(const T& element) {
102 // FIXME This needs to be generalized
103 return element->first;
104 }
105
106public:
107
108 hash_index() {
109 buckets.reserve(256);
110 for (std::size_t i = 0; i < 256; ++i) {
111 buckets.push_back(bucket {});
112 }
113 }
114
115 using value_type = T;
116 using reference = T&;
117
120
121 void insert(T element) {
122 const auto& key = get_key(element);
123 const auto h = hasher(key);
124 auto& bucket = buckets[h % buckets.size()];
125 bucket.push_back(element);
126 }
127
128 iterator lookup(const KeyT& key) {
129 const auto h = hasher(key);
130 const auto bucket_index = h % buckets.size();
131 auto& bucket = buckets[bucket_index];
132 std::size_t i = 0;
133 const auto end = bucket.end();
134 for (auto it = bucket.begin(); it != end; ++it, ++i) {
135 if (get_key(*it) == key) {
136 return hash_index_iterator(bucket, bucket_index, i);
137 }
138 }
139 return end();
140 }
141
142 const_iterator lookup(const KeyT& key) const {
143 const auto h = hasher(key);
144 const auto bucket_index = h % buckets.size();
145 auto& bucket = buckets[bucket_index];
146 std::size_t i = 0;
147 const auto end = bucket.end();
148 for (auto it = bucket.begin(); it != end; ++it, ++i) {
149 if (get_key(*it) == key) {
150 return const_hash_index_iterator(bucket, bucket_index, i);
151 }
152 }
153 return cend();
154 }
155
156 iterator begin() noexcept {
157 return iterator(buckets, 0, 0);
158 }
159
160 iterator end() noexcept {
161 return iterator(buckets, buckets.size(), 0);
162 }
163
164 const_iterator begin() const noexcept {
165 return cbegin();
166 }
167
168 const_iterator end() const noexcept {
169 return cend();
170 }
171
172 const_iterator cbegin() const noexcept {
173 return const_iterator(buckets, 0, 0);
174 }
175
176 const_iterator cend() const noexcept {
177 return const_iterator(buckets, buckets.size(), 0);
178 }
179
180};
181
182ZEN_NAMESPACE_END
183
184#endif // of #ifndef ZEN_HASHINDEX_HPP
Definition hash_index.hpp:88
Definition concepts.hpp:45