map.h 22 KB

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