|  | // 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_SCHEDULER_TASK_TRAITS_DETAILS_H_ | 
|  | #define BASE_TASK_SCHEDULER_TASK_TRAITS_DETAILS_H_ | 
|  |  | 
|  | #include <type_traits> | 
|  | #include <utility> | 
|  |  | 
|  | namespace base { | 
|  | namespace internal { | 
|  |  | 
|  | // HasArgOfType<CheckedType, ArgTypes...>::value is true iff a type in ArgTypes | 
|  | // matches CheckedType. | 
|  | template <class...> | 
|  | struct HasArgOfType : std::false_type {}; | 
|  | template <class CheckedType, class FirstArgType, class... ArgTypes> | 
|  | struct HasArgOfType<CheckedType, FirstArgType, ArgTypes...> | 
|  | : std::conditional<std::is_same<CheckedType, FirstArgType>::value, | 
|  | std::true_type, | 
|  | HasArgOfType<CheckedType, ArgTypes...>>::type {}; | 
|  |  | 
|  | // When the following call is made: | 
|  | //    GetValueFromArgListImpl(CallFirstTag(), GetterType(), args...); | 
|  | // If |args| is empty, the compiler selects the first overload. This overload | 
|  | // returns getter.GetDefaultValue(). If |args| is not empty, the compiler | 
|  | // prefers using the second overload because the type of the first argument | 
|  | // matches exactly. This overload returns getter.GetValueFromArg(first_arg), | 
|  | // where |first_arg| is the first element in |args|. If | 
|  | // getter.GetValueFromArg(first_arg) isn't defined, the compiler uses the third | 
|  | // overload instead. This overload discards the first argument in |args| and | 
|  | // makes a recursive call to GetValueFromArgListImpl() with CallFirstTag() as | 
|  | // first argument. | 
|  |  | 
|  | // Tag dispatching. | 
|  | struct CallSecondTag {}; | 
|  | struct CallFirstTag : CallSecondTag {}; | 
|  |  | 
|  | // Overload 1: Default value. | 
|  | template <class GetterType> | 
|  | constexpr typename GetterType::ValueType GetValueFromArgListImpl( | 
|  | CallFirstTag, | 
|  | GetterType getter) { | 
|  | return getter.GetDefaultValue(); | 
|  | } | 
|  |  | 
|  | // Overload 2: Get value from first argument. Check that no argument in |args| | 
|  | // has the same type as |first_arg|. | 
|  | template <class GetterType, | 
|  | class FirstArgType, | 
|  | class... ArgTypes, | 
|  | class TestGetValueFromArgDefined = | 
|  | decltype(std::declval<GetterType>().GetValueFromArg( | 
|  | std::declval<FirstArgType>()))> | 
|  | constexpr typename GetterType::ValueType GetValueFromArgListImpl( | 
|  | CallFirstTag, | 
|  | GetterType getter, | 
|  | const FirstArgType& first_arg, | 
|  | const ArgTypes&... args) { | 
|  | static_assert(!HasArgOfType<FirstArgType, ArgTypes...>::value, | 
|  | "Multiple arguments of the same type were provided to the " | 
|  | "constructor of TaskTraits."); | 
|  | return getter.GetValueFromArg(first_arg); | 
|  | } | 
|  |  | 
|  | // Overload 3: Discard first argument. | 
|  | template <class GetterType, class FirstArgType, class... ArgTypes> | 
|  | constexpr typename GetterType::ValueType GetValueFromArgListImpl( | 
|  | CallSecondTag, | 
|  | GetterType getter, | 
|  | const FirstArgType&, | 
|  | const ArgTypes&... args) { | 
|  | return GetValueFromArgListImpl(CallFirstTag(), getter, args...); | 
|  | } | 
|  |  | 
|  | // If there is an argument |arg_of_type| of type Getter::ArgType in |args|, | 
|  | // returns getter.GetValueFromArg(arg_of_type). If there are more than one | 
|  | // argument of type Getter::ArgType in |args|, generates a compile-time error. | 
|  | // Otherwise, returns getter.GetDefaultValue(). | 
|  | // | 
|  | // |getter| must provide: | 
|  | // | 
|  | // ValueType: | 
|  | //     The return type of GetValueFromArgListImpl(). | 
|  | // | 
|  | // ArgType: | 
|  | //     The type of the argument from which GetValueFromArgListImpl() derives its | 
|  | //     return value. | 
|  | // | 
|  | // ValueType GetValueFromArg(ArgType): | 
|  | //     Converts an argument of type ArgType into a value returned by | 
|  | //     GetValueFromArgListImpl(). | 
|  | // | 
|  | // ValueType GetDefaultValue(): | 
|  | //     Returns the value returned by GetValueFromArgListImpl() if none of its | 
|  | //     arguments is of type ArgType. | 
|  | template <class GetterType, class... ArgTypes> | 
|  | constexpr typename GetterType::ValueType GetValueFromArgList( | 
|  | GetterType getter, | 
|  | const ArgTypes&... args) { | 
|  | return GetValueFromArgListImpl(CallFirstTag(), getter, args...); | 
|  | } | 
|  |  | 
|  | template <typename ArgType> | 
|  | struct BooleanArgGetter { | 
|  | using ValueType = bool; | 
|  | constexpr ValueType GetValueFromArg(ArgType) const { return true; } | 
|  | constexpr ValueType GetDefaultValue() const { return false; } | 
|  | }; | 
|  |  | 
|  | template <typename ArgType, ArgType DefaultValue> | 
|  | struct EnumArgGetter { | 
|  | using ValueType = ArgType; | 
|  | constexpr ValueType GetValueFromArg(ArgType arg) const { return arg; } | 
|  | constexpr ValueType GetDefaultValue() const { return DefaultValue; } | 
|  | }; | 
|  |  | 
|  | // Allows instantiation of multiple types in one statement. Used to prevent | 
|  | // instantiation of the constructor of TaskTraits with inappropriate argument | 
|  | // types. | 
|  | template <class...> | 
|  | struct InitTypes {}; | 
|  |  | 
|  | }  // namespace internal | 
|  | }  // namespace base | 
|  |  | 
|  | #endif  // BASE_TASK_SCHEDULER_TASK_TRAITS_DETAILS_H_ |