canonical_value_store.h 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  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_TOOLCHAIN_BASE_CANONICAL_VALUE_STORE_H_
  5. #define CARBON_TOOLCHAIN_BASE_CANONICAL_VALUE_STORE_H_
  6. #include "common/hashtable_key_context.h"
  7. #include "common/set.h"
  8. #include "toolchain/base/mem_usage.h"
  9. #include "toolchain/base/value_store.h"
  10. #include "toolchain/base/value_store_types.h"
  11. #include "toolchain/base/yaml.h"
  12. namespace Carbon {
  13. // A wrapper for accumulating immutable values with deduplication, providing IDs
  14. // to later retrieve the value.
  15. //
  16. // `ValueT` represents the type being stored.
  17. //
  18. // `KeyT` can optionally be different from `ValueT`, and if so is used for the
  19. // argument to `Lookup`. In this case, `ValueT` must provide a `GetAsKey` member
  20. // function that returns the corresponding key.
  21. template <typename IdT, typename KeyT, typename TagIdT = Untagged,
  22. typename ValueT = KeyT>
  23. class CanonicalValueStore {
  24. public:
  25. using IdType = IdT;
  26. using IdTagType = IdTag<IdT, TagIdT>;
  27. using KeyType = std::remove_cvref_t<KeyT>;
  28. using ValueType = ValueStoreTypes<ValueT>::ValueType;
  29. using RefType = ValueStoreTypes<ValueT>::RefType;
  30. using ConstRefType = ValueStoreTypes<ValueT>::ConstRefType;
  31. CanonicalValueStore() = default;
  32. template <typename Id>
  33. explicit CanonicalValueStore(Id id, int32_t initial_reserved_ids = 0)
  34. : values_(id, initial_reserved_ids) {}
  35. // Stores a canonical copy of the value and returns an ID to reference it. If
  36. // the value is already in the store, returns the ID of the existing value.
  37. auto Add(ValueType value) -> IdT;
  38. // Returns the value for an ID.
  39. auto Get(IdT id) const -> ConstRefType { return values_.Get(id); }
  40. // Looks up the canonical ID for a value, or returns `None` if not in the
  41. // store.
  42. auto Lookup(KeyType key) const -> IdT;
  43. // Reserves space.
  44. auto Reserve(size_t size) -> void;
  45. // These are to support printable structures, and are not guaranteed.
  46. auto OutputYaml() const -> Yaml::OutputMapping {
  47. return values_.OutputYaml();
  48. }
  49. auto values() const [[clang::lifetimebound]]
  50. -> ValueStore<IdT, ValueType, TagIdT>::Range {
  51. return values_.values();
  52. }
  53. auto size() const -> size_t { return values_.size(); }
  54. auto enumerate() const -> auto { return values_.enumerate(); }
  55. // Collects memory usage of the values and deduplication set.
  56. auto CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
  57. -> void {
  58. mem_usage.Collect(MemUsage::ConcatLabel(label, "values_"), values_);
  59. auto bytes = set_.ComputeMetrics(KeyContext(&values_)).storage_bytes;
  60. mem_usage.Add(MemUsage::ConcatLabel(label, "set_"), bytes, bytes);
  61. }
  62. auto GetRawIndex(IdT id) const -> int32_t { return values_.GetRawIndex(id); }
  63. auto GetIdTag() const -> IdTagType { return values_.GetIdTag(); }
  64. private:
  65. class KeyContext;
  66. static auto GetAsKey(ConstRefType value) -> ConstRefType
  67. requires std::same_as<KeyT, ValueT>
  68. {
  69. return value;
  70. }
  71. template <typename T>
  72. static auto GetAsKey(T&& value) -> decltype(value.GetAsKey()) {
  73. return value.GetAsKey();
  74. }
  75. ValueStore<IdT, ValueType, TagIdT> values_;
  76. Set<IdT, /*SmallSize=*/0, KeyContext> set_;
  77. };
  78. template <typename IdT, typename KeyT, typename TagIdT, typename ValueT>
  79. class CanonicalValueStore<IdT, KeyT, TagIdT, ValueT>::KeyContext
  80. : public TranslatingKeyContext<KeyContext> {
  81. public:
  82. explicit KeyContext(const ValueStore<IdT, ValueType, TagIdT>* values)
  83. : values_(values) {}
  84. // Note that it is safe to return a reference here as the underlying object's
  85. // lifetime is provided by the `ValueStore`.
  86. auto TranslateKey(IdT id) const
  87. -> decltype(GetAsKey(std::declval<ConstRefType>())) {
  88. return GetAsKey(values_->Get(id));
  89. }
  90. private:
  91. const ValueStore<IdT, ValueType, TagIdT>* values_;
  92. };
  93. template <typename IdT, typename KeyT, typename TagIdT, typename ValueT>
  94. auto CanonicalValueStore<IdT, KeyT, TagIdT, ValueT>::Add(ValueType value)
  95. -> IdT {
  96. auto make_key = [&] { return IdT(values_.Add(std::move(value))); };
  97. return set_.Insert(GetAsKey(value), make_key, KeyContext(&values_)).key();
  98. }
  99. template <typename IdT, typename KeyT, typename TagIdT, typename ValueT>
  100. auto CanonicalValueStore<IdT, KeyT, TagIdT, ValueT>::Lookup(KeyType key) const
  101. -> IdT {
  102. if (auto result = set_.Lookup(key, KeyContext(&values_))) {
  103. return result.key();
  104. }
  105. return IdT::None;
  106. }
  107. template <typename IdT, typename KeyT, typename TagIdT, typename ValueT>
  108. auto CanonicalValueStore<IdT, KeyT, TagIdT, ValueT>::Reserve(size_t size)
  109. -> void {
  110. // Compute the resulting new insert count using the size of values -- the
  111. // set doesn't have a fast to compute current size.
  112. if (size > values_.size()) {
  113. set_.GrowForInsertCount(size - values_.size(), KeyContext(&values_));
  114. }
  115. values_.Reserve(size);
  116. }
  117. } // namespace Carbon
  118. #endif // CARBON_TOOLCHAIN_BASE_CANONICAL_VALUE_STORE_H_