OGLplus  (0.59.0) a C++ wrapper for rendering APIs

flat_map.hpp
Go to the documentation of this file.
1 
9 #ifndef EAGINE_FLAT_MAP_HPP
10 #define EAGINE_FLAT_MAP_HPP
11 
12 #include "assert.hpp"
13 #include "types.hpp"
14 #include <algorithm>
15 #include <stdexcept>
16 #include <utility>
17 #include <vector>
18 
19 namespace eagine {
20 //------------------------------------------------------------------------------
21 template <typename Key, typename Val, typename Cmp>
22 struct flat_map_value_compare : Cmp {
23 
24  constexpr auto key_comp() const noexcept -> const Cmp& {
25  return *this;
26  }
27 
28  template <typename L, typename R>
29  constexpr auto operator()(
30  const std::pair<L, Val>& a,
31  const std::pair<R, Val>& b) const noexcept -> bool {
32  return key_comp()(a.first, b.first);
33  }
34 
35  template <typename K>
36  constexpr auto
37  operator()(const std::pair<K, Val>& a, const Key& b) const noexcept {
38  return key_comp()(a.first, b);
39  }
40 
41  template <typename K>
42  constexpr auto
43  operator()(const Key& a, const std::pair<K, Val>& b) const noexcept {
44  return key_comp()(a, b.first);
45  }
46 };
47 //------------------------------------------------------------------------------
48 template <typename Key, typename Val, typename Cmp>
49 struct flat_map_ops : flat_map_value_compare<Key, Val, Cmp> {
50  using value_type = std::pair<const Key, Val>;
51 
52  constexpr auto value_comp() const noexcept
53  -> const flat_map_value_compare<Key, Val, Cmp>& {
54  return *this;
55  }
56 
57  template <typename I>
58  static auto empty(I b, I e) noexcept {
59  return b == e;
60  }
61 
62  template <typename I>
63  static auto size(I b, I e) noexcept {
65  return static_cast<span_size_t>(distance(b, e));
66  }
67 
68  template <typename I>
69  auto lower_bound(I b, I e, const Key& key) const noexcept {
70  return ::std::lower_bound(b, e, key, value_comp());
71  }
72 
73  template <typename I>
74  auto upper_bound(I b, I e, const Key& key) const noexcept {
75  return ::std::upper_bound(b, e, key, value_comp());
76  }
77 
78  template <typename I>
79  auto equal_range(I b, I e, const Key& key) const noexcept {
80  return ::std::equal_range(b, e, key, value_comp());
81  }
82 
83  template <typename I>
84  auto find(I b, I e, const Key& key) const noexcept {
85  b = lower_bound(b, e, key);
86  if((b != e) && value_comp()(key, *b)) {
87  b = e;
88  }
89  return b;
90  }
91 
92  template <typename I>
93  auto at(I b, I e, const Key& key) const -> auto& {
94  b = find(b, e, key);
95  if(b == e) {
96  throw std::out_of_range("Invalid flat map key");
97  }
98  return b->second;
99  }
100 
101  template <typename I>
102  auto get(I b, I e, const Key& key) const noexcept -> auto& {
103  b = find(b, e, key);
104  EAGINE_ASSERT(b != e);
105  return b->second;
106  }
107 };
108 //------------------------------------------------------------------------------
109 template <typename Key, typename Val, typename Cmp, typename Derived>
110 class flat_map_view_crtp : flat_map_ops<Key, Val, Cmp> {
111 private:
112  auto _self() const noexcept -> const Derived& {
113  return *static_cast<const Derived*>(this);
114  }
115  auto _self() noexcept -> Derived& {
116  return *static_cast<Derived*>(this);
117  }
118 
119  auto _b() const noexcept {
120  return _self().begin();
121  }
122  auto _b() noexcept {
123  return _self().begin();
124  }
125 
126  auto _e() const noexcept {
127  return _self().end();
128  }
129  auto _e() noexcept {
130  return _self().end();
131  }
132 
133 protected:
134  using _ops_t = flat_map_ops<Key, Val, Cmp>;
135 
136  constexpr auto _ops() const noexcept -> const _ops_t& {
137  return *this;
138  }
139 
140 public:
141  using key_type = Key;
142  using mapped_type = Val;
143  using value_type = std::pair<const Key, Val>;
144  using reference = value_type&;
145  using const_reference = const value_type&;
146 
147  using key_compare = Cmp;
148  using value_compare = flat_map_value_compare<Key, Val, Cmp>;
149 
150  auto key_comp() const noexcept -> const key_compare& {
151  return _ops().value_comp().key_comp();
152  }
153 
154  auto value_comp() const noexcept -> const value_compare& {
155  return _ops().value_comp();
156  }
157 
158  auto empty() const noexcept {
159  return _ops().empty(_b(), _e());
160  }
161 
162  auto size() const {
163  return _ops().size(_b(), _e());
164  }
165 
166  auto find(const Key& key) {
167  return _ops().find(_b(), _e(), key);
168  }
169 
170  auto find(const Key& key) const {
171  return _ops().find(_b(), _e(), key);
172  }
173 
174  auto lower_bound(const Key& key) {
175  return _ops().lower_bound(_b(), _e(), key);
176  }
177 
178  auto lower_bound(const Key& key) const {
179  return _ops().lower_bound(_b(), _e(), key);
180  }
181 
182  auto upper_bound(const Key& key) {
183  return _ops().upper_bound(_b(), _e(), key);
184  }
185 
186  auto upper_bound(const Key& key) const {
187  return _ops().upper_bound(_b(), _e(), key);
188  }
189 
190  auto equal_range(const Key& key) {
191  return _ops().equal_range(_b(), _e(), key);
192  }
193 
194  auto equal_range(const Key& key) const {
195  return _ops().equal_range(_b(), _e(), key);
196  }
197 
198  auto at(const Key& key) -> Val& {
199  return _ops().at(_b(), _e(), key);
200  }
201 
202  auto at(const Key& key) const -> const Val& {
203  return _ops().at(_b(), _e(), key);
204  }
205 };
206 //------------------------------------------------------------------------------
207 template <
208  typename Key,
209  typename Val,
210  typename Cmp = std::less<Key>,
211  typename Allocator = std::allocator<std::pair<Key, Val>>>
212 class flat_map
213  : public flat_map_view_crtp<Key, Val, Cmp, flat_map<Key, Val, Cmp, Allocator>> {
214 private:
215  using _base =
216  flat_map_view_crtp<Key, Val, Cmp, flat_map<Key, Val, Cmp, Allocator>>;
217  using _base::_ops;
218 
219  using _alloc_t =
220  typename Allocator::template rebind<std::pair<Key, Val>>::other;
221 
222  using _vec_t = std::vector<std::pair<Key, Val>, _alloc_t>;
223  _vec_t _vec{};
224 
225  auto _find_insert_pos(const Key& k) noexcept {
226  const auto b = _vec.begin();
227  const auto e = _vec.end();
228  const auto p = _ops().lower_bound(b, e, k);
229 
230  return std::pair{p, (p == e) || (k != p->first)};
231  }
232 
233  template <typename I>
234  auto _find_insert_pos(I p, const Key& k) {
235  auto b = _vec.begin();
236  auto e = _vec.end();
237  if(p == e) {
238  if(_vec.empty() || value_comp()(_vec.back(), k)) {
239  return std::pair{p, true};
240  }
241  p = _ops().lower_bound(b, e, k);
242  }
243  if(k == p->first) {
244  return std::pair{p, false};
245  }
246  if(key_comp()(k, p->first)) {
247  if(p != b) {
248  p = _ops().lower_bound(b, p, k);
249  }
250  } else {
251  p = _ops().lower_bound(p, e, k);
252  }
253  return std::pair{p, true};
254  }
255 
256  template <typename I, typename... Args>
257  auto _do_emplace(I ip, const Key& key, Args&&... args) -> I {
258  if(ip.second) {
259  ip.first =
260  _vec.emplace(ip.first, key, Val{std::forward<Args>(args)...});
261  }
262  return ip;
263  }
264 
265  template <typename I, typename V>
266  auto _do_insert(I ip, const V& value) -> I {
267  if(ip.second) {
268  ip.first = _vec.insert(ip.first, value);
269  }
270  return ip;
271  }
272 
273 public:
274  using typename _base::key_compare;
275  using typename _base::key_type;
276  using typename _base::mapped_type;
277  using typename _base::value_type;
278  using size_type = typename _vec_t::size_type;
279  using difference_type = typename _vec_t::difference_type;
280  using iterator = typename _vec_t::iterator;
281  using const_iterator = typename _vec_t::const_iterator;
282  using allocator_type = Allocator;
283 
284  using _base::key_comp;
285  using _base::lower_bound;
286  using _base::value_comp;
287 
288  flat_map() noexcept = default;
289  flat_map(const flat_map&) = default;
290  flat_map(flat_map&&) noexcept = default;
291  auto operator=(const flat_map&) -> flat_map& = default;
292  auto operator=(flat_map&&) noexcept -> flat_map& = default;
293  ~flat_map() noexcept = default;
294 
295  flat_map(std::initializer_list<std::pair<Key, Val>> il) {
296  assign(il);
297  }
298 
299  flat_map(const std::vector<value_type>& v) {
300  assign(v);
301  }
302 
303  void assign(std::initializer_list<std::pair<Key, Val>> il) {
304  _vec = _vec_t(il);
305  std::sort(_vec.begin(), _vec.end(), value_comp());
306  }
307 
308  void assign(const std::vector<value_type>& v) {
309  _vec = _vec_t(v.begin(), v.end());
310  std::sort(_vec.begin(), _vec.end(), value_comp());
311  }
312 
313  auto empty() const -> bool {
314  return _vec.empty();
315  }
316 
317  auto size() const -> size_type {
318  return _vec.size();
319  }
320 
321  auto max_size() const -> size_type {
322  return _vec.max_size();
323  }
324 
325  auto reserve(size_type sz) -> auto& {
326  _vec.reserve(sz);
327  return *this;
328  }
329 
330  auto clear() -> auto& {
331  _vec.clear();
332  return *this;
333  }
334 
335  auto begin() -> iterator {
336  return _vec.begin();
337  }
338 
339  auto begin() const -> const_iterator {
340  return _vec.begin();
341  }
342 
343  auto end() -> iterator {
344  return _vec.end();
345  }
346 
347  auto end() const -> const_iterator {
348  return _vec.end();
349  }
350 
351  auto operator[](const Key& key) -> auto& {
352  auto ip = _find_insert_pos(key);
353  ip = _do_emplace(ip, key);
354  return ip.first->second;
355  }
356 
357  template <typename... Args>
358  auto emplace(const Key& key, Args&&... args) -> std::pair<iterator, bool> {
359  auto ip = _find_insert_pos(key);
360  ip = _do_emplace(ip, key, std::forward<Args>(args)...);
361  return ip;
362  }
363 
364  template <typename... Args>
365  auto try_emplace(const Key& key, Args&&... args)
366  -> std::pair<iterator, bool> {
367  auto ip = _find_insert_pos(key);
368  ip = _do_emplace(ip, key, std::forward<Args>(args)...);
369  return ip;
370  }
371 
372  auto insert(const value_type& value) -> std::pair<iterator, bool> {
373  auto ip = _find_insert_pos(value.first);
374  ip = _do_insert(ip, value);
375  return {ip.first, ip.second};
376  }
377 
378  auto insert(iterator p, const value_type& value) -> iterator {
379  const auto ip = _find_insert_pos(p, value.first);
380  return _do_insert(ip, value).first;
381  }
382 
383  auto erase(iterator p) -> iterator {
384  return _vec.erase(p);
385  }
386 
387  auto erase(iterator f, iterator t) -> iterator {
388  return _vec.erase(f, t);
389  }
390 
391  auto erase(const Key& key) -> size_type {
392  const auto p = _ops().equal_range(_vec.begin(), _vec.end(), key);
393  const auto res = size_type(std::distance(p.first, p.second));
394  EAGINE_ASSERT(res <= 1);
395  _vec.erase(p.first, p.second);
396  return res;
397  }
398 
399  template <typename Predicate>
400  auto erase_if(const Predicate& predicate) -> size_type {
401  const auto p = std::remove_if(_vec.begin(), _vec.end(), predicate);
402  const auto res = size_type(std::distance(p, _vec.end()));
403  _vec.erase(p, _vec.end());
404  return res;
405  }
406 };
407 //------------------------------------------------------------------------------
408 } // namespace eagine
409 
410 #endif // EAGINE_FLAT_MAP_HPP
value_type
Value tree value element data type enumeration.
Definition: interface.hpp:27
std::ptrdiff_t span_size_t
Signed span size type used by eagine.
Definition: types.hpp:36
Common code is placed in this namespace.
Definition: eagine.hpp:21
static constexpr auto distance(const vector< T, N, V > &a, const vector< T, N, V > &b) noexcept
Returns the distance between two vectors.
Definition: vector.hpp:388
static auto find(basic_span< T1, P1, S1 > where, basic_span< T2, P2, S2 > what) -> basic_span< T1, P1, S1 >
Finds the position of the last occurrence of what in a span.
Definition: span_algo.hpp:374
static auto sort(basic_span< T, P, S > spn) -> basic_span< T, P, S >
Sorts the elements of a span.
Definition: span_algo.hpp:609

Copyright © 2015-2021 Matúš Chochlík.
<chochlik -at -gmail.com>
Documentation generated on Tue Apr 13 2021 by Doxygen (version 1.8.17).