Repo created
This commit is contained in:
parent
81b91f4139
commit
f8c34fa5ee
22732 changed files with 4815320 additions and 2 deletions
260
TMessagesProj/jni/voip/webrtc/base/traits_bag.h
Normal file
260
TMessagesProj/jni/voip/webrtc/base/traits_bag.h
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
// Copyright 2018 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_TRAITS_BAG_H_
|
||||
#define BASE_TRAITS_BAG_H_
|
||||
|
||||
#include <initializer_list>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "base/optional.h"
|
||||
#include "base/parameter_pack.h"
|
||||
#include "base/template_util.h"
|
||||
|
||||
// A bag of Traits (structs / enums / etc...) can be an elegant alternative to
|
||||
// the builder pattern and multiple default arguments for configuring things.
|
||||
// Traits are terser than the builder pattern and can be evaluated at compile
|
||||
// time, however they require the use of variadic templates which complicates
|
||||
// matters. This file contains helpers that make Traits easier to use.
|
||||
//
|
||||
// WARNING: Trait bags are currently too heavy for non-constexpr usage in prod
|
||||
// code due to template bloat, although adding NOINLINE to template constructors
|
||||
// configured via trait bags can help.
|
||||
//
|
||||
// E.g.
|
||||
// struct EnableFeatureX {};
|
||||
// struct UnusedTrait {};
|
||||
// enum Color { RED, BLUE };
|
||||
//
|
||||
// struct ValidTraits {
|
||||
// ValidTraits(EnableFeatureX);
|
||||
// ValidTraits(Color);
|
||||
// };
|
||||
// ...
|
||||
// DoSomethingAwesome(); // Use defaults (Color::BLUE &
|
||||
// // feature X not enabled)
|
||||
// DoSomethingAwesome(EnableFeatureX(), // Turn feature X on
|
||||
// Color::RED); // And make it red.
|
||||
// DoSomethingAwesome(UnusedTrait(), // Compile time error.
|
||||
// Color::RED);
|
||||
//
|
||||
// DoSomethingAwesome might be defined as:
|
||||
//
|
||||
// template <class... ArgTypes,
|
||||
// class CheckArgumentsAreValid = std::enable_if_t<
|
||||
// trait_helpers::AreValidTraits<ValidTraits,
|
||||
// ArgTypes...>::value>>
|
||||
// constexpr void DoSomethingAwesome(ArgTypes... args)
|
||||
// : enable_feature_x(
|
||||
// trait_helpers::HasTrait<EnableFeatureX, ArgTypes...>()),
|
||||
// color(trait_helpers::GetEnum<Color, EnumTraitA::BLUE>(args...)) {}
|
||||
|
||||
namespace base {
|
||||
namespace trait_helpers {
|
||||
|
||||
// Represents a trait that has been removed by a predicate.
|
||||
struct EmptyTrait {};
|
||||
|
||||
// Predicate used to remove any traits from the given list of types by
|
||||
// converting them to EmptyTrait. E.g.
|
||||
//
|
||||
// template <typename... Args>
|
||||
// void MyFunc(Args... args) {
|
||||
// DoSomethingWithTraits(
|
||||
// base::trait_helpers::Exclude<UnwantedTrait1,
|
||||
// UnwantedTrait2>::Filter(args)...);
|
||||
// }
|
||||
//
|
||||
// NB It's possible to actually remove the unwanted trait from the pack, but
|
||||
// that requires constructing a filtered tuple and applying it to the function,
|
||||
// which isn't worth the complexity over ignoring EmptyTrait.
|
||||
template <typename... TraitsToExclude>
|
||||
struct Exclude {
|
||||
template <typename T,
|
||||
std::enable_if_t<ParameterPack<
|
||||
TraitsToExclude...>::template HasType<T>::value>* = nullptr>
|
||||
static constexpr EmptyTrait Filter(T t) {
|
||||
return EmptyTrait();
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
std::enable_if_t<!ParameterPack<
|
||||
TraitsToExclude...>::template HasType<T>::value>* = nullptr>
|
||||
static constexpr T Filter(T t) {
|
||||
return t;
|
||||
}
|
||||
};
|
||||
|
||||
// CallFirstTag is an argument tag that helps to avoid ambiguous overloaded
|
||||
// functions. When the following call is made:
|
||||
// func(CallFirstTag(), arg...);
|
||||
// the compiler will give precedence to an overload candidate that directly
|
||||
// takes CallFirstTag. Another overload that takes CallSecondTag will be
|
||||
// considered iff the preferred overload candidates were all invalids and
|
||||
// therefore discarded.
|
||||
struct CallSecondTag {};
|
||||
struct CallFirstTag : CallSecondTag {};
|
||||
|
||||
// A trait filter class |TraitFilterType| implements the protocol to get a value
|
||||
// of type |ArgType| from an argument list and convert it to a value of type
|
||||
// |TraitType|. If the argument list contains an argument of type |ArgType|, the
|
||||
// filter class will be instantiated with that argument. If the argument list
|
||||
// contains no argument of type |ArgType|, the filter class will be instantiated
|
||||
// using the default constructor if available; a compile error is issued
|
||||
// otherwise. The filter class must have the conversion operator TraitType()
|
||||
// which returns a value of type TraitType.
|
||||
|
||||
// |InvalidTrait| is used to return from GetTraitFromArg when the argument is
|
||||
// not compatible with the desired trait.
|
||||
struct InvalidTrait {};
|
||||
|
||||
// Returns an object of type |TraitFilterType| constructed from |arg| if
|
||||
// compatible, or |InvalidTrait| otherwise.
|
||||
template <class TraitFilterType,
|
||||
class ArgType,
|
||||
class CheckArgumentIsCompatible = std::enable_if_t<
|
||||
std::is_constructible<TraitFilterType, ArgType>::value>>
|
||||
constexpr TraitFilterType GetTraitFromArg(CallFirstTag, ArgType arg) {
|
||||
return TraitFilterType(arg);
|
||||
}
|
||||
|
||||
template <class TraitFilterType, class ArgType>
|
||||
constexpr InvalidTrait GetTraitFromArg(CallSecondTag, ArgType arg) {
|
||||
return InvalidTrait();
|
||||
}
|
||||
|
||||
// Returns an object of type |TraitFilterType| constructed from a compatible
|
||||
// argument in |args...|, or default constructed if none of the arguments are
|
||||
// compatible. This is the implementation of GetTraitFromArgList() with a
|
||||
// disambiguation tag.
|
||||
template <class TraitFilterType,
|
||||
class... ArgTypes,
|
||||
class TestCompatibleArgument = std::enable_if_t<any_of(
|
||||
{std::is_constructible<TraitFilterType, ArgTypes>::value...})>>
|
||||
constexpr TraitFilterType GetTraitFromArgListImpl(CallFirstTag,
|
||||
ArgTypes... args) {
|
||||
return std::get<TraitFilterType>(std::make_tuple(
|
||||
GetTraitFromArg<TraitFilterType>(CallFirstTag(), args)...));
|
||||
}
|
||||
|
||||
template <class TraitFilterType, class... ArgTypes>
|
||||
constexpr TraitFilterType GetTraitFromArgListImpl(CallSecondTag,
|
||||
ArgTypes... args) {
|
||||
static_assert(std::is_constructible<TraitFilterType>::value,
|
||||
"The traits bag is missing a required trait.");
|
||||
return TraitFilterType();
|
||||
}
|
||||
|
||||
// Constructs an object of type |TraitFilterType| from a compatible argument in
|
||||
// |args...|, or using the default constructor, and returns its associated trait
|
||||
// value using conversion to |TraitFilterType::ValueType|. If there are more
|
||||
// than one compatible argument in |args|, generates a compile-time error.
|
||||
template <class TraitFilterType, class... ArgTypes>
|
||||
constexpr typename TraitFilterType::ValueType GetTraitFromArgList(
|
||||
ArgTypes... args) {
|
||||
static_assert(
|
||||
count({std::is_constructible<TraitFilterType, ArgTypes>::value...},
|
||||
true) <= 1,
|
||||
"The traits bag contains multiple traits of the same type.");
|
||||
return GetTraitFromArgListImpl<TraitFilterType>(CallFirstTag(), args...);
|
||||
}
|
||||
|
||||
// Helper class to implemnent a |TraitFilterType|.
|
||||
template <typename T, typename _ValueType = T>
|
||||
struct BasicTraitFilter {
|
||||
using ValueType = _ValueType;
|
||||
|
||||
constexpr BasicTraitFilter(ValueType v) : value(v) {}
|
||||
|
||||
constexpr operator ValueType() const { return value; }
|
||||
|
||||
ValueType value = {};
|
||||
};
|
||||
|
||||
template <typename ArgType, ArgType DefaultValue>
|
||||
struct EnumTraitFilter : public BasicTraitFilter<ArgType> {
|
||||
constexpr EnumTraitFilter() : BasicTraitFilter<ArgType>(DefaultValue) {}
|
||||
constexpr EnumTraitFilter(ArgType arg) : BasicTraitFilter<ArgType>(arg) {}
|
||||
};
|
||||
|
||||
template <typename ArgType>
|
||||
struct OptionalEnumTraitFilter
|
||||
: public BasicTraitFilter<ArgType, Optional<ArgType>> {
|
||||
constexpr OptionalEnumTraitFilter()
|
||||
: BasicTraitFilter<ArgType, Optional<ArgType>>(nullopt) {}
|
||||
constexpr OptionalEnumTraitFilter(ArgType arg)
|
||||
: BasicTraitFilter<ArgType, Optional<ArgType>>(arg) {}
|
||||
};
|
||||
|
||||
// Tests whether multiple given argtument types are all valid traits according
|
||||
// to the provided ValidTraits. To use, define a ValidTraits
|
||||
template <typename ArgType>
|
||||
struct RequiredEnumTraitFilter : public BasicTraitFilter<ArgType> {
|
||||
constexpr RequiredEnumTraitFilter(ArgType arg)
|
||||
: BasicTraitFilter<ArgType>(arg) {}
|
||||
};
|
||||
|
||||
// Note EmptyTrait is always regarded as valid to support filtering.
|
||||
template <class ValidTraits, class T>
|
||||
using IsValidTrait = disjunction<std::is_constructible<ValidTraits, T>,
|
||||
std::is_same<T, EmptyTrait>>;
|
||||
|
||||
// Tests whether a given trait type is valid or invalid by testing whether it is
|
||||
// convertible to the provided ValidTraits type. To use, define a ValidTraits
|
||||
// type like this:
|
||||
//
|
||||
// struct ValidTraits {
|
||||
// ValidTraits(MyTrait);
|
||||
// ...
|
||||
// };
|
||||
//
|
||||
// You can 'inherit' valid traits like so:
|
||||
//
|
||||
// struct MoreValidTraits {
|
||||
// MoreValidTraits(ValidTraits); // Pull in traits from ValidTraits.
|
||||
// MoreValidTraits(MyOtherTrait);
|
||||
// ...
|
||||
// };
|
||||
template <class ValidTraits, class... ArgTypes>
|
||||
using AreValidTraits =
|
||||
bool_constant<all_of({IsValidTrait<ValidTraits, ArgTypes>::value...})>;
|
||||
|
||||
// Helper to make getting an enum from a trait more readable.
|
||||
template <typename Enum, typename... Args>
|
||||
static constexpr Enum GetEnum(Args... args) {
|
||||
return GetTraitFromArgList<RequiredEnumTraitFilter<Enum>>(args...);
|
||||
}
|
||||
|
||||
// Helper to make getting an enum from a trait with a default more readable.
|
||||
template <typename Enum, Enum DefaultValue, typename... Args>
|
||||
static constexpr Enum GetEnum(Args... args) {
|
||||
return GetTraitFromArgList<EnumTraitFilter<Enum, DefaultValue>>(args...);
|
||||
}
|
||||
|
||||
// Helper to make getting an optional enum from a trait with a default more
|
||||
// readable.
|
||||
template <typename Enum, typename... Args>
|
||||
static constexpr Optional<Enum> GetOptionalEnum(Args... args) {
|
||||
return GetTraitFromArgList<OptionalEnumTraitFilter<Enum>>(args...);
|
||||
}
|
||||
|
||||
// Helper to make checking for the presence of a trait more readable.
|
||||
template <typename Trait, typename... Args>
|
||||
struct HasTrait : ParameterPack<Args...>::template HasType<Trait> {
|
||||
static_assert(
|
||||
count({std::is_constructible<Trait, Args>::value...}, true) <= 1,
|
||||
"The traits bag contains multiple traits of the same type.");
|
||||
};
|
||||
|
||||
// If you need a template vararg constructor to delegate to a private
|
||||
// constructor, you may need to add this to the private constructor to ensure
|
||||
// it's not matched by accident.
|
||||
struct NotATraitTag {};
|
||||
|
||||
} // namespace trait_helpers
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_TRAITS_BAG_H_
|
||||
Loading…
Add table
Add a link
Reference in a new issue