map.h 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  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. // NOLINTNEXTLINE(google-explicit-constructor)
  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. // NOLINTNEXTLINE(google-explicit-constructor): Implicit by design.
  119. MapView(ImplT base) : ImplT(base) {}
  120. MapView(ssize_t size, RawHashtable::Storage* storage)
  121. : ImplT(size, storage) {}
  122. };
  123. // A base class for a `Map` type that remains mutable while type-erasing the
  124. // `SmallSize` (SSO) template parameter.
  125. //
  126. // A pointer or reference to this type is the preferred way to pass a mutable
  127. // handle to a `Map` type across API boundaries as it avoids encoding specific
  128. // SSO sizing information while providing a near-complete mutable API.
  129. template <typename InputKeyT, typename InputValueT,
  130. typename InputKeyContextT = DefaultKeyContext>
  131. class MapBase : protected RawHashtable::BaseImpl<InputKeyT, InputValueT,
  132. InputKeyContextT> {
  133. protected:
  134. using ImplT =
  135. RawHashtable::BaseImpl<InputKeyT, InputValueT, InputKeyContextT>;
  136. using EntryT = typename ImplT::EntryT;
  137. public:
  138. using KeyT = typename ImplT::KeyT;
  139. using ValueT = typename ImplT::ValueT;
  140. using KeyContextT = typename ImplT::KeyContextT;
  141. using ViewT = MapView<KeyT, ValueT, KeyContextT>;
  142. using LookupKVResult = typename ViewT::LookupKVResult;
  143. using MetricsT = typename ImplT::MetricsT;
  144. // The result type for insertion operations both indicates whether an insert
  145. // was needed (as opposed to finding an existing element), and provides access
  146. // to the element's key and value.
  147. class InsertKVResult {
  148. public:
  149. InsertKVResult() = default;
  150. explicit InsertKVResult(bool inserted, EntryT& entry)
  151. : entry_(&entry), inserted_(inserted) {}
  152. auto is_inserted() const -> bool { return inserted_; }
  153. auto key() const -> KeyT& { return entry_->key(); }
  154. auto value() const -> ValueT& { return entry_->value(); }
  155. private:
  156. EntryT* entry_;
  157. bool inserted_;
  158. };
  159. // Implicitly convertible to the relevant view type.
  160. //
  161. // NOLINTNEXTLINE(google-explicit-constructor): Designed to implicitly decay.
  162. operator ViewT() const { return this->view_impl(); }
  163. // We can't chain the above conversion with the conversions on `ViewT` to add
  164. // const, so explicitly support adding const to produce a view here.
  165. template <typename OtherKeyT, typename OtherValueT>
  166. // NOLINTNEXTLINE(google-explicit-constructor)
  167. operator MapView<OtherKeyT, OtherValueT, KeyContextT>() const
  168. requires(SameAsOneOf<OtherKeyT, KeyT, const KeyT> &&
  169. SameAsOneOf<OtherValueT, ValueT, const ValueT>)
  170. {
  171. return ViewT(*this);
  172. }
  173. // Convenience forwarder to the view type.
  174. template <typename LookupKeyT>
  175. auto Contains(LookupKeyT lookup_key,
  176. KeyContextT key_context = KeyContextT()) const -> bool {
  177. return ViewT(*this).Contains(lookup_key, key_context);
  178. }
  179. // Convenience forwarder to the view type.
  180. template <typename LookupKeyT>
  181. auto Lookup(LookupKeyT lookup_key,
  182. KeyContextT key_context = KeyContextT()) const -> LookupKVResult {
  183. return ViewT(*this).Lookup(lookup_key, key_context);
  184. }
  185. // Convenience forwarder to the view type.
  186. template <typename LookupKeyT>
  187. auto operator[](LookupKeyT lookup_key) const
  188. -> ValueT* requires(std::default_initializable<KeyContextT>) {
  189. return ViewT(*this)[lookup_key];
  190. }
  191. // Convenience forwarder to the view type.
  192. template <typename CallbackT>
  193. auto ForEach(CallbackT callback) const -> void
  194. requires(std::invocable<CallbackT, KeyT&, ValueT&>)
  195. {
  196. return ViewT(*this).ForEach(callback);
  197. }
  198. // Convenience forwarder to the view type.
  199. auto ComputeMetrics(KeyContextT key_context = KeyContextT()) const
  200. -> MetricsT {
  201. return ViewT(*this).ComputeMetrics(key_context);
  202. }
  203. // Insert a key and value into the map. If the key is already present, the new
  204. // value is discarded and the existing value preserved.
  205. template <typename LookupKeyT>
  206. auto Insert(LookupKeyT lookup_key, ValueT new_v,
  207. KeyContextT key_context = KeyContextT()) -> InsertKVResult;
  208. // Insert a key into the map and call the provided callback if necessary to
  209. // produce a new value when no existing value is found.
  210. //
  211. // Example: `m.Insert(key, [] { return default_value; });`
  212. //
  213. // TODO: The `;` formatting below appears to be bugs in clang-format with
  214. // concepts that should be filed upstream.
  215. template <typename LookupKeyT, typename ValueCallbackT>
  216. auto Insert(LookupKeyT lookup_key, ValueCallbackT value_cb,
  217. KeyContextT key_context = KeyContextT()) -> InsertKVResult
  218. requires(
  219. !std::same_as<ValueT, ValueCallbackT> &&
  220. std::convertible_to<decltype(std::declval<ValueCallbackT>()()), ValueT>)
  221. ;
  222. // Lookup a key in the map and if missing insert it and call the provided
  223. // callback to in-place construct both the key and value. The lookup key is
  224. // passed through to the callback so it needn't be captured and can be kept in
  225. // a register argument throughout.
  226. //
  227. // Example:
  228. // ```cpp
  229. // m.Insert("widget", [](MyStringViewType lookup_key, void* key_storage,
  230. // void* value_storage) {
  231. // new (key_storage) MyStringType(lookup_key);
  232. // new (value_storage) MyValueType(....);
  233. // });
  234. // ```
  235. template <typename LookupKeyT, typename InsertCallbackT>
  236. auto Insert(LookupKeyT lookup_key, InsertCallbackT insert_cb,
  237. KeyContextT key_context = KeyContextT()) -> InsertKVResult
  238. requires(!std::same_as<ValueT, InsertCallbackT> &&
  239. std::invocable<InsertCallbackT, LookupKeyT, void*, void*>);
  240. // Replace a key's value in a map if already present or insert it if not
  241. // already present. The new value is always used.
  242. template <typename LookupKeyT>
  243. auto Update(LookupKeyT lookup_key, ValueT new_v,
  244. KeyContextT key_context = KeyContextT()) -> InsertKVResult;
  245. // Lookup or insert a key into the map, and set it's value to the result of
  246. // the `value_cb` callback. The callback is always run and its result is
  247. // always used, whether the key was already in the map or not. Any existing
  248. // value is replaced with the result.
  249. //
  250. // Example: `m.Update(key, [] { return new_value; });`
  251. template <typename LookupKeyT, typename ValueCallbackT>
  252. auto Update(LookupKeyT lookup_key, ValueCallbackT value_cb,
  253. KeyContextT key_context = KeyContextT()) -> InsertKVResult
  254. requires(
  255. !std::same_as<ValueT, ValueCallbackT> &&
  256. std::convertible_to<decltype(std::declval<ValueCallbackT>()()), ValueT>)
  257. ;
  258. // Lookup or insert a key into the map. If not already present and the key is
  259. // inserted, the `insert_cb` is used to construct the new key and value in
  260. // place. When inserting, the lookup key is passed through to the callback so
  261. // it needn't be captured and can be kept in a register argument throughout.
  262. // If the key was already present, the `update_cb` is called to update the
  263. // existing key and value as desired.
  264. //
  265. // Example of counting occurrences:
  266. // ```cpp
  267. // m.Update(item, /*insert_cb=*/[](MyStringViewType lookup_key,
  268. // void* key_storage, void* value_storage) {
  269. // new (key_storage) MyItem(lookup_key);
  270. // new (value_storage) Count(1);
  271. // },
  272. // /*update_cb=*/[](MyItem& /*key*/, Count& count) {
  273. // ++count;
  274. // });
  275. // ```
  276. template <typename LookupKeyT, typename InsertCallbackT,
  277. typename UpdateCallbackT>
  278. auto Update(LookupKeyT lookup_key, InsertCallbackT insert_cb,
  279. UpdateCallbackT update_cb,
  280. KeyContextT key_context = KeyContextT()) -> InsertKVResult
  281. requires(!std::same_as<ValueT, InsertCallbackT> &&
  282. std::invocable<InsertCallbackT, LookupKeyT, void*, void*> &&
  283. std::invocable<UpdateCallbackT, KeyT&, ValueT&>);
  284. // Grow the map to a specific allocation size.
  285. //
  286. // This will grow the map's hashtable if necessary for it to have an
  287. // allocation size of `target_alloc_size` which must be a power of two. Note
  288. // that this will not allow that many keys to be inserted, but a smaller
  289. // number based on the maximum load factor. If a specific number of insertions
  290. // need to be achieved without triggering growth, use the `GrowForInsertCount`
  291. // method.
  292. auto GrowToAllocSize(ssize_t target_alloc_size,
  293. KeyContextT key_context = KeyContextT()) -> void;
  294. // Grow the map sufficiently to allow inserting the specified number of keys.
  295. auto GrowForInsertCount(ssize_t count,
  296. KeyContextT key_context = KeyContextT()) -> void;
  297. // Erase a key from the map.
  298. template <typename LookupKeyT>
  299. auto Erase(LookupKeyT lookup_key, KeyContextT key_context = KeyContextT())
  300. -> bool;
  301. // Clear all key/value pairs from the map but leave the underlying hashtable
  302. // allocated and in place.
  303. auto Clear() -> void;
  304. protected:
  305. using ImplT::ImplT;
  306. };
  307. // A data structure mapping from key to value.
  308. //
  309. // This map also supports small size optimization (or "SSO"). The provided
  310. // `SmallSize` type parameter indicates the size of an embedded buffer for
  311. // storing maps small enough to fit. The default is zero, which always allocates
  312. // a heap buffer on construction. When non-zero, must be a multiple of the
  313. // `MaxGroupSize` which is currently 16. The library will check that the size is
  314. // valid and provide an error at compile time if not. We don't automatically
  315. // select the next multiple or otherwise fit the size to the constraints to make
  316. // it clear in the code how much memory is used by the SSO buffer.
  317. //
  318. // This data structure optimizes heavily for small key types that are cheap to
  319. // move and even copy. Using types with large keys or expensive to copy keys may
  320. // create surprising performance bottlenecks. A `std::string` key should be fine
  321. // with generally small strings, but if some or many strings are large heap
  322. // allocations the performance of hashtable routines may be unacceptably bad and
  323. // another data structure or key design is likely preferable.
  324. //
  325. // Note that this type should typically not appear on API boundaries; either
  326. // `MapBase` or `MapView` should be used instead.
  327. template <typename InputKeyT, typename InputValueT, ssize_t SmallSize = 0,
  328. typename InputKeyContextT = DefaultKeyContext>
  329. class Map : public RawHashtable::TableImpl<
  330. MapBase<InputKeyT, InputValueT, InputKeyContextT>, SmallSize> {
  331. using BaseT = MapBase<InputKeyT, InputValueT, InputKeyContextT>;
  332. using ImplT = RawHashtable::TableImpl<BaseT, SmallSize>;
  333. public:
  334. using KeyT = typename BaseT::KeyT;
  335. using ValueT = typename BaseT::ValueT;
  336. Map() = default;
  337. Map(const Map& arg) = default;
  338. Map(Map&& arg) noexcept = default;
  339. auto operator=(const Map& arg) -> Map& = default;
  340. auto operator=(Map&& arg) noexcept -> Map& = default;
  341. // Reset the entire state of the hashtable to as it was when constructed,
  342. // throwing away any intervening allocations.
  343. auto Reset() -> void;
  344. };
  345. template <typename InputKeyT, typename InputValueT, typename InputKeyContextT>
  346. template <typename LookupKeyT>
  347. auto MapView<InputKeyT, InputValueT, InputKeyContextT>::Contains(
  348. LookupKeyT lookup_key, KeyContextT key_context) const -> bool {
  349. return this->LookupEntry(lookup_key, key_context) != nullptr;
  350. }
  351. template <typename InputKeyT, typename InputValueT, typename InputKeyContextT>
  352. template <typename LookupKeyT>
  353. auto MapView<InputKeyT, InputValueT, InputKeyContextT>::Lookup(
  354. LookupKeyT lookup_key, KeyContextT key_context) const -> LookupKVResult {
  355. return LookupKVResult(this->LookupEntry(lookup_key, key_context));
  356. }
  357. template <typename InputKeyT, typename InputValueT, typename InputKeyContextT>
  358. template <typename LookupKeyT>
  359. auto MapView<InputKeyT, InputValueT, InputKeyContextT>::operator[](
  360. LookupKeyT lookup_key) const
  361. -> ValueT* requires(std::default_initializable<KeyContextT>) {
  362. auto result = Lookup(lookup_key, KeyContextT());
  363. return result ? &result.value() : nullptr;
  364. }
  365. template <typename InputKeyT, typename InputValueT, typename InputKeyContextT>
  366. template <typename CallbackT>
  367. auto MapView<InputKeyT, InputValueT, InputKeyContextT>::ForEach(
  368. CallbackT callback) -> void
  369. requires(std::invocable<CallbackT, KeyT&, ValueT&>)
  370. {
  371. this->ForEachEntry(
  372. [callback](EntryT& entry) { callback(entry.key(), entry.value()); },
  373. [](auto...) {});
  374. }
  375. template <typename InputKeyT, typename InputValueT, typename InputKeyContextT>
  376. template <typename LookupKeyT>
  377. [[clang::always_inline]] auto
  378. MapBase<InputKeyT, InputValueT, InputKeyContextT>::Insert(
  379. LookupKeyT lookup_key, ValueT new_v, KeyContextT key_context)
  380. -> InsertKVResult {
  381. return Insert(
  382. lookup_key,
  383. [&new_v](LookupKeyT lookup_key, void* key_storage, void* value_storage) {
  384. new (key_storage) KeyT(lookup_key);
  385. new (value_storage) ValueT(std::move(new_v));
  386. },
  387. key_context);
  388. }
  389. template <typename InputKeyT, typename InputValueT, typename InputKeyContextT>
  390. template <typename LookupKeyT, typename ValueCallbackT>
  391. [[clang::always_inline]] auto
  392. MapBase<InputKeyT, InputValueT, InputKeyContextT>::Insert(
  393. LookupKeyT lookup_key, ValueCallbackT value_cb, KeyContextT key_context)
  394. -> InsertKVResult
  395. requires(
  396. !std::same_as<ValueT, ValueCallbackT> &&
  397. std::convertible_to<decltype(std::declval<ValueCallbackT>()()), ValueT>)
  398. {
  399. return Insert(
  400. lookup_key,
  401. [&value_cb](LookupKeyT lookup_key, void* key_storage,
  402. void* value_storage) {
  403. new (key_storage) KeyT(lookup_key);
  404. new (value_storage) ValueT(value_cb());
  405. },
  406. key_context);
  407. }
  408. template <typename InputKeyT, typename InputValueT, typename InputKeyContextT>
  409. template <typename LookupKeyT, typename InsertCallbackT>
  410. [[clang::always_inline]] auto
  411. MapBase<InputKeyT, InputValueT, InputKeyContextT>::Insert(
  412. LookupKeyT lookup_key, InsertCallbackT insert_cb, KeyContextT key_context)
  413. -> InsertKVResult
  414. requires(!std::same_as<ValueT, InsertCallbackT> &&
  415. std::invocable<InsertCallbackT, LookupKeyT, void*, void*>)
  416. {
  417. auto [entry, inserted] = this->InsertImpl(lookup_key, key_context);
  418. CARBON_DCHECK(entry, "Should always result in a valid index.");
  419. if (LLVM_LIKELY(!inserted)) {
  420. return InsertKVResult(false, *entry);
  421. }
  422. insert_cb(lookup_key, static_cast<void*>(&entry->key_storage),
  423. static_cast<void*>(&entry->value_storage));
  424. return InsertKVResult(true, *entry);
  425. }
  426. template <typename InputKeyT, typename InputValueT, typename InputKeyContextT>
  427. template <typename LookupKeyT>
  428. [[clang::always_inline]] auto
  429. MapBase<InputKeyT, InputValueT, InputKeyContextT>::Update(
  430. LookupKeyT lookup_key, ValueT new_v, KeyContextT key_context)
  431. -> InsertKVResult {
  432. return Update(
  433. lookup_key,
  434. [&new_v](LookupKeyT lookup_key, void* key_storage, void* value_storage) {
  435. new (key_storage) KeyT(lookup_key);
  436. new (value_storage) ValueT(std::move(new_v));
  437. },
  438. [&new_v](KeyT& /*key*/, ValueT& value) {
  439. value.~ValueT();
  440. new (&value) ValueT(std::move(new_v));
  441. },
  442. key_context);
  443. }
  444. template <typename InputKeyT, typename InputValueT, typename InputKeyContextT>
  445. template <typename LookupKeyT, typename ValueCallbackT>
  446. [[clang::always_inline]] auto
  447. MapBase<InputKeyT, InputValueT, InputKeyContextT>::Update(
  448. LookupKeyT lookup_key, ValueCallbackT value_cb, KeyContextT key_context)
  449. -> InsertKVResult
  450. requires(
  451. !std::same_as<ValueT, ValueCallbackT> &&
  452. std::convertible_to<decltype(std::declval<ValueCallbackT>()()), ValueT>)
  453. {
  454. return Update(
  455. lookup_key,
  456. [&value_cb](LookupKeyT lookup_key, void* key_storage,
  457. void* value_storage) {
  458. new (key_storage) KeyT(lookup_key);
  459. new (value_storage) ValueT(value_cb());
  460. },
  461. [&value_cb](KeyT& /*key*/, ValueT& value) {
  462. value.~ValueT();
  463. new (&value) ValueT(value_cb());
  464. },
  465. key_context);
  466. }
  467. template <typename InputKeyT, typename InputValueT, typename InputKeyContextT>
  468. template <typename LookupKeyT, typename InsertCallbackT,
  469. typename UpdateCallbackT>
  470. [[clang::always_inline]] auto
  471. MapBase<InputKeyT, InputValueT, InputKeyContextT>::Update(
  472. LookupKeyT lookup_key, InsertCallbackT insert_cb, UpdateCallbackT update_cb,
  473. KeyContextT key_context) -> InsertKVResult
  474. requires(!std::same_as<ValueT, InsertCallbackT> &&
  475. std::invocable<InsertCallbackT, LookupKeyT, void*, void*> &&
  476. std::invocable<UpdateCallbackT, KeyT&, ValueT&>)
  477. {
  478. auto [entry, inserted] = this->InsertImpl(lookup_key, key_context);
  479. CARBON_DCHECK(entry, "Should always result in a valid index.");
  480. if (LLVM_LIKELY(!inserted)) {
  481. update_cb(entry->key(), entry->value());
  482. return InsertKVResult(false, *entry);
  483. }
  484. insert_cb(lookup_key, static_cast<void*>(&entry->key_storage),
  485. static_cast<void*>(&entry->value_storage));
  486. return InsertKVResult(true, *entry);
  487. }
  488. template <typename InputKeyT, typename InputValueT, typename InputKeyContextT>
  489. auto MapBase<InputKeyT, InputValueT, InputKeyContextT>::GrowToAllocSize(
  490. ssize_t target_alloc_size, KeyContextT key_context) -> void {
  491. this->GrowToAllocSizeImpl(target_alloc_size, key_context);
  492. }
  493. template <typename InputKeyT, typename InputValueT, typename InputKeyContextT>
  494. auto MapBase<InputKeyT, InputValueT, InputKeyContextT>::GrowForInsertCount(
  495. ssize_t count, KeyContextT key_context) -> void {
  496. this->GrowForInsertCountImpl(count, key_context);
  497. }
  498. template <typename InputKeyT, typename InputValueT, typename InputKeyContextT>
  499. template <typename LookupKeyT>
  500. auto MapBase<InputKeyT, InputValueT, InputKeyContextT>::Erase(
  501. LookupKeyT lookup_key, KeyContextT key_context) -> bool {
  502. return this->EraseImpl(lookup_key, key_context);
  503. }
  504. template <typename InputKeyT, typename InputValueT, typename InputKeyContextT>
  505. auto MapBase<InputKeyT, InputValueT, InputKeyContextT>::Clear() -> void {
  506. this->ClearImpl();
  507. }
  508. template <typename InputKeyT, typename InputValueT, ssize_t SmallSize,
  509. typename InputKeyContextT>
  510. auto Map<InputKeyT, InputValueT, SmallSize, InputKeyContextT>::Reset() -> void {
  511. this->ResetImpl();
  512. }
  513. } // namespace Carbon
  514. #endif // CARBON_COMMON_MAP_H_