P4C
The P4 Compiler
Loading...
Searching...
No Matches
hvec_map.h
1/*
2Copyright 2023-present Intel
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17#ifndef LIB_HVEC_MAP_H_
18#define LIB_HVEC_MAP_H_
19
20#include <initializer_list>
21#include <tuple>
22#include <vector>
23
24#include "exceptions.h"
25#include "hashvec.h"
26
27template <class KEY, class VAL, class HASH = std::hash<KEY>, class PRED = std::equal_to<KEY>,
28 class ALLOC = std::allocator<std::pair<const KEY, VAL>>>
30 HASH hf; // FIXME -- use empty base optimization for these?
31 PRED eql;
32
33 public:
34 typedef KEY key_type;
35 typedef std::pair<const KEY, VAL> value_type;
36 typedef VAL mapped_type;
37 typedef HASH hasher;
38 typedef PRED key_equal;
39 typedef ALLOC allocator_type;
40
41 typedef typename std::vector<value_type>::pointer pointer;
42 typedef typename std::vector<value_type>::const_pointer const_pointer;
43 typedef typename std::vector<value_type>::reference reference;
44 typedef typename std::vector<value_type>::const_reference const_reference;
45
47
48 explicit hvec_map(size_t icap = 0, const hasher &hf = hasher(),
49 const key_equal &eql = key_equal(),
50 const allocator_type &a = allocator_type())
51 : hash_vector_base(true, false, icap), hf(hf), eql(eql), data(a) {
52 data.reserve(icap);
53 }
54 hvec_map(const hvec_map &) = default;
55 hvec_map(hvec_map &&) = default;
56 hvec_map &operator=(const hvec_map &that) {
57 if (this != std::addressof(that)) {
58 clear();
59 hf = that.hf;
60 eql = that.eql;
61
62 data.reserve(that.size());
63 insert(that.begin(), that.end());
64 }
65
66 return *this;
67 }
68 hvec_map &operator=(hvec_map &&) = default;
69 ~hvec_map() = default;
70 template <class ITER>
71 hvec_map(ITER begin, ITER end, const hasher &hf = hasher(), const key_equal &eql = key_equal(),
72 const allocator_type &a = allocator_type())
73 : hash_vector_base(true, false, end - begin), hf(hf), eql(eql), data(a) {
74 data.reserve(end - begin);
75 for (auto it = begin; it != end; ++it) insert(*it);
76 }
77 hvec_map(std::initializer_list<value_type> il, const hasher &hf = hasher(),
78 const key_equal &eql = key_equal(), const allocator_type &a = allocator_type())
79 : hash_vector_base(true, false, il.size()), hf(hf), eql(eql), data(a) {
80 data.reserve(il.size());
81 for (auto &i : il) insert(i);
82 }
83
84 private:
85 template <class HVM, class VT>
86 class _iter {
87 HVM *self;
88 size_t idx;
89
90 friend class hvec_map;
91 _iter(HVM &s, size_t i) : self(&s), idx(i) {}
92
93 public:
94 using value_type = VT;
95 using difference_type = ssize_t;
96 using pointer = typename HVM::pointer;
97 using reference = typename HVM::reference;
98 using iterator_category = std::bidirectional_iterator_tag;
99 _iter(const _iter &) = default;
100 _iter &operator=(const _iter &a) {
101 self = a.self;
102 idx = a.idx;
103 return *this;
104 }
105 value_type &operator*() const { return self->data[idx]; }
106 value_type *operator->() const { return &self->data[idx]; }
107 _iter &operator++() {
108 do {
109 ++idx;
110 } while (self->erased[idx]);
111 return *this;
112 }
113 _iter &operator--() {
114 do {
115 --idx;
116 } while (self->erased[idx]);
117 return *this;
118 }
119 _iter operator++(int) {
120 auto copy = *this;
121 ++*this;
122 return copy;
123 }
124 _iter operator--(int) {
125 auto copy = *this;
126 --*this;
127 return copy;
128 }
129 bool operator==(const _iter &a) const { return self == a.self && idx == a.idx; }
130 bool operator!=(const _iter &a) const { return self != a.self || idx != a.idx; }
131 operator _iter<const HVM, const VT>() const {
132 return _iter<const HVM, const VT>(*self, idx);
133 }
134 };
135
136 public:
137 typedef _iter<hvec_map, value_type> iterator;
138 typedef _iter<const hvec_map, const value_type> const_iterator;
139 iterator begin() { return iterator(*this, erased.ffz()); }
140 iterator end() { return iterator(*this, data.size()); }
141 const_iterator begin() const { return const_iterator(*this, erased.ffz()); }
142 const_iterator end() const { return const_iterator(*this, data.size()); }
143 const_iterator cbegin() const { return const_iterator(*this, erased.ffz()); }
144 const_iterator cend() const { return const_iterator(*this, data.size()); }
145
146 bool empty() const { return inuse == 0; }
147 size_t size() const { return inuse; }
148 size_t max_size() const { return UINT32_MAX; }
149 bool operator==(const hvec_map &a) const {
150 if (inuse != a.inuse) return false;
151 auto it = begin();
152 for (auto &el : a)
153 if (el != *it++) return false;
154 return true;
155 }
156 bool operator!=(const hvec_map &a) const { return !(*this == a); }
157 void clear() {
158 hash_vector_base::clear();
159 data.clear();
160 }
161
162 iterator find(const KEY &k) {
164 size_t idx = hash_vector_base::find(&k, &cache);
165 return idx ? iterator(*this, idx - 1) : end();
166 }
167 const_iterator find(const KEY &k) const {
169 size_t idx = hash_vector_base::find(&k, &cache);
170 return idx ? const_iterator(*this, idx - 1) : end();
171 }
172 size_t count(const KEY &k) const {
174 size_t idx = hash_vector_base::find(&k, &cache);
175 return idx > 0;
176 }
177
178 // FIXME -- how to do this without duplicating the code for lvalue/rvalue?
179 VAL &operator[](const KEY &k) {
180 size_t idx = hv_insert(&k);
181 if (idx >= data.size()) {
182 data.emplace_back(k, VAL());
183 return data.back().second;
184 } else {
185 if (erased[idx]) {
186 erased[idx] = 0;
187 const_cast<KEY &>(data[idx].first) = k;
188 data[idx].second = VAL();
189 }
190 return data[idx].second;
191 }
192 }
193 VAL &operator[](KEY &&k) {
194 size_t idx = hv_insert(&k);
195 if (idx >= data.size()) {
196 data.emplace_back(std::move(k), VAL());
197 return data.back().second;
198 } else {
199 if (erased[idx]) {
200 erased[idx] = 0;
201 const_cast<KEY &>(data[idx].first) = std::move(k);
202 data[idx].second = VAL();
203 }
204 return data[idx].second;
205 }
206 }
207
208 // FIXME -- how to do this without duplicating the code for lvalue/rvalue?
209 template <typename... VV>
210 std::pair<iterator, bool> emplace(const KEY &k, VV &&...v) {
211 bool new_key = false;
212 size_t idx = hv_insert(&k);
213 if (idx >= data.size()) {
214 idx = data.size();
215 data.emplace_back(std::piecewise_construct_t(), std::forward_as_tuple(k),
216 std::forward_as_tuple(std::forward<VV>(v)...));
217 new_key = true;
218 } else {
219 if ((new_key = erased[idx])) {
220 erased[idx] = 0;
221 const_cast<KEY &>(data[idx].first) = k;
222 data[idx].second = VAL(std::forward<VV>(v)...);
223 } else {
224 data[idx].second = VAL(std::forward<VV>(v)...);
225 }
226 }
227 return std::make_pair(iterator(*this, idx), new_key);
228 }
229 template <typename... VV>
230 std::pair<iterator, bool> emplace(KEY &&k, VV &&...v) {
231 bool new_key = false;
232 size_t idx = hv_insert(&k);
233 if (idx >= data.size()) {
234 idx = data.size();
235 data.emplace_back(std::piecewise_construct_t(), std::forward_as_tuple(std::move(k)),
236 std::forward_as_tuple(std::forward<VV>(v)...));
237 new_key = true;
238 } else if ((new_key = erased[idx])) {
239 erased[idx] = 0;
240 const_cast<KEY &>(data[idx].first) = std::move(k);
241 data[idx].second = VAL(std::forward<VV>(v)...);
242 }
243 return std::make_pair(iterator(*this, idx), new_key);
244 }
245 std::pair<iterator, bool> insert(const value_type &v) {
246 bool new_key = false;
247 size_t idx = hv_insert(&v.first);
248 if (idx >= data.size()) {
249 idx = data.size();
250 data.push_back(v);
251 new_key = true;
252 } else if ((new_key = erased[idx])) {
253 erased[idx] = 0;
254 const_cast<KEY &>(data[idx].first) = v.first;
255 data[idx].second = v.second;
256 }
257 return std::make_pair(iterator(*this, idx), new_key);
258 }
259 template <typename InputIterator>
260 void insert(InputIterator first, InputIterator last) {
261 for (; first != last; ++first) insert(*first);
262 }
263 void insert(std::initializer_list<value_type> vl) { return insert(vl.begin(), vl.end()); }
264 template <class HVM, class VT>
265 _iter<HVM, VT> erase(_iter<HVM, VT> it) {
266 BUG_CHECK(this == it.self, "incorrect iterator for hvec_map::erase");
267 erased[it.idx] = 1;
268 // FIXME -- would be better to call dtor here, but that will cause
269 // problems with the vector when it resized or is destroyed. Could
270 // use raw memory and manual construct instead.
271 const_cast<KEY &>(data[it.idx].first) = KEY();
272 data[it.idx].second = VAL();
273 ++it;
274 --inuse;
275 return it;
276 }
277 size_t erase(const KEY &k) {
278 size_t idx = remove(&k);
279 if (idx + 1 == 0) return 0;
280 if (idx < data.size()) {
281 const_cast<KEY &>(data[idx].first) = KEY();
282 data[idx].second = VAL();
283 }
284 return 1;
285 }
286#ifdef DEBUG
287 using hash_vector_base::dump;
288#endif
289
290 private:
291 std::vector<value_type, ALLOC> data;
292 size_t hashfn(const void *a) const override { return hf(*static_cast<const KEY *>(a)); }
293 bool cmpfn(const void *a, const void *b) const override {
294 return eql(*static_cast<const KEY *>(a), *static_cast<const KEY *>(b));
295 }
296 bool cmpfn(const void *a, size_t b) const override {
297 return eql(*static_cast<const KEY *>(a), data[b].first);
298 }
299 const void *getkey(uint32_t i) const override { return &data[i].first; }
300 void *getval(uint32_t i) override { return &data[i].second; }
301 uint32_t limit() override { return data.size(); }
302 void resizedata(size_t sz) override { data.resize(sz); }
303 void moveentry(size_t to, size_t from) override {
304 // can't just assign, as the keys are const -- need to destruct & construct
305 data[to].~value_type();
306 new (&data[to]) value_type(std::move(data[from]));
307 }
308};
309
310template <class K, class T, class V, class Comp, class Alloc>
311inline V get(const hvec_map<K, V, Comp, Alloc> &m, T key, V def = V()) {
312 auto it = m.find(key);
313 if (it != m.end()) return it->second;
314 return def;
315}
316
317template <class K, class T, class V, class Comp, class Alloc>
318inline V *getref(hvec_map<K, V, Comp, Alloc> &m, T key) {
319 auto it = m.find(key);
320 if (it != m.end()) return &it->second;
321 return 0;
322}
323
324template <class K, class T, class V, class Comp, class Alloc>
325inline const V *getref(const hvec_map<K, V, Comp, Alloc> &m, T key) {
326 auto it = m.find(key);
327 if (it != m.end()) return &it->second;
328 return 0;
329}
330
331template <class K, class T, class V, class Comp, class Alloc>
332inline V get(const hvec_map<K, V, Comp, Alloc> *m, T key, V def = V()) {
333 return m ? get(*m, key, def) : def;
334}
335
336template <class K, class T, class V, class Comp, class Alloc>
337inline V *getref(hvec_map<K, V, Comp, Alloc> *m, T key) {
338 return m ? getref(*m, key) : 0;
339}
340
341template <class K, class T, class V, class Comp, class Alloc>
342inline const V *getref(const hvec_map<K, V, Comp, Alloc> *m, T key) {
343 return m ? getref(*m, key) : 0;
344}
345
346#endif /* LIB_HVEC_MAP_H_ */
Definition hashvec.h:27
Definition hvec_map.h:29
Definition hashvec.h:49