P4C
The P4 Compiler
Loading...
Searching...
No Matches
ordered_set.h
1/*
2 * SPDX-FileCopyrightText: 2013 Barefoot Networks, Inc.
3 * Copyright 2013-present Barefoot Networks, Inc.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8#ifndef LIB_ORDERED_SET_H_
9#define LIB_ORDERED_SET_H_
10
11#include <cassert>
12#include <functional>
13#include <initializer_list>
14#include <list>
15#include <map>
16#include <set>
17#include <utility>
18
19namespace P4 {
20
21// Remembers items in insertion order
22template <class T, class COMP = std::less<T>, class ALLOC = std::allocator<T>>
23class ordered_set {
24 public:
25 typedef T key_type;
26 typedef T value_type;
27 typedef COMP key_compare;
28 typedef COMP value_compare;
29 typedef ALLOC allocator_type;
30 typedef const T &reference;
31 typedef const T &const_reference;
32
33 private:
34 typedef std::list<T, ALLOC> list_type;
35 typedef typename list_type::iterator list_iterator;
36 list_type data;
37
38 public:
39 // This is a set, so we can't provide any iterator that would make it
40 // possible to modify the values in the set and therefore possibly make the
41 // set contain duplicate values. Therefore we base all our iterators on
42 // list's const_iterator.
43 typedef typename list_type::const_iterator iterator;
44 typedef typename list_type::const_iterator const_iterator;
45 typedef std::reverse_iterator<iterator> reverse_iterator;
46 typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
47
48 private:
49 struct mapcmp {
50 COMP comp;
51 bool operator()(const T *a, const T *b) const { return comp(*a, *b); }
52 };
53 using map_alloc = typename std::allocator_traits<ALLOC>::template rebind_alloc<
54 std::pair<const T *const, list_iterator>>;
55 using map_type = std::map<const T *, list_iterator, mapcmp, map_alloc>;
56 map_type data_map;
57 void init_data_map() {
58 data_map.clear();
59 for (auto it = data.begin(); it != data.end(); it++) data_map.emplace(&*it, it);
60 }
61 iterator tr_iter(typename map_type::iterator i) {
62 if (i == data_map.end()) return data.end();
63 return i->second;
64 }
65 const_iterator tr_iter(typename map_type::const_iterator i) const {
66 if (i == data_map.end()) return data.end();
67 return i->second;
68 }
69
70 public:
71 typedef typename map_type::size_type size_type;
72 class sorted_iterator : public std::iterator<std::bidirectional_iterator_tag, T> {
73 friend class ordered_set;
74 typename map_type::const_iterator iter;
75 sorted_iterator(typename map_type::const_iterator it) // NOLINT(runtime/explicit)
76 : iter(it) {}
77
78 public:
79 const T &operator*() const { return *iter->first; }
80 const T *operator->() const { return iter->first; }
81 sorted_iterator operator++() {
82 ++iter;
83 return *this;
84 }
85 sorted_iterator operator--() {
86 --iter;
87 return *this;
88 }
89 sorted_iterator operator++(int) {
90 auto copy = *this;
91 ++iter;
92 return copy;
93 }
94 sorted_iterator operator--(int) {
95 auto copy = *this;
96 --iter;
97 return copy;
98 }
99 bool operator==(const sorted_iterator i) const { return iter == i.iter; }
100 bool operator!=(const sorted_iterator i) const { return iter != i.iter; }
101 };
102
103 ordered_set() {}
104 ordered_set(const ordered_set &a) : data(a.data) { init_data_map(); }
105 ordered_set(std::initializer_list<T> init) : data(init) { init_data_map(); }
106 template <typename InputIt>
107 ordered_set(InputIt first, InputIt last) : data(first, last) {
108 init_data_map();
109 }
110 ordered_set(ordered_set &&a) = default; /* move is ok? */
111 ordered_set &operator=(const ordered_set &a) {
112 data = a.data;
113 init_data_map();
114 return *this;
115 }
116 ordered_set &operator=(ordered_set &&a) = default; /* move is ok? */
117 bool operator==(const ordered_set &a) const { return data == a.data; }
118 bool operator!=(const ordered_set &a) const { return data != a.data; }
119 bool operator<(const ordered_set &a) const {
120 // we define this to work INDEPENDENT of the order -- so it is possible to have
121 // two ordered_sets where !(a < b) && !(b < a) && !(a == b) -- such sets have the
122 // same elements but in a different order. This is generally what you want if you
123 // have a set of ordered_sets (or use ordered_set as a map key).
124 // For individual element comparison, we defer to COMP, which is 'operator<' in the
125 // common case.
126 auto it = a.data_map.begin();
127 for (auto &el : data_map) {
128 if (it == a.data_map.end()) return false;
129 if (mapcmp()(el.first, it->first)) return true;
130 if (mapcmp()(it->first, el.first)) return false;
131 ++it;
132 }
133 return it != a.data_map.end();
134 }
135
136 // FIXME add allocator and comparator ctors...
137
138 iterator begin() noexcept { return data.begin(); }
139 const_iterator begin() const noexcept { return data.begin(); }
140 iterator end() noexcept { return data.end(); }
141 const_iterator end() const noexcept { return data.end(); }
142 reverse_iterator rbegin() noexcept { return data.rbegin(); }
143 const_reverse_iterator rbegin() const noexcept { return data.rbegin(); }
144 reverse_iterator rend() noexcept { return data.rend(); }
145 const_reverse_iterator rend() const noexcept { return data.rend(); }
146 const_iterator cbegin() const noexcept { return data.cbegin(); }
147 const_iterator cend() const noexcept { return data.cend(); }
148 const_reverse_iterator crbegin() const noexcept { return data.crbegin(); }
149 const_reverse_iterator crend() const noexcept { return data.crend(); }
150 sorted_iterator sorted_begin() const noexcept { return data_map.begin(); }
151 sorted_iterator sorted_end() const noexcept { return data_map.end(); }
152
153 reference front() const noexcept { return *data.begin(); }
154 reference back() const noexcept { return *data.rbegin(); }
155
156 bool empty() const noexcept { return data.empty(); }
157 size_type size() const noexcept { return data_map.size(); }
158 size_type max_size() const noexcept { return data_map.max_size(); }
159 void clear() {
160 data.clear();
161 data_map.clear();
162 }
163
164 iterator find(const T &a) { return tr_iter(data_map.find(&a)); }
165 const_iterator find(const T &a) const { return tr_iter(data_map.find(&a)); }
166 size_type count(const T &a) const { return data_map.count(&a); }
167 iterator upper_bound(const T &a) { return tr_iter(data_map.upper_bound(&a)); }
168 const_iterator upper_bound(const T &a) const { return tr_iter(data_map.upper_bound(&a)); }
169 iterator lower_bound(const T &a) { return tr_iter(data_map.lower_bound(&a)); }
170 const_iterator lower_bound(const T &a) const { return tr_iter(data_map.lower_bound(&a)); }
171
172 std::pair<iterator, bool> insert(const T &v) {
173 iterator it = find(v);
174 if (it == data.end()) {
175 list_iterator it = data.insert(data.end(), v);
176 data_map.emplace(&*it, it);
177 return std::make_pair(it, true);
178 }
179 return std::make_pair(it, false);
180 }
181 std::pair<iterator, bool> insert(T &&v) {
182 iterator it = find(v);
183 if (it == data.end()) {
184 list_iterator it = data.insert(data.end(), std::move(v));
185 data_map.emplace(&*it, it);
186 return std::make_pair(it, true);
187 }
188 return std::make_pair(it, false);
189 }
190 void insert(ordered_set::const_iterator begin, ordered_set::const_iterator end) {
191 for (auto it = begin; it != end; ++it) insert(*it);
192 }
193 iterator insert(const_iterator pos, const T &v) {
194 iterator it = find(v);
195 if (it == data.end()) {
196 list_iterator it = data.insert(pos, v);
197 data_map.emplace(&*it, it);
198 return it;
199 }
200 return it;
201 }
202 iterator insert(const_iterator pos, T &&v) {
203 iterator it = find(v);
204 if (it == data.end()) {
205 list_iterator it = data.insert(pos, std::move(v));
206 data_map.emplace(&*it, it);
207 return it;
208 }
209 return it;
210 }
211
212 void push_back(const T &v) {
213 iterator it = find(v);
214 if (it == data.end()) {
215 list_iterator it = data.insert(data.end(), v);
216 data_map.emplace(&*it, it);
217 } else {
218 data.splice(data.end(), data, it);
219 }
220 }
221 void push_back(T &&v) {
222 iterator it = find(v);
223 if (it == data.end()) {
224 list_iterator it = data.insert(data.end(), std::move(v));
225 data_map.emplace(&*it, it);
226 } else {
227 data.splice(data.end(), data, it);
228 }
229 }
230
231 template <class... Args>
232 std::pair<iterator, bool> emplace(Args &&...args) {
233 auto it = data.emplace(data.end(), std::forward<Args>(args)...);
234 auto old = find(*it);
235 if (old == data.end()) {
236 data_map.emplace(&*it, it);
237 return std::make_pair(it, true);
238 } else {
239 data.erase(it);
240 return std::make_pair(old, false);
241 }
242 }
243
244 template <class... Args>
245 std::pair<iterator, bool> emplace_back(Args &&...args) {
246 auto it = data.emplace(data.end(), std::forward<Args>(args)...);
247 auto old = find(*it);
248 if (old != data.end()) {
249 data.erase(old);
250 }
251 data_map.emplace(&*it, it);
252 return std::make_pair(it, true);
253 }
254
255 iterator erase(const_iterator pos) {
256 auto it = data_map.find(&*pos);
257 assert(it != data_map.end());
258 // get the non-const std::list iterator -- libstdc++ is missing
259 // std::list::erase(const_iterator) overload
260 auto list_it = it->second;
261 data_map.erase(it);
262 return data.erase(list_it);
263 }
264 size_type erase(const T &v) {
265 auto it = find(v);
266 if (it != data.end()) {
267 data_map.erase(&v);
268 data.erase(it);
269 return 1;
270 }
271 return 0;
272 }
273};
274
275template <class T, class C1, class A1, class U>
276inline auto operator|=(ordered_set<T, C1, A1> &a, const U &b) -> decltype(b.begin(), a) {
277 for (auto &el : b) a.insert(el);
278 return a;
279}
280template <class T, class C1, class A1, class U>
281inline auto operator-=(ordered_set<T, C1, A1> &a, const U &b) -> decltype(b.begin(), a) {
282 for (auto &el : b) a.erase(el);
283 return a;
284}
285template <class T, class C1, class A1, class U>
286inline auto operator&=(ordered_set<T, C1, A1> &a, const U &b) -> decltype(b.begin(), a) {
287 for (auto it = a.begin(); it != a.end();) {
288 if (b.count(*it))
289 ++it;
290 else
291 it = a.erase(it);
292 }
293 return a;
294}
295
296template <class T, class C1, class A1, class U>
297inline auto contains(const ordered_set<T, C1, A1> &a, const U &b) -> decltype(b.begin(), true) {
298 for (auto &el : b)
299 if (!a.count(el)) return false;
300 return true;
301}
302template <class T, class C1, class A1, class U>
303inline auto intersects(const ordered_set<T, C1, A1> &a, const U &b) -> decltype(b.begin(), true) {
304 for (auto &el : b)
305 if (a.count(el)) return true;
306 return false;
307}
308
309} // namespace P4
310
311#endif /* LIB_ORDERED_SET_H_ */
Definition ordered_set.h:72
Definition ordered_set.h:23
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:13