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