• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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