flat_map.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. // Copyright 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef BASE_CONTAINERS_FLAT_MAP_H_
  5. #define BASE_CONTAINERS_FLAT_MAP_H_
  6. #include <functional>
  7. #include <tuple>
  8. #include <utility>
  9. #include "base/check.h"
  10. #include "base/containers/flat_tree.h"
  11. #include "base/template_util.h"
  12. namespace base {
  13. namespace internal {
  14. // An implementation of the flat_tree GetKeyFromValue template parameter that
  15. // extracts the key as the first element of a pair.
  16. template <class Key, class Mapped>
  17. struct GetKeyFromValuePairFirst {
  18. const Key& operator()(const std::pair<Key, Mapped>& p) const {
  19. return p.first;
  20. }
  21. };
  22. } // namespace internal
  23. // flat_map is a container with a std::map-like interface that stores its
  24. // contents in a sorted vector.
  25. //
  26. // Please see //base/containers/README.md for an overview of which container
  27. // to select.
  28. //
  29. // PROS
  30. //
  31. // - Good memory locality.
  32. // - Low overhead, especially for smaller maps.
  33. // - Performance is good for more workloads than you might expect (see
  34. // overview link above).
  35. // - Supports C++14 map interface.
  36. //
  37. // CONS
  38. //
  39. // - Inserts and removals are O(n).
  40. //
  41. // IMPORTANT NOTES
  42. //
  43. // - Iterators are invalidated across mutations.
  44. // - If possible, construct a flat_map in one operation by inserting into
  45. // a std::vector and moving that vector into the flat_map constructor.
  46. //
  47. // QUICK REFERENCE
  48. //
  49. // Most of the core functionality is inherited from flat_tree. Please see
  50. // flat_tree.h for more details for most of these functions. As a quick
  51. // reference, the functions available are:
  52. //
  53. // Constructors (inputs need not be sorted):
  54. // flat_map(InputIterator first, InputIterator last,
  55. // const Compare& compare = Compare());
  56. // flat_map(const flat_map&);
  57. // flat_map(flat_map&&);
  58. // flat_map(const std::vector<value_type>& items,
  59. // const Compare& compare = Compare());
  60. // flat_map(std::vector<value_type>&& items,
  61. // const Compare& compare = Compare()); // Re-use storage.
  62. // flat_map(std::initializer_list<value_type> ilist,
  63. // const Compare& comp = Compare());
  64. //
  65. // Assignment functions:
  66. // flat_map& operator=(const flat_map&);
  67. // flat_map& operator=(flat_map&&);
  68. // flat_map& operator=(initializer_list<value_type>);
  69. //
  70. // Memory management functions:
  71. // void reserve(size_t);
  72. // size_t capacity() const;
  73. // void shrink_to_fit();
  74. //
  75. // Size management functions:
  76. // void clear();
  77. // size_t size() const;
  78. // size_t max_size() const;
  79. // bool empty() const;
  80. //
  81. // Iterator functions:
  82. // iterator begin();
  83. // const_iterator begin() const;
  84. // const_iterator cbegin() const;
  85. // iterator end();
  86. // const_iterator end() const;
  87. // const_iterator cend() const;
  88. // reverse_iterator rbegin();
  89. // const reverse_iterator rbegin() const;
  90. // const_reverse_iterator crbegin() const;
  91. // reverse_iterator rend();
  92. // const_reverse_iterator rend() const;
  93. // const_reverse_iterator crend() const;
  94. //
  95. // Insert and accessor functions:
  96. // mapped_type& operator[](const key_type&);
  97. // mapped_type& operator[](key_type&&);
  98. // mapped_type& at(const K&);
  99. // const mapped_type& at(const K&) const;
  100. // pair<iterator, bool> insert(const value_type&);
  101. // pair<iterator, bool> insert(value_type&&);
  102. // iterator insert(const_iterator hint, const value_type&);
  103. // iterator insert(const_iterator hint, value_type&&);
  104. // void insert(InputIterator first, InputIterator last);
  105. // pair<iterator, bool> insert_or_assign(K&&, M&&);
  106. // iterator insert_or_assign(const_iterator hint, K&&, M&&);
  107. // pair<iterator, bool> emplace(Args&&...);
  108. // iterator emplace_hint(const_iterator, Args&&...);
  109. // pair<iterator, bool> try_emplace(K&&, Args&&...);
  110. // iterator try_emplace(const_iterator hint, K&&, Args&&...);
  111. // Underlying type functions:
  112. // underlying_type extract() &&;
  113. // void replace(underlying_type&&);
  114. //
  115. // Erase functions:
  116. // iterator erase(iterator);
  117. // iterator erase(const_iterator);
  118. // iterator erase(const_iterator first, const_iterator& last);
  119. // template <class K> size_t erase(const K& key);
  120. //
  121. // Comparators (see std::map documentation).
  122. // key_compare key_comp() const;
  123. // value_compare value_comp() const;
  124. //
  125. // Search functions:
  126. // template <typename K> size_t count(const K&) const;
  127. // template <typename K> iterator find(const K&);
  128. // template <typename K> const_iterator find(const K&) const;
  129. // template <typename K> bool contains(const K&) const;
  130. // template <typename K> pair<iterator, iterator> equal_range(const K&);
  131. // template <typename K> iterator lower_bound(const K&);
  132. // template <typename K> const_iterator lower_bound(const K&) const;
  133. // template <typename K> iterator upper_bound(const K&);
  134. // template <typename K> const_iterator upper_bound(const K&) const;
  135. //
  136. // General functions:
  137. // void swap(flat_map&&);
  138. //
  139. // Non-member operators:
  140. // bool operator==(const flat_map&, const flat_map);
  141. // bool operator!=(const flat_map&, const flat_map);
  142. // bool operator<(const flat_map&, const flat_map);
  143. // bool operator>(const flat_map&, const flat_map);
  144. // bool operator>=(const flat_map&, const flat_map);
  145. // bool operator<=(const flat_map&, const flat_map);
  146. //
  147. template <class Key, class Mapped, class Compare = std::less<>>
  148. class flat_map : public ::base::internal::flat_tree<
  149. Key,
  150. std::pair<Key, Mapped>,
  151. ::base::internal::GetKeyFromValuePairFirst<Key, Mapped>,
  152. Compare> {
  153. private:
  154. using tree = typename ::base::internal::flat_tree<
  155. Key,
  156. std::pair<Key, Mapped>,
  157. ::base::internal::GetKeyFromValuePairFirst<Key, Mapped>,
  158. Compare>;
  159. using underlying_type = typename tree::underlying_type;
  160. public:
  161. using key_type = typename tree::key_type;
  162. using mapped_type = Mapped;
  163. using value_type = typename tree::value_type;
  164. using iterator = typename tree::iterator;
  165. using const_iterator = typename tree::const_iterator;
  166. // --------------------------------------------------------------------------
  167. // Lifetime and assignments.
  168. //
  169. // Note: we could do away with these constructors, destructor and assignment
  170. // operator overloads by inheriting |tree|'s, but this breaks the GCC build
  171. // due to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84782 (see
  172. // https://crbug.com/837221).
  173. flat_map() = default;
  174. explicit flat_map(const Compare& comp);
  175. template <class InputIterator>
  176. flat_map(InputIterator first,
  177. InputIterator last,
  178. const Compare& comp = Compare());
  179. flat_map(const flat_map&) = default;
  180. flat_map(flat_map&&) noexcept = default;
  181. flat_map(const underlying_type& items, const Compare& comp = Compare());
  182. flat_map(underlying_type&& items, const Compare& comp = Compare());
  183. flat_map(std::initializer_list<value_type> ilist,
  184. const Compare& comp = Compare());
  185. ~flat_map() = default;
  186. flat_map& operator=(const flat_map&) = default;
  187. flat_map& operator=(flat_map&&) noexcept = default;
  188. // Takes the first if there are duplicates in the initializer list.
  189. flat_map& operator=(std::initializer_list<value_type> ilist);
  190. // Out-of-bound calls to at() will CHECK.
  191. template <class K>
  192. mapped_type& at(const K& key);
  193. template <class K>
  194. const mapped_type& at(const K& key) const;
  195. // --------------------------------------------------------------------------
  196. // Map-specific insert operations.
  197. //
  198. // Normal insert() functions are inherited from flat_tree.
  199. //
  200. // Assume that every operation invalidates iterators and references.
  201. // Insertion of one element can take O(size).
  202. mapped_type& operator[](const key_type& key);
  203. mapped_type& operator[](key_type&& key);
  204. template <class K, class M>
  205. std::pair<iterator, bool> insert_or_assign(K&& key, M&& obj);
  206. template <class K, class M>
  207. iterator insert_or_assign(const_iterator hint, K&& key, M&& obj);
  208. template <class K, class... Args>
  209. std::enable_if_t<std::is_constructible<key_type, K&&>::value,
  210. std::pair<iterator, bool>>
  211. try_emplace(K&& key, Args&&... args);
  212. template <class K, class... Args>
  213. std::enable_if_t<std::is_constructible<key_type, K&&>::value, iterator>
  214. try_emplace(const_iterator hint, K&& key, Args&&... args);
  215. // --------------------------------------------------------------------------
  216. // General operations.
  217. //
  218. // Assume that swap invalidates iterators and references.
  219. void swap(flat_map& other) noexcept;
  220. friend void swap(flat_map& lhs, flat_map& rhs) noexcept { lhs.swap(rhs); }
  221. };
  222. // ----------------------------------------------------------------------------
  223. // Lifetime.
  224. template <class Key, class Mapped, class Compare>
  225. flat_map<Key, Mapped, Compare>::flat_map(const Compare& comp) : tree(comp) {}
  226. template <class Key, class Mapped, class Compare>
  227. template <class InputIterator>
  228. flat_map<Key, Mapped, Compare>::flat_map(InputIterator first,
  229. InputIterator last,
  230. const Compare& comp)
  231. : tree(first, last, comp) {}
  232. template <class Key, class Mapped, class Compare>
  233. flat_map<Key, Mapped, Compare>::flat_map(const underlying_type& items,
  234. const Compare& comp)
  235. : tree(items, comp) {}
  236. template <class Key, class Mapped, class Compare>
  237. flat_map<Key, Mapped, Compare>::flat_map(underlying_type&& items,
  238. const Compare& comp)
  239. : tree(std::move(items), comp) {}
  240. template <class Key, class Mapped, class Compare>
  241. flat_map<Key, Mapped, Compare>::flat_map(
  242. std::initializer_list<value_type> ilist,
  243. const Compare& comp)
  244. : flat_map(std::begin(ilist), std::end(ilist), comp) {}
  245. // ----------------------------------------------------------------------------
  246. // Assignments.
  247. template <class Key, class Mapped, class Compare>
  248. auto flat_map<Key, Mapped, Compare>::operator=(
  249. std::initializer_list<value_type> ilist) -> flat_map& {
  250. // When https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84782 gets fixed, we
  251. // need to remember to inherit tree::operator= to prevent
  252. // flat_map<...> x;
  253. // x = {...};
  254. // from first creating a flat_map and then move assigning it. This most
  255. // likely would be optimized away but still affects our debug builds.
  256. tree::operator=(ilist);
  257. return *this;
  258. }
  259. // ----------------------------------------------------------------------------
  260. // Lookups.
  261. template <class Key, class Mapped, class Compare>
  262. template <class K>
  263. auto flat_map<Key, Mapped, Compare>::at(const K& key) -> mapped_type& {
  264. iterator found = tree::find(key);
  265. CHECK(found != tree::end());
  266. return found->second;
  267. }
  268. template <class Key, class Mapped, class Compare>
  269. template <class K>
  270. auto flat_map<Key, Mapped, Compare>::at(const K& key) const
  271. -> const mapped_type& {
  272. const_iterator found = tree::find(key);
  273. CHECK(found != tree::cend());
  274. return found->second;
  275. }
  276. // ----------------------------------------------------------------------------
  277. // Insert operations.
  278. template <class Key, class Mapped, class Compare>
  279. auto flat_map<Key, Mapped, Compare>::operator[](const key_type& key)
  280. -> mapped_type& {
  281. iterator found = tree::lower_bound(key);
  282. if (found == tree::end() || tree::key_comp()(key, found->first))
  283. found = tree::unsafe_emplace(found, key, mapped_type());
  284. return found->second;
  285. }
  286. template <class Key, class Mapped, class Compare>
  287. auto flat_map<Key, Mapped, Compare>::operator[](key_type&& key)
  288. -> mapped_type& {
  289. iterator found = tree::lower_bound(key);
  290. if (found == tree::end() || tree::key_comp()(key, found->first))
  291. found = tree::unsafe_emplace(found, std::move(key), mapped_type());
  292. return found->second;
  293. }
  294. template <class Key, class Mapped, class Compare>
  295. template <class K, class M>
  296. auto flat_map<Key, Mapped, Compare>::insert_or_assign(K&& key, M&& obj)
  297. -> std::pair<iterator, bool> {
  298. auto result =
  299. tree::emplace_key_args(key, std::forward<K>(key), std::forward<M>(obj));
  300. if (!result.second)
  301. result.first->second = std::forward<M>(obj);
  302. return result;
  303. }
  304. template <class Key, class Mapped, class Compare>
  305. template <class K, class M>
  306. auto flat_map<Key, Mapped, Compare>::insert_or_assign(const_iterator hint,
  307. K&& key,
  308. M&& obj) -> iterator {
  309. auto result = tree::emplace_hint_key_args(hint, key, std::forward<K>(key),
  310. std::forward<M>(obj));
  311. if (!result.second)
  312. result.first->second = std::forward<M>(obj);
  313. return result.first;
  314. }
  315. template <class Key, class Mapped, class Compare>
  316. template <class K, class... Args>
  317. auto flat_map<Key, Mapped, Compare>::try_emplace(K&& key, Args&&... args)
  318. -> std::enable_if_t<std::is_constructible<key_type, K&&>::value,
  319. std::pair<iterator, bool>> {
  320. return tree::emplace_key_args(
  321. key, std::piecewise_construct,
  322. std::forward_as_tuple(std::forward<K>(key)),
  323. std::forward_as_tuple(std::forward<Args>(args)...));
  324. }
  325. template <class Key, class Mapped, class Compare>
  326. template <class K, class... Args>
  327. auto flat_map<Key, Mapped, Compare>::try_emplace(const_iterator hint,
  328. K&& key,
  329. Args&&... args)
  330. -> std::enable_if_t<std::is_constructible<key_type, K&&>::value, iterator> {
  331. return tree::emplace_hint_key_args(
  332. hint, key, std::piecewise_construct,
  333. std::forward_as_tuple(std::forward<K>(key)),
  334. std::forward_as_tuple(std::forward<Args>(args)...))
  335. .first;
  336. }
  337. // ----------------------------------------------------------------------------
  338. // General operations.
  339. template <class Key, class Mapped, class Compare>
  340. void flat_map<Key, Mapped, Compare>::swap(flat_map& other) noexcept {
  341. tree::swap(other);
  342. }
  343. } // namespace base
  344. #endif // BASE_CONTAINERS_FLAT_MAP_H_