blob: f9a9c5d43eb9e3a417ff535a1da1f8c9ba569e72 [file] [log] [blame]
fdoray879b2fc2017-05-01 21:34:111// 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 Charette04b138f2018-08-06 00:03:225#ifndef BASE_TASK_TASK_TRAITS_DETAILS_H_
6#define BASE_TASK_TASK_TRAITS_DETAILS_H_
fdoray879b2fc2017-05-01 21:34:117
Etienne Pierre-doray883966072018-10-03 20:19:568#include <initializer_list>
Eric Seckler97f22e8b2018-08-16 09:03:059#include <tuple>
fdoray879b2fc2017-05-01 21:34:1110#include <type_traits>
11#include <utility>
12
13namespace base {
Eric Seckler97f22e8b2018-08-16 09:03:0514namespace trait_helpers {
fdoray879b2fc2017-05-01 21:34:1115
Etienne Pierre-doray883966072018-10-03 20:19:5616// Checks if any of the elements in |ilist| is true.
17// Similar to std::any_of for the case of constexpr initializer_list.
18inline 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}
fdoray879b2fc2017-05-01 21:34:1125
Etienne Pierre-doray883966072018-10-03 20:19:5626// Checks if all of the elements in |ilist| are true.
27// Similar to std::any_of for the case of constexpr initializer_list.
28inline 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}
fdoray879b2fc2017-05-01 21:34:1135
Etienne Pierre-doray883966072018-10-03 20:19:5636// Counts the elements in |ilist| that are equal to |value|.
37// Similar to std::count for the case of constexpr initializer_list.
38template <class T>
39inline 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.
fdoray879b2fc2017-05-01 21:34:1154struct CallSecondTag {};
55struct CallFirstTag : CallSecondTag {};
56
Etienne Pierre-doray883966072018-10-03 20:19:5657// 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.
68struct InvalidTrait {};
69
70// Returns an object of type |TraitFilterType| constructed from |arg| if
71// compatible, or |InvalidTrait| otherwise.
72template <class TraitFilterType,
73 class ArgType,
74 class CheckArgumentIsCompatible = std::enable_if_t<
75 std::is_constructible<TraitFilterType, ArgType>::value>>
76constexpr TraitFilterType GetTraitFromArg(CallFirstTag, ArgType arg) {
77 return TraitFilterType(arg);
fdoray879b2fc2017-05-01 21:34:1178}
79
Etienne Pierre-doray883966072018-10-03 20:19:5680template <class TraitFilterType, class ArgType>
81constexpr 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.
89template <class TraitFilterType,
fdoray879b2fc2017-05-01 21:34:1190 class... ArgTypes,
Etienne Pierre-doray883966072018-10-03 20:19:5691 class TestCompatibleArgument = std::enable_if_t<any_of(
92 {std::is_constructible<TraitFilterType, ArgTypes>::value...})>>
93constexpr TraitFilterType GetTraitFromArgListImpl(CallFirstTag,
94 ArgTypes... args) {
95 return std::get<TraitFilterType>(std::make_tuple(
96 GetTraitFromArg<TraitFilterType>(CallFirstTag(), args)...));
fdoray879b2fc2017-05-01 21:34:1197}
98
Etienne Pierre-doray883966072018-10-03 20:19:5699template <class TraitFilterType, class... ArgTypes>
100constexpr 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();
fdoray879b2fc2017-05-01 21:34:11106}
107
Etienne Pierre-doray883966072018-10-03 20:19:56108// 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.
112template <class TraitFilterType, class... ArgTypes>
113constexpr 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...);
fdoray879b2fc2017-05-01 21:34:11121}
122
Etienne Pierre-doray883966072018-10-03 20:19:56123// 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...|.
125template <class TraitFilterType, class... ArgTypes>
126constexpr bool TraitIsDefined(ArgTypes... args) {
127 return any_of({std::is_constructible<TraitFilterType, ArgTypes>::value...});
128}
129
130// Helper class to implemnent a |TraitFilterType|.
131template <typename T>
132struct BasicTraitFilter {
133 using ValueType = T;
134
135 constexpr operator ValueType() const { return value; }
136
137 ValueType value = {};
138};
139
fdoray879b2fc2017-05-01 21:34:11140template <typename ArgType>
Etienne Pierre-doray883966072018-10-03 20:19:56141struct BooleanTraitFilter : public BasicTraitFilter<bool> {
142 constexpr BooleanTraitFilter() { this->value = false; }
143 constexpr BooleanTraitFilter(ArgType) { this->value = true; }
fdoray879b2fc2017-05-01 21:34:11144};
145
146template <typename ArgType, ArgType DefaultValue>
Etienne Pierre-doray883966072018-10-03 20:19:56147struct EnumTraitFilter : public BasicTraitFilter<ArgType> {
148 constexpr EnumTraitFilter() { this->value = DefaultValue; }
149 constexpr EnumTraitFilter(ArgType arg) { this->value = arg; }
fdoray879b2fc2017-05-01 21:34:11150};
151
Etienne Pierre-doray883966072018-10-03 20:19:56152// Tests whether multiple given argtument types are all valid traits according
153// to the provided ValidTraits. To use, define a ValidTraits
Eric Secklere329cb92018-08-28 16:09:40154template <typename ArgType>
Etienne Pierre-doray883966072018-10-03 20:19:56155struct RequiredEnumTraitFilter : public BasicTraitFilter<ArgType> {
156 constexpr RequiredEnumTraitFilter(ArgType arg) { this->value = arg; }
Eric Secklere329cb92018-08-28 16:09:40157};
158
Eric Seckler97f22e8b2018-08-16 09:03:05159// 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-doray883966072018-10-03 20:19:56164// ValidTraits(MyTrait);
Eric Seckler97f22e8b2018-08-16 09:03:05165// ...
166// };
Etienne Pierre-doray883966072018-10-03 20:19:56167template <class ValidTraits, class... ArgTypes>
168struct AreValidTraits
169 : std::integral_constant<
170 bool,
171 all_of({std::is_convertible<ArgTypes, ValidTraits>::value...})> {};
Eric Seckler97f22e8b2018-08-16 09:03:05172
173} // namespace trait_helpers
fdoray879b2fc2017-05-01 21:34:11174} // namespace base
175
Gabriel Charette04b138f2018-08-06 00:03:22176#endif // BASE_TASK_TASK_TRAITS_DETAILS_H_