• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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