fixed_size_value_store.h 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  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_FIXED_SIZE_VALUE_STORE_H_
  5. #define CARBON_TOOLCHAIN_BASE_FIXED_SIZE_VALUE_STORE_H_
  6. #include <concepts>
  7. #include <type_traits>
  8. #include "common/check.h"
  9. #include "llvm/ADT/SmallVector.h"
  10. #include "llvm/ADT/StringRef.h"
  11. #include "llvm/ADT/iterator_range.h"
  12. #include "toolchain/base/mem_usage.h"
  13. #include "toolchain/base/value_store.h"
  14. #include "toolchain/base/value_store_types.h"
  15. namespace Carbon {
  16. // A value store with a predetermined size.
  17. template <typename IdT, typename ValueT, typename TagIdT = Untagged>
  18. class FixedSizeValueStore {
  19. public:
  20. using IdType = IdT;
  21. using IdTagType = IdTag<IdT, TagIdT>;
  22. using ValueType = ValueStoreTypes<ValueT>::ValueType;
  23. using RefType = ValueStoreTypes<ValueT>::RefType;
  24. using ConstRefType = ValueStoreTypes<ValueT>::ConstRefType;
  25. // Makes a ValueStore of the specified size, but without initializing values.
  26. // Entries must be set before reading.
  27. static auto MakeForOverwriteWithExplicitSize(size_t size,
  28. IdTagType::TagIdType tag_id,
  29. int32_t initial_reserved_ids = 0)
  30. -> FixedSizeValueStore
  31. requires(!IdTagIsUntagged<IdTagType>)
  32. {
  33. FixedSizeValueStore store(IdTagType(tag_id, initial_reserved_ids));
  34. store.values_.resize_for_overwrite(size);
  35. return store;
  36. }
  37. static auto MakeForOverwriteWithExplicitSize(size_t size)
  38. -> FixedSizeValueStore
  39. requires(IdTagIsUntagged<IdTagType>)
  40. {
  41. FixedSizeValueStore store;
  42. store.values_.resize_for_overwrite(size);
  43. return store;
  44. }
  45. // Makes a ValueStore of the same size as a source `ValueStoreT`, but without
  46. // initializing values. Entries must be set before reading.
  47. template <typename ValueStoreT>
  48. requires(std::same_as<IdT, typename ValueStoreT::IdType> &&
  49. !IdTagIsUntagged<typename ValueStoreT::IdTagType>)
  50. static auto MakeForOverwrite(const ValueStoreT& size_source)
  51. -> FixedSizeValueStore {
  52. FixedSizeValueStore store(size_source.GetIdTag());
  53. store.values_.resize_for_overwrite(size_source.size());
  54. return store;
  55. }
  56. // Makes a ValueStore of the specified size, initialized to a default.
  57. static auto MakeWithExplicitSize(size_t size, IdTagType tag,
  58. ConstRefType default_value)
  59. -> FixedSizeValueStore
  60. requires(!IdTagIsUntagged<IdTagType>)
  61. {
  62. FixedSizeValueStore store(tag);
  63. store.values_.resize(size, default_value);
  64. return store;
  65. }
  66. static auto MakeWithExplicitSize(size_t size, ConstRefType default_value)
  67. -> FixedSizeValueStore
  68. requires(IdTagIsUntagged<IdTagType>)
  69. {
  70. FixedSizeValueStore store;
  71. store.values_.resize(size, default_value);
  72. return store;
  73. }
  74. // Makes a ValueStore of the specified size, initialized to values returned
  75. // from a callback. This allows initializing non-copyable values.
  76. static auto MakeWithExplicitSizeFrom(
  77. size_t size, llvm::function_ref<auto()->ValueT> callable)
  78. -> FixedSizeValueStore {
  79. FixedSizeValueStore store;
  80. store.values_.reserve(size);
  81. for (auto _ : llvm::seq(size)) {
  82. store.values_.push_back(callable());
  83. }
  84. return store;
  85. }
  86. // Makes a ValueStore of the same size as a source `ValueStoreT`. This is
  87. // the safest constructor to use, since it ensures everything's initialized to
  88. // a default, and verifies a matching `IdT` for the size.
  89. template <typename ValueStoreT>
  90. requires(std::same_as<IdT, typename ValueStoreT::IdType> &&
  91. !IdTagIsUntagged<IdTagType> && !IdTagIsUntagged<ValueStoreT>)
  92. explicit FixedSizeValueStore(const ValueStoreT& size_source,
  93. ConstRefType default_value)
  94. : tag_(size_source.GetIdTag()) {
  95. values_.resize(size_source.size(), default_value);
  96. }
  97. template <typename ValueStoreT>
  98. requires(std::same_as<IdT, typename ValueStoreT::IdType> &&
  99. IdTagIsUntagged<IdTagType> && IdTagIsUntagged<ValueStoreT>)
  100. explicit FixedSizeValueStore(const ValueStoreT& size_source,
  101. ConstRefType default_value) {
  102. values_.resize(size_source.size(), default_value);
  103. }
  104. explicit FixedSizeValueStore(IdTagType tag) : tag_(tag) {}
  105. // Makes a ValueStore using a mapped range of `source`. The `factory_fn`
  106. // receives each enumerated entry for construction of `ValueType`.
  107. template <typename ValueStoreT>
  108. requires(std::same_as<IdT, typename ValueStoreT::IdType> &&
  109. !IdTagIsUntagged<IdTagType> && !IdTagIsUntagged<ValueStoreT>)
  110. explicit FixedSizeValueStore(
  111. const ValueStoreT& source,
  112. llvm::function_ref<
  113. auto(IdT, typename ValueStoreT::ConstRefType)->ValueType>
  114. factory_fn)
  115. : values_(llvm::map_range(source.enumerate(), factory_fn)),
  116. tag_(GetIdTag(source)) {}
  117. template <typename ValueStoreT>
  118. requires(std::same_as<IdT, typename ValueStoreT::IdType> &&
  119. IdTagIsUntagged<IdTagType> && IdTagIsUntagged<ValueStoreT>)
  120. explicit FixedSizeValueStore(
  121. const ValueStoreT& source,
  122. llvm::function_ref<
  123. auto(IdT, typename ValueStoreT::ConstRefType)->ValueType>
  124. factory_fn)
  125. : values_(llvm::map_range(source.enumerate(), factory_fn)) {}
  126. // Move-only.
  127. FixedSizeValueStore(FixedSizeValueStore&&) noexcept = default;
  128. auto operator=(FixedSizeValueStore&&) noexcept
  129. -> FixedSizeValueStore& = default;
  130. // Sets the value for an ID.
  131. auto Set(IdT id, ValueType value) -> void {
  132. CARBON_DCHECK(id.index >= 0, "{0}", id);
  133. auto index = tag_.Remove(id);
  134. values_[index] = value;
  135. }
  136. // Returns a mutable value for an ID.
  137. auto Get(IdT id) -> RefType {
  138. CARBON_DCHECK(id.index >= 0, "{0}", id);
  139. auto index = tag_.Remove(id);
  140. return values_[index];
  141. }
  142. // Returns the value for an ID.
  143. auto Get(IdT id) const -> ConstRefType {
  144. CARBON_DCHECK(id.index >= 0, "{0}", id);
  145. auto index = tag_.Remove(id);
  146. return values_[index];
  147. }
  148. // Collects memory usage of the values.
  149. auto CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
  150. -> void {
  151. mem_usage.Collect(label.str(), values_);
  152. }
  153. auto size() const -> size_t { return values_.size(); }
  154. auto values()
  155. -> llvm::iterator_range<typename llvm::SmallVector<ValueT, 0>::iterator> {
  156. return llvm::make_range(values_.begin(), values_.end());
  157. }
  158. auto values() const -> llvm::iterator_range<
  159. typename llvm::SmallVector<ValueT, 0>::const_iterator> {
  160. return llvm::make_range(values_.begin(), values_.end());
  161. }
  162. private:
  163. // Allow default construction for `Make` functions.
  164. FixedSizeValueStore() = default;
  165. // Storage for the `ValueT` objects, indexed by the id.
  166. llvm::SmallVector<ValueT, 0> values_;
  167. IdTagType tag_;
  168. };
  169. } // namespace Carbon
  170. #endif // CARBON_TOOLCHAIN_BASE_FIXED_SIZE_VALUE_STORE_H_