// Copyright 2017 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_TASK_TASK_TRAITS_DETAILS_H_ #define BASE_TASK_TASK_TRAITS_DETAILS_H_ #include #include #include #include namespace base { namespace trait_helpers { // Checks if any of the elements in |ilist| is true. // Similar to std::any_of for the case of constexpr initializer_list. inline constexpr bool any_of(std::initializer_list ilist) { for (auto c : ilist) { if (c) return true; } return false; } // Checks if all of the elements in |ilist| are true. // Similar to std::any_of for the case of constexpr initializer_list. inline constexpr bool all_of(std::initializer_list ilist) { for (auto c : ilist) { if (!c) return false; } return true; } // Counts the elements in |ilist| that are equal to |value|. // Similar to std::count for the case of constexpr initializer_list. template inline constexpr size_t count(std::initializer_list ilist, T value) { size_t c = 0; for (const auto& v : ilist) { c += (v == value); } return c; } // 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 ::value>> constexpr TraitFilterType GetTraitFromArg(CallFirstTag, ArgType arg) { return TraitFilterType(arg); } template 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 ::value...})>> constexpr TraitFilterType GetTraitFromArgListImpl(CallFirstTag, ArgTypes... args) { return std::get(std::make_tuple( GetTraitFromArg(CallFirstTag(), args)...)); } template constexpr TraitFilterType GetTraitFromArgListImpl(CallSecondTag, ArgTypes... args) { static_assert(std::is_constructible::value, "TaskTraits contains a Trait that must be explicity " "initialized in its constructor."); 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 constexpr typename TraitFilterType::ValueType GetTraitFromArgList( ArgTypes... args) { // static_assert( // count_matches(bool, true, std::is_constructible...) <= 1, // "Multiple arguments of the same type were provided to the " // "constructor of TaskTraits."); return GetTraitFromArgListImpl(CallFirstTag(), args...); } // Returns true if this trait is explicitly defined in an argument list, i.e. // there is an argument compatible with this trait in |args...|. template constexpr bool TraitIsDefined(ArgTypes... args) { return any_of({std::is_constructible::value...}); } // Helper class to implemnent a |TraitFilterType|. template struct BasicTraitFilter { using ValueType = T; constexpr operator ValueType() const { return value; } ValueType value = {}; }; template struct BooleanTraitFilter : public BasicTraitFilter { constexpr BooleanTraitFilter() { this->value = false; } constexpr BooleanTraitFilter(ArgType) { this->value = true; } }; template struct EnumTraitFilter : public BasicTraitFilter { constexpr EnumTraitFilter() { this->value = DefaultValue; } constexpr EnumTraitFilter(ArgType arg) { this->value = arg; } }; // Tests whether multiple given argtument types are all valid traits according // to the provided ValidTraits. To use, define a ValidTraits template struct RequiredEnumTraitFilter : public BasicTraitFilter { constexpr RequiredEnumTraitFilter(ArgType arg) { this->value = arg; } }; // 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); // ... // }; template struct if_all; template <> struct if_all<> : std::integral_constant {}; template struct if_all : std::conditional, std::integral_constant>::type {}; template struct AreValidTraits : std::integral_constant< bool, if_all...>::value> {}; } // namespace trait_helpers } // namespace base #endif // BASE_TASK_TASK_TRAITS_DETAILS_H_