canonical_value_store.h 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  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`. It must be valid to use both `KeyT` and `ValueT` as
  20. // lookup types in the underlying `Set`.
  21. template <typename IdT, typename KeyT, typename ValueT = KeyT>
  22. class CanonicalValueStore {
  23. public:
  24. using KeyType = std::remove_cvref_t<KeyT>;
  25. using ValueType = ValueStoreTypes<ValueT>::ValueType;
  26. using RefType = ValueStoreTypes<ValueT>::RefType;
  27. using ConstRefType = ValueStoreTypes<ValueT>::ConstRefType;
  28. // Stores a canonical copy of the value and returns an ID to reference it. If
  29. // the value is already in the store, returns the ID of the existing value.
  30. auto Add(ValueType value) -> IdT;
  31. // Returns the value for an ID.
  32. auto Get(IdT id) const -> ConstRefType { return values_.Get(id); }
  33. // Looks up the canonical ID for a value, or returns `None` if not in the
  34. // store.
  35. auto Lookup(KeyType key) const -> IdT;
  36. // Reserves space.
  37. auto Reserve(size_t size) -> void;
  38. // These are to support printable structures, and are not guaranteed.
  39. auto OutputYaml() const -> Yaml::OutputMapping {
  40. return values_.OutputYaml();
  41. }
  42. auto values() const [[clang::lifetimebound]]
  43. -> ValueStore<IdT, ValueType>::Range {
  44. return values_.values();
  45. }
  46. auto size() const -> size_t { return values_.size(); }
  47. // Collects memory usage of the values and deduplication set.
  48. auto CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
  49. -> void {
  50. mem_usage.Collect(MemUsage::ConcatLabel(label, "values_"), values_);
  51. auto bytes = set_.ComputeMetrics(KeyContext(&values_)).storage_bytes;
  52. mem_usage.Add(MemUsage::ConcatLabel(label, "set_"), bytes, bytes);
  53. }
  54. private:
  55. class KeyContext;
  56. ValueStore<IdT, ValueType> values_;
  57. Set<IdT, /*SmallSize=*/0, KeyContext> set_;
  58. };
  59. template <typename IdT, typename KeyT, typename ValueT>
  60. class CanonicalValueStore<IdT, KeyT, ValueT>::KeyContext
  61. : public TranslatingKeyContext<KeyContext> {
  62. public:
  63. explicit KeyContext(const ValueStore<IdT, ValueType>* values)
  64. : values_(values) {}
  65. // Note that it is safe to return a `const` reference here as the underlying
  66. // object's lifetime is provided by the `ValueStore`.
  67. auto TranslateKey(IdT id) const -> ConstRefType { return values_->Get(id); }
  68. private:
  69. const ValueStore<IdT, ValueType>* values_;
  70. };
  71. template <typename IdT, typename KeyT, typename ValueT>
  72. auto CanonicalValueStore<IdT, KeyT, ValueT>::Add(ValueType value) -> IdT {
  73. auto make_key = [&] { return IdT(values_.Add(std::move(value))); };
  74. return set_.Insert(value, make_key, KeyContext(&values_)).key();
  75. }
  76. template <typename IdT, typename KeyT, typename ValueT>
  77. auto CanonicalValueStore<IdT, KeyT, ValueT>::Lookup(KeyType key) const -> IdT {
  78. if (auto result = set_.Lookup(key, KeyContext(&values_))) {
  79. return result.key();
  80. }
  81. return IdT::None;
  82. }
  83. template <typename IdT, typename KeyT, typename ValueT>
  84. auto CanonicalValueStore<IdT, KeyT, ValueT>::Reserve(size_t size) -> void {
  85. // Compute the resulting new insert count using the size of values -- the
  86. // set doesn't have a fast to compute current size.
  87. if (size > values_.size()) {
  88. set_.GrowForInsertCount(size - values_.size(), KeyContext(&values_));
  89. }
  90. values_.Reserve(size);
  91. }
  92. } // namespace Carbon
  93. #endif // CARBON_TOOLCHAIN_BASE_CANONICAL_VALUE_STORE_H_