P4C
The P4 Compiler
Loading...
Searching...
No Matches
hvec_set.h
1/*
2 * SPDX-FileCopyrightText: 2023 Intel
3 * Copyright 2023-present Intel
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8#ifndef LIB_HVEC_SET_H_
9#define LIB_HVEC_SET_H_
10
11#include <initializer_list>
12#include <tuple>
13#include <vector>
14
15#include "exceptions.h"
16#include "hashvec.h"
17
18namespace P4 {
19
20template <class KEY, class HASH = std::hash<KEY>, class PRED = std::equal_to<KEY>,
21 class ALLOC = std::allocator<KEY>>
22class hvec_set : hash_vector_base {
23 HASH hf; // FIXME -- use empty base optimization for these?
24 PRED eql;
25
26 public:
27 typedef const KEY value_type;
28 typedef HASH hasher;
29 typedef PRED key_equal;
30 typedef ALLOC allocator_type;
31 typedef value_type *pointer, *const_pointer, &reference, &const_reference;
32 typedef hash_vector_base::lookup_cache lookup_cache;
33
34 explicit hvec_set(size_t icap = 0, const hasher &hf = hasher(),
35 const key_equal &eql = key_equal(),
36 const allocator_type &a = allocator_type())
37 : hash_vector_base(false, false, icap), hf(hf), eql(eql), data(a) {
38 data.reserve(icap);
39 }
40 hvec_set(const hvec_set &) = default;
41 hvec_set(hvec_set &&) = default;
42 hvec_set &operator=(const hvec_set &that) {
43 if (this != std::addressof(that)) {
44 clear();
45 hf = that.hf;
46 eql = that.eql;
47
48 data.reserve(that.size());
49 insert(that.begin(), that.end());
50 }
51
52 return *this;
53 }
54 hvec_set &operator=(hvec_set &&) = default;
55 ~hvec_set() = default;
56 template <class ITER>
57 hvec_set(ITER begin, ITER end, const hasher &hf = hasher(), const key_equal &eql = key_equal(),
58 const allocator_type &a = allocator_type())
59 : hash_vector_base(false, false, end - begin), hf(hf), eql(eql), data(a) {
60 data.reserve(end - begin);
61 for (auto it = begin; it != end; ++it) insert(*it);
62 }
63 hvec_set(std::initializer_list<value_type> il, const hasher &hf = hasher(),
64 const key_equal &eql = key_equal(), const allocator_type &a = allocator_type())
65 : hash_vector_base(false, false, il.size()), hf(hf), eql(eql), data(a) {
66 data.reserve(il.size());
67 for (auto &i : il) insert(i);
68 }
69
70 private:
71 template <class HVM, class VT>
72 class _iter {
73 HVM *self;
74 size_t idx;
75
76 friend class hvec_set;
77 _iter(HVM &s, size_t i) : self(&s), idx(i) {}
78
79 public:
80 using value_type = VT;
81 using difference_type = ssize_t;
82 using pointer = typename HVM::pointer;
83 using reference = typename HVM::reference;
84 using iterator_category = std::bidirectional_iterator_tag;
85 _iter(const _iter &) = default;
86 _iter &operator=(const _iter &a) {
87 self = a.self;
88 idx = a.idx;
89 return *this;
90 }
91 value_type &operator*() const { return self->data[idx]; }
92 value_type *operator->() const { return &self->data[idx]; }
93 _iter &operator++() {
94 do {
95 ++idx;
96 } while (self->erased[idx]);
97 return *this;
98 }
99 _iter &operator--() {
100 do {
101 --idx;
102 } while (self->erased[idx]);
103 return *this;
104 }
105 _iter operator++(int) {
106 auto copy = *this;
107 ++*this;
108 return copy;
109 }
110 _iter operator--(int) {
111 auto copy = *this;
112 --*this;
113 return copy;
114 }
115 bool operator==(const _iter &a) const { return self == a.self && idx == a.idx; }
116 bool operator!=(const _iter &a) const { return self != a.self || idx != a.idx; }
117 operator _iter<const HVM, const VT>() const {
118 return _iter<const HVM, const VT>(*self, idx);
119 }
120 };
121
122 public:
123 typedef _iter<hvec_set, value_type> iterator;
124 typedef _iter<const hvec_set, const value_type> const_iterator;
125 iterator begin() { return iterator(*this, erased.ffz()); }
126 iterator end() { return iterator(*this, data.size()); }
127 const_iterator begin() const { return const_iterator(*this, erased.ffz()); }
128 const_iterator end() const { return const_iterator(*this, data.size()); }
129 const_iterator cbegin() const { return const_iterator(*this, erased.ffz()); }
130 const_iterator cend() const { return const_iterator(*this, data.size()); }
131 value_type &front() const { return *begin(); }
132 value_type &back() const {
133 auto it = end();
134 return *--it;
135 }
136
137 bool empty() const { return inuse == 0; }
138 size_t size() const { return inuse; }
139 size_t max_size() const { return UINT32_MAX; }
140 bool operator==(const hvec_set &a) const {
141 if (inuse != a.inuse) return false;
142 auto it = begin();
143 for (auto &el : a)
144 if (el != *it++) return false;
145 return true;
146 }
147 bool operator!=(const hvec_set &a) const { return !(*this == a); }
148 void clear() {
149 hash_vector_base::clear();
150 data.clear();
151 }
152
153 iterator find(const KEY &k) {
155 size_t idx = hash_vector_base::find(&k, &cache);
156 return idx ? iterator(*this, idx - 1) : end();
157 }
158 const_iterator find(const KEY &k) const {
160 size_t idx = hash_vector_base::find(&k, &cache);
161 return idx ? const_iterator(*this, idx - 1) : end();
162 }
163 size_t count(const KEY &k) const {
165 size_t idx = hash_vector_base::find(&k, &cache);
166 return idx > 0;
167 }
168
169 template <typename... KK>
170 std::pair<iterator, bool> emplace(KK &&...k) {
171 return insert(value_type(std::forward<KK>(k)...));
172 }
173 std::pair<iterator, bool> insert(const value_type &v) {
174 bool new_key = false;
175 size_t idx = hv_insert(&v);
176 if (idx >= data.size()) {
177 idx = data.size();
178 data.push_back(v);
179 new_key = true;
180 } else if ((new_key = erased[idx])) {
181 erased[idx] = 0;
182 data[idx] = v;
183 }
184 return std::make_pair(iterator(*this, idx), new_key);
185 }
186 std::pair<iterator, bool> insert(value_type &&v) {
187 bool new_key = false;
188 size_t idx = hv_insert(&v);
189 if (idx >= data.size()) {
190 idx = data.size();
191 data.push_back(std::move(v));
192 new_key = true;
193 } else if ((new_key = erased[idx])) {
194 erased[idx] = 0;
195 data[idx] = std::move(v);
196 }
197 return std::make_pair(iterator(*this, idx), new_key);
198 }
199
200 template <typename InputIterator>
201 void insert(InputIterator first, InputIterator last) {
202 for (; first != last; ++first) insert(*first);
203 }
204 void insert(std::initializer_list<value_type> vl) { return insert(vl.begin(), vl.end()); }
205 template <class HVM, class VT>
206 _iter<HVM, VT> erase(_iter<HVM, VT> it) {
207 BUG_CHECK(this == it.self, "incorrect iterator for hvec_set::erase");
208 erased[it.idx] = 1;
209 // FIXME -- would be better to call dtor here, but that will cause
210 // problems with the vector when it is resized or destroyed. Could
211 // use raw memory and manual construct instead.
212 data[it.idx] = KEY();
213 ++it;
214 --inuse;
215 return it;
216 }
217 size_t erase(const KEY &k) {
218 size_t idx = remove(&k);
219 if (idx + 1 == 0) return 0;
220 if (idx < data.size()) {
221 data[idx] = KEY();
222 }
223 return 1;
224 }
225#ifdef DEBUG
226 using hash_vector_base::dump;
227#endif
228
229 private:
230 std::vector<KEY, ALLOC> data;
231 size_t hashfn(const void *a) const override { return hf(*static_cast<const KEY *>(a)); }
232 bool cmpfn(const void *a, const void *b) const override {
233 return eql(*static_cast<const KEY *>(a), *static_cast<const KEY *>(b));
234 }
235 bool cmpfn(const void *a, size_t b) const override {
236 return eql(*static_cast<const KEY *>(a), data[b]);
237 }
238 const void *getkey(uint32_t i) const override { return &data[i]; }
239 void *getval(uint32_t) override {
240 BUG("getval in set");
241 return nullptr;
242 }
243 uint32_t limit() override { return data.size(); }
244 void resizedata(size_t sz) override { data.resize(sz); }
245 void moveentry(size_t to, size_t from) override { data[to] = data[from]; }
246};
247
248} // namespace P4
249
250#endif /* LIB_HVEC_SET_H_ */
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:13
Definition hashvec.h:42