[M85 Dev][EFL] Fix crashes at webview launch
[platform/framework/web/chromium-efl.git] / base / traits_bag.h
1 // Copyright 2018 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_TRAITS_BAG_H_
6 #define BASE_TRAITS_BAG_H_
7
8 #include <initializer_list>
9 #include <tuple>
10 #include <type_traits>
11 #include <utility>
12
13 #include "base/optional.h"
14 #include "base/parameter_pack.h"
15 #include "base/template_util.h"
16
17 // A bag of Traits (structs / enums / etc...) can be an elegant alternative to
18 // the builder pattern and multiple default arguments for configuring things.
19 // Traits are terser than the builder pattern and can be evaluated at compile
20 // time, however they require the use of variadic templates which complicates
21 // matters. This file contains helpers that make Traits easier to use.
22 //
23 // WARNING: Trait bags are currently too heavy for non-constexpr usage in prod
24 // code due to template bloat, although adding NOINLINE to template constructors
25 // configured via trait bags can help.
26 //
27 // E.g.
28 //   struct EnableFeatureX {};
29 //   struct UnusedTrait {};
30 //   enum Color { RED, BLUE };
31 //
32 //   struct ValidTraits {
33 //      ValidTraits(EnableFeatureX);
34 //      ValidTraits(Color);
35 //   };
36 //   ...
37 //   DoSomethingAwesome();                 // Use defaults (Color::BLUE &
38 //                                         // feature X not enabled)
39 //   DoSomethingAwesome(EnableFeatureX(),  // Turn feature X on
40 //                      Color::RED);       // And make it red.
41 //   DoSomethingAwesome(UnusedTrait(),     // Compile time error.
42 //                      Color::RED);
43 //
44 // DoSomethingAwesome might be defined as:
45 //
46 //   template <class... ArgTypes,
47 //             class CheckArgumentsAreValid = std::enable_if_t<
48 //                 trait_helpers::AreValidTraits<ValidTraits,
49 //                                               ArgTypes...>::value>>
50 //   constexpr void DoSomethingAwesome(ArgTypes... args)
51 //      : enable_feature_x(
52 //            trait_helpers::HasTrait<EnableFeatureX, ArgTypes...>()),
53 //        color(trait_helpers::GetEnum<Color, EnumTraitA::BLUE>(args...)) {}
54
55 namespace base {
56 namespace trait_helpers {
57
58 // Represents a trait that has been removed by a predicate.
59 struct EmptyTrait {};
60
61 // Predicate used to remove any traits from the given list of types by
62 // converting them to EmptyTrait. E.g.
63 //
64 // template <typename... Args>
65 // void MyFunc(Args... args) {
66 //   DoSomethingWithTraits(
67 //       base::trait_helpers::Exclude<UnwantedTrait1,
68 //                                    UnwantedTrait2>::Filter(args)...);
69 // }
70 //
71 // NB It's possible to actually remove the unwanted trait from the pack, but
72 // that requires constructing a filtered tuple and applying it to the function,
73 // which isn't worth the complexity over ignoring EmptyTrait.
74 template <typename... TraitsToExclude>
75 struct Exclude {
76   template <typename T,
77             std::enable_if_t<ParameterPack<
78                 TraitsToExclude...>::template HasType<T>::value>* = nullptr>
79   static constexpr EmptyTrait Filter(T t) {
80     return EmptyTrait();
81   }
82
83   template <typename T,
84             std::enable_if_t<!ParameterPack<
85                 TraitsToExclude...>::template HasType<T>::value>* = nullptr>
86   static constexpr T Filter(T t) {
87     return t;
88   }
89 };
90
91 // CallFirstTag is an argument tag that helps to avoid ambiguous overloaded
92 // functions. When the following call is made:
93 //    func(CallFirstTag(), arg...);
94 // the compiler will give precedence to an overload candidate that directly
95 // takes CallFirstTag. Another overload that takes CallSecondTag will be
96 // considered iff the preferred overload candidates were all invalids and
97 // therefore discarded.
98 struct CallSecondTag {};
99 struct CallFirstTag : CallSecondTag {};
100
101 // A trait filter class |TraitFilterType| implements the protocol to get a value
102 // of type |ArgType| from an argument list and convert it to a value of type
103 // |TraitType|. If the argument list contains an argument of type |ArgType|, the
104 // filter class will be instantiated with that argument. If the argument list
105 // contains no argument of type |ArgType|, the filter class will be instantiated
106 // using the default constructor if available; a compile error is issued
107 // otherwise. The filter class must have the conversion operator TraitType()
108 // which returns a value of type TraitType.
109
110 // |InvalidTrait| is used to return from GetTraitFromArg when the argument is
111 // not compatible with the desired trait.
112 struct InvalidTrait {};
113
114 // Returns an object of type |TraitFilterType| constructed from |arg| if
115 // compatible, or |InvalidTrait| otherwise.
116 template <class TraitFilterType,
117           class ArgType,
118           class CheckArgumentIsCompatible = std::enable_if_t<
119               std::is_constructible<TraitFilterType, ArgType>::value>>
120 constexpr TraitFilterType GetTraitFromArg(CallFirstTag, ArgType arg) {
121   return TraitFilterType(arg);
122 }
123
124 template <class TraitFilterType, class ArgType>
125 constexpr InvalidTrait GetTraitFromArg(CallSecondTag, ArgType arg) {
126   return InvalidTrait();
127 }
128
129 // Returns an object of type |TraitFilterType| constructed from a compatible
130 // argument in |args...|, or default constructed if none of the arguments are
131 // compatible. This is the implementation of GetTraitFromArgList() with a
132 // disambiguation tag.
133 template <class TraitFilterType,
134           class... ArgTypes,
135           class TestCompatibleArgument = std::enable_if_t<any_of(
136               {std::is_constructible<TraitFilterType, ArgTypes>::value...})>>
137 constexpr TraitFilterType GetTraitFromArgListImpl(CallFirstTag,
138                                                   ArgTypes... args) {
139   return std::get<TraitFilterType>(std::make_tuple(
140       GetTraitFromArg<TraitFilterType>(CallFirstTag(), args)...));
141 }
142
143 template <class TraitFilterType, class... ArgTypes>
144 constexpr TraitFilterType GetTraitFromArgListImpl(CallSecondTag,
145                                                   ArgTypes... args) {
146   static_assert(std::is_constructible<TraitFilterType>::value,
147                 "The traits bag is missing a required trait.");
148   return TraitFilterType();
149 }
150
151 // Constructs an object of type |TraitFilterType| from a compatible argument in
152 // |args...|, or using the default constructor, and returns its associated trait
153 // value using conversion to |TraitFilterType::ValueType|. If there are more
154 // than one compatible argument in |args|, generates a compile-time error.
155 template <class TraitFilterType, class... ArgTypes>
156 constexpr typename TraitFilterType::ValueType GetTraitFromArgList(
157     ArgTypes... args) {
158   static_assert(
159       count({std::is_constructible<TraitFilterType, ArgTypes>::value...},
160             true) <= 1,
161       "The traits bag contains multiple traits of the same type.");
162   return GetTraitFromArgListImpl<TraitFilterType>(CallFirstTag(), args...);
163 }
164
165 // Helper class to implemnent a |TraitFilterType|.
166 template <typename T, typename _ValueType = T>
167 struct BasicTraitFilter {
168   using ValueType = _ValueType;
169
170   constexpr BasicTraitFilter(ValueType v) : value(v) {}
171
172   constexpr operator ValueType() const { return value; }
173
174   ValueType value = {};
175 };
176
177 template <typename ArgType, ArgType DefaultValue>
178 struct EnumTraitFilter : public BasicTraitFilter<ArgType> {
179   constexpr EnumTraitFilter() : BasicTraitFilter<ArgType>(DefaultValue) {}
180   constexpr EnumTraitFilter(ArgType arg) : BasicTraitFilter<ArgType>(arg) {}
181 };
182
183 template <typename ArgType>
184 struct OptionalEnumTraitFilter
185     : public BasicTraitFilter<ArgType, Optional<ArgType>> {
186   constexpr OptionalEnumTraitFilter()
187       : BasicTraitFilter<ArgType, Optional<ArgType>>(nullopt) {}
188   constexpr OptionalEnumTraitFilter(ArgType arg)
189       : BasicTraitFilter<ArgType, Optional<ArgType>>(arg) {}
190 };
191
192 // Tests whether multiple given argtument types are all valid traits according
193 // to the provided ValidTraits. To use, define a ValidTraits
194 template <typename ArgType>
195 struct RequiredEnumTraitFilter : public BasicTraitFilter<ArgType> {
196   constexpr RequiredEnumTraitFilter(ArgType arg)
197       : BasicTraitFilter<ArgType>(arg) {}
198 };
199
200 // Note EmptyTrait is always regarded as valid to support filtering.
201 template <class ValidTraits, class T>
202 using IsValidTrait = disjunction<std::is_constructible<ValidTraits, T>,
203                                  std::is_same<T, EmptyTrait>>;
204
205 // Tests whether a given trait type is valid or invalid by testing whether it is
206 // convertible to the provided ValidTraits type. To use, define a ValidTraits
207 // type like this:
208 //
209 // struct ValidTraits {
210 //   ValidTraits(MyTrait);
211 //   ...
212 // };
213 //
214 // You can 'inherit' valid traits like so:
215 //
216 // struct MoreValidTraits {
217 //   MoreValidTraits(ValidTraits);  // Pull in traits from ValidTraits.
218 //   MoreValidTraits(MyOtherTrait);
219 //   ...
220 // };
221 template <class ValidTraits, class... ArgTypes>
222 using AreValidTraits =
223     bool_constant<all_of({IsValidTrait<ValidTraits, ArgTypes>::value...})>;
224
225 // Helper to make getting an enum from a trait more readable.
226 template <typename Enum, typename... Args>
227 static constexpr Enum GetEnum(Args... args) {
228   return GetTraitFromArgList<RequiredEnumTraitFilter<Enum>>(args...);
229 }
230
231 // Helper to make getting an enum from a trait with a default more readable.
232 template <typename Enum, Enum DefaultValue, typename... Args>
233 static constexpr Enum GetEnum(Args... args) {
234   return GetTraitFromArgList<EnumTraitFilter<Enum, DefaultValue>>(args...);
235 }
236
237 // Helper to make getting an optional enum from a trait with a default more
238 // readable.
239 template <typename Enum, typename... Args>
240 static constexpr Optional<Enum> GetOptionalEnum(Args... args) {
241   return GetTraitFromArgList<OptionalEnumTraitFilter<Enum>>(args...);
242 }
243
244 // Helper to make checking for the presence of a trait more readable.
245 template <typename Trait, typename... Args>
246 struct HasTrait : ParameterPack<Args...>::template HasType<Trait> {
247   static_assert(
248       count({std::is_constructible<Trait, Args>::value...}, true) <= 1,
249       "The traits bag contains multiple traits of the same type.");
250 };
251
252 // If you need a template vararg constructor to delegate to a private
253 // constructor, you may need to add this to the private constructor to ensure
254 // it's not matched by accident.
255 struct NotATraitTag {};
256
257 }  // namespace trait_helpers
258 }  // namespace base
259
260 #endif  // BASE_TRAITS_BAG_H_