1 /*
2 The code is licensed under the MIT License <http://opensource.org/licenses/MIT>:
3
4 Copyright (c) 2015-2017 Niels Lohmann.
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy of
7 this software and associated documentation files (the "Software"), to deal in
8 the Software without restriction, including without limitation the rights to
9 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
10 of the Software, and to permit persons to whom the Software is furnished to do
11 so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in all
14 copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 SOFTWARE.
23 */
24
25 #ifndef NLOHMANN_FIFO_MAP_HPP
26 #define NLOHMANN_FIFO_MAP_HPP
27
28 #include <algorithm>
29 #include <cstdlib>
30 #include <functional>
31 #include <iostream>
32 #include <limits>
33 #include <map>
34 #include <memory>
35 #include <unordered_map>
36 #include <utility>
37 #include <vector>
38
39 /*!
40 @brief namespace for Niels Lohmann
41 @see https://github.com/nlohmann
42 */
43 namespace nlohmann
44 {
45
46 template<class Key>
47 class fifo_map_compare
48 {
49 public:
50 /// constructor given a pointer to a key storage
fifo_map_compare(std::unordered_map<Key,std::size_t> * k)51 fifo_map_compare(std::unordered_map<Key, std::size_t>* k) : keys(k) {}
52
53 /*!
54 This function compares two keys with respect to the order in which they
55 were added to the container. For this, the mapping keys is used.
56 */
operator ()(const Key & lhs,const Key & rhs) const57 bool operator()(const Key& lhs, const Key& rhs) const
58 {
59 // look up timestamps for both keys
60 const auto timestamp_lhs = keys->find(lhs);
61 const auto timestamp_rhs = keys->find(rhs);
62
63 if (timestamp_lhs == keys->end())
64 {
65 // timestamp for lhs not found - cannot be smaller than for rhs
66 return false;
67 }
68
69 if (timestamp_rhs == keys->end())
70 {
71 // timestamp for rhs not found - timestamp for lhs is smaller
72 return true;
73 }
74
75 // compare timestamps
76 return timestamp_lhs->second < timestamp_rhs->second;
77 }
78
add_key(const Key & key)79 void add_key(const Key& key)
80 {
81 keys->insert({key, timestamp++});
82 }
83
remove_key(const Key & key)84 void remove_key(const Key& key)
85 {
86 keys->erase(key);
87 }
88
89 private:
90 /// pointer to a mapping from keys to insertion timestamps
91 std::unordered_map<Key, std::size_t>* keys = nullptr;
92 /// the next valid insertion timestamp
93 size_t timestamp = 1;
94 };
95
96
97 template <
98 class Key,
99 class T,
100 class Compare = fifo_map_compare<Key>,
101 class Allocator = std::allocator<std::pair<const Key, T>>
102 > class fifo_map
103 {
104 public:
105 using key_type = Key;
106 using mapped_type = T;
107 using value_type = std::pair<const Key, T>;
108 using size_type = std::size_t;
109 using difference_type = std::ptrdiff_t;
110 using key_compare = Compare;
111 using allocator_type = Allocator;
112 using reference = value_type&;
113 using const_reference = const value_type&;
114 using pointer = typename std::allocator_traits<Allocator>::pointer;
115 using const_pointer = typename std::allocator_traits<Allocator>::const_pointer;
116
117 using internal_map_type = std::map<Key, T, Compare, Allocator>;
118
119 using iterator = typename internal_map_type::iterator;
120 using const_iterator = typename internal_map_type::const_iterator;
121 using reverse_iterator = typename internal_map_type::reverse_iterator;
122 using const_reverse_iterator = typename internal_map_type::const_reverse_iterator;
123
124 public:
125 /// default constructor
fifo_map()126 fifo_map() : m_keys(), m_compare(&m_keys), m_map(m_compare) {}
127
128 /// copy constructor
fifo_map(const fifo_map & f)129 fifo_map(const fifo_map &f) : m_keys(f.m_keys), m_compare(&m_keys), m_map(f.m_map.begin(), f.m_map.end(), m_compare) {}
130
131 /// constructor for a range of elements
132 template<class InputIterator>
fifo_map(InputIterator first,InputIterator last)133 fifo_map(InputIterator first, InputIterator last)
134 : m_keys(), m_compare(&m_keys), m_map(m_compare)
135 {
136 for (auto it = first; it != last; ++it)
137 {
138 insert(*it);
139 }
140 }
141
142 /// constructor for a list of elements
fifo_map(std::initializer_list<value_type> init)143 fifo_map(std::initializer_list<value_type> init) : fifo_map()
144 {
145 for (auto x : init)
146 {
147 insert(x);
148 }
149 }
150
151
152 /*
153 * Element access
154 */
155
156 /// access specified element with bounds checking
at(const Key & key)157 T& at(const Key& key)
158 {
159 return m_map.at(key);
160 }
161
162 /// access specified element with bounds checking
at(const Key & key) const163 const T& at(const Key& key) const
164 {
165 return m_map.at(key);
166 }
167
168 /// access specified element
operator [](const Key & key)169 T& operator[](const Key& key)
170 {
171 m_compare.add_key(key);
172 return m_map[key];
173 }
174
175 /// access specified element
operator [](Key && key)176 T& operator[](Key&& key)
177 {
178 m_compare.add_key(key);
179 return m_map[key];
180 }
181
182
183 /*
184 * Iterators
185 */
186
187 /// returns an iterator to the beginning
begin()188 iterator begin() noexcept
189 {
190 return m_map.begin();
191 }
192
193 /// returns an iterator to the end
end()194 iterator end() noexcept
195 {
196 return m_map.end();
197 }
198
199 /// returns an iterator to the beginning
begin() const200 const_iterator begin() const noexcept
201 {
202 return m_map.begin();
203 }
204
205 /// returns an iterator to the end
end() const206 const_iterator end() const noexcept
207 {
208 return m_map.end();
209 }
210
211 /// returns an iterator to the beginning
cbegin() const212 const_iterator cbegin() const noexcept
213 {
214 return m_map.cbegin();
215 }
216
217 /// returns an iterator to the end
cend() const218 const_iterator cend() const noexcept
219 {
220 return m_map.cend();
221 }
222
223 /// returns a reverse iterator to the beginning
rbegin()224 reverse_iterator rbegin() noexcept
225 {
226 return m_map.rbegin();
227 }
228
229 /// returns a reverse iterator to the end
rend()230 reverse_iterator rend() noexcept
231 {
232 return m_map.rend();
233 }
234
235 /// returns a reverse iterator to the beginning
rbegin() const236 const_reverse_iterator rbegin() const noexcept
237 {
238 return m_map.rbegin();
239 }
240
241 /// returns a reverse iterator to the end
rend() const242 const_reverse_iterator rend() const noexcept
243 {
244 return m_map.rend();
245 }
246
247 /// returns a reverse iterator to the beginning
crbegin() const248 const_reverse_iterator crbegin() const noexcept
249 {
250 return m_map.crbegin();
251 }
252
253 /// returns a reverse iterator to the end
crend() const254 const_reverse_iterator crend() const noexcept
255 {
256 return m_map.crend();
257 }
258
259
260 /*
261 * Capacity
262 */
263
264 /// checks whether the container is empty
empty() const265 bool empty() const noexcept
266 {
267 return m_map.empty();
268 }
269
270 /// returns the number of elements
size() const271 size_type size() const noexcept
272 {
273 return m_map.size();
274 }
275
276 /// returns the maximum possible number of elements
max_size() const277 size_type max_size() const noexcept
278 {
279 return m_map.max_size();
280 }
281
282
283 /*
284 * Modifiers
285 */
286
287 /// clears the contents
clear()288 void clear() noexcept
289 {
290 m_map.clear();
291 m_keys.clear();
292 }
293
294 /// insert value
insert(const value_type & value)295 std::pair<iterator, bool> insert(const value_type& value)
296 {
297 m_compare.add_key(value.first);
298 return m_map.insert(value);
299 }
300
301 /// insert value
302 template<class P>
insert(P && value)303 std::pair<iterator, bool> insert( P&& value )
304 {
305 m_compare.add_key(value.first);
306 return m_map.insert(value);
307 }
308
309 /// insert value with hint
insert(const_iterator hint,const value_type & value)310 iterator insert(const_iterator hint, const value_type& value)
311 {
312 m_compare.add_key(value.first);
313 return m_map.insert(hint, value);
314 }
315
316 /// insert value with hint
insert(const_iterator hint,value_type && value)317 iterator insert(const_iterator hint, value_type&& value)
318 {
319 m_compare.add_key(value.first);
320 return m_map.insert(hint, value);
321 }
322
323 /// insert value range
324 template<class InputIt>
insert(InputIt first,InputIt last)325 void insert(InputIt first, InputIt last)
326 {
327 for (const_iterator it = first; it != last; ++it)
328 {
329 m_compare.add_key(it->first);
330 }
331
332 m_map.insert(first, last);
333 }
334
335 /// insert value list
insert(std::initializer_list<value_type> ilist)336 void insert(std::initializer_list<value_type> ilist)
337 {
338 for (auto value : ilist)
339 {
340 m_compare.add_key(value.first);
341 }
342
343 m_map.insert(ilist);
344 }
345
346 /// constructs element in-place
347 template<class... Args>
emplace(Args &&...args)348 std::pair<iterator, bool> emplace(Args&& ... args)
349 {
350 typename fifo_map::value_type value(std::forward<Args>(args)...);
351 m_compare.add_key(value.first);
352 return m_map.emplace(std::move(value));
353 }
354
355 /// constructs element in-place with hint
356 template<class... Args>
emplace_hint(const_iterator hint,Args &&...args)357 iterator emplace_hint(const_iterator hint, Args&& ... args)
358 {
359 typename fifo_map::value_type value(std::forward<Args>(args)...);
360 m_compare.add_key(value.first);
361 return m_map.emplace_hint(hint, std::move(value));
362 }
363
364 /// remove element at position
erase(const_iterator pos)365 iterator erase(const_iterator pos)
366 {
367 m_compare.remove_key(pos->first);
368 return m_map.erase(pos);
369 }
370
371 /// remove elements in range
erase(const_iterator first,const_iterator last)372 iterator erase(const_iterator first, const_iterator last)
373 {
374 for (const_iterator it = first; it != last; ++it)
375 {
376 m_compare.remove_key(it->first);
377 }
378
379 return m_map.erase(first, last);
380 }
381
382 /// remove elements with key
erase(const key_type & key)383 size_type erase(const key_type& key)
384 {
385 size_type res = m_map.erase(key);
386
387 if (res > 0)
388 {
389 m_compare.remove_key(key);
390 }
391
392 return res;
393 }
394
395 /// swaps the contents
swap(fifo_map & other)396 void swap(fifo_map& other)
397 {
398 std::swap(m_map, other.m_map);
399 std::swap(m_compare, other.m_compare);
400 std::swap(m_keys, other.m_keys);
401 }
402
403
404 /*
405 * Lookup
406 */
407
408 /// returns the number of elements matching specific key
count(const Key & key) const409 size_type count(const Key& key) const
410 {
411 return m_map.count(key);
412 }
413
414 /// finds element with specific key
find(const Key & key)415 iterator find(const Key& key)
416 {
417 return m_map.find(key);
418 }
419
420 /// finds element with specific key
find(const Key & key) const421 const_iterator find(const Key& key) const
422 {
423 return m_map.find(key);
424 }
425
426 /// returns range of elements matching a specific key
equal_range(const Key & key)427 std::pair<iterator, iterator> equal_range(const Key& key)
428 {
429 return m_map.equal_range(key);
430 }
431
432 /// returns range of elements matching a specific key
equal_range(const Key & key) const433 std::pair<const_iterator, const_iterator> equal_range(const Key& key) const
434 {
435 return m_map.equal_range(key);
436 }
437
438 /// returns an iterator to the first element not less than the given key
lower_bound(const Key & key)439 iterator lower_bound(const Key& key)
440 {
441 return m_map.lower_bound(key);
442 }
443
444 /// returns an iterator to the first element not less than the given key
lower_bound(const Key & key) const445 const_iterator lower_bound(const Key& key) const
446 {
447 return m_map.lower_bound(key);
448 }
449
450 /// returns an iterator to the first element greater than the given key
upper_bound(const Key & key)451 iterator upper_bound(const Key& key)
452 {
453 return m_map.upper_bound(key);
454 }
455
456 /// returns an iterator to the first element greater than the given key
upper_bound(const Key & key) const457 const_iterator upper_bound(const Key& key) const
458 {
459 return m_map.upper_bound(key);
460 }
461
462
463 /*
464 * Observers
465 */
466
467 /// returns the function that compares keys
key_comp() const468 key_compare key_comp() const
469 {
470 return m_compare;
471 }
472
473
474 /*
475 * Non-member functions
476 */
477
operator ==(const fifo_map & lhs,const fifo_map & rhs)478 friend bool operator==(const fifo_map& lhs, const fifo_map& rhs)
479 {
480 return lhs.m_map == rhs.m_map;
481 }
482
operator !=(const fifo_map & lhs,const fifo_map & rhs)483 friend bool operator!=(const fifo_map& lhs, const fifo_map& rhs)
484 {
485 return lhs.m_map != rhs.m_map;
486 }
487
operator <(const fifo_map & lhs,const fifo_map & rhs)488 friend bool operator<(const fifo_map& lhs, const fifo_map& rhs)
489 {
490 return lhs.m_map < rhs.m_map;
491 }
492
operator <=(const fifo_map & lhs,const fifo_map & rhs)493 friend bool operator<=(const fifo_map& lhs, const fifo_map& rhs)
494 {
495 return lhs.m_map <= rhs.m_map;
496 }
497
operator >(const fifo_map & lhs,const fifo_map & rhs)498 friend bool operator>(const fifo_map& lhs, const fifo_map& rhs)
499 {
500 return lhs.m_map > rhs.m_map;
501 }
502
operator >=(const fifo_map & lhs,const fifo_map & rhs)503 friend bool operator>=(const fifo_map& lhs, const fifo_map& rhs)
504 {
505 return lhs.m_map >= rhs.m_map;
506 }
507
508 private:
509 /// the keys
510 std::unordered_map<Key, std::size_t> m_keys;
511 /// the comparison object
512 Compare m_compare;
513 /// the internal data structure
514 internal_map_type m_map;
515 };
516
517 }
518
519 // specialization of std::swap
520 namespace std
521 {
522 template <class Key, class T, class Compare, class Allocator>
swap(nlohmann::fifo_map<Key,T,Compare,Allocator> & m1,nlohmann::fifo_map<Key,T,Compare,Allocator> & m2)523 inline void swap(nlohmann::fifo_map<Key, T, Compare, Allocator>& m1,
524 nlohmann::fifo_map<Key, T, Compare, Allocator>& m2)
525 {
526 m1.swap(m2);
527 }
528 }
529
530 #endif
531