910e62b5创建于 1月15日历史提交
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BASE_CONTAINERS_VARIANT_MAP_H_
#define BASE_CONTAINERS_VARIANT_MAP_H_

#include <map>
#include <type_traits>

#include "base/check_op.h"
#include "base/features.h"
#include "base/gtest_prod_util.h"
#include "base/notreached.h"
#include "base/types/pass_key.h"
#include "build/build_config.h"
#include "third_party/abseil-cpp/absl/container/flat_hash_map.h"

namespace metrics {
class SubprocessMetricsProvider;
}

namespace mojo {
template <typename ContextType>
class BinderMapWithContext;

class ReceiverSetState;

template <typename ReceiverType, typename ContextType>
class ReceiverSetBase;
}

namespace resource_attribution {
class CPUMeasurementMonitor;
class FakeMemoryMeasurementDelegateFactory;
class MemoryMeasurementDelegate;
class QueryResultMap;
}  // namespace resource_attribution

namespace base {

// Enum to specify which underlying map implementation to use.
enum class MapType {
  // See StdMapVariant
  kStdMap,
  // See FlatHashMapVariant
  kFlatHashMap,
};

// Whether the AbslFlatMapInVariantMap feature is enabled.
BASE_EXPORT bool IsAbslFlatMapInVariantMapEnabled();

// Initializes VariantMap features. See `base::features::Init()`.
BASE_EXPORT void InitializeVariantMapFeatures();

// Class used to evaluate the performance of switching from std::map to
// absl::flat_hash_map in place. This class is used exactly like the underlying
// map implementation for the implemented subset of operations. Constructing can
// be done with a chosen `MapType` or if the default constructor is used the
// variant is chosen automatically with a base::Feature.
//
// Example:
//   VariantMap<int, int> map(MapType::kFlatHashMap);
//   map[4] = 5;
//
// Since this class supports backing map implementations with different
// guarantees users have to assume that the least permissive guarantees apply.
// This includes but is not limited to:
// 1) No specific entry ordering
// 2) No iterator stability through modifications
// 3) No storage stability through modifications
//
// TODO(crbug.com/433462519): Remove this entire class by M145.
template <typename Key, typename Value>
class VariantMap {
 public:
  using StdMapVariant = std::map<Key, Value>;
  using FlatHashMapVariant = absl::flat_hash_map<Key, Value>;
  using value_type = std::pair<const Key, Value>;

  // Iterator class used to erase the difference in backend variant. This should
  // mostly be a drop-in replacement for the iterator types of the underlying
  // map and user code that already uses `auto` for iterator variables should
  // not need to be updated.
  template <bool is_const>
  class IteratorImpl {
   public:
    using StdMapIter =
        std::conditional_t<is_const,
                           typename StdMapVariant::const_iterator,
                           typename StdMapVariant::iterator>;
    using FlatHashMapIter =
        std::conditional_t<is_const,
                           typename FlatHashMapVariant::const_iterator,
                           typename FlatHashMapVariant::iterator>;

    using pointer =
        std::conditional_t<is_const, const value_type*, value_type*>;
    using reference =
        std::conditional_t<is_const, const value_type&, value_type&>;

    explicit IteratorImpl(StdMapIter it) : iter_variant_(it) {}
    explicit IteratorImpl(FlatHashMapIter it) : iter_variant_(it) {}

    // Allow narrowing access from a non-const iterator to a const iterator but
    // not the opposite.
    template <bool other_is_const>
      requires(is_const && !other_is_const)
    explicit IteratorImpl(IteratorImpl<other_is_const> other)
        : iter_variant_(std::visit(
              [](const auto& it) { return decltype(iter_variant_)(it); },
              other.iter_variant_)) {}

    IteratorImpl& operator++() {
      std::visit([](auto& it) { ++it; }, iter_variant_);
      return *this;
    }

    reference operator*() const {
      return std::visit([](auto& it) -> reference { return *it; },
                        iter_variant_);
    }

    pointer operator->() const {
      // Tie the implementation of this operator to operator*.
      // *this accesses this instance * of that uses the * operator.
      // & of that result is a pointer to the value.
      return &(**this);
    }

    bool operator==(const IteratorImpl& other) const {
      // Comparing iterators from different variants should never happen.
      CHECK_EQ(iter_variant_.index(), other.iter_variant_.index());

      return iter_variant_ == other.iter_variant_;
    }

   private:
    template <bool>
    friend class IteratorImpl;

    // For access to `iter_variant_`.
    friend class VariantMap;

    // The variant holds the specific iterator from the underlying map.
    std::variant<StdMapIter, FlatHashMapIter> iter_variant_;
  };

  using iterator = IteratorImpl<false>;
  using const_iterator = IteratorImpl<true>;

  // Protected by PassKey because not intended for general use but only
  // experimenting.
  template <typename ContextType>
  explicit VariantMap(
      base::PassKey<mojo::BinderMapWithContext<ContextType>> passkey)
      : VariantMap() {}

  template <typename ReceiverType, typename ContextType>
  explicit VariantMap(
      base::PassKey<mojo::ReceiverSetBase<ReceiverType, ContextType>> passkey)
      : VariantMap() {}

  explicit VariantMap(base::PassKey<metrics::SubprocessMetricsProvider> passkey)
      : VariantMap() {}

  explicit VariantMap(base::PassKey<mojo::ReceiverSetState> passkey)
      : VariantMap() {}

  explicit VariantMap(
      base::PassKey<resource_attribution::CPUMeasurementMonitor> passkey)
      : VariantMap() {}

  explicit VariantMap(
      base::PassKey<resource_attribution::FakeMemoryMeasurementDelegateFactory>
          passkey)
      : VariantMap() {}

  explicit VariantMap(
      base::PassKey<resource_attribution::MemoryMeasurementDelegate> passkey)
      : VariantMap() {}

  explicit VariantMap(
      base::PassKey<resource_attribution::QueryResultMap> passkey)
      : VariantMap() {}

  size_t size() const {
    return std::visit([](const auto& map) { return map.size(); }, data_);
  }

  bool empty() const {
    return std::visit([](const auto& map) { return map.empty(); }, data_);
  }

  void clear() {
    return std::visit([](auto& map) { return map.clear(); }, data_);
  }

  Value& operator[](const Key& key) {
    return std::visit([&key](auto& map) -> Value& { return map[key]; }, data_);
  }

  Value& at(const Key& key) {
    return std::visit([&key](auto& map) -> Value& { return map.at(key); },
                      data_);
  }

  const Value& at(const Key& key) const {
    return std::visit(
        [&key](const auto& map) -> const Value& { return map.at(key); }, data_);
  }

  template <class... Args>
  std::pair<iterator, bool> emplace(Args&&... args) {
    return std::visit(
        [&](auto& map) {
          auto result = map.emplace(std::forward<Args>(args)...);
          return std::make_pair(iterator(result.first), result.second);
        },
        data_);
  }

  template <class... Args>
  std::pair<iterator, bool> try_emplace(Args&&... args) {
    return std::visit(
        [&](auto& map) {
          auto result = map.try_emplace(std::forward<Args>(args)...);
          return std::make_pair(iterator(result.first), result.second);
        },
        data_);
  }

  std::pair<iterator, bool> insert(value_type&& value) {
    return std::visit(
        [&](auto& map) {
          auto result = map.insert(std::move(value));
          return std::make_pair(iterator(result.first), result.second);
        },
        data_);
  }

  size_t erase(const Key& key) {
    return std::visit([&](auto& map) { return map.erase(key); }, data_);
  }

  void erase(iterator pos) {
    std::visit(
        [&](auto& map) {
          // Get the correct native_iterator out.
          using MapType = typename std::decay<decltype(map)>::type;
          auto native_it =
              std::get<typename MapType::iterator>(pos.iter_variant_);

          map.erase(native_it);
        },
        data_);
  }

  iterator begin() {
    return std::visit([](auto& map) { return iterator(map.begin()); }, data_);
  }
  const_iterator begin() const {
    return const_iterator(const_cast<VariantMap*>(this)->begin());
  }

  iterator end() {
    return std::visit([](auto& map) { return iterator(map.end()); }, data_);
  }
  const_iterator end() const {
    return const_iterator(const_cast<VariantMap*>(this)->end());
  }

  iterator find(const Key& key) {
    return std::visit([&key](auto& map) { return iterator(map.find(key)); },
                      data_);
  }
  const_iterator find(const Key& key) const {
    return const_iterator(const_cast<VariantMap*>(this)->find(key));
  }

 private:
  FRIEND_TEST_ALL_PREFIXES(VariantMapTest, Construction);
  FRIEND_TEST_ALL_PREFIXES(VariantMapTest, Insertion);
  FRIEND_TEST_ALL_PREFIXES(VariantMapTest, At);
  FRIEND_TEST_ALL_PREFIXES(VariantMapTest, Find);
  FRIEND_TEST_ALL_PREFIXES(VariantMapTest, Iteration);
  FRIEND_TEST_ALL_PREFIXES(VariantMapTest, Empty);
  FRIEND_TEST_ALL_PREFIXES(VariantMapTest, Clear);

  using Map = std::variant<StdMapVariant, FlatHashMapVariant>;

  // Constructors private because protected via PassKey.

  explicit VariantMap(MapType type)
      : data_([&]() {
          switch (type) {
            case MapType::kStdMap:
              return Map(std::in_place_index_t<0>());
            case MapType::kFlatHashMap:
              return Map(std::in_place_index_t<1>());

              NOTREACHED();
          }
        }()) {}

  VariantMap()
      : VariantMap(base::IsAbslFlatMapInVariantMapEnabled()
                       ? MapType::kFlatHashMap
                       : MapType::kStdMap) {}

  // The variant that holds one of the two map types.
  Map data_;
};

}  // namespace base

#endif  // BASE_CONTAINERS_VARIANT_MAP_H_