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>>>
32class ordered_map {
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
53 class value_compare {
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 void clear() {
130 data.clear();
131 data_map.clear();
132 }
133
134 iterator find(const key_type &a) { return tr_iter(data_map.find(&a)); }
135 const_iterator find(const key_type &a) const { return tr_iter(data_map.find(&a)); }
136 size_type count(const key_type &a) const { return data_map.count(&a); }
137 iterator lower_bound(const key_type &a) { return tr_iter(data_map.lower_bound(&a)); }
138 const_iterator lower_bound(const key_type &a) const {
139 return tr_iter(data_map.lower_bound(&a));
140 }
141 iterator upper_bound(const key_type &a) { return tr_iter(data_map.upper_bound(&a)); }
142 const_iterator upper_bound(const key_type &a) const {
143 return tr_iter(data_map.upper_bound(&a));
144 }
145 iterator upper_bound_pred(const key_type &a) {
146 auto ub = data_map.upper_bound(&a);
147 if (ub == data_map.begin()) return end();
148 return tr_iter(--ub);
149 }
150 const_iterator upper_bound_pred(const key_type &a) const {
151 auto ub = data_map.upper_bound(&a);
152 if (ub == data_map.begin()) return end();
153 return tr_iter(--ub);
154 }
155
156 V &operator[](const K &x) {
157 auto it = find(x);
158 if (it == data.end()) {
159 it = data.emplace(data.end(), x, V());
160 data_map.emplace(&it->first, it);
161 }
162 return it->second;
163 }
164 V &operator[](K &&x) {
165 auto it = find(x);
166 if (it == data.end()) {
167 it = data.emplace(data.end(), std::move(x), V());
168 data_map.emplace(&it->first, it);
169 }
170 return it->second;
171 }
172 V &at(const K &x) { return data_map.at(&x)->second; }
173 const V &at(const K &x) const { return data_map.at(&x)->second; }
174
175 template <typename KK, typename... VV>
176 std::pair<iterator, bool> emplace(KK &&k, VV &&...v) {
177 auto it = find(k);
178 if (it == data.end()) {
179 it = data.emplace(data.end(), std::piecewise_construct_t(), std::forward_as_tuple(k),
180 std::forward_as_tuple(std::forward<VV>(v)...));
181 data_map.emplace(&it->first, it);
182 return std::make_pair(it, true);
183 }
184 return std::make_pair(it, false);
185 }
186 template <typename KK, typename... VV>
187 std::pair<iterator, bool> emplace_hint(iterator pos, KK &&k, VV &&...v) {
188 /* should be const_iterator pos, but glibc++ std::list is broken */
189 auto it = find(k);
190 if (it == data.end()) {
191 it = data.emplace(pos, std::piecewise_construct_t(), std::forward_as_tuple(k),
192 std::forward_as_tuple(std::forward<VV>(v)...));
193 data_map.emplace(&it->first, it);
194 return std::make_pair(it, true);
195 }
196 return std::make_pair(it, false);
197 }
198
199 std::pair<iterator, bool> insert(const value_type &v) {
200 auto it = find(v.first);
201 if (it == data.end()) {
202 it = data.insert(data.end(), v);
203 data_map.emplace(&it->first, it);
204 return std::make_pair(it, true);
205 }
206 return std::make_pair(it, false);
207 }
208
209 /* TODO: should not exist, does not make sense for map that preserves
210 * insertion order. This function does not preserve it. */
211 std::pair<iterator, bool> insert(iterator pos, const value_type &v) {
212 /* should be const_iterator pos, but glibc++ std::list is broken */
213 auto it = find(v.first);
214 if (it == data.end()) {
215 it = data.insert(pos, v);
216 data_map.emplace(&it->first, it);
217 return std::make_pair(it, true);
218 }
219 return std::make_pair(it, false);
220 }
221 template <class InputIterator>
222 void insert(InputIterator b, InputIterator e) {
223 while (b != e) insert(*b++);
224 }
225
226 /* TODO: should not exist, does not make sense for map that preserves
227 * insertion order. This function does not preserve it. */
228 template <class InputIterator>
229 void insert(iterator pos, InputIterator b, InputIterator e) {
230 /* should be const_iterator pos, but glibc++ std::list is broken */
231 while (b != e) insert(pos, *b++);
232 }
233
234 iterator erase(const_iterator pos) {
235 auto it = data_map.find(&pos->first);
236 assert(it != data_map.end());
237 // get the non-const std::list iterator -- libstdc++ is missing
238 // std::list::erase(const_iterator) overload
239 auto list_it = it->second;
240 data_map.erase(it);
241 return data.erase(list_it);
242 }
243 size_type erase(const K &k) {
244 auto it = find(k);
245 if (it != data.end()) {
246 data_map.erase(&k);
247 data.erase(it);
248 return 1;
249 }
250 return 0;
251 }
252
253 template <class Compare>
254 void sort(Compare comp) {
255 data.sort(comp);
256 }
257};
258
259} // namespace P4
260
261#endif /* LIB_ORDERED_MAP_H_ */
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:24