Repository: carbon-language/carbon-lang
File: toolchain/base/value_store.h (C/C++)

Code before:
    return values_[id.index];
  }

  // Reserves space.
  auto Reserve(size_t size) -> void { values_.reserve(size); }

  // These are to support printable structures, and are not guaranteed.
  auto OutputYaml() const -> Yaml::OutputMapping {
    return Yaml::OutputMapping([&](Yaml::OutputMapping::Map map) {
      for (auto [id, value] : enumerate()) {
        map.Add(PrintToString(id), Yaml::OutputScalar(value));
      }
    });
  }

  // Collects memory usage of the values.
  auto CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
      -> void {
    mem_usage.Collect(label.str(), values_);
  }

  auto array_ref() const -> llvm::ArrayRef<ValueType> { return values_; }
  auto size() const -> size_t { return values_.size(); }

  // Makes an iterable range over pairs of the index and value for each value in
  // the store.
  auto enumerate() const -> auto {
    auto index_to_id = [](auto pair) -> std::pair<IdT, ConstRefType> {
      auto [index, value] = pair;
      return std::pair<IdT, ConstRefType>(IdT(index), value);
    };
    auto range = llvm::enumerate(values_);
    using Iter =
        llvm::mapped_iterator<decltype(range.begin()), decltype(index_to_id)>;
    auto begin = Iter(range.begin(), index_to_id);
    auto end = Iter(range.end(), index_to_id);
    return llvm::make_range(begin, end);
  }

 private:
  // Set inline size to 0 because these will typically be too large for the
  // stack, while this does make File smaller.
  llvm::SmallVector<std::decay_t<ValueType>, 0> values_;
};

// A wrapper for accumulating immutable values with deduplication, providing IDs
// to later retrieve the value.
//
// IdT::ValueType must represent the type being indexed.
template <typename IdT>
class CanonicalValueStore {

Review comment (suggestion):
```suggestion
  // Makes an iterable range over pairs of the index and a reference to the value for each value in
  // the store.
```
I also wonder if it's worth pointing out that
```c++
for (auto [id, value] : store.enumerate())
```
doesn't make copies of `value` -- that's a pretty subtle consequence of the pair holding a reference member, given that `auto` by itself usually does make copies.

Code after:
    return values_[id.index];
  }

  // Reserves space.
  auto Reserve(size_t size) -> void { values_.reserve(size); }

  // These are to support printable structures, and are not guaranteed.
  auto OutputYaml() const -> Yaml::OutputMapping {
    return Yaml::OutputMapping([&](Yaml::OutputMapping::Map map) {
      for (auto [id, value] : enumerate()) {
        map.Add(PrintToString(id), Yaml::OutputScalar(value));
      }
    });
  }

  // Collects memory usage of the values.
  auto CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
      -> void {
    mem_usage.Collect(label.str(), values_);
  }

  auto array_ref() const -> llvm::ArrayRef<ValueType> { return values_; }
  auto size() const -> size_t { return values_.size(); }

  // Makes an iterable range over pairs of the index and a reference to the
  // value for each value in the store.
  //
  // The range is over references to the values in the store, even if used with
  // `auto` to destructure the pair. In this example, the `value` is a
  // `ConstRefType`:
  // ```
  // for (auto [id, value] : store.enumerate()) { ... }
  // ```
  auto enumerate() const -> auto {
    auto index_to_id = [](auto pair) -> std::pair<IdT, ConstRefType> {
      auto [index, value] = pair;
      return std::pair<IdT, ConstRefType>(IdT(index), value);
    };
    auto range = llvm::enumerate(values_);
    using Iter =
        llvm::mapped_iterator<decltype(range.begin()), decltype(index_to_id)>;
    auto begin = Iter(range.begin(), index_to_id);
    auto end = Iter(range.end(), index_to_id);
    return llvm::make_range(begin, end);
  }

 private:
  // Set inline size to 0 because these will typically be too large for the
  // stack, while this does make File smaller.
  llvm::SmallVector<std::decay_t<ValueType>, 0> values_;
};