map.h 24 KB

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