fdoray | 879b2fc | 2017-05-01 21:34:11 | [diff] [blame] | 1 | // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Gabriel Charette | 04b138f | 2018-08-06 00:03:22 | [diff] [blame] | 5 | #ifndef BASE_TASK_TASK_TRAITS_DETAILS_H_ |
| 6 | #define BASE_TASK_TASK_TRAITS_DETAILS_H_ |
fdoray | 879b2fc | 2017-05-01 21:34:11 | [diff] [blame] | 7 | |
Etienne Pierre-doray | 88396607 | 2018-10-03 20:19:56 | [diff] [blame] | 8 | #include <initializer_list> |
Eric Seckler | 97f22e8b | 2018-08-16 09:03:05 | [diff] [blame] | 9 | #include <tuple> |
fdoray | 879b2fc | 2017-05-01 21:34:11 | [diff] [blame] | 10 | #include <type_traits> |
| 11 | #include <utility> |
| 12 | |
| 13 | namespace base { |
Eric Seckler | 97f22e8b | 2018-08-16 09:03:05 | [diff] [blame] | 14 | namespace trait_helpers { |
fdoray | 879b2fc | 2017-05-01 21:34:11 | [diff] [blame] | 15 | |
Etienne Pierre-doray | 88396607 | 2018-10-03 20:19:56 | [diff] [blame] | 16 | // Checks if any of the elements in |ilist| is true. |
| 17 | // Similar to std::any_of for the case of constexpr initializer_list. |
| 18 | inline constexpr bool any_of(std::initializer_list<bool> ilist) { |
| 19 | for (auto c : ilist) { |
| 20 | if (c) |
| 21 | return true; |
| 22 | } |
| 23 | return false; |
| 24 | } |
fdoray | 879b2fc | 2017-05-01 21:34:11 | [diff] [blame] | 25 | |
Etienne Pierre-doray | 88396607 | 2018-10-03 20:19:56 | [diff] [blame] | 26 | // Checks if all of the elements in |ilist| are true. |
| 27 | // Similar to std::any_of for the case of constexpr initializer_list. |
| 28 | inline constexpr bool all_of(std::initializer_list<bool> ilist) { |
| 29 | for (auto c : ilist) { |
| 30 | if (!c) |
| 31 | return false; |
| 32 | } |
| 33 | return true; |
| 34 | } |
fdoray | 879b2fc | 2017-05-01 21:34:11 | [diff] [blame] | 35 | |
Etienne Pierre-doray | 88396607 | 2018-10-03 20:19:56 | [diff] [blame] | 36 | // Counts the elements in |ilist| that are equal to |value|. |
| 37 | // Similar to std::count for the case of constexpr initializer_list. |
| 38 | template <class T> |
| 39 | inline constexpr size_t count(std::initializer_list<T> ilist, T value) { |
| 40 | size_t c = 0; |
| 41 | for (const auto& v : ilist) { |
| 42 | c += (v == value); |
| 43 | } |
| 44 | return c; |
| 45 | } |
| 46 | |
| 47 | // CallFirstTag is an argument tag that helps to avoid ambiguous overloaded |
| 48 | // functions. When the following call is made: |
| 49 | // func(CallFirstTag(), arg...); |
| 50 | // the compiler will give precedence to an overload candidate that directly |
| 51 | // takes CallFirstTag. Another overload that takes CallSecondTag will be |
| 52 | // considered iff the preferred overload candidates were all invalids and |
| 53 | // therefore discarded. |
fdoray | 879b2fc | 2017-05-01 21:34:11 | [diff] [blame] | 54 | struct CallSecondTag {}; |
| 55 | struct CallFirstTag : CallSecondTag {}; |
| 56 | |
Etienne Pierre-doray | 88396607 | 2018-10-03 20:19:56 | [diff] [blame] | 57 | // A trait filter class |TraitFilterType| implements the protocol to get a value |
| 58 | // of type |ArgType| from an argument list and convert it to a value of type |
| 59 | // |TraitType|. If the argument list contains an argument of type |ArgType|, the |
| 60 | // filter class will be instantiated with that argument. If the argument list |
| 61 | // contains no argument of type |ArgType|, the filter class will be instantiated |
| 62 | // using the default constructor if available; a compile error is issued |
| 63 | // otherwise. The filter class must have the conversion operator TraitType() |
| 64 | // which returns a value of type TraitType. |
| 65 | |
| 66 | // |InvalidTrait| is used to return from GetTraitFromArg when the argument is |
| 67 | // not compatible with the desired trait. |
| 68 | struct InvalidTrait {}; |
| 69 | |
| 70 | // Returns an object of type |TraitFilterType| constructed from |arg| if |
| 71 | // compatible, or |InvalidTrait| otherwise. |
| 72 | template <class TraitFilterType, |
| 73 | class ArgType, |
| 74 | class CheckArgumentIsCompatible = std::enable_if_t< |
| 75 | std::is_constructible<TraitFilterType, ArgType>::value>> |
| 76 | constexpr TraitFilterType GetTraitFromArg(CallFirstTag, ArgType arg) { |
| 77 | return TraitFilterType(arg); |
fdoray | 879b2fc | 2017-05-01 21:34:11 | [diff] [blame] | 78 | } |
| 79 | |
Etienne Pierre-doray | 88396607 | 2018-10-03 20:19:56 | [diff] [blame] | 80 | template <class TraitFilterType, class ArgType> |
| 81 | constexpr InvalidTrait GetTraitFromArg(CallSecondTag, ArgType arg) { |
| 82 | return InvalidTrait(); |
| 83 | } |
| 84 | |
| 85 | // Returns an object of type |TraitFilterType| constructed from a compatible |
| 86 | // argument in |args...|, or default constructed if none of the arguments are |
| 87 | // compatible. This is the implementation of GetTraitFromArgList() with a |
| 88 | // disambiguation tag. |
| 89 | template <class TraitFilterType, |
fdoray | 879b2fc | 2017-05-01 21:34:11 | [diff] [blame] | 90 | class... ArgTypes, |
Etienne Pierre-doray | 88396607 | 2018-10-03 20:19:56 | [diff] [blame] | 91 | class TestCompatibleArgument = std::enable_if_t<any_of( |
| 92 | {std::is_constructible<TraitFilterType, ArgTypes>::value...})>> |
| 93 | constexpr TraitFilterType GetTraitFromArgListImpl(CallFirstTag, |
| 94 | ArgTypes... args) { |
| 95 | return std::get<TraitFilterType>(std::make_tuple( |
| 96 | GetTraitFromArg<TraitFilterType>(CallFirstTag(), args)...)); |
fdoray | 879b2fc | 2017-05-01 21:34:11 | [diff] [blame] | 97 | } |
| 98 | |
Etienne Pierre-doray | 88396607 | 2018-10-03 20:19:56 | [diff] [blame] | 99 | template <class TraitFilterType, class... ArgTypes> |
| 100 | constexpr TraitFilterType GetTraitFromArgListImpl(CallSecondTag, |
| 101 | ArgTypes... args) { |
| 102 | static_assert(std::is_constructible<TraitFilterType>::value, |
| 103 | "TaskTraits contains a Trait that must be explicity " |
| 104 | "initialized in its constructor."); |
| 105 | return TraitFilterType(); |
fdoray | 879b2fc | 2017-05-01 21:34:11 | [diff] [blame] | 106 | } |
| 107 | |
Etienne Pierre-doray | 88396607 | 2018-10-03 20:19:56 | [diff] [blame] | 108 | // Constructs an object of type |TraitFilterType| from a compatible argument in |
| 109 | // |args...|, or using the default constructor, and returns its associated trait |
| 110 | // value using conversion to |TraitFilterType::ValueType|. If there are more |
| 111 | // than one compatible argument in |args|, generates a compile-time error. |
| 112 | template <class TraitFilterType, class... ArgTypes> |
| 113 | constexpr typename TraitFilterType::ValueType GetTraitFromArgList( |
| 114 | ArgTypes... args) { |
| 115 | static_assert( |
| 116 | count({std::is_constructible<TraitFilterType, ArgTypes>::value...}, |
| 117 | true) <= 1, |
| 118 | "Multiple arguments of the same type were provided to the " |
| 119 | "constructor of TaskTraits."); |
| 120 | return GetTraitFromArgListImpl<TraitFilterType>(CallFirstTag(), args...); |
fdoray | 879b2fc | 2017-05-01 21:34:11 | [diff] [blame] | 121 | } |
| 122 | |
Etienne Pierre-doray | 88396607 | 2018-10-03 20:19:56 | [diff] [blame] | 123 | // Returns true if this trait is explicitly defined in an argument list, i.e. |
| 124 | // there is an argument compatible with this trait in |args...|. |
| 125 | template <class TraitFilterType, class... ArgTypes> |
| 126 | constexpr bool TraitIsDefined(ArgTypes... args) { |
| 127 | return any_of({std::is_constructible<TraitFilterType, ArgTypes>::value...}); |
| 128 | } |
| 129 | |
| 130 | // Helper class to implemnent a |TraitFilterType|. |
| 131 | template <typename T> |
| 132 | struct BasicTraitFilter { |
| 133 | using ValueType = T; |
| 134 | |
| 135 | constexpr operator ValueType() const { return value; } |
| 136 | |
| 137 | ValueType value = {}; |
| 138 | }; |
| 139 | |
fdoray | 879b2fc | 2017-05-01 21:34:11 | [diff] [blame] | 140 | template <typename ArgType> |
Etienne Pierre-doray | 88396607 | 2018-10-03 20:19:56 | [diff] [blame] | 141 | struct BooleanTraitFilter : public BasicTraitFilter<bool> { |
| 142 | constexpr BooleanTraitFilter() { this->value = false; } |
| 143 | constexpr BooleanTraitFilter(ArgType) { this->value = true; } |
fdoray | 879b2fc | 2017-05-01 21:34:11 | [diff] [blame] | 144 | }; |
| 145 | |
| 146 | template <typename ArgType, ArgType DefaultValue> |
Etienne Pierre-doray | 88396607 | 2018-10-03 20:19:56 | [diff] [blame] | 147 | struct EnumTraitFilter : public BasicTraitFilter<ArgType> { |
| 148 | constexpr EnumTraitFilter() { this->value = DefaultValue; } |
| 149 | constexpr EnumTraitFilter(ArgType arg) { this->value = arg; } |
fdoray | 879b2fc | 2017-05-01 21:34:11 | [diff] [blame] | 150 | }; |
| 151 | |
Etienne Pierre-doray | 88396607 | 2018-10-03 20:19:56 | [diff] [blame] | 152 | // Tests whether multiple given argtument types are all valid traits according |
| 153 | // to the provided ValidTraits. To use, define a ValidTraits |
Eric Seckler | e329cb9 | 2018-08-28 16:09:40 | [diff] [blame] | 154 | template <typename ArgType> |
Etienne Pierre-doray | 88396607 | 2018-10-03 20:19:56 | [diff] [blame] | 155 | struct RequiredEnumTraitFilter : public BasicTraitFilter<ArgType> { |
| 156 | constexpr RequiredEnumTraitFilter(ArgType arg) { this->value = arg; } |
Eric Seckler | e329cb9 | 2018-08-28 16:09:40 | [diff] [blame] | 157 | }; |
| 158 | |
Eric Seckler | 97f22e8b | 2018-08-16 09:03:05 | [diff] [blame] | 159 | // Tests whether a given trait type is valid or invalid by testing whether it is |
| 160 | // convertible to the provided ValidTraits type. To use, define a ValidTraits |
| 161 | // type like this: |
| 162 | // |
| 163 | // struct ValidTraits { |
Etienne Pierre-doray | 88396607 | 2018-10-03 20:19:56 | [diff] [blame] | 164 | // ValidTraits(MyTrait); |
Eric Seckler | 97f22e8b | 2018-08-16 09:03:05 | [diff] [blame] | 165 | // ... |
| 166 | // }; |
Etienne Pierre-doray | 88396607 | 2018-10-03 20:19:56 | [diff] [blame] | 167 | template <class ValidTraits, class... ArgTypes> |
| 168 | struct AreValidTraits |
| 169 | : std::integral_constant< |
| 170 | bool, |
| 171 | all_of({std::is_convertible<ArgTypes, ValidTraits>::value...})> {}; |
Eric Seckler | 97f22e8b | 2018-08-16 09:03:05 | [diff] [blame] | 172 | |
| 173 | } // namespace trait_helpers |
fdoray | 879b2fc | 2017-05-01 21:34:11 | [diff] [blame] | 174 | } // namespace base |
| 175 | |
Gabriel Charette | 04b138f | 2018-08-06 00:03:22 | [diff] [blame] | 176 | #endif // BASE_TASK_TASK_TRAITS_DETAILS_H_ |