Home | History | Annotate | Download | only in task_scheduler
      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 
      5 #ifndef BASE_TASK_SCHEDULER_TASK_TRAITS_DETAILS_H_
      6 #define BASE_TASK_SCHEDULER_TASK_TRAITS_DETAILS_H_
      7 
      8 #include <type_traits>
      9 #include <utility>
     10 
     11 namespace base {
     12 namespace internal {
     13 
     14 // HasArgOfType<CheckedType, ArgTypes...>::value is true iff a type in ArgTypes
     15 // matches CheckedType.
     16 template <class...>
     17 struct HasArgOfType : std::false_type {};
     18 template <class CheckedType, class FirstArgType, class... ArgTypes>
     19 struct HasArgOfType<CheckedType, FirstArgType, ArgTypes...>
     20     : std::conditional<std::is_same<CheckedType, FirstArgType>::value,
     21                        std::true_type,
     22                        HasArgOfType<CheckedType, ArgTypes...>>::type {};
     23 
     24 // When the following call is made:
     25 //    GetValueFromArgListImpl(CallFirstTag(), GetterType(), args...);
     26 // If |args| is empty, the compiler selects the first overload. This overload
     27 // returns getter.GetDefaultValue(). If |args| is not empty, the compiler
     28 // prefers using the second overload because the type of the first argument
     29 // matches exactly. This overload returns getter.GetValueFromArg(first_arg),
     30 // where |first_arg| is the first element in |args|. If
     31 // getter.GetValueFromArg(first_arg) isn't defined, the compiler uses the third
     32 // overload instead. This overload discards the first argument in |args| and
     33 // makes a recursive call to GetValueFromArgListImpl() with CallFirstTag() as
     34 // first argument.
     35 
     36 // Tag dispatching.
     37 struct CallSecondTag {};
     38 struct CallFirstTag : CallSecondTag {};
     39 
     40 // Overload 1: Default value.
     41 template <class GetterType>
     42 constexpr typename GetterType::ValueType GetValueFromArgListImpl(
     43     CallFirstTag,
     44     GetterType getter) {
     45   return getter.GetDefaultValue();
     46 }
     47 
     48 // Overload 2: Get value from first argument. Check that no argument in |args|
     49 // has the same type as |first_arg|.
     50 template <class GetterType,
     51           class FirstArgType,
     52           class... ArgTypes,
     53           class TestGetValueFromArgDefined =
     54               decltype(std::declval<GetterType>().GetValueFromArg(
     55                   std::declval<FirstArgType>()))>
     56 constexpr typename GetterType::ValueType GetValueFromArgListImpl(
     57     CallFirstTag,
     58     GetterType getter,
     59     const FirstArgType& first_arg,
     60     const ArgTypes&... args) {
     61   static_assert(!HasArgOfType<FirstArgType, ArgTypes...>::value,
     62                 "Multiple arguments of the same type were provided to the "
     63                 "constructor of TaskTraits.");
     64   return getter.GetValueFromArg(first_arg);
     65 }
     66 
     67 // Overload 3: Discard first argument.
     68 template <class GetterType, class FirstArgType, class... ArgTypes>
     69 constexpr typename GetterType::ValueType GetValueFromArgListImpl(
     70     CallSecondTag,
     71     GetterType getter,
     72     const FirstArgType&,
     73     const ArgTypes&... args) {
     74   return GetValueFromArgListImpl(CallFirstTag(), getter, args...);
     75 }
     76 
     77 // If there is an argument |arg_of_type| of type Getter::ArgType in |args|,
     78 // returns getter.GetValueFromArg(arg_of_type). If there are more than one
     79 // argument of type Getter::ArgType in |args|, generates a compile-time error.
     80 // Otherwise, returns getter.GetDefaultValue().
     81 //
     82 // |getter| must provide:
     83 //
     84 // ValueType:
     85 //     The return type of GetValueFromArgListImpl().
     86 //
     87 // ArgType:
     88 //     The type of the argument from which GetValueFromArgListImpl() derives its
     89 //     return value.
     90 //
     91 // ValueType GetValueFromArg(ArgType):
     92 //     Converts an argument of type ArgType into a value returned by
     93 //     GetValueFromArgListImpl().
     94 //
     95 // ValueType GetDefaultValue():
     96 //     Returns the value returned by GetValueFromArgListImpl() if none of its
     97 //     arguments is of type ArgType.
     98 template <class GetterType, class... ArgTypes>
     99 constexpr typename GetterType::ValueType GetValueFromArgList(
    100     GetterType getter,
    101     const ArgTypes&... args) {
    102   return GetValueFromArgListImpl(CallFirstTag(), getter, args...);
    103 }
    104 
    105 template <typename ArgType>
    106 struct BooleanArgGetter {
    107   using ValueType = bool;
    108   constexpr ValueType GetValueFromArg(ArgType) const { return true; }
    109   constexpr ValueType GetDefaultValue() const { return false; }
    110 };
    111 
    112 template <typename ArgType, ArgType DefaultValue>
    113 struct EnumArgGetter {
    114   using ValueType = ArgType;
    115   constexpr ValueType GetValueFromArg(ArgType arg) const { return arg; }
    116   constexpr ValueType GetDefaultValue() const { return DefaultValue; }
    117 };
    118 
    119 // Allows instantiation of multiple types in one statement. Used to prevent
    120 // instantiation of the constructor of TaskTraits with inappropriate argument
    121 // types.
    122 template <class...>
    123 struct InitTypes {};
    124 
    125 }  // namespace internal
    126 }  // namespace base
    127 
    128 #endif  // BASE_TASK_SCHEDULER_TASK_TRAITS_DETAILS_H_
    129