#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 base {
enum class MapType {
kStdMap,
kFlatHashMap,
};
BASE_EXPORT bool IsAbslFlatMapInVariantMapEnabled();
BASE_EXPORT void InitializeVariantMapFeatures();
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>;
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) {}
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 {
return &(**this);
}
bool operator==(const IteratorImpl& other) const {
CHECK_EQ(iter_variant_.index(), other.iter_variant_.index());
return iter_variant_ == other.iter_variant_;
}
private:
template <bool>
friend class IteratorImpl;
friend class VariantMap;
std::variant<StdMapIter, FlatHashMapIter> iter_variant_;
};
using iterator = IteratorImpl<false>;
using const_iterator = IteratorImpl<true>;
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) {
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>;
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) {}
Map data_;
};
}
#endif