P4C
The P4 Compiler
Loading...
Searching...
No Matches
ordered_map.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_MAP_H_
18#define LIB_ORDERED_MAP_H_
19
20#include <cassert>
21#include <functional>
22#include <initializer_list>
23#include <list>
24#include <map>
25#include <utility>
26
27namespace P4 {
28
29// Map is ordered by order of element insertion.
30template <class K, class V, class COMP = std::less<K>,
31 class ALLOC = std::allocator<std::pair<const K, V>>>
33 public:
34 typedef K key_type;
35 typedef V mapped_type;
36 typedef std::pair<const K, V> value_type;
37 typedef COMP key_compare;
38 typedef ALLOC allocator_type;
39 typedef value_type &reference;
40 typedef const value_type &const_reference;
41
42 private:
43 typedef std::list<value_type, ALLOC> list_type;
44 typedef typename list_type::iterator list_iterator;
45 list_type data;
46
47 public:
48 typedef typename list_type::iterator iterator;
49 typedef typename list_type::const_iterator const_iterator;
50 typedef std::reverse_iterator<iterator> reverse_iterator;
51 typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
52
54 friend class ordered_map;
55
56 protected:
57 COMP comp;
58 explicit value_compare(COMP c) : comp(c) {}
59
60 public:
61 bool operator()(const value_type &a, const value_type &b) const {
62 return comp(a.first, b.first);
63 }
64 };
65
66 private:
67 struct mapcmp {
68 COMP comp;
69 bool operator()(const K *a, const K *b) const { return comp(*a, *b); }
70 };
71 using map_alloc = typename std::allocator_traits<ALLOC>::template rebind_alloc<
72 std::pair<const K *const, list_iterator>>;
73 using map_type = std::map<const K *, list_iterator, mapcmp, map_alloc>;
74 map_type data_map;
75 void init_data_map() {
76 data_map.clear();
77 for (auto it = data.begin(); it != data.end(); it++) data_map.emplace(&it->first, it);
78 }
79 iterator tr_iter(typename map_type::iterator i) {
80 if (i == data_map.end()) return data.end();
81 return i->second;
82 }
83 const_iterator tr_iter(typename map_type::const_iterator i) const {
84 if (i == data_map.end()) return data.end();
85 return i->second;
86 }
87
88 public:
89 typedef typename map_type::size_type size_type;
90
91 ordered_map() {}
92 ordered_map(const ordered_map &a) : data(a.data) { init_data_map(); }
93 template <typename InputIt>
94 ordered_map(InputIt first, InputIt last) : data(first, last) {
95 init_data_map();
96 }
97 ordered_map(ordered_map &&a) = default; /* move is ok? */
98 ordered_map &operator=(const ordered_map &a) {
99 /* std::list assignment broken by spec if elements are const... */
100 if (this != &a) {
101 data.clear();
102 for (auto &el : a.data) data.push_back(el);
103 init_data_map();
104 }
105 return *this;
106 }
107 ordered_map &operator=(ordered_map &&a) = default; /* move is ok? */
108 ordered_map(std::initializer_list<value_type> il) : data(il) { init_data_map(); }
109 // FIXME add allocator and comparator ctors...
110
111 iterator begin() noexcept { return data.begin(); }
112 const_iterator begin() const noexcept { return data.begin(); }
113 iterator end() noexcept { return data.end(); }
114 const_iterator end() const noexcept { return data.end(); }
115 reverse_iterator rbegin() noexcept { return data.rbegin(); }
116 const_reverse_iterator rbegin() const noexcept { return data.rbegin(); }
117 reverse_iterator rend() noexcept { return data.rend(); }
118 const_reverse_iterator rend() const noexcept { return data.rend(); }
119 const_iterator cbegin() const noexcept { return data.cbegin(); }
120 const_iterator cend() const noexcept { return data.cend(); }
121 const_reverse_iterator crbegin() const noexcept { return data.crbegin(); }
122 const_reverse_iterator crend() const noexcept { return data.crend(); }
123
124 bool empty() const noexcept { return data.empty(); }
125 size_type size() const noexcept { return data_map.size(); }
126 size_type max_size() const noexcept { return data_map.max_size(); }
127 bool operator==(const ordered_map &a) const { return data == a.data; }
128 bool operator!=(const ordered_map &a) const { return data != a.data; }
129 bool operator<(const ordered_map &a) const {
130 // we define this to work INDEPENDENT of the order -- so it is possible to have
131 // two ordered_maps where !(a < b) && !(b < a) && !(a == b) -- such sets have the
132 // same elements but in a different order. This is generally what you want if you
133 // have a set of ordered_maps (or use ordered_map as a map key).
134 // For individual element comparison, we defer to COMP, which is 'operator<' in the
135 // common case.
136 auto it = a.data_map.begin();
137 for (auto &el : data_map) {
138 if (it == a.data_map.end()) return false;
139 if (mapcmp()(el.first, it->first)) return true;
140 if (mapcmp()(it->first, el.first)) return false;
141 ++it;
142 }
143 return it != a.data_map.end();
144 }
145 void clear() {
146 data.clear();
147 data_map.clear();
148 }
149
150 iterator find(const key_type &a) { return tr_iter(data_map.find(&a)); }
151 const_iterator find(const key_type &a) const { return tr_iter(data_map.find(&a)); }
152 size_type count(const key_type &a) const { return data_map.count(&a); }
153 iterator lower_bound(const key_type &a) { return tr_iter(data_map.lower_bound(&a)); }
154 const_iterator lower_bound(const key_type &a) const {
155 return tr_iter(data_map.lower_bound(&a));
156 }
157 iterator upper_bound(const key_type &a) { return tr_iter(data_map.upper_bound(&a)); }
158 const_iterator upper_bound(const key_type &a) const {
159 return tr_iter(data_map.upper_bound(&a));
160 }
161 iterator upper_bound_pred(const key_type &a) {
162 auto ub = data_map.upper_bound(&a);
163 if (ub == data_map.begin()) return end();
164 return tr_iter(--ub);
165 }
166 const_iterator upper_bound_pred(const key_type &a) const {
167 auto ub = data_map.upper_bound(&a);
168 if (ub == data_map.begin()) return end();
169 return tr_iter(--ub);
170 }
171
172 V &operator[](const K &x) {
173 auto it = find(x);
174 if (it == data.end()) {
175 it = data.emplace(data.end(), x, V());
176 data_map.emplace(&it->first, it);
177 }
178 return it->second;
179 }
180 V &operator[](K &&x) {
181 auto it = find(x);
182 if (it == data.end()) {
183 it = data.emplace(data.end(), std::move(x), V());
184 data_map.emplace(&it->first, it);
185 }
186 return it->second;
187 }
188 V &at(const K &x) { return data_map.at(&x)->second; }
189 const V &at(const K &x) const { return data_map.at(&x)->second; }
190
191 template <typename KK, typename... VV>
192 std::pair<iterator, bool> emplace(KK &&k, VV &&...v) {
193 auto it = find(k);
194 if (it == data.end()) {
195 it = data.emplace(data.end(), std::piecewise_construct_t(), std::forward_as_tuple(k),
196 std::forward_as_tuple(std::forward<VV>(v)...));
197 data_map.emplace(&it->first, it);
198 return std::make_pair(it, true);
199 }
200 return std::make_pair(it, false);
201 }
202 template <typename KK, typename... VV>
203 std::pair<iterator, bool> emplace_hint(iterator pos, KK &&k, VV &&...v) {
204 /* should be const_iterator pos, but glibc++ std::list is broken */
205 auto it = find(k);
206 if (it == data.end()) {
207 it = data.emplace(pos, std::piecewise_construct_t(), std::forward_as_tuple(k),
208 std::forward_as_tuple(std::forward<VV>(v)...));
209 data_map.emplace(&it->first, it);
210 return std::make_pair(it, true);
211 }
212 return std::make_pair(it, false);
213 }
214
215 std::pair<iterator, bool> insert(const value_type &v) {
216 auto it = find(v.first);
217 if (it == data.end()) {
218 it = data.insert(data.end(), v);
219 data_map.emplace(&it->first, it);
220 return std::make_pair(it, true);
221 }
222 return std::make_pair(it, false);
223 }
224
225 /* TODO: should not exist, does not make sense for map that preserves
226 * insertion order. This function does not preserve it. */
227 std::pair<iterator, bool> insert(iterator pos, const value_type &v) {
228 /* should be const_iterator pos, but glibc++ std::list is broken */
229 auto it = find(v.first);
230 if (it == data.end()) {
231 it = data.insert(pos, v);
232 data_map.emplace(&it->first, it);
233 return std::make_pair(it, true);
234 }
235 return std::make_pair(it, false);
236 }
237 template <class InputIterator>
238 void insert(InputIterator b, InputIterator e) {
239 while (b != e) insert(*b++);
240 }
241
242 /* TODO: should not exist, does not make sense for map that preserves
243 * insertion order. This function does not preserve it. */
244 template <class InputIterator>
245 void insert(iterator pos, InputIterator b, InputIterator e) {
246 /* should be const_iterator pos, but glibc++ std::list is broken */
247 while (b != e) insert(pos, *b++);
248 }
249
250 iterator erase(const_iterator pos) {
251 auto it = data_map.find(&pos->first);
252 assert(it != data_map.end());
253 // get the non-const std::list iterator -- libstdc++ is missing
254 // std::list::erase(const_iterator) overload
255 auto list_it = it->second;
256 data_map.erase(it);
257 return data.erase(list_it);
258 }
259 size_type erase(const K &k) {
260 auto it = find(k);
261 if (it != data.end()) {
262 data_map.erase(&k);
263 data.erase(it);
264 return 1;
265 }
266 return 0;
267 }
268
269 template <class Compare>
270 void sort(Compare comp) {
271 data.sort(comp);
272 }
273};
274
275} // namespace P4
276
277#endif /* LIB_ORDERED_MAP_H_ */
Definition ordered_map.h:53
Definition ordered_map.h:32
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:24