map.h 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #ifndef CARBON_COMMON_MAP_H_
  5. #define CARBON_COMMON_MAP_H_
  6. #include <algorithm>
  7. #include <concepts>
  8. #include <utility>
  9. #include "common/check.h"
  10. #include "common/concepts.h"
  11. #include "common/hashtable_key_context.h"
  12. #include "common/raw_hashtable.h"
  13. #include "llvm/Support/Compiler.h"
  14. namespace Carbon {
  15. // Forward declarations to resolve cyclic references.
  16. template <typename KeyT, typename ValueT, typename KeyContextT>
  17. class MapView;
  18. template <typename KeyT, typename ValueT, typename KeyContextT>
  19. class MapBase;
  20. template <typename KeyT, typename ValueT, ssize_t SmallSize,
  21. typename KeyContextT>
  22. class Map;
  23. // A read-only view type for a map from key to value.
  24. //
  25. // This view is a cheap-to-copy type that should be passed by value, but
  26. // provides view or read-only reference semantics to the underlying map data
  27. // structure.
  28. //
  29. // This should always be preferred to a `const`-ref parameter for the `MapBase`
  30. // or `Map` type as it provides more flexibility and a cleaner API.
  31. //
  32. // Note that while this type is a read-only view, that applies to the underlying
  33. // *map* data structure, not the individual entries stored within it. Those can
  34. // be mutated freely as long as both the hashes and equality of the keys are
  35. // preserved. If we applied a deep-`const` design here, it would prevent using
  36. // this type in many useful situations where the elements are mutated but the
  37. // associative container is not. A view of immutable data can always be obtained
  38. // by using `MapView<const T, const V>`, and we enable conversions to more-const
  39. // views. This mirrors the semantics of views like `std::span`.
  40. //
  41. // A specific `KeyContextT` type can optionally be provided to configure how
  42. // keys will be hashed and compared. The default is `DefaultKeyContext` which is
  43. // stateless and will hash using `Carbon::HashValue` and compare using
  44. // `operator==`. Every method accepting a lookup key or operating on the keys in
  45. // the table will also accept an instance of this type. For stateless context
  46. // types, including the default, an instance will be default constructed if not
  47. // provided to these methods. However, stateful contexts should be constructed
  48. // and passed in explicitly. The context type should be small and reasonable to
  49. // pass by value, often a wrapper or pointer to the relevant context needed for
  50. // hashing and comparing keys. For more details about the key context, see
  51. // `hashtable_key_context.h`.
  52. template <typename InputKeyT, typename InputValueT,
  53. typename InputKeyContextT = DefaultKeyContext>
  54. class MapView
  55. : RawHashtable::ViewImpl<InputKeyT, InputValueT, InputKeyContextT> {
  56. using ImplT =
  57. RawHashtable::ViewImpl<InputKeyT, InputValueT, InputKeyContextT>;
  58. using EntryT = typename ImplT::EntryT;
  59. public:
  60. using KeyT = typename ImplT::KeyT;
  61. using ValueT = typename ImplT::ValueT;
  62. using KeyContextT = typename ImplT::KeyContextT;
  63. using MetricsT = typename ImplT::MetricsT;
  64. // This type represents the result of lookup operations. It encodes whether
  65. // the lookup was a success as well as accessors for the key and value.
  66. class LookupKVResult {
  67. public:
  68. LookupKVResult() = default;
  69. explicit LookupKVResult(EntryT* entry) : entry_(entry) {}
  70. explicit operator bool() const { return entry_ != nullptr; }
  71. auto key() const -> KeyT& { return entry_->key(); }
  72. auto value() const -> ValueT& { return entry_->value(); }
  73. private:
  74. EntryT* entry_ = nullptr;
  75. };
  76. // Enable implicit conversions that add `const`-ness to either key or value
  77. // type. This is always safe to do with a view. We use a template to avoid
  78. // needing all 3 versions.
  79. template <typename OtherKeyT, typename OtherValueT>
  80. explicit(false)
  81. MapView(MapView<OtherKeyT, OtherValueT, KeyContextT> other_view)
  82. requires(SameAsOneOf<KeyT, OtherKeyT, const OtherKeyT> &&
  83. SameAsOneOf<ValueT, OtherValueT, const OtherValueT>)
  84. : ImplT(other_view) {}
  85. // Tests whether a key is present in the map.
  86. template <typename LookupKeyT>
  87. auto Contains(LookupKeyT lookup_key,
  88. KeyContextT key_context = KeyContextT()) const -> bool;
  89. // Lookup a key in the map.
  90. template <typename LookupKeyT>
  91. auto Lookup(LookupKeyT lookup_key,
  92. KeyContextT key_context = KeyContextT()) const -> LookupKVResult;
  93. // Lookup a key in the map and try to return a pointer to its value. Returns
  94. // null on a missing key.
  95. template <typename LookupKeyT>
  96. auto operator[](LookupKeyT lookup_key) const
  97. -> ValueT* requires(std::default_initializable<KeyContextT>);
  98. // Run the provided callback for every key and value in the map.
  99. template <typename CallbackT>
  100. auto ForEach(CallbackT callback) -> void
  101. requires(std::invocable<CallbackT, KeyT&, ValueT&>);
  102. // This routine is relatively inefficient and only intended for use in
  103. // benchmarking or logging of performance anomalies. The specific metrics
  104. // returned have no specific guarantees beyond being informative in
  105. // benchmarks.
  106. auto ComputeMetrics(KeyContextT key_context = KeyContextT()) -> MetricsT {
  107. return ImplT::ComputeMetricsImpl(key_context);
  108. }
  109. private:
  110. template <typename MapKeyT, typename MapValueT, ssize_t MinSmallSize,
  111. typename KeyContextT>
  112. friend class Map;
  113. friend class MapBase<KeyT, ValueT, KeyContextT>;
  114. friend class MapView<const KeyT, ValueT, KeyContextT>;
  115. friend class MapView<KeyT, const ValueT, KeyContextT>;
  116. friend class MapView<const KeyT, const ValueT, KeyContextT>;
  117. MapView() = default;
  118. explicit(false) MapView(ImplT base) : ImplT(base) {}
  119. MapView(ssize_t size, RawHashtable::Storage* storage)
  120. : ImplT(size, storage) {}
  121. };
  122. // A base class for a `Map` type that remains mutable while type-erasing the
  123. // `SmallSize` (SSO) template parameter.
  124. //
  125. // A pointer or reference to this type is the preferred way to pass a mutable
  126. // handle to a `Map` type across API boundaries as it avoids encoding specific
  127. // SSO sizing information while providing a near-complete mutable API.
  128. template <typename InputKeyT, typename InputValueT,
  129. typename InputKeyContextT = DefaultKeyContext>
  130. class MapBase : protected RawHashtable::BaseImpl<InputKeyT, InputValueT,
  131. InputKeyContextT> {
  132. protected:
  133. using ImplT =
  134. RawHashtable::BaseImpl<InputKeyT, InputValueT, InputKeyContextT>;
  135. using EntryT = typename ImplT::EntryT;
  136. public:
  137. using KeyT = typename ImplT::KeyT;
  138. using ValueT = typename ImplT::ValueT;
  139. using KeyContextT = typename ImplT::KeyContextT;
  140. using ViewT = MapView<KeyT, ValueT, KeyContextT>;
  141. using LookupKVResult = typename ViewT::LookupKVResult;
  142. using MetricsT = typename ImplT::MetricsT;
  143. // The result type for insertion operations both indicates whether an insert
  144. // was needed (as opposed to finding an existing element), and provides access
  145. // to the element's key and value.
  146. class InsertKVResult {
  147. public:
  148. InsertKVResult() = default;
  149. explicit InsertKVResult(bool inserted, EntryT& entry)
  150. : entry_(&entry), inserted_(inserted) {}
  151. auto is_inserted() const -> bool { return inserted_; }
  152. auto key() const -> KeyT& { return entry_->key(); }
  153. auto value() const -> ValueT& { return entry_->value(); }
  154. private:
  155. EntryT* entry_;
  156. bool inserted_;
  157. };
  158. // Implicitly convertible to the relevant view type.
  159. //
  160. // NOLINTNEXTLINE(google-explicit-constructor): Designed to implicitly decay.
  161. explicit(false) operator ViewT() const { return this->view_impl(); }
  162. // We can't chain the above conversion with the conversions on `ViewT` to add
  163. // const, so explicitly support adding const to produce a view here.
  164. template <typename OtherKeyT, typename OtherValueT>
  165. // NOLINTNEXTLINE(google-explicit-constructor)
  166. explicit(false) operator MapView<OtherKeyT, OtherValueT, KeyContextT>() const
  167. requires(SameAsOneOf<OtherKeyT, KeyT, const KeyT> &&
  168. SameAsOneOf<OtherValueT, ValueT, const ValueT>)
  169. {
  170. return ViewT(*this);
  171. }
  172. // Convenience forwarder to the view type.
  173. template <typename LookupKeyT>
  174. auto Contains(LookupKeyT lookup_key,
  175. KeyContextT key_context = KeyContextT()) const -> bool {
  176. return ViewT(*this).Contains(lookup_key, key_context);
  177. }
  178. // Convenience forwarder to the view type.
  179. template <typename LookupKeyT>
  180. auto Lookup(LookupKeyT lookup_key,
  181. KeyContextT key_context = KeyContextT()) const -> LookupKVResult {
  182. return ViewT(*this).Lookup(lookup_key, key_context);
  183. }
  184. // Convenience forwarder to the view type.
  185. template <typename LookupKeyT>
  186. auto operator[](LookupKeyT lookup_key) const
  187. -> ValueT* requires(std::default_initializable<KeyContextT>) {
  188. return ViewT(*this)[lookup_key];
  189. }
  190. // Convenience forwarder to the view type.
  191. template <typename CallbackT>
  192. auto ForEach(CallbackT callback) const -> void
  193. requires(std::invocable<CallbackT, KeyT&, ValueT&>)
  194. {
  195. return ViewT(*this).ForEach(callback);
  196. }
  197. // Convenience forwarder to the view type.
  198. auto ComputeMetrics(KeyContextT key_context = KeyContextT()) const
  199. -> MetricsT {
  200. return ViewT(*this).ComputeMetrics(key_context);
  201. }
  202. // Insert a key and value into the map. If the key is already present, the new
  203. // value is discarded and the existing value preserved.
  204. template <typename LookupKeyT>
  205. auto Insert(LookupKeyT lookup_key, ValueT new_v,
  206. KeyContextT key_context = KeyContextT()) -> InsertKVResult;
  207. // Insert a key into the map and call the provided callback if necessary to
  208. // produce a new value when no existing value is found.
  209. //
  210. // Example: `m.Insert(key, [] { return default_value; });`
  211. //
  212. // TODO: The `;` formatting below appears to be bugs in clang-format with
  213. // concepts that should be filed upstream.
  214. template <typename LookupKeyT, typename ValueCallbackT>
  215. auto Insert(LookupKeyT lookup_key, ValueCallbackT value_cb,
  216. KeyContextT key_context = KeyContextT()) -> InsertKVResult
  217. requires(
  218. !std::same_as<ValueT, ValueCallbackT> &&
  219. std::convertible_to<decltype(std::declval<ValueCallbackT>()()), ValueT>)
  220. ;
  221. // Lookup a key in the map and if missing insert it and call the provided
  222. // callback to in-place construct both the key and value. The lookup key is
  223. // passed through to the callback so it needn't be captured and can be kept in
  224. // a register argument throughout.
  225. //
  226. // Example:
  227. // ```cpp
  228. // m.Insert("widget", [](MyStringViewType lookup_key, void* key_storage,
  229. // void* value_storage) {
  230. // new (key_storage) MyStringType(lookup_key);
  231. // new (value_storage) MyValueType(....);
  232. // });
  233. // ```
  234. template <typename LookupKeyT, typename InsertCallbackT>
  235. auto Insert(LookupKeyT lookup_key, InsertCallbackT insert_cb,
  236. KeyContextT key_context = KeyContextT()) -> InsertKVResult
  237. requires(!std::same_as<ValueT, InsertCallbackT> &&
  238. std::invocable<InsertCallbackT, LookupKeyT, void*, void*>);
  239. // Replace a key's value in a map if already present or insert it if not
  240. // already present. The new value is always used.
  241. template <typename LookupKeyT>
  242. auto Update(LookupKeyT lookup_key, ValueT new_v,
  243. KeyContextT key_context = KeyContextT()) -> InsertKVResult;
  244. // Lookup or insert a key into the map, and set it's value to the result of
  245. // the `value_cb` callback. The callback is always run and its result is
  246. // always used, whether the key was already in the map or not. Any existing
  247. // value is replaced with the result.
  248. //
  249. // Example: `m.Update(key, [] { return new_value; });`
  250. template <typename LookupKeyT, typename ValueCallbackT>
  251. auto Update(LookupKeyT lookup_key, ValueCallbackT value_cb,
  252. KeyContextT key_context = KeyContextT()) -> InsertKVResult
  253. requires(
  254. !std::same_as<ValueT, ValueCallbackT> &&
  255. std::convertible_to<decltype(std::declval<ValueCallbackT>()()), ValueT>)
  256. ;
  257. // Lookup or insert a key into the map. If not already present and the key is
  258. // inserted, the `insert_cb` is used to construct the new key and value in
  259. // place. When inserting, the lookup key is passed through to the callback so
  260. // it needn't be captured and can be kept in a register argument throughout.
  261. // If the key was already present, the `update_cb` is called to update the
  262. // existing key and value as desired.
  263. //
  264. // Example of counting occurrences:
  265. // ```cpp
  266. // m.Update(item, /*insert_cb=*/[](MyStringViewType lookup_key,
  267. // void* key_storage, void* value_storage) {
  268. // new (key_storage) MyItem(lookup_key);
  269. // new (value_storage) Count(1);
  270. // },
  271. // /*update_cb=*/[](MyItem& /*key*/, Count& count) {
  272. // ++count;
  273. // });
  274. // ```
  275. template <typename LookupKeyT, typename InsertCallbackT,
  276. typename UpdateCallbackT>
  277. auto Update(LookupKeyT lookup_key, InsertCallbackT insert_cb,
  278. UpdateCallbackT update_cb,
  279. KeyContextT key_context = KeyContextT()) -> InsertKVResult
  280. requires(!std::same_as<ValueT, InsertCallbackT> &&
  281. std::invocable<InsertCallbackT, LookupKeyT, void*, void*> &&
  282. std::invocable<UpdateCallbackT, KeyT&, ValueT&>);
  283. // Grow the map to a specific allocation size.
  284. //
  285. // This will grow the map's hashtable if necessary for it to have an
  286. // allocation size of `target_alloc_size` which must be a power of two. Note
  287. // that this will not allow that many keys to be inserted, but a smaller
  288. // number based on the maximum load factor. If a specific number of insertions
  289. // need to be achieved without triggering growth, use the `GrowForInsertCount`
  290. // method.
  291. auto GrowToAllocSize(ssize_t target_alloc_size,
  292. KeyContextT key_context = KeyContextT()) -> void;
  293. // Grow the map sufficiently to allow inserting the specified number of keys.
  294. auto GrowForInsertCount(ssize_t count,
  295. KeyContextT key_context = KeyContextT()) -> void;
  296. // Erase a key from the map.
  297. template <typename LookupKeyT>
  298. auto Erase(LookupKeyT lookup_key, KeyContextT key_context = KeyContextT())
  299. -> bool;
  300. // Clear all key/value pairs from the map but leave the underlying hashtable
  301. // allocated and in place.
  302. auto Clear() -> void;
  303. protected:
  304. using ImplT::ImplT;
  305. };
  306. // A data structure mapping from key to value.
  307. //
  308. // This map also supports small size optimization (or "SSO"). The provided
  309. // `SmallSize` type parameter indicates the size of an embedded buffer for
  310. // storing maps small enough to fit. The default is zero, which always allocates
  311. // a heap buffer on construction. When non-zero, must be a multiple of the
  312. // `MaxGroupSize` which is currently 16. The library will check that the size is
  313. // valid and provide an error at compile time if not. We don't automatically
  314. // select the next multiple or otherwise fit the size to the constraints to make
  315. // it clear in the code how much memory is used by the SSO buffer.
  316. //
  317. // This data structure optimizes heavily for small key types that are cheap to
  318. // move and even copy. Using types with large keys or expensive to copy keys may
  319. // create surprising performance bottlenecks. A `std::string` key should be fine
  320. // with generally small strings, but if some or many strings are large heap
  321. // allocations the performance of hashtable routines may be unacceptably bad and
  322. // another data structure or key design is likely preferable.
  323. //
  324. // Note that this type should typically not appear on API boundaries; either
  325. // `MapBase` or `MapView` should be used instead.
  326. template <typename InputKeyT, typename InputValueT, ssize_t SmallSize = 0,
  327. typename InputKeyContextT = DefaultKeyContext>
  328. class Map : public RawHashtable::TableImpl<
  329. MapBase<InputKeyT, InputValueT, InputKeyContextT>, SmallSize> {
  330. using BaseT = MapBase<InputKeyT, InputValueT, InputKeyContextT>;
  331. using ImplT = RawHashtable::TableImpl<BaseT, SmallSize>;
  332. public:
  333. using KeyT = typename BaseT::KeyT;
  334. using ValueT = typename BaseT::ValueT;
  335. Map() = default;
  336. Map(const Map& arg) = default;
  337. Map(Map&& arg) noexcept = default;
  338. auto operator=(const Map& arg) -> Map& = default;
  339. auto operator=(Map&& arg) noexcept -> Map& = default;
  340. // Reset the entire state of the hashtable to as it was when constructed,
  341. // throwing away any intervening allocations.
  342. auto Reset() -> void;
  343. };
  344. template <typename InputKeyT, typename InputValueT, typename InputKeyContextT>
  345. template <typename LookupKeyT>
  346. auto MapView<InputKeyT, InputValueT, InputKeyContextT>::Contains(
  347. LookupKeyT lookup_key, KeyContextT key_context) const -> bool {
  348. return this->LookupEntry(lookup_key, key_context) != nullptr;
  349. }
  350. template <typename InputKeyT, typename InputValueT, typename InputKeyContextT>
  351. template <typename LookupKeyT>
  352. auto MapView<InputKeyT, InputValueT, InputKeyContextT>::Lookup(
  353. LookupKeyT lookup_key, KeyContextT key_context) const -> LookupKVResult {
  354. return LookupKVResult(this->LookupEntry(lookup_key, key_context));
  355. }
  356. template <typename InputKeyT, typename InputValueT, typename InputKeyContextT>
  357. template <typename LookupKeyT>
  358. auto MapView<InputKeyT, InputValueT, InputKeyContextT>::operator[](
  359. LookupKeyT lookup_key) const
  360. -> ValueT* requires(std::default_initializable<KeyContextT>) {
  361. auto result = Lookup(lookup_key, KeyContextT());
  362. return result ? &result.value() : nullptr;
  363. }
  364. template <typename InputKeyT, typename InputValueT, typename InputKeyContextT>
  365. template <typename CallbackT>
  366. auto MapView<InputKeyT, InputValueT, InputKeyContextT>::ForEach(
  367. CallbackT callback) -> void
  368. requires(std::invocable<CallbackT, KeyT&, ValueT&>)
  369. {
  370. this->ForEachEntry(
  371. [callback](EntryT& entry) { callback(entry.key(), entry.value()); },
  372. [](auto...) {});
  373. }
  374. template <typename InputKeyT, typename InputValueT, typename InputKeyContextT>
  375. template <typename LookupKeyT>
  376. [[clang::always_inline]] auto
  377. MapBase<InputKeyT, InputValueT, InputKeyContextT>::Insert(
  378. LookupKeyT lookup_key, ValueT new_v, KeyContextT key_context)
  379. -> InsertKVResult {
  380. return Insert(
  381. lookup_key,
  382. [&new_v](LookupKeyT lookup_key, void* key_storage, void* value_storage) {
  383. new (key_storage) KeyT(lookup_key);
  384. new (value_storage) ValueT(std::move(new_v));
  385. },
  386. key_context);
  387. }
  388. template <typename InputKeyT, typename InputValueT, typename InputKeyContextT>
  389. template <typename LookupKeyT, typename ValueCallbackT>
  390. [[clang::always_inline]] auto
  391. MapBase<InputKeyT, InputValueT, InputKeyContextT>::Insert(
  392. LookupKeyT lookup_key, ValueCallbackT value_cb, KeyContextT key_context)
  393. -> InsertKVResult
  394. requires(
  395. !std::same_as<ValueT, ValueCallbackT> &&
  396. std::convertible_to<decltype(std::declval<ValueCallbackT>()()), ValueT>)
  397. {
  398. return Insert(
  399. lookup_key,
  400. [&value_cb](LookupKeyT lookup_key, void* key_storage,
  401. void* value_storage) {
  402. new (key_storage) KeyT(lookup_key);
  403. new (value_storage) ValueT(value_cb());
  404. },
  405. key_context);
  406. }
  407. template <typename InputKeyT, typename InputValueT, typename InputKeyContextT>
  408. template <typename LookupKeyT, typename InsertCallbackT>
  409. [[clang::always_inline]] auto
  410. MapBase<InputKeyT, InputValueT, InputKeyContextT>::Insert(
  411. LookupKeyT lookup_key, InsertCallbackT insert_cb, KeyContextT key_context)
  412. -> InsertKVResult
  413. requires(!std::same_as<ValueT, InsertCallbackT> &&
  414. std::invocable<InsertCallbackT, LookupKeyT, void*, void*>)
  415. {
  416. auto [entry, inserted] = this->InsertImpl(lookup_key, key_context);
  417. CARBON_DCHECK(entry, "Should always result in a valid index.");
  418. if (LLVM_LIKELY(!inserted)) {
  419. return InsertKVResult(false, *entry);
  420. }
  421. insert_cb(lookup_key, static_cast<void*>(&entry->key_storage),
  422. static_cast<void*>(&entry->value_storage));
  423. return InsertKVResult(true, *entry);
  424. }
  425. template <typename InputKeyT, typename InputValueT, typename InputKeyContextT>
  426. template <typename LookupKeyT>
  427. [[clang::always_inline]] auto
  428. MapBase<InputKeyT, InputValueT, InputKeyContextT>::Update(
  429. LookupKeyT lookup_key, ValueT new_v, KeyContextT key_context)
  430. -> InsertKVResult {
  431. return Update(
  432. lookup_key,
  433. [&new_v](LookupKeyT lookup_key, void* key_storage, void* value_storage) {
  434. new (key_storage) KeyT(lookup_key);
  435. new (value_storage) ValueT(std::move(new_v));
  436. },
  437. [&new_v](KeyT& /*key*/, ValueT& value) {
  438. value.~ValueT();
  439. new (&value) ValueT(std::move(new_v));
  440. },
  441. key_context);
  442. }
  443. template <typename InputKeyT, typename InputValueT, typename InputKeyContextT>
  444. template <typename LookupKeyT, typename ValueCallbackT>
  445. [[clang::always_inline]] auto
  446. MapBase<InputKeyT, InputValueT, InputKeyContextT>::Update(
  447. LookupKeyT lookup_key, ValueCallbackT value_cb, KeyContextT key_context)
  448. -> InsertKVResult
  449. requires(
  450. !std::same_as<ValueT, ValueCallbackT> &&
  451. std::convertible_to<decltype(std::declval<ValueCallbackT>()()), ValueT>)
  452. {
  453. return Update(
  454. lookup_key,
  455. [&value_cb](LookupKeyT lookup_key, void* key_storage,
  456. void* value_storage) {
  457. new (key_storage) KeyT(lookup_key);
  458. new (value_storage) ValueT(value_cb());
  459. },
  460. [&value_cb](KeyT& /*key*/, ValueT& value) {
  461. value.~ValueT();
  462. new (&value) ValueT(value_cb());
  463. },
  464. key_context);
  465. }
  466. template <typename InputKeyT, typename InputValueT, typename InputKeyContextT>
  467. template <typename LookupKeyT, typename InsertCallbackT,
  468. typename UpdateCallbackT>
  469. [[clang::always_inline]] auto
  470. MapBase<InputKeyT, InputValueT, InputKeyContextT>::Update(
  471. LookupKeyT lookup_key, InsertCallbackT insert_cb, UpdateCallbackT update_cb,
  472. KeyContextT key_context) -> InsertKVResult
  473. requires(!std::same_as<ValueT, InsertCallbackT> &&
  474. std::invocable<InsertCallbackT, LookupKeyT, void*, void*> &&
  475. std::invocable<UpdateCallbackT, KeyT&, ValueT&>)
  476. {
  477. auto [entry, inserted] = this->InsertImpl(lookup_key, key_context);
  478. CARBON_DCHECK(entry, "Should always result in a valid index.");
  479. if (LLVM_LIKELY(!inserted)) {
  480. update_cb(entry->key(), entry->value());
  481. return InsertKVResult(false, *entry);
  482. }
  483. insert_cb(lookup_key, static_cast<void*>(&entry->key_storage),
  484. static_cast<void*>(&entry->value_storage));
  485. return InsertKVResult(true, *entry);
  486. }
  487. template <typename InputKeyT, typename InputValueT, typename InputKeyContextT>
  488. auto MapBase<InputKeyT, InputValueT, InputKeyContextT>::GrowToAllocSize(
  489. ssize_t target_alloc_size, KeyContextT key_context) -> void {
  490. this->GrowToAllocSizeImpl(target_alloc_size, key_context);
  491. }
  492. template <typename InputKeyT, typename InputValueT, typename InputKeyContextT>
  493. auto MapBase<InputKeyT, InputValueT, InputKeyContextT>::GrowForInsertCount(
  494. ssize_t count, KeyContextT key_context) -> void {
  495. this->GrowForInsertCountImpl(count, key_context);
  496. }
  497. template <typename InputKeyT, typename InputValueT, typename InputKeyContextT>
  498. template <typename LookupKeyT>
  499. auto MapBase<InputKeyT, InputValueT, InputKeyContextT>::Erase(
  500. LookupKeyT lookup_key, KeyContextT key_context) -> bool {
  501. return this->EraseImpl(lookup_key, key_context);
  502. }
  503. template <typename InputKeyT, typename InputValueT, typename InputKeyContextT>
  504. auto MapBase<InputKeyT, InputValueT, InputKeyContextT>::Clear() -> void {
  505. this->ClearImpl();
  506. }
  507. template <typename InputKeyT, typename InputValueT, ssize_t SmallSize,
  508. typename InputKeyContextT>
  509. auto Map<InputKeyT, InputValueT, SmallSize, InputKeyContextT>::Reset() -> void {
  510. this->ResetImpl();
  511. }
  512. } // namespace Carbon
  513. #endif // CARBON_COMMON_MAP_H_