map.h 24 KB

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