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

Code before:
    __asan_unpoison_memory_region(values_.data(),
                                  values_.size() * sizeof(values_[0]));
    all_poisoned_ = false;
#endif
  }
  // Poison a single element.
  auto PoisonElement([[maybe_unused]] int element) const -> void {
#if CARBON_POISON_VALUE_STORES
    __asan_unpoison_memory_region(values_.data() + element, sizeof(values_[0]));
#endif
  }
  // Unpoison a single element.
  auto UnpoisonElement([[maybe_unused]] int element) const -> void {
#if CARBON_POISON_VALUE_STORES
    __asan_unpoison_memory_region(values_.data() + element, sizeof(values_[0]));
    all_poisoned_ = false;
#endif
  }

  // 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_;

#if CARBON_POISON_VALUE_STORES
  // Whether the vector is currently fully poisoned.
  mutable bool all_poisoned_ = true;
#endif
};

// 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 {
 public:
  using ValueType = typename IdT::ValueType;
  using RefType = typename ValueStore<IdT>::RefType;
  using ConstRefType = typename ValueStore<IdT>::ConstRefType;

  // Stores a canonical copy of the value and returns an ID to reference it.
  auto Add(ValueType value) -> IdT;

  // Returns the value for an ID.
  auto Get(IdT id) const -> ConstRefType { return values_.Get(id); }

  // Looks up the canonical ID for a value, or returns `None` if not in the
  // store.
  auto Lookup(ValueType value) const -> IdT;

  // Reserves space.

Review comment (suggestion):
Seems useful to capture the underlying reason for this optimization being so important. Maybe something like:

```suggestion
  // Whether the vector is currently fully poisoned.
  //
  // We use this to avoid repeated re-poisoning of the entire store. Doing so is linear in the size of the store, and we trigger re-poisoning frequently, for example on each import. Tracking that here allows us to coalesce these into a single linear operation.
  mutable bool all_poisoned_ = true;
```

Code after:
#endif
  }
  // Unpoison the entire contents of the value store.
  auto UnpoisonAll() const -> void {
#if CARBON_POISON_VALUE_STORES
    __asan_unpoison_memory_region(values_.data(),
                                  values_.size() * sizeof(values_[0]));
    all_poisoned_ = false;
#endif
  }
  // Poison a single element.
  auto PoisonElement([[maybe_unused]] int element) const -> void {
#if CARBON_POISON_VALUE_STORES
    __asan_unpoison_memory_region(values_.data() + element, sizeof(values_[0]));
#endif
  }
  // Unpoison a single element.
  auto UnpoisonElement([[maybe_unused]] int element) const -> void {
#if CARBON_POISON_VALUE_STORES
    __asan_unpoison_memory_region(values_.data() + element, sizeof(values_[0]));
    all_poisoned_ = false;
#endif
  }

  // 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_;

#if CARBON_POISON_VALUE_STORES
  // Whether the vector is currently fully poisoned.
  //
  // We use this to avoid repeated re-poisoning of the entire store. Doing so is
  // linear in the size of the store, and we trigger re-poisoning frequently,
  // for example on each import. Tracking that here allows us to coalesce these
  // into a single linear operation.
  mutable bool all_poisoned_ = true;
#endif
};

// 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 {
 public:
  using ValueType = typename IdT::ValueType;
  using RefType = typename ValueStore<IdT>::RefType;
  using ConstRefType = typename ValueStore<IdT>::ConstRefType;

  // Stores a canonical copy of the value and returns an ID to reference it.