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

Code before:
  // Collects memory usage of the values and deduplication set.
  auto CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
      -> void {
    mem_usage.Collect(MemUsage::ConcatLabel(label, "values_"), values_);
    auto bytes = set_.ComputeMetrics(KeyContext(&values_)).storage_bytes;
    mem_usage.Add(MemUsage::ConcatLabel(label, "set_"), bytes, bytes);
  }

 private:
  class KeyContext;

  ValueStore<IdT, ValueType> values_;
  Set<IdT, /*SmallSize=*/0, KeyContext> set_;
};

template <typename IdT, typename KeyT, typename ValueT, auto ValueToKeyFn>
class CanonicalValueStore<IdT, KeyT, ValueT, ValueToKeyFn>::KeyContext
    : public TranslatingKeyContext<KeyContext> {
 public:
  explicit KeyContext(const ValueStore<IdT, ValueType>* values)
      : values_(values) {}

  // Note that it is safe to return a `const` reference here as the underlying
  // object's lifetime is provided by the `ValueStore`. Returns `auto` to pick
  // up the return type of `ValueToKeyFn`.
  auto TranslateKey(IdT id) const -> auto {
    return ValueToKeyFn(values_->Get(id));
  }

 private:
  const ValueStore<IdT, ValueType>* values_;
};

template <typename IdT, typename KeyT, typename ValueT, auto ValueToKeyFn>
auto CanonicalValueStore<IdT, KeyT, ValueT, ValueToKeyFn>::Add(ValueType value)
    -> IdT {
  auto make_key = [&] { return IdT(values_.Add(std::move(value))); };
  return set_.Insert(ValueToKeyFn(value), make_key, KeyContext(&values_)).key();
}

template <typename IdT, typename KeyT, typename ValueT, auto ValueToKeyFn>
auto CanonicalValueStore<IdT, KeyT, ValueT, ValueToKeyFn>::Lookup(
    KeyType key) const -> IdT {
  if (auto result = set_.Lookup(key, KeyContext(&values_))) {
    return result.key();
  }
  return IdT::None;
}

template <typename IdT, typename KeyT, typename ValueT, auto ValueToKeyFn>
auto CanonicalValueStore<IdT, KeyT, ValueT, ValueToKeyFn>::Reserve(size_t size)

Review comment (suggestion):
Consider returning `decltype(auto)` instead so that a reference return type is properly forwarded.

Code after:
    return values_.values();
  }
  auto size() const -> size_t { return values_.size(); }

  // Collects memory usage of the values and deduplication set.
  auto CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
      -> void {
    mem_usage.Collect(MemUsage::ConcatLabel(label, "values_"), values_);
    auto bytes = set_.ComputeMetrics(KeyContext(&values_)).storage_bytes;
    mem_usage.Add(MemUsage::ConcatLabel(label, "set_"), bytes, bytes);
  }

 private:
  class KeyContext;

  ValueStore<IdT, ValueType> values_;
  Set<IdT, /*SmallSize=*/0, KeyContext> set_;
};

template <typename IdT, typename KeyT, typename ValueT, auto ValueToKeyFn>
class CanonicalValueStore<IdT, KeyT, ValueT, ValueToKeyFn>::KeyContext
    : public TranslatingKeyContext<KeyContext> {
 public:
  explicit KeyContext(const ValueStore<IdT, ValueType>* values)
      : values_(values) {}

  // Note that it is safe to return a `const` reference here as the underlying
  // object's lifetime is provided by the `ValueStore`.
  auto TranslateKey(IdT id) const
      -> llvm::function_traits<decltype(ValueToKeyFn)>::result_t {
    return ValueToKeyFn(values_->Get(id));
  }

 private:
  const ValueStore<IdT, ValueType>* values_;
};

template <typename IdT, typename KeyT, typename ValueT, auto ValueToKeyFn>
auto CanonicalValueStore<IdT, KeyT, ValueT, ValueToKeyFn>::Add(ValueType value)
    -> IdT {
  auto make_key = [&] { return IdT(values_.Add(std::move(value))); };
  return set_.Insert(ValueToKeyFn(value), make_key, KeyContext(&values_)).key();
}

template <typename IdT, typename KeyT, typename ValueT, auto ValueToKeyFn>
auto CanonicalValueStore<IdT, KeyT, ValueT, ValueToKeyFn>::Lookup(
    KeyType key) const -> IdT {
  if (auto result = set_.Lookup(key, KeyContext(&values_))) {
    return result.key();
  }
  return IdT::None;