ordered_map.hpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. #pragma once
  2. #include <functional> // less
  3. #include <initializer_list> // initializer_list
  4. #include <iterator> // input_iterator_tag, iterator_traits
  5. #include <memory> // allocator
  6. #include <stdexcept> // for out_of_range
  7. #include <type_traits> // enable_if, is_convertible
  8. #include <utility> // pair
  9. #include <vector> // vector
  10. #include <nlohmann/detail/macro_scope.hpp>
  11. namespace nlohmann
  12. {
  13. /// ordered_map: a minimal map-like container that preserves insertion order
  14. /// for use within nlohmann::basic_json<ordered_map>
  15. template <class Key, class T, class IgnoredLess = std::less<Key>,
  16. class Allocator = std::allocator<std::pair<const Key, T>>>
  17. struct ordered_map : std::vector<std::pair<const Key, T>, Allocator>
  18. {
  19. using key_type = Key;
  20. using mapped_type = T;
  21. using Container = std::vector<std::pair<const Key, T>, Allocator>;
  22. using iterator = typename Container::iterator;
  23. using const_iterator = typename Container::const_iterator;
  24. using size_type = typename Container::size_type;
  25. using value_type = typename Container::value_type;
  26. // Explicit constructors instead of `using Container::Container`
  27. // otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4)
  28. ordered_map(const Allocator& alloc = Allocator()) : Container{alloc} {}
  29. template <class It>
  30. ordered_map(It first, It last, const Allocator& alloc = Allocator())
  31. : Container{first, last, alloc} {}
  32. ordered_map(std::initializer_list<T> init, const Allocator& alloc = Allocator() )
  33. : Container{init, alloc} {}
  34. std::pair<iterator, bool> emplace(const key_type& key, T&& t)
  35. {
  36. for (auto it = this->begin(); it != this->end(); ++it)
  37. {
  38. if (it->first == key)
  39. {
  40. return {it, false};
  41. }
  42. }
  43. Container::emplace_back(key, t);
  44. return {--this->end(), true};
  45. }
  46. T& operator[](const Key& key)
  47. {
  48. return emplace(key, T{}).first->second;
  49. }
  50. const T& operator[](const Key& key) const
  51. {
  52. return at(key);
  53. }
  54. T& at(const Key& key)
  55. {
  56. for (auto it = this->begin(); it != this->end(); ++it)
  57. {
  58. if (it->first == key)
  59. {
  60. return it->second;
  61. }
  62. }
  63. JSON_THROW(std::out_of_range("key not found"));
  64. }
  65. const T& at(const Key& key) const
  66. {
  67. for (auto it = this->begin(); it != this->end(); ++it)
  68. {
  69. if (it->first == key)
  70. {
  71. return it->second;
  72. }
  73. }
  74. JSON_THROW(std::out_of_range("key not found"));
  75. }
  76. size_type erase(const Key& key)
  77. {
  78. for (auto it = this->begin(); it != this->end(); ++it)
  79. {
  80. if (it->first == key)
  81. {
  82. // Since we cannot move const Keys, re-construct them in place
  83. for (auto next = it; ++next != this->end(); ++it)
  84. {
  85. it->~value_type(); // Destroy but keep allocation
  86. new (&*it) value_type{std::move(*next)};
  87. }
  88. Container::pop_back();
  89. return 1;
  90. }
  91. }
  92. return 0;
  93. }
  94. iterator erase(iterator pos)
  95. {
  96. return erase(pos, std::next(pos));
  97. }
  98. iterator erase(iterator first, iterator last)
  99. {
  100. const auto elements_affected = std::distance(first, last);
  101. const auto offset = std::distance(Container::begin(), first);
  102. // This is the start situation. We need to delete elements_affected
  103. // elements (3 in this example: e, f, g), and need to return an
  104. // iterator past the last deleted element (h in this example).
  105. // Note that offset is the distance from the start of the vector
  106. // to first. We will need this later.
  107. // [ a, b, c, d, e, f, g, h, i, j ]
  108. // ^ ^
  109. // first last
  110. // Since we cannot move const Keys, we re-construct them in place.
  111. // We start at first and re-construct (viz. copy) the elements from
  112. // the back of the vector. Example for first iteration:
  113. // ,--------.
  114. // v | destroy e and re-construct with h
  115. // [ a, b, c, d, e, f, g, h, i, j ]
  116. // ^ ^
  117. // it it + elements_affected
  118. for (auto it = first; std::next(it, elements_affected) != Container::end(); ++it)
  119. {
  120. it->~value_type(); // destroy but keep allocation
  121. new (&*it) value_type{std::move(*std::next(it, elements_affected))}; // "move" next element to it
  122. }
  123. // [ a, b, c, d, h, i, j, h, i, j ]
  124. // ^ ^
  125. // first last
  126. // remove the unneeded elements at the end of the vector
  127. Container::resize(this->size() - static_cast<size_type>(elements_affected));
  128. // [ a, b, c, d, h, i, j ]
  129. // ^ ^
  130. // first last
  131. // first is now pointing past the last deleted element, but we cannot
  132. // use this iterator, because it may have been invalidated by the
  133. // resize call. Instead, we can return begin() + offset.
  134. return Container::begin() + offset;
  135. }
  136. size_type count(const Key& key) const
  137. {
  138. for (auto it = this->begin(); it != this->end(); ++it)
  139. {
  140. if (it->first == key)
  141. {
  142. return 1;
  143. }
  144. }
  145. return 0;
  146. }
  147. iterator find(const Key& key)
  148. {
  149. for (auto it = this->begin(); it != this->end(); ++it)
  150. {
  151. if (it->first == key)
  152. {
  153. return it;
  154. }
  155. }
  156. return Container::end();
  157. }
  158. const_iterator find(const Key& key) const
  159. {
  160. for (auto it = this->begin(); it != this->end(); ++it)
  161. {
  162. if (it->first == key)
  163. {
  164. return it;
  165. }
  166. }
  167. return Container::end();
  168. }
  169. std::pair<iterator, bool> insert( value_type&& value )
  170. {
  171. return emplace(value.first, std::move(value.second));
  172. }
  173. std::pair<iterator, bool> insert( const value_type& value )
  174. {
  175. for (auto it = this->begin(); it != this->end(); ++it)
  176. {
  177. if (it->first == value.first)
  178. {
  179. return {it, false};
  180. }
  181. }
  182. Container::push_back(value);
  183. return {--this->end(), true};
  184. }
  185. template<typename InputIt>
  186. using require_input_iter = typename std::enable_if<std::is_convertible<typename std::iterator_traits<InputIt>::iterator_category,
  187. std::input_iterator_tag>::value>::type;
  188. template<typename InputIt, typename = require_input_iter<InputIt>>
  189. void insert(InputIt first, InputIt last)
  190. {
  191. for (auto it = first; it != last; ++it)
  192. {
  193. insert(*it);
  194. }
  195. }
  196. };
  197. } // namespace nlohmann