value_store.h 6.6 KB

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