F14Map.h 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368
  1. /*
  2. * Copyright 2017-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #pragma once
  17. /**
  18. * F14NodeMap, F14ValueMap, and F14VectorMap
  19. *
  20. * F14FastMap conditionally inherits from F14ValueMap or F14VectorMap
  21. *
  22. * See F14.md
  23. *
  24. * @author Nathan Bronson <ngbronson@fb.com>
  25. * @author Xiao Shi <xshi@fb.com>
  26. */
  27. #include <stdexcept>
  28. #include <folly/Traits.h>
  29. #include <folly/functional/ApplyTuple.h>
  30. #include <folly/lang/Exception.h>
  31. #include <folly/lang/SafeAssert.h>
  32. #include <folly/container/F14Map-fwd.h>
  33. #include <folly/container/detail/F14Policy.h>
  34. #include <folly/container/detail/F14Table.h>
  35. #if !FOLLY_F14_VECTOR_INTRINSICS_AVAILABLE
  36. //////// Compatibility for unsupported platforms (not x86_64 and not aarch64)
  37. #include <string>
  38. #include <unordered_map>
  39. namespace folly {
  40. namespace f14 {
  41. namespace detail {
  42. template <typename K, typename M, typename H, typename E, typename A>
  43. class F14BasicMap : public std::unordered_map<K, M, H, E, A> {
  44. using Super = std::unordered_map<K, M, H, E, A>;
  45. public:
  46. using typename Super::pointer;
  47. using typename Super::value_type;
  48. F14BasicMap() = default;
  49. using Super::Super;
  50. //// PUBLIC - F14 Extensions
  51. // exact for libstdc++, approximate for others
  52. std::size_t getAllocatedMemorySize() const {
  53. std::size_t rv = 0;
  54. visitAllocationClasses(
  55. [&](std::size_t bytes, std::size_t n) { rv += bytes * n; });
  56. return rv;
  57. }
  58. // exact for libstdc++, approximate for others
  59. template <typename V>
  60. void visitAllocationClasses(V&& visitor) const {
  61. auto bc = this->bucket_count();
  62. if (bc > 1) {
  63. visitor(bc * sizeof(pointer), 1);
  64. }
  65. if (this->size() > 0) {
  66. visitor(sizeof(StdNodeReplica<K, value_type, H>), this->size());
  67. }
  68. }
  69. template <typename V>
  70. void visitContiguousRanges(V&& visitor) const {
  71. for (value_type const& entry : *this) {
  72. value_type const* b = std::addressof(entry);
  73. visitor(b, b + 1);
  74. }
  75. }
  76. };
  77. } // namespace detail
  78. } // namespace f14
  79. template <
  80. typename Key,
  81. typename Mapped,
  82. typename Hasher,
  83. typename KeyEqual,
  84. typename Alloc>
  85. class F14ValueMap
  86. : public f14::detail::F14BasicMap<Key, Mapped, Hasher, KeyEqual, Alloc> {
  87. using Super = f14::detail::F14BasicMap<Key, Mapped, Hasher, KeyEqual, Alloc>;
  88. public:
  89. using typename Super::value_type;
  90. F14ValueMap() = default;
  91. using Super::Super;
  92. F14ValueMap& operator=(std::initializer_list<value_type> ilist) {
  93. Super::operator=(ilist);
  94. return *this;
  95. }
  96. };
  97. template <
  98. typename Key,
  99. typename Mapped,
  100. typename Hasher,
  101. typename KeyEqual,
  102. typename Alloc>
  103. class F14NodeMap
  104. : public f14::detail::F14BasicMap<Key, Mapped, Hasher, KeyEqual, Alloc> {
  105. using Super = f14::detail::F14BasicMap<Key, Mapped, Hasher, KeyEqual, Alloc>;
  106. public:
  107. using typename Super::value_type;
  108. F14NodeMap() = default;
  109. using Super::Super;
  110. F14NodeMap& operator=(std::initializer_list<value_type> ilist) {
  111. Super::operator=(ilist);
  112. return *this;
  113. }
  114. };
  115. template <
  116. typename Key,
  117. typename Mapped,
  118. typename Hasher,
  119. typename KeyEqual,
  120. typename Alloc>
  121. class F14VectorMap
  122. : public f14::detail::F14BasicMap<Key, Mapped, Hasher, KeyEqual, Alloc> {
  123. using Super = f14::detail::F14BasicMap<Key, Mapped, Hasher, KeyEqual, Alloc>;
  124. public:
  125. using typename Super::value_type;
  126. F14VectorMap() = default;
  127. using Super::Super;
  128. F14VectorMap& operator=(std::initializer_list<value_type> ilist) {
  129. Super::operator=(ilist);
  130. return *this;
  131. }
  132. };
  133. } // namespace folly
  134. #else // FOLLY_F14_VECTOR_INTRINSICS_AVAILABLE
  135. //////// Common case for supported platforms
  136. namespace folly {
  137. namespace f14 {
  138. namespace detail {
  139. template <typename Policy>
  140. class F14BasicMap {
  141. template <typename K, typename T>
  142. using EnableHeterogeneousFind = std::enable_if_t<
  143. EligibleForHeterogeneousFind<
  144. typename Policy::Key,
  145. typename Policy::Hasher,
  146. typename Policy::KeyEqual,
  147. K>::value,
  148. T>;
  149. template <typename K, typename T>
  150. using EnableHeterogeneousInsert = std::enable_if_t<
  151. EligibleForHeterogeneousInsert<
  152. typename Policy::Key,
  153. typename Policy::Hasher,
  154. typename Policy::KeyEqual,
  155. K>::value,
  156. T>;
  157. template <typename K, typename T>
  158. using EnableHeterogeneousErase = std::enable_if_t<
  159. EligibleForHeterogeneousFind<
  160. typename Policy::Value,
  161. typename Policy::Hasher,
  162. typename Policy::KeyEqual,
  163. K>::value &&
  164. !std::is_same<typename Policy::Iter, remove_cvref_t<K>>::value &&
  165. !std::is_same<typename Policy::ConstIter, remove_cvref_t<K>>::value,
  166. T>;
  167. public:
  168. //// PUBLIC - Member types
  169. using key_type = typename Policy::Key;
  170. using mapped_type = typename Policy::Mapped;
  171. using value_type = typename Policy::Value;
  172. using size_type = std::size_t;
  173. using difference_type = std::ptrdiff_t;
  174. using hasher = typename Policy::Hasher;
  175. using key_equal = typename Policy::KeyEqual;
  176. using allocator_type = typename Policy::Alloc;
  177. using reference = value_type&;
  178. using const_reference = value_type const&;
  179. using pointer = typename Policy::AllocTraits::pointer;
  180. using const_pointer = typename Policy::AllocTraits::const_pointer;
  181. using iterator = typename Policy::Iter;
  182. using const_iterator = typename Policy::ConstIter;
  183. private:
  184. using ItemIter = typename Policy::ItemIter;
  185. public:
  186. //// PUBLIC - Member functions
  187. F14BasicMap() noexcept(Policy::kDefaultConstructIsNoexcept)
  188. : F14BasicMap(0) {}
  189. explicit F14BasicMap(
  190. std::size_t initialCapacity,
  191. hasher const& hash = hasher{},
  192. key_equal const& eq = key_equal{},
  193. allocator_type const& alloc = allocator_type{})
  194. : table_{initialCapacity, hash, eq, alloc} {}
  195. explicit F14BasicMap(std::size_t initialCapacity, allocator_type const& alloc)
  196. : F14BasicMap(initialCapacity, hasher{}, key_equal{}, alloc) {}
  197. explicit F14BasicMap(
  198. std::size_t initialCapacity,
  199. hasher const& hash,
  200. allocator_type const& alloc)
  201. : F14BasicMap(initialCapacity, hash, key_equal{}, alloc) {}
  202. explicit F14BasicMap(allocator_type const& alloc)
  203. : F14BasicMap(0, hasher{}, key_equal{}, alloc) {}
  204. template <typename InputIt>
  205. F14BasicMap(
  206. InputIt first,
  207. InputIt last,
  208. std::size_t initialCapacity = 0,
  209. hasher const& hash = hasher{},
  210. key_equal const& eq = key_equal{},
  211. allocator_type const& alloc = allocator_type{})
  212. : table_{initialCapacity, hash, eq, alloc} {
  213. initialInsert(first, last, initialCapacity);
  214. }
  215. template <typename InputIt>
  216. F14BasicMap(
  217. InputIt first,
  218. InputIt last,
  219. std::size_t initialCapacity,
  220. allocator_type const& alloc)
  221. : table_{initialCapacity, hasher{}, key_equal{}, alloc} {
  222. initialInsert(first, last, initialCapacity);
  223. }
  224. template <typename InputIt>
  225. F14BasicMap(
  226. InputIt first,
  227. InputIt last,
  228. std::size_t initialCapacity,
  229. hasher const& hash,
  230. allocator_type const& alloc)
  231. : table_{initialCapacity, hash, key_equal{}, alloc} {
  232. initialInsert(first, last, initialCapacity);
  233. }
  234. F14BasicMap(F14BasicMap const& rhs) = default;
  235. F14BasicMap(F14BasicMap const& rhs, allocator_type const& alloc)
  236. : table_{rhs.table_, alloc} {}
  237. F14BasicMap(F14BasicMap&& rhs) = default;
  238. F14BasicMap(F14BasicMap&& rhs, allocator_type const& alloc) noexcept(
  239. Policy::kAllocIsAlwaysEqual)
  240. : table_{std::move(rhs.table_), alloc} {}
  241. F14BasicMap(
  242. std::initializer_list<value_type> init,
  243. std::size_t initialCapacity = 0,
  244. hasher const& hash = hasher{},
  245. key_equal const& eq = key_equal{},
  246. allocator_type const& alloc = allocator_type{})
  247. : table_{initialCapacity, hash, eq, alloc} {
  248. initialInsert(init.begin(), init.end(), initialCapacity);
  249. }
  250. F14BasicMap(
  251. std::initializer_list<value_type> init,
  252. std::size_t initialCapacity,
  253. allocator_type const& alloc)
  254. : table_{initialCapacity, hasher{}, key_equal{}, alloc} {
  255. initialInsert(init.begin(), init.end(), initialCapacity);
  256. }
  257. F14BasicMap(
  258. std::initializer_list<value_type> init,
  259. std::size_t initialCapacity,
  260. hasher const& hash,
  261. allocator_type const& alloc)
  262. : table_{initialCapacity, hash, key_equal{}, alloc} {
  263. initialInsert(init.begin(), init.end(), initialCapacity);
  264. }
  265. F14BasicMap& operator=(F14BasicMap const&) = default;
  266. F14BasicMap& operator=(F14BasicMap&&) = default;
  267. F14BasicMap& operator=(std::initializer_list<value_type> ilist) {
  268. clear();
  269. bulkInsert(ilist.begin(), ilist.end(), false);
  270. return *this;
  271. }
  272. allocator_type get_allocator() const noexcept {
  273. return table_.alloc();
  274. }
  275. //// PUBLIC - Iterators
  276. iterator begin() noexcept {
  277. return table_.makeIter(table_.begin());
  278. }
  279. const_iterator begin() const noexcept {
  280. return cbegin();
  281. }
  282. const_iterator cbegin() const noexcept {
  283. return table_.makeConstIter(table_.begin());
  284. }
  285. iterator end() noexcept {
  286. return table_.makeIter(table_.end());
  287. }
  288. const_iterator end() const noexcept {
  289. return cend();
  290. }
  291. const_iterator cend() const noexcept {
  292. return table_.makeConstIter(table_.end());
  293. }
  294. //// PUBLIC - Capacity
  295. bool empty() const noexcept {
  296. return table_.empty();
  297. }
  298. std::size_t size() const noexcept {
  299. return table_.size();
  300. }
  301. std::size_t max_size() const noexcept {
  302. return table_.max_size();
  303. }
  304. //// PUBLIC - Modifiers
  305. void clear() noexcept {
  306. table_.clear();
  307. }
  308. std::pair<iterator, bool> insert(value_type const& value) {
  309. return emplace(value);
  310. }
  311. template <typename P>
  312. std::enable_if_t<
  313. std::is_constructible<value_type, P&&>::value,
  314. std::pair<iterator, bool>>
  315. insert(P&& value) {
  316. return emplace(std::forward<P>(value));
  317. }
  318. // TODO(T31574848): Work around libstdc++ versions (e.g., GCC < 6) with no
  319. // implementation of N4387 ("perfect initialization" for pairs and tuples).
  320. template <typename U1, typename U2>
  321. std::enable_if_t<
  322. std::is_constructible<key_type, U1 const&>::value &&
  323. std::is_constructible<mapped_type, U2 const&>::value,
  324. std::pair<iterator, bool>>
  325. insert(std::pair<U1, U2> const& value) {
  326. return emplace(value);
  327. }
  328. // TODO(T31574848)
  329. template <typename U1, typename U2>
  330. std::enable_if_t<
  331. std::is_constructible<key_type, U1&&>::value &&
  332. std::is_constructible<mapped_type, U2&&>::value,
  333. std::pair<iterator, bool>>
  334. insert(std::pair<U1, U2>&& value) {
  335. return emplace(std::move(value));
  336. }
  337. std::pair<iterator, bool> insert(value_type&& value) {
  338. return emplace(std::move(value));
  339. }
  340. // std::unordered_map's hinted insertion API is misleading. No
  341. // implementation I've seen actually uses the hint. Code restructuring
  342. // by the caller to use the hinted API is at best unnecessary, and at
  343. // worst a pessimization. It is used, however, so we provide it.
  344. iterator insert(const_iterator /*hint*/, value_type const& value) {
  345. return insert(value).first;
  346. }
  347. template <typename P>
  348. std::enable_if_t<std::is_constructible<value_type, P&&>::value, iterator>
  349. insert(const_iterator /*hint*/, P&& value) {
  350. return insert(std::forward<P>(value)).first;
  351. }
  352. iterator insert(const_iterator /*hint*/, value_type&& value) {
  353. return insert(std::move(value)).first;
  354. }
  355. template <class... Args>
  356. iterator emplace_hint(const_iterator /*hint*/, Args&&... args) {
  357. return emplace(std::forward<Args>(args)...).first;
  358. }
  359. private:
  360. template <class InputIt>
  361. FOLLY_ALWAYS_INLINE void
  362. bulkInsert(InputIt first, InputIt last, bool autoReserve) {
  363. if (autoReserve) {
  364. table_.reserveForInsert(std::distance(first, last));
  365. }
  366. while (first != last) {
  367. insert(*first);
  368. ++first;
  369. }
  370. }
  371. template <class InputIt>
  372. void initialInsert(InputIt first, InputIt last, std::size_t initialCapacity) {
  373. FOLLY_SAFE_DCHECK(empty() && bucket_count() >= initialCapacity, "");
  374. // It's possible that there are a lot of duplicates in first..last and
  375. // so we will oversize ourself. The common case, however, is that
  376. // we can avoid a lot of rehashing if we pre-expand. The behavior
  377. // is easy to disable at a particular call site by asking for an
  378. // initialCapacity of 1.
  379. bool autoReserve =
  380. std::is_same<
  381. typename std::iterator_traits<InputIt>::iterator_category,
  382. std::random_access_iterator_tag>::value &&
  383. initialCapacity == 0;
  384. bulkInsert(first, last, autoReserve);
  385. }
  386. public:
  387. template <class InputIt>
  388. void insert(InputIt first, InputIt last) {
  389. // Bulk reserve is a heuristic choice, so it can backfire. We restrict
  390. // ourself to situations that mimic bulk construction without an
  391. // explicit initialCapacity.
  392. bool autoReserve =
  393. std::is_same<
  394. typename std::iterator_traits<InputIt>::iterator_category,
  395. std::random_access_iterator_tag>::value &&
  396. bucket_count() == 0;
  397. bulkInsert(first, last, autoReserve);
  398. }
  399. void insert(std::initializer_list<value_type> ilist) {
  400. insert(ilist.begin(), ilist.end());
  401. }
  402. template <typename M>
  403. std::pair<iterator, bool> insert_or_assign(key_type const& key, M&& obj) {
  404. auto rv = try_emplace(key, std::forward<M>(obj));
  405. if (!rv.second) {
  406. rv.first->second = std::forward<M>(obj);
  407. }
  408. return rv;
  409. }
  410. template <typename M>
  411. std::pair<iterator, bool> insert_or_assign(key_type&& key, M&& obj) {
  412. auto rv = try_emplace(std::move(key), std::forward<M>(obj));
  413. if (!rv.second) {
  414. rv.first->second = std::forward<M>(obj);
  415. }
  416. return rv;
  417. }
  418. template <typename M>
  419. iterator
  420. insert_or_assign(const_iterator /*hint*/, key_type const& key, M&& obj) {
  421. return insert_or_assign(key, std::move(obj)).first;
  422. }
  423. template <typename M>
  424. iterator insert_or_assign(const_iterator /*hint*/, key_type&& key, M&& obj) {
  425. return insert_or_assign(std::move(key), std::move(obj)).first;
  426. }
  427. template <typename K, typename M>
  428. EnableHeterogeneousInsert<K, std::pair<iterator, bool>> insert_or_assign(
  429. K&& key,
  430. M&& obj) {
  431. auto rv = try_emplace(std::forward<K>(key), std::forward<M>(obj));
  432. if (!rv.second) {
  433. rv.first->second = std::forward<M>(obj);
  434. }
  435. return rv;
  436. }
  437. private:
  438. std::pair<ItemIter, bool> emplaceItem() {
  439. // rare but valid
  440. return table_.tryEmplaceValue(key_type{});
  441. }
  442. template <typename U1, typename U2>
  443. std::pair<ItemIter, bool> emplaceItem(U1&& x, U2&& y) {
  444. using K = KeyTypeForEmplace<key_type, hasher, key_equal, U1>;
  445. K key(std::forward<U1>(x));
  446. // TODO(T31574848): piecewise_construct is to work around libstdc++ versions
  447. // (e.g., GCC < 6) with no implementation of N4387 ("perfect initialization"
  448. // for pairs and tuples). Otherwise we could just pass key, forwarded key,
  449. // and forwarded y to tryEmplaceValue.
  450. return table_.tryEmplaceValue(
  451. key,
  452. std::piecewise_construct,
  453. std::forward_as_tuple(std::forward<K>(key)),
  454. std::forward_as_tuple(std::forward<U2>(y)));
  455. }
  456. template <typename U1, typename U2>
  457. std::pair<ItemIter, bool> emplaceItem(std::pair<U1, U2> const& p) {
  458. return emplaceItem(p.first, p.second);
  459. }
  460. template <typename U1, typename U2>
  461. std::pair<ItemIter, bool> emplaceItem(std::pair<U1, U2>&& p) {
  462. return emplaceItem(std::move(p.first), std::move(p.second));
  463. }
  464. template <typename Arg1, typename... Args2>
  465. std::pair<ItemIter, bool> emplaceItem(
  466. std::piecewise_construct_t,
  467. std::tuple<Arg1>&& first_args,
  468. std::tuple<Args2...>&& second_args) {
  469. using K = KeyTypeForEmplace<key_type, hasher, key_equal, Arg1>;
  470. K key(std::get<0>(std::move(first_args)));
  471. // Args2&&... holds only references even if the caller gave us a
  472. // tuple that directly contains values.
  473. return table_.tryEmplaceValue(
  474. key,
  475. std::piecewise_construct,
  476. std::forward_as_tuple(std::forward<K>(key)),
  477. std::tuple<Args2&&...>(std::move(second_args)));
  478. }
  479. template <typename... Args1, typename... Args2>
  480. std::enable_if_t<sizeof...(Args1) != 1, std::pair<ItemIter, bool>>
  481. emplaceItem(
  482. std::piecewise_construct_t,
  483. std::tuple<Args1...>&& first_args,
  484. std::tuple<Args2...>&& second_args) {
  485. auto key = make_from_tuple<key_type>(
  486. std::tuple<Args1&&...>(std::move(first_args)));
  487. return table_.tryEmplaceValue(
  488. key,
  489. std::piecewise_construct,
  490. std::forward_as_tuple(std::move(key)),
  491. std::tuple<Args2&&...>(std::move(second_args)));
  492. }
  493. public:
  494. template <typename... Args>
  495. std::pair<iterator, bool> emplace(Args&&... args) {
  496. auto rv = emplaceItem(std::forward<Args>(args)...);
  497. return std::make_pair(table_.makeIter(rv.first), rv.second);
  498. }
  499. template <typename... Args>
  500. std::pair<iterator, bool> try_emplace(key_type const& key, Args&&... args) {
  501. auto rv = table_.tryEmplaceValue(
  502. key,
  503. std::piecewise_construct,
  504. std::forward_as_tuple(key),
  505. std::forward_as_tuple(std::forward<Args>(args)...));
  506. return std::make_pair(table_.makeIter(rv.first), rv.second);
  507. }
  508. template <typename... Args>
  509. std::pair<iterator, bool> try_emplace(key_type&& key, Args&&... args) {
  510. auto rv = table_.tryEmplaceValue(
  511. key,
  512. std::piecewise_construct,
  513. std::forward_as_tuple(std::move(key)),
  514. std::forward_as_tuple(std::forward<Args>(args)...));
  515. return std::make_pair(table_.makeIter(rv.first), rv.second);
  516. }
  517. template <typename... Args>
  518. iterator
  519. try_emplace(const_iterator /*hint*/, key_type const& key, Args&&... args) {
  520. auto rv = table_.tryEmplaceValue(
  521. key,
  522. std::piecewise_construct,
  523. std::forward_as_tuple(key),
  524. std::forward_as_tuple(std::forward<Args>(args)...));
  525. return table_.makeIter(rv.first);
  526. }
  527. template <typename... Args>
  528. iterator
  529. try_emplace(const_iterator /*hint*/, key_type&& key, Args&&... args) {
  530. auto rv = table_.tryEmplaceValue(
  531. key,
  532. std::piecewise_construct,
  533. std::forward_as_tuple(std::move(key)),
  534. std::forward_as_tuple(std::forward<Args>(args)...));
  535. return table_.makeIter(rv.first);
  536. }
  537. template <typename K, typename... Args>
  538. EnableHeterogeneousInsert<K, std::pair<iterator, bool>> try_emplace(
  539. K&& key,
  540. Args&&... args) {
  541. auto rv = table_.tryEmplaceValue(
  542. key,
  543. std::piecewise_construct,
  544. std::forward_as_tuple(std::forward<K>(key)),
  545. std::forward_as_tuple(std::forward<Args>(args)...));
  546. return std::make_pair(table_.makeIter(rv.first), rv.second);
  547. }
  548. FOLLY_ALWAYS_INLINE iterator erase(const_iterator pos) {
  549. // If we are inlined then gcc and clang can optimize away all of the
  550. // work of itemPos.advance() if our return value is discarded.
  551. auto itemPos = table_.unwrapIter(pos);
  552. table_.eraseIter(itemPos);
  553. itemPos.advanceLikelyDead();
  554. return table_.makeIter(itemPos);
  555. }
  556. // This form avoids ambiguity when key_type has a templated constructor
  557. // that accepts const_iterator
  558. iterator erase(iterator pos) {
  559. auto itemPos = table_.unwrapIter(pos);
  560. table_.eraseIter(itemPos);
  561. itemPos.advanceLikelyDead();
  562. return table_.makeIter(itemPos);
  563. }
  564. iterator erase(const_iterator first, const_iterator last) {
  565. auto itemFirst = table_.unwrapIter(first);
  566. auto itemLast = table_.unwrapIter(last);
  567. while (itemFirst != itemLast) {
  568. table_.eraseIter(itemFirst);
  569. itemFirst.advance();
  570. }
  571. return table_.makeIter(itemFirst);
  572. }
  573. size_type erase(key_type const& key) {
  574. return table_.eraseKey(key);
  575. }
  576. template <typename K>
  577. EnableHeterogeneousErase<K, size_type> erase(K const& key) {
  578. return table_.eraseKey(key);
  579. }
  580. //// PUBLIC - Lookup
  581. FOLLY_ALWAYS_INLINE mapped_type& at(key_type const& key) {
  582. return at(*this, key);
  583. }
  584. FOLLY_ALWAYS_INLINE mapped_type const& at(key_type const& key) const {
  585. return at(*this, key);
  586. }
  587. template <typename K>
  588. EnableHeterogeneousFind<K, mapped_type&> at(K const& key) {
  589. return at(*this, key);
  590. }
  591. template <typename K>
  592. EnableHeterogeneousFind<K, mapped_type const&> at(K const& key) const {
  593. return at(*this, key);
  594. }
  595. mapped_type& operator[](key_type const& key) {
  596. return try_emplace(key).first->second;
  597. }
  598. mapped_type& operator[](key_type&& key) {
  599. return try_emplace(std::move(key)).first->second;
  600. }
  601. template <typename K>
  602. EnableHeterogeneousInsert<K, mapped_type&> operator[](K&& key) {
  603. return try_emplace(std::forward<K>(key)).first->second;
  604. }
  605. FOLLY_ALWAYS_INLINE std::size_t count(key_type const& key) const {
  606. return table_.find(key).atEnd() ? 0 : 1;
  607. }
  608. template <typename K>
  609. FOLLY_ALWAYS_INLINE EnableHeterogeneousFind<K, std::size_t> count(
  610. K const& key) const {
  611. return table_.find(key).atEnd() ? 0 : 1;
  612. }
  613. // prehash(key) does the work of evaluating hash_function()(key)
  614. // (including additional bit-mixing for non-avalanching hash functions),
  615. // wraps the result of that work in a token for later reuse, and
  616. // begins prefetching the first steps of looking for key into the
  617. // local CPU cache.
  618. //
  619. // The returned token may be used at any time, may be used more than
  620. // once, and may be used in other F14 sets and maps. Tokens are
  621. // transferrable between any F14 containers (maps and sets) with the
  622. // same key_type and equal hash_function()s.
  623. //
  624. // Hash tokens are not hints -- it is a bug to call any method on this
  625. // class with a token t and key k where t isn't the result of a call
  626. // to prehash(k2) with k2 == k.
  627. F14HashToken prehash(key_type const& key) const {
  628. return table_.prehash(key);
  629. }
  630. template <typename K>
  631. EnableHeterogeneousFind<K, F14HashToken> prehash(K const& key) const {
  632. return table_.prehash(key);
  633. }
  634. FOLLY_ALWAYS_INLINE iterator find(key_type const& key) {
  635. return table_.makeIter(table_.find(key));
  636. }
  637. FOLLY_ALWAYS_INLINE const_iterator find(key_type const& key) const {
  638. return table_.makeConstIter(table_.find(key));
  639. }
  640. FOLLY_ALWAYS_INLINE iterator
  641. find(F14HashToken const& token, key_type const& key) {
  642. return table_.makeIter(table_.find(token, key));
  643. }
  644. FOLLY_ALWAYS_INLINE const_iterator
  645. find(F14HashToken const& token, key_type const& key) const {
  646. return table_.makeConstIter(table_.find(token, key));
  647. }
  648. template <typename K>
  649. FOLLY_ALWAYS_INLINE EnableHeterogeneousFind<K, iterator> find(K const& key) {
  650. return table_.makeIter(table_.find(key));
  651. }
  652. template <typename K>
  653. FOLLY_ALWAYS_INLINE EnableHeterogeneousFind<K, const_iterator> find(
  654. K const& key) const {
  655. return table_.makeConstIter(table_.find(key));
  656. }
  657. template <typename K>
  658. FOLLY_ALWAYS_INLINE EnableHeterogeneousFind<K, iterator> find(
  659. F14HashToken const& token,
  660. K const& key) {
  661. return table_.makeIter(table_.find(token, key));
  662. }
  663. template <typename K>
  664. FOLLY_ALWAYS_INLINE EnableHeterogeneousFind<K, const_iterator> find(
  665. F14HashToken const& token,
  666. K const& key) const {
  667. return table_.makeConstIter(table_.find(token, key));
  668. }
  669. std::pair<iterator, iterator> equal_range(key_type const& key) {
  670. return equal_range(*this, key);
  671. }
  672. std::pair<const_iterator, const_iterator> equal_range(
  673. key_type const& key) const {
  674. return equal_range(*this, key);
  675. }
  676. template <typename K>
  677. EnableHeterogeneousFind<K, std::pair<iterator, iterator>> equal_range(
  678. K const& key) {
  679. return equal_range(*this, key);
  680. }
  681. template <typename K>
  682. EnableHeterogeneousFind<K, std::pair<const_iterator, const_iterator>>
  683. equal_range(K const& key) const {
  684. return equal_range(*this, key);
  685. }
  686. //// PUBLIC - Bucket interface
  687. std::size_t bucket_count() const noexcept {
  688. return table_.bucket_count();
  689. }
  690. std::size_t max_bucket_count() const noexcept {
  691. return table_.max_bucket_count();
  692. }
  693. //// PUBLIC - Hash policy
  694. float load_factor() const noexcept {
  695. return table_.load_factor();
  696. }
  697. float max_load_factor() const noexcept {
  698. return table_.max_load_factor();
  699. }
  700. void max_load_factor(float v) {
  701. table_.max_load_factor(v);
  702. }
  703. void rehash(std::size_t bucketCapacity) {
  704. // The standard's rehash() requires understanding the max load factor,
  705. // which is easy to get wrong. Since we don't actually allow adjustment
  706. // of max_load_factor there is no difference.
  707. reserve(bucketCapacity);
  708. }
  709. void reserve(std::size_t capacity) {
  710. table_.reserve(capacity);
  711. }
  712. //// PUBLIC - Observers
  713. hasher hash_function() const {
  714. return table_.hasher();
  715. }
  716. key_equal key_eq() const {
  717. return table_.keyEqual();
  718. }
  719. //// PUBLIC - F14 Extensions
  720. // Get memory footprint, not including sizeof(*this).
  721. std::size_t getAllocatedMemorySize() const {
  722. return table_.getAllocatedMemorySize();
  723. }
  724. // Enumerates classes of allocated memory blocks currently owned
  725. // by this table, calling visitor(allocationSize, allocationCount).
  726. // This can be used to get a more accurate indication of memory footprint
  727. // than getAllocatedMemorySize() if you have some way of computing the
  728. // internal fragmentation of the allocator, such as JEMalloc's nallocx.
  729. // The visitor might be called twice with the same allocationSize. The
  730. // visitor's computation should produce the same result for visitor(8,
  731. // 2) as for two calls to visitor(8, 1), for example. The visitor may
  732. // be called with a zero allocationCount.
  733. template <typename V>
  734. void visitAllocationClasses(V&& visitor) const {
  735. return table_.visitAllocationClasses(visitor);
  736. }
  737. // Calls visitor with two value_type const*, b and e, such that every
  738. // entry in the table is included in exactly one of the ranges [b,e).
  739. // This can be used to efficiently iterate elements in bulk when crossing
  740. // an API boundary that supports contiguous blocks of items.
  741. template <typename V>
  742. void visitContiguousRanges(V&& visitor) const;
  743. F14TableStats computeStats() const noexcept {
  744. return table_.computeStats();
  745. }
  746. private:
  747. template <typename Self, typename K>
  748. FOLLY_ALWAYS_INLINE static auto& at(Self& self, K const& key) {
  749. auto iter = self.find(key);
  750. if (iter == self.end()) {
  751. throw_exception<std::out_of_range>("at() did not find key");
  752. }
  753. return iter->second;
  754. }
  755. template <typename Self, typename K>
  756. static auto equal_range(Self& self, K const& key) {
  757. auto first = self.find(key);
  758. auto last = first;
  759. if (last != self.end()) {
  760. ++last;
  761. }
  762. return std::make_pair(first, last);
  763. }
  764. protected:
  765. F14Table<Policy> table_;
  766. };
  767. template <typename M>
  768. bool mapsEqual(M const& lhs, M const& rhs) {
  769. if (lhs.size() != rhs.size()) {
  770. return false;
  771. }
  772. for (auto& kv : lhs) {
  773. auto iter = rhs.find(kv.first);
  774. if (iter == rhs.end()) {
  775. return false;
  776. }
  777. if (std::is_same<
  778. typename M::key_equal,
  779. std::equal_to<typename M::key_type>>::value) {
  780. // find already checked key, just check value
  781. if (!(kv.second == iter->second)) {
  782. return false;
  783. }
  784. } else {
  785. // spec says we compare key with == as well as with key_eq()
  786. if (!(kv == *iter)) {
  787. return false;
  788. }
  789. }
  790. }
  791. return true;
  792. }
  793. } // namespace detail
  794. } // namespace f14
  795. template <
  796. typename Key,
  797. typename Mapped,
  798. typename Hasher,
  799. typename KeyEqual,
  800. typename Alloc>
  801. class F14ValueMap
  802. : public f14::detail::F14BasicMap<f14::detail::MapPolicyWithDefaults<
  803. f14::detail::ValueContainerPolicy,
  804. Key,
  805. Mapped,
  806. Hasher,
  807. KeyEqual,
  808. Alloc>> {
  809. using Policy = f14::detail::MapPolicyWithDefaults<
  810. f14::detail::ValueContainerPolicy,
  811. Key,
  812. Mapped,
  813. Hasher,
  814. KeyEqual,
  815. Alloc>;
  816. using Super = f14::detail::F14BasicMap<Policy>;
  817. public:
  818. using typename Super::value_type;
  819. F14ValueMap() = default;
  820. using Super::Super;
  821. F14ValueMap& operator=(std::initializer_list<value_type> ilist) {
  822. Super::operator=(ilist);
  823. return *this;
  824. }
  825. void swap(F14ValueMap& rhs) noexcept(Policy::kSwapIsNoexcept) {
  826. this->table_.swap(rhs.table_);
  827. }
  828. template <typename V>
  829. void visitContiguousRanges(V&& visitor) const {
  830. this->table_.visitContiguousItemRanges(visitor);
  831. }
  832. };
  833. template <typename K, typename M, typename H, typename E, typename A>
  834. bool operator==(
  835. F14ValueMap<K, M, H, E, A> const& lhs,
  836. F14ValueMap<K, M, H, E, A> const& rhs) {
  837. return mapsEqual(lhs, rhs);
  838. }
  839. template <typename K, typename M, typename H, typename E, typename A>
  840. bool operator!=(
  841. F14ValueMap<K, M, H, E, A> const& lhs,
  842. F14ValueMap<K, M, H, E, A> const& rhs) {
  843. return !(lhs == rhs);
  844. }
  845. template <
  846. typename Key,
  847. typename Mapped,
  848. typename Hasher,
  849. typename KeyEqual,
  850. typename Alloc>
  851. class F14NodeMap
  852. : public f14::detail::F14BasicMap<f14::detail::MapPolicyWithDefaults<
  853. f14::detail::NodeContainerPolicy,
  854. Key,
  855. Mapped,
  856. Hasher,
  857. KeyEqual,
  858. Alloc>> {
  859. using Policy = f14::detail::MapPolicyWithDefaults<
  860. f14::detail::NodeContainerPolicy,
  861. Key,
  862. Mapped,
  863. Hasher,
  864. KeyEqual,
  865. Alloc>;
  866. using Super = f14::detail::F14BasicMap<Policy>;
  867. public:
  868. using typename Super::value_type;
  869. F14NodeMap() = default;
  870. using Super::Super;
  871. F14NodeMap& operator=(std::initializer_list<value_type> ilist) {
  872. Super::operator=(ilist);
  873. return *this;
  874. }
  875. void swap(F14NodeMap& rhs) noexcept(Policy::kSwapIsNoexcept) {
  876. this->table_.swap(rhs.table_);
  877. }
  878. template <typename V>
  879. void visitContiguousRanges(V&& visitor) const {
  880. this->table_.visitItems([&](typename Policy::Item ptr) {
  881. value_type const* b = std::addressof(*ptr);
  882. visitor(b, b + 1);
  883. });
  884. }
  885. // TODO extract and node_handle insert
  886. };
  887. template <typename K, typename M, typename H, typename E, typename A>
  888. bool operator==(
  889. F14NodeMap<K, M, H, E, A> const& lhs,
  890. F14NodeMap<K, M, H, E, A> const& rhs) {
  891. return mapsEqual(lhs, rhs);
  892. }
  893. template <typename K, typename M, typename H, typename E, typename A>
  894. bool operator!=(
  895. F14NodeMap<K, M, H, E, A> const& lhs,
  896. F14NodeMap<K, M, H, E, A> const& rhs) {
  897. return !(lhs == rhs);
  898. }
  899. template <
  900. typename Key,
  901. typename Mapped,
  902. typename Hasher,
  903. typename KeyEqual,
  904. typename Alloc>
  905. class F14VectorMap
  906. : public f14::detail::F14BasicMap<f14::detail::MapPolicyWithDefaults<
  907. f14::detail::VectorContainerPolicy,
  908. Key,
  909. Mapped,
  910. Hasher,
  911. KeyEqual,
  912. Alloc>> {
  913. using Policy = f14::detail::MapPolicyWithDefaults<
  914. f14::detail::VectorContainerPolicy,
  915. Key,
  916. Mapped,
  917. Hasher,
  918. KeyEqual,
  919. Alloc>;
  920. using Super = f14::detail::F14BasicMap<Policy>;
  921. template <typename K, typename T>
  922. using EnableHeterogeneousVectorErase = std::enable_if_t<
  923. f14::detail::EligibleForHeterogeneousFind<
  924. typename Policy::Value,
  925. typename Policy::Hasher,
  926. typename Policy::KeyEqual,
  927. K>::value &&
  928. !std::is_same<typename Policy::Iter, remove_cvref_t<K>>::value &&
  929. !std::is_same<typename Policy::ConstIter, remove_cvref_t<K>>::value &&
  930. !std::is_same<typename Policy::ReverseIter, remove_cvref_t<K>>::
  931. value &&
  932. !std::is_same<typename Policy::ConstReverseIter, remove_cvref_t<K>>::
  933. value,
  934. T>;
  935. public:
  936. using typename Super::const_iterator;
  937. using typename Super::iterator;
  938. using typename Super::key_type;
  939. using typename Super::value_type;
  940. using reverse_iterator = typename Policy::ReverseIter;
  941. using const_reverse_iterator = typename Policy::ConstReverseIter;
  942. F14VectorMap() = default;
  943. // inherit constructors
  944. using Super::Super;
  945. F14VectorMap& operator=(std::initializer_list<value_type> ilist) {
  946. Super::operator=(ilist);
  947. return *this;
  948. }
  949. void swap(F14VectorMap& rhs) noexcept(Policy::kSwapIsNoexcept) {
  950. this->table_.swap(rhs.table_);
  951. }
  952. // ITERATION ORDER
  953. //
  954. // Deterministic iteration order for insert-only workloads is part of
  955. // F14VectorMap's supported API: iterator is LIFO and reverse_iterator
  956. // is FIFO.
  957. //
  958. // If there have been no calls to erase() then iterator and
  959. // const_iterator enumerate entries in the opposite of insertion order.
  960. // begin()->first is the key most recently inserted. reverse_iterator
  961. // and reverse_const_iterator, therefore, enumerate in LIFO (insertion)
  962. // order for insert-only workloads. Deterministic iteration order is
  963. // only guaranteed if no keys were removed since the last time the
  964. // map was empty. Iteration order is preserved across rehashes and
  965. // F14VectorMap copies and moves.
  966. //
  967. // iterator uses LIFO order so that erasing while iterating with begin()
  968. // and end() is safe using the erase(it++) idiom, which is supported
  969. // by std::map and std::unordered_map. erase(iter) invalidates iter
  970. // and all iterators before iter in the non-reverse iteration order.
  971. // Every successful erase invalidates all reverse iterators.
  972. iterator begin() {
  973. return this->table_.linearBegin(this->size());
  974. }
  975. const_iterator begin() const {
  976. return cbegin();
  977. }
  978. const_iterator cbegin() const {
  979. return this->table_.linearBegin(this->size());
  980. }
  981. iterator end() {
  982. return this->table_.linearEnd();
  983. }
  984. const_iterator end() const {
  985. return cend();
  986. }
  987. const_iterator cend() const {
  988. return this->table_.linearEnd();
  989. }
  990. reverse_iterator rbegin() {
  991. return this->table_.values_;
  992. }
  993. const_reverse_iterator rbegin() const {
  994. return crbegin();
  995. }
  996. const_reverse_iterator crbegin() const {
  997. return this->table_.values_;
  998. }
  999. reverse_iterator rend() {
  1000. return this->table_.values_ + this->table_.size();
  1001. }
  1002. const_reverse_iterator rend() const {
  1003. return crend();
  1004. }
  1005. const_reverse_iterator crend() const {
  1006. return this->table_.values_ + this->table_.size();
  1007. }
  1008. // explicit conversions between iterator and reverse_iterator
  1009. iterator iter(reverse_iterator riter) {
  1010. return this->table_.iter(riter);
  1011. }
  1012. const_iterator iter(const_reverse_iterator riter) const {
  1013. return this->table_.iter(riter);
  1014. }
  1015. reverse_iterator riter(iterator it) {
  1016. return this->table_.riter(it);
  1017. }
  1018. const_reverse_iterator riter(const_iterator it) const {
  1019. return this->table_.riter(it);
  1020. }
  1021. private:
  1022. void eraseUnderlying(typename Policy::ItemIter underlying) {
  1023. Alloc& a = this->table_.alloc();
  1024. auto values = this->table_.values_;
  1025. // Remove the ptr from the base table and destroy the value.
  1026. auto index = underlying.item();
  1027. // The item still needs to be hashable during this call, so we must destroy
  1028. // the value _afterwards_.
  1029. this->table_.eraseIter(underlying);
  1030. Policy::AllocTraits::destroy(a, std::addressof(values[index]));
  1031. // move the last element in values_ down and fix up the inbound index
  1032. auto tailIndex = this->size();
  1033. if (tailIndex != index) {
  1034. auto tail = this->table_.find(f14::detail::VectorContainerIndexSearch{
  1035. static_cast<uint32_t>(tailIndex)});
  1036. tail.item() = index;
  1037. auto p = std::addressof(values[index]);
  1038. assume(p != nullptr);
  1039. this->table_.transfer(a, std::addressof(values[tailIndex]), p, 1);
  1040. }
  1041. }
  1042. template <typename K>
  1043. std::size_t eraseUnderlyingKey(K const& key) {
  1044. auto underlying = this->table_.find(key);
  1045. if (underlying.atEnd()) {
  1046. return 0;
  1047. } else {
  1048. eraseUnderlying(underlying);
  1049. return 1;
  1050. }
  1051. }
  1052. public:
  1053. FOLLY_ALWAYS_INLINE iterator erase(const_iterator pos) {
  1054. auto index = this->table_.iterToIndex(pos);
  1055. auto underlying =
  1056. this->table_.find(f14::detail::VectorContainerIndexSearch{index});
  1057. eraseUnderlying(underlying);
  1058. return index == 0 ? end() : this->table_.indexToIter(index - 1);
  1059. }
  1060. // This form avoids ambiguity when key_type has a templated constructor
  1061. // that accepts const_iterator
  1062. FOLLY_ALWAYS_INLINE iterator erase(iterator pos) {
  1063. const_iterator cpos{pos};
  1064. return erase(cpos);
  1065. }
  1066. iterator erase(const_iterator first, const_iterator last) {
  1067. while (first != last) {
  1068. first = erase(first);
  1069. }
  1070. auto index = this->table_.iterToIndex(first);
  1071. return index == 0 ? end() : this->table_.indexToIter(index - 1);
  1072. }
  1073. // No erase is provided for reverse_iterator or const_reverse_iterator
  1074. // to make it harder to shoot yourself in the foot by erasing while
  1075. // reverse-iterating. You can write that as map.erase(map.iter(riter)).
  1076. std::size_t erase(key_type const& key) {
  1077. return eraseUnderlyingKey(key);
  1078. }
  1079. template <typename K>
  1080. EnableHeterogeneousVectorErase<K, std::size_t> erase(K const& key) {
  1081. return eraseUnderlyingKey(key);
  1082. }
  1083. template <typename V>
  1084. void visitContiguousRanges(V&& visitor) const {
  1085. auto n = this->table_.size();
  1086. if (n > 0) {
  1087. value_type const* b = std::addressof(this->table_.values_[0]);
  1088. visitor(b, b + n);
  1089. }
  1090. }
  1091. };
  1092. template <typename K, typename M, typename H, typename E, typename A>
  1093. bool operator==(
  1094. F14VectorMap<K, M, H, E, A> const& lhs,
  1095. F14VectorMap<K, M, H, E, A> const& rhs) {
  1096. return mapsEqual(lhs, rhs);
  1097. }
  1098. template <typename K, typename M, typename H, typename E, typename A>
  1099. bool operator!=(
  1100. F14VectorMap<K, M, H, E, A> const& lhs,
  1101. F14VectorMap<K, M, H, E, A> const& rhs) {
  1102. return !(lhs == rhs);
  1103. }
  1104. } // namespace folly
  1105. #endif // FOLLY_F14_VECTOR_INTRINSICS_AVAILABLE
  1106. namespace folly {
  1107. template <
  1108. typename Key,
  1109. typename Mapped,
  1110. typename Hasher,
  1111. typename KeyEqual,
  1112. typename Alloc>
  1113. class F14FastMap : public std::conditional_t<
  1114. sizeof(std::pair<Key const, Mapped>) < 24,
  1115. F14ValueMap<Key, Mapped, Hasher, KeyEqual, Alloc>,
  1116. F14VectorMap<Key, Mapped, Hasher, KeyEqual, Alloc>> {
  1117. using Super = std::conditional_t<
  1118. sizeof(std::pair<Key const, Mapped>) < 24,
  1119. F14ValueMap<Key, Mapped, Hasher, KeyEqual, Alloc>,
  1120. F14VectorMap<Key, Mapped, Hasher, KeyEqual, Alloc>>;
  1121. public:
  1122. using typename Super::value_type;
  1123. F14FastMap() = default;
  1124. using Super::Super;
  1125. F14FastMap& operator=(std::initializer_list<value_type> ilist) {
  1126. Super::operator=(ilist);
  1127. return *this;
  1128. }
  1129. };
  1130. template <typename K, typename M, typename H, typename E, typename A>
  1131. void swap(
  1132. F14ValueMap<K, M, H, E, A>& lhs,
  1133. F14ValueMap<K, M, H, E, A>& rhs) noexcept(noexcept(lhs.swap(rhs))) {
  1134. lhs.swap(rhs);
  1135. }
  1136. template <typename K, typename M, typename H, typename E, typename A>
  1137. void swap(
  1138. F14NodeMap<K, M, H, E, A>& lhs,
  1139. F14NodeMap<K, M, H, E, A>& rhs) noexcept(noexcept(lhs.swap(rhs))) {
  1140. lhs.swap(rhs);
  1141. }
  1142. template <typename K, typename M, typename H, typename E, typename A>
  1143. void swap(
  1144. F14VectorMap<K, M, H, E, A>& lhs,
  1145. F14VectorMap<K, M, H, E, A>& rhs) noexcept(noexcept(lhs.swap(rhs))) {
  1146. lhs.swap(rhs);
  1147. }
  1148. template <typename K, typename M, typename H, typename E, typename A>
  1149. void swap(
  1150. F14FastMap<K, M, H, E, A>& lhs,
  1151. F14FastMap<K, M, H, E, A>& rhs) noexcept(noexcept(lhs.swap(rhs))) {
  1152. lhs.swap(rhs);
  1153. }
  1154. } // namespace folly