value_store.h 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  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_VALUE_STORE_H_
  5. #define CARBON_TOOLCHAIN_BASE_VALUE_STORE_H_
  6. #include <type_traits>
  7. #include "common/check.h"
  8. #include "common/hashtable_key_context.h"
  9. #include "common/ostream.h"
  10. #include "common/set.h"
  11. #include "llvm/ADT/Sequence.h"
  12. #include "llvm/ADT/SmallVector.h"
  13. #include "toolchain/base/mem_usage.h"
  14. #include "toolchain/base/yaml.h"
  15. namespace Carbon {
  16. namespace Internal {
  17. // Used as a parent class for non-printable types. This is just for
  18. // std::conditional, not as an API.
  19. class ValueStoreNotPrintable {};
  20. } // namespace Internal
  21. // A simple wrapper for accumulating values, providing IDs to later retrieve the
  22. // value. This does not do deduplication.
  23. //
  24. // IdT::ValueType must represent the type being indexed.
  25. template <typename IdT>
  26. class ValueStore
  27. : public std::conditional<
  28. std::is_base_of_v<Printable<typename IdT::ValueType>,
  29. typename IdT::ValueType>,
  30. Yaml::Printable<ValueStore<IdT>>, Internal::ValueStoreNotPrintable> {
  31. public:
  32. using ValueType = typename IdT::ValueType;
  33. // Typically we want to use `ValueType&` and `const ValueType& to avoid
  34. // copies, but when the value type is a `StringRef`, we assume external
  35. // storage for the string data and both our value type and ref type will be
  36. // `StringRef`. This will preclude mutation of the string data.
  37. using RefType = std::conditional_t<std::same_as<llvm::StringRef, ValueType>,
  38. llvm::StringRef, ValueType&>;
  39. using ConstRefType =
  40. std::conditional_t<std::same_as<llvm::StringRef, ValueType>,
  41. llvm::StringRef, const ValueType&>;
  42. // Stores the value and returns an ID to reference it.
  43. auto Add(ValueType value) -> IdT {
  44. IdT id(values_.size());
  45. // This routine is especially hot and the check here relatively expensive
  46. // for the value provided, so only do this in debug builds to make tracking
  47. // down issues easier.
  48. CARBON_DCHECK(id.index >= 0, "Id overflow");
  49. values_.push_back(std::move(value));
  50. return id;
  51. }
  52. // Adds a default constructed value and returns an ID to reference it.
  53. auto AddDefaultValue() -> IdT {
  54. IdT id(values_.size());
  55. values_.resize(id.index + 1);
  56. return id;
  57. }
  58. // Returns a mutable value for an ID.
  59. auto Get(IdT id) -> RefType {
  60. CARBON_DCHECK(id.index >= 0, "{0}", id);
  61. return values_[id.index];
  62. }
  63. // Returns the value for an ID.
  64. auto Get(IdT id) const -> ConstRefType {
  65. CARBON_DCHECK(id.index >= 0, "{0}", id);
  66. return values_[id.index];
  67. }
  68. // Reserves space.
  69. auto Reserve(size_t size) -> void { values_.reserve(size); }
  70. // These are to support printable structures, and are not guaranteed.
  71. auto OutputYaml() const -> Yaml::OutputMapping {
  72. return Yaml::OutputMapping([&](Yaml::OutputMapping::Map map) {
  73. for (auto i : llvm::seq(values_.size())) {
  74. IdT id(i);
  75. map.Add(PrintToString(id), Yaml::OutputScalar(Get(id)));
  76. }
  77. });
  78. }
  79. // Collects memory usage of the values.
  80. auto CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
  81. -> void {
  82. mem_usage.Collect(label.str(), values_);
  83. }
  84. auto array_ref() const -> llvm::ArrayRef<ValueType> { return values_; }
  85. auto size() const -> size_t { return values_.size(); }
  86. private:
  87. // Set inline size to 0 because these will typically be too large for the
  88. // stack, while this does make File smaller.
  89. llvm::SmallVector<std::decay_t<ValueType>, 0> values_;
  90. };
  91. // A wrapper for accumulating immutable values with deduplication, providing IDs
  92. // to later retrieve the value.
  93. //
  94. // IdT::ValueType must represent the type being indexed.
  95. template <typename IdT>
  96. class CanonicalValueStore {
  97. public:
  98. using ValueType = typename IdT::ValueType;
  99. using RefType = typename ValueStore<IdT>::RefType;
  100. using ConstRefType = typename ValueStore<IdT>::ConstRefType;
  101. // Stores a canonical copy of the value and returns an ID to reference it.
  102. auto Add(ValueType value) -> IdT;
  103. // Returns the value for an ID.
  104. auto Get(IdT id) const -> ConstRefType { return values_.Get(id); }
  105. // Looks up the canonical ID for a value, or returns `None` if not in the
  106. // store.
  107. auto Lookup(ValueType value) const -> IdT;
  108. // Reserves space.
  109. auto Reserve(size_t size) -> void;
  110. // These are to support printable structures, and are not guaranteed.
  111. auto OutputYaml() const -> Yaml::OutputMapping {
  112. return values_.OutputYaml();
  113. }
  114. auto array_ref() const -> llvm::ArrayRef<ValueType> {
  115. return values_.array_ref();
  116. }
  117. auto size() const -> size_t { return values_.size(); }
  118. // Collects memory usage of the values and deduplication set.
  119. auto CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
  120. -> void {
  121. mem_usage.Collect(MemUsage::ConcatLabel(label, "values_"), values_);
  122. auto bytes =
  123. set_.ComputeMetrics(KeyContext(values_.array_ref())).storage_bytes;
  124. mem_usage.Add(MemUsage::ConcatLabel(label, "set_"), bytes, bytes);
  125. }
  126. private:
  127. class KeyContext;
  128. ValueStore<IdT> values_;
  129. Set<IdT, /*SmallSize=*/0, KeyContext> set_;
  130. };
  131. template <typename IdT>
  132. class CanonicalValueStore<IdT>::KeyContext
  133. : public TranslatingKeyContext<KeyContext> {
  134. public:
  135. explicit KeyContext(llvm::ArrayRef<ValueType> values) : values_(values) {}
  136. // Note that it is safe to return a `const` reference here as the underlying
  137. // object's lifetime is provided by the `store_`.
  138. auto TranslateKey(IdT id) const -> const ValueType& {
  139. return values_[id.index];
  140. }
  141. private:
  142. llvm::ArrayRef<ValueType> values_;
  143. };
  144. template <typename IdT>
  145. auto CanonicalValueStore<IdT>::Add(ValueType value) -> IdT {
  146. auto make_key = [&] { return IdT(values_.Add(std::move(value))); };
  147. return set_.Insert(value, make_key, KeyContext(values_.array_ref())).key();
  148. }
  149. template <typename IdT>
  150. auto CanonicalValueStore<IdT>::Lookup(ValueType value) const -> IdT {
  151. if (auto result = set_.Lookup(value, KeyContext(values_.array_ref()))) {
  152. return result.key();
  153. }
  154. return IdT::None;
  155. }
  156. template <typename IdT>
  157. auto CanonicalValueStore<IdT>::Reserve(size_t size) -> void {
  158. // Compute the resulting new insert count using the size of values -- the
  159. // set doesn't have a fast to compute current size.
  160. if (size > values_.size()) {
  161. set_.GrowForInsertCount(size - values_.size(),
  162. KeyContext(values_.array_ref()));
  163. }
  164. values_.Reserve(size);
  165. }
  166. } // namespace Carbon
  167. #endif // CARBON_TOOLCHAIN_BASE_VALUE_STORE_H_