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