Line | Branch | Exec | Source |
---|---|---|---|
1 | // Copyright Contributors to the OpenVDB Project | ||
2 | // SPDX-License-Identifier: MPL-2.0 | ||
3 | |||
4 | /// @file TypeList.h | ||
5 | /// | ||
6 | /// @brief A TypeList provides a compile time sequence of heterogeneous types | ||
7 | /// which can be accessed, transformed and executed over in various ways. | ||
8 | /// It incorporates a subset of functionality similar to boost::mpl::vector | ||
9 | /// however provides most of its content through using declarations rather | ||
10 | /// than additional typed classes. | ||
11 | |||
12 | #ifndef OPENVDB_TYPELIST_HAS_BEEN_INCLUDED | ||
13 | #define OPENVDB_TYPELIST_HAS_BEEN_INCLUDED | ||
14 | |||
15 | #include "version.h" | ||
16 | |||
17 | #include <tuple> | ||
18 | #include <type_traits> | ||
19 | |||
20 | namespace openvdb { | ||
21 | OPENVDB_USE_VERSION_NAMESPACE | ||
22 | namespace OPENVDB_VERSION_NAME { | ||
23 | |||
24 | /// @cond OPENVDB_DOCS_INTERNAL | ||
25 | |||
26 | template<typename... Ts> struct TypeList; // forward declaration | ||
27 | |||
28 | namespace typelist_internal { | ||
29 | |||
30 | // Implementation details of @c TypeList | ||
31 | |||
32 | /// @brief Dummy struct, used as the return type from invalid or out-of-range | ||
33 | /// @c TypeList queries. | ||
34 | struct NullType {}; | ||
35 | |||
36 | |||
37 | /// @brief Type resolver for index queries | ||
38 | /// @details Defines a type at a given location within a @c TypeList or the | ||
39 | /// @c NullType if the index is out-of-range. The last template | ||
40 | /// parameter is used to determine if the index is in range. | ||
41 | /// @tparam ListT The @c TypeList | ||
42 | /// @tparam Idx The index of the type to get | ||
43 | template<typename ListT, size_t Idx, typename = void> struct TSGetElementImpl; | ||
44 | |||
45 | /// @brief Partial specialization for valid (in range) index queries. | ||
46 | /// @tparam Ts Unpacked types from a @c TypeList | ||
47 | /// @tparam Idx The index of the type to get | ||
48 | template<typename... Ts, size_t Idx> | ||
49 | struct TSGetElementImpl<TypeList<Ts...>, Idx, | ||
50 | typename std::enable_if<(Idx < sizeof...(Ts) && sizeof...(Ts))>::type> { | ||
51 | using type = typename std::tuple_element<Idx, std::tuple<Ts...>>::type; | ||
52 | }; | ||
53 | |||
54 | /// @brief Partial specialization for invalid index queries (i.e. out-of-range | ||
55 | /// indices such as @c TypeList<Int32>::Get<1>). Defines the NullType. | ||
56 | /// @tparam Ts Unpacked types from a @c TypeList | ||
57 | /// @tparam Idx The index of the type to get | ||
58 | template<typename... Ts, size_t Idx> | ||
59 | struct TSGetElementImpl<TypeList<Ts...>, Idx, | ||
60 | typename std::enable_if<!(Idx < sizeof...(Ts) && sizeof...(Ts))>::type> { | ||
61 | using type = NullType; | ||
62 | }; | ||
63 | |||
64 | |||
65 | /// @brief Search for a given type within a @c TypeList. | ||
66 | /// @details If the type is found, a @c bool constant @c Value is set to true | ||
67 | /// and an @c int64_t @c Index points to the location of the type. If | ||
68 | /// multiple versions of the types exist, the value of @c Index is | ||
69 | /// always the location of the first matching type. If the type is not | ||
70 | /// found, @c Value is set to false and @c Index is set to -1. | ||
71 | /// @note This implementation is recursively defined until the type is found | ||
72 | /// or until the end of the list is reached. The last template argument | ||
73 | /// is used as an internal counter to track the current index being | ||
74 | /// evaluated. | ||
75 | /// @tparam ListT The @c TypeList | ||
76 | /// @tparam T The type to find | ||
77 | template <typename ListT, typename T, size_t=0> | ||
78 | struct TSHasTypeImpl; | ||
79 | |||
80 | /// @brief Partial specialization on an empty @c TypeList, instantiated when | ||
81 | /// @c TSHasTypeImpl has been invoked with an empty @c TypeList or when | ||
82 | /// a recursive search reaches the end of a @c TypeList. | ||
83 | /// @tparam T The type to find | ||
84 | /// @tparam Idx Current index | ||
85 | template <typename T, size_t Idx> | ||
86 | struct TSHasTypeImpl<TypeList<>, T, Idx> { | ||
87 | static constexpr bool Value = false; | ||
88 | static constexpr int64_t Index = -1; | ||
89 | }; | ||
90 | |||
91 | /// @brief Partial specialization on a @c TypeList which still contains types, | ||
92 | /// but the current type being evaluated @c U does not match the given | ||
93 | /// type @C T. | ||
94 | /// @tparam U The current type being evaluated within the @c TypeList | ||
95 | /// @tparam T The type to find | ||
96 | /// @tparam Ts Remaining types | ||
97 | /// @tparam Idx Current index | ||
98 | template <typename U, typename T, typename... Ts, size_t Idx> | ||
99 | struct TSHasTypeImpl<TypeList<U, Ts...>, T, Idx> : | ||
100 | TSHasTypeImpl<TypeList<Ts...>, T, Idx+1> {}; | ||
101 | |||
102 | /// @brief Partial specialization on a @c TypeList where @c T matches the | ||
103 | /// current type (i.e. the type has been found). | ||
104 | /// @tparam T The type to find | ||
105 | /// @tparam Ts Remaining types | ||
106 | /// @tparam Idx Current index | ||
107 | template <typename T, typename... Ts, size_t Idx> | ||
108 | struct TSHasTypeImpl<TypeList<T, Ts...>, T, Idx> | ||
109 | { | ||
110 | static constexpr bool Value = true; | ||
111 | static constexpr int64_t Index = static_cast<int64_t>(Idx); | ||
112 | }; | ||
113 | |||
114 | |||
115 | /// @brief Similar to TsAppendImpl but only appends types to a list if the | ||
116 | /// type does not alreay exist in the list. | ||
117 | /// @details Defines a new @c TypeList with non-unique types appended | ||
118 | /// @tparam U Type to append | ||
119 | /// @tparam ListT The @c TypeList to append to | ||
120 | template <typename U, typename ListT, | ||
121 | bool ListContainsType = TSHasTypeImpl<ListT, U>::Value> | ||
122 | struct TSAppendUniqueImpl; | ||
123 | |||
124 | /// @brief Partial specialization where the currently evaluating type @c U in | ||
125 | /// a @c TypeList already exists in the list. Returns the unmodified list. | ||
126 | /// @tparam U Type to append | ||
127 | /// @tparam Ts Other types within the @c TypeList | ||
128 | template <typename U, typename... Ts> | ||
129 | struct TSAppendUniqueImpl<U, TypeList<Ts...>, true> { | ||
130 | private: | ||
131 | using RemovedU = typename TypeList<Ts...>::template Remove<U>; | ||
132 | public: | ||
133 | /// @note It's simpler to remove the current type U and append the rest by | ||
134 | /// just having "using type = TypeList<Ts...>". However this ends up with | ||
135 | /// with keeping the last seen type rather than the first which this | ||
136 | /// method historically did. e.g: | ||
137 | /// TypeList<float, int, float>::Unique<> can become: | ||
138 | /// a) TypeList<float, int> currently | ||
139 | /// b) TypeList<int, float> if we used the afformentioned technique | ||
140 | /// Might be useful to have both? Complexity in (a) is currently linear so | ||
141 | /// this shouldn't be a problem, but be careful this doesn't change. | ||
142 | //using type = TypeList<Ts...>; | ||
143 | using type = typename TypeList<U>::template Append<RemovedU>; | ||
144 | }; | ||
145 | |||
146 | /// @brief Partial specialization where the currently evaluating type @c U in | ||
147 | /// a @c TypeList does not exists in the list. Returns the appended list. | ||
148 | /// @tparam U Type to append | ||
149 | /// @tparam Ts Other types within the @c TypeList | ||
150 | template <typename U, typename... Ts> | ||
151 | struct TSAppendUniqueImpl<U, TypeList<Ts...>, false> { | ||
152 | using type = TypeList<U, Ts...>; | ||
153 | }; | ||
154 | |||
155 | /// @brief Reconstruct a @c TypeList containing only unique types. | ||
156 | /// @details This implementation effectively rebuilds a @c TypeList by | ||
157 | /// starting with an empty @c TypeList and recursively defining an expanded | ||
158 | /// @c TypeList for every type (first to last), only if the type does not | ||
159 | /// already exist in the new @c TypeList. This has the effect of dropping all | ||
160 | /// but the first of duplicate types. | ||
161 | /// @warning This implementation previously used an embdedded std::conditional | ||
162 | /// which resulted in drastically slow compilation times. If you're changing | ||
163 | /// this implementation make sure to profile compile times with larger lists. | ||
164 | /// @tparam Ts Types within the @c TypeList | ||
165 | template <typename... Ts> | ||
166 | struct TSRecurseAppendUniqueImpl; | ||
167 | |||
168 | /// @brief Terminate type recursion when the end of a @c TypeList is reached. | ||
169 | template <> | ||
170 | struct TSRecurseAppendUniqueImpl<> { | ||
171 | using type = TypeList<>; | ||
172 | }; | ||
173 | |||
174 | /// @brief Merge and unpack an initial @c TypeList from the first argument if | ||
175 | /// such a @c TypeList has been provided. | ||
176 | /// @tparam Ts Types within the first @c TypeList | ||
177 | /// @tparam OtherTs Other types | ||
178 | template <typename... Ts, typename... OtherTs> | ||
179 | struct TSRecurseAppendUniqueImpl<TypeList<Ts...>, OtherTs...> { | ||
180 | using type = typename TSRecurseAppendUniqueImpl<OtherTs..., Ts...>::type; | ||
181 | }; | ||
182 | |||
183 | /// @brief Recursively call TSRecurseAppendUniqueImpl with each type in the | ||
184 | /// provided @c TypeLists, rebuilding a new list with only the unique set | ||
185 | /// of types. | ||
186 | /// @tparam U Next type to check for uniqueness and append | ||
187 | /// @tparam Ts Remaining types within the @c TypeList | ||
188 | template <typename U, typename... Ts> | ||
189 | struct TSRecurseAppendUniqueImpl<U, Ts...> | ||
190 | { | ||
191 | using type = typename TSAppendUniqueImpl<U, | ||
192 | typename TSRecurseAppendUniqueImpl<Ts...>::type | ||
193 | >::type; | ||
194 | }; | ||
195 | |||
196 | |||
197 | /// @brief Append any number of types to a @c TypeList | ||
198 | /// @details Defines a new @c TypeList with the provided types appended | ||
199 | /// @tparam ListT The @c TypeList to append to | ||
200 | /// @tparam Ts Types to append | ||
201 | template<typename ListT, typename... Ts> struct TSAppendImpl; | ||
202 | |||
203 | /// @brief Partial specialization for a @c TypeList with a list of zero or more | ||
204 | /// types to append | ||
205 | /// @tparam Ts Current types within the @c TypeList | ||
206 | /// @tparam OtherTs Other types to append | ||
207 | template<typename... Ts, typename... OtherTs> | ||
208 | struct TSAppendImpl<TypeList<Ts...>, OtherTs...> { | ||
209 | using type = TypeList<Ts..., OtherTs...>; | ||
210 | }; | ||
211 | |||
212 | /// @brief Partial specialization for a @c TypeList with another @c TypeList. | ||
213 | /// Appends the other TypeList's members. | ||
214 | /// @tparam Ts Types within the first @c TypeList | ||
215 | /// @tparam OtherTs Types within the second @c TypeList | ||
216 | template<typename... Ts, typename... OtherTs> | ||
217 | struct TSAppendImpl<TypeList<Ts...>, TypeList<OtherTs...>> { | ||
218 | using type = TypeList<Ts..., OtherTs...>; | ||
219 | }; | ||
220 | |||
221 | |||
222 | /// @brief Remove all occurrences of type T from a @c TypeList | ||
223 | /// @details Defines a new @c TypeList with the provided types removed | ||
224 | /// @tparam ListT The @c TypeList | ||
225 | /// @tparam T Type to remove | ||
226 | template<typename ListT, typename T> struct TSEraseImpl; | ||
227 | |||
228 | /// @brief Partial specialization for an empty @c TypeList | ||
229 | /// @tparam T Type to remove, has no effect | ||
230 | template<typename T> | ||
231 | struct TSEraseImpl<TypeList<>, T> { using type = TypeList<>; }; | ||
232 | |||
233 | /// @brief Partial specialization where the currently evaluating type in a | ||
234 | /// @c TypeList matches the type to remove. Recursively defines this | ||
235 | /// implementation with the remaining types. | ||
236 | /// @tparam Ts Unpacked types within the @c TypeList | ||
237 | /// @tparam T Type to remove | ||
238 | template<typename... Ts, typename T> | ||
239 | struct TSEraseImpl<TypeList<T, Ts...>, T> { | ||
240 | using type = typename TSEraseImpl<TypeList<Ts...>, T>::type; | ||
241 | }; | ||
242 | |||
243 | /// @brief Partial specialization where the currently evaluating type @c T2 in | ||
244 | /// a @c TypeList does not match the type to remove @c T. Recursively | ||
245 | /// defines this implementation with the remaining types. | ||
246 | /// @tparam T2 Current type within the @c TypeList, which does not match @c T | ||
247 | /// @tparam Ts Other types within the @c TypeList | ||
248 | /// @tparam T Type to remove | ||
249 | template<typename T2, typename... Ts, typename T> | ||
250 | struct TSEraseImpl<TypeList<T2, Ts...>, T> { | ||
251 | using type = typename TSAppendImpl<TypeList<T2>, | ||
252 | typename TSEraseImpl<TypeList<Ts...>, T>::type>::type; | ||
253 | }; | ||
254 | |||
255 | /// @brief Front end implementation to call TSEraseImpl which removes all | ||
256 | /// occurrences of a type from a @c TypeList. This struct handles the | ||
257 | /// case where the type to remove is another @c TypeList, in which case | ||
258 | /// all types in the second @c TypeList are removed from the first. | ||
259 | /// @tparam ListT The @c TypeList | ||
260 | /// @tparam Ts Types in the @c TypeList | ||
261 | template<typename ListT, typename... Ts> struct TSRemoveImpl; | ||
262 | |||
263 | /// @brief Partial specialization when there are no types in the @c TypeList. | ||
264 | /// @tparam ListT The @c TypeList | ||
265 | template<typename ListT> | ||
266 | struct TSRemoveImpl<ListT> { using type = ListT; }; | ||
267 | |||
268 | /// @brief Partial specialization when the type to remove @c T is not another | ||
269 | /// @c TypeList. @c T is removed from the @c TypeList. | ||
270 | /// @tparam ListT The @c TypeList | ||
271 | /// @tparam T Type to remove | ||
272 | /// @tparam Ts Types in the @c TypeList | ||
273 | template<typename ListT, typename T, typename... Ts> | ||
274 | struct TSRemoveImpl<ListT, T, Ts...> { | ||
275 | using type = typename TSRemoveImpl<typename TSEraseImpl<ListT, T>::type, Ts...>::type; | ||
276 | }; | ||
277 | |||
278 | /// @brief Partial specialization when the type to remove is another | ||
279 | /// @c TypeList. All types within the other type list are removed from | ||
280 | /// the first list. | ||
281 | /// @tparam ListT The @c TypeList | ||
282 | /// @tparam Ts Types from the second @c TypeList to remove from the first | ||
283 | template<typename ListT, typename... Ts> | ||
284 | struct TSRemoveImpl<ListT, TypeList<Ts...>> { | ||
285 | using type = typename TSRemoveImpl<ListT, Ts...>::type; | ||
286 | }; | ||
287 | |||
288 | /// @brief Remove the first element of a type list. If the list is empty, | ||
289 | /// nothing is done. This base configuration handles the empty list. | ||
290 | /// @note Much cheaper to instantiate than TSRemoveIndicesImpl | ||
291 | /// @tparam T The @c TypeList | ||
292 | template<typename T> | ||
293 | struct TSRemoveFirstImpl { | ||
294 | using type = TypeList<>; | ||
295 | }; | ||
296 | |||
297 | /// @brief Partial specialization for removing the first type of a @c TypeList | ||
298 | /// when the list is not empty i.e. does that actual work. | ||
299 | /// @tparam T The first type in the @c TypeList. | ||
300 | /// @tparam Ts Remaining types in the @c TypeList | ||
301 | template<typename T, typename... Ts> | ||
302 | struct TSRemoveFirstImpl<TypeList<T, Ts...>> { | ||
303 | using type = TypeList<Ts...>; | ||
304 | }; | ||
305 | |||
306 | |||
307 | /// @brief Remove the last element of a type list. If the list is empty, | ||
308 | /// nothing is done. This base configuration handles the empty list. | ||
309 | /// @note Cheaper to instantiate than TSRemoveIndicesImpl | ||
310 | /// @tparam T The @c TypeList | ||
311 | template<typename T> | ||
312 | struct TSRemoveLastImpl { using type = TypeList<>; }; | ||
313 | |||
314 | /// @brief Partial specialization for removing the last type of a @c TypeList. | ||
315 | /// This instance is instantiated when the @c TypeList contains a | ||
316 | /// single type, or the primary struct which recursively removes types | ||
317 | /// (see below) hits the last type. Evaluates the last type to the empty | ||
318 | /// list (see above). | ||
319 | /// @tparam T The last type in the @c TypeList | ||
320 | template<typename T> | ||
321 | struct TSRemoveLastImpl<TypeList<T>> : TSRemoveLastImpl<T> {}; | ||
322 | |||
323 | /// @brief Partial specialization for removing the last type of a @c TypeList | ||
324 | /// with a type list size of two or more. Recursively defines this | ||
325 | /// implementation with the remaining types, effectively rebuilding the | ||
326 | /// @c TypeList until the last type is hit, which is dropped. | ||
327 | /// @tparam T The current type in the @c TypeList | ||
328 | /// @tparam Ts Remaining types in the @c TypeList | ||
329 | template<typename T, typename... Ts> | ||
330 | struct TSRemoveLastImpl<TypeList<T, Ts...>> | ||
331 | { | ||
332 | using type = | ||
333 | typename TypeList<T>::template | ||
334 | Append<typename TSRemoveLastImpl<TypeList<Ts...>>::type>; | ||
335 | }; | ||
336 | |||
337 | |||
338 | /// @brief Remove a number of types from a @c TypeList based on a @c First and | ||
339 | /// @c Last index. | ||
340 | /// @details Both indices are inclusive, such that when <tt>First == Last</tt> | ||
341 | /// a single type is removed (assuming the index exists). If | ||
342 | /// <tt>Last < First</tt>, nothing is done. Any indices which do not | ||
343 | /// exist are ignored. If @c Last is greater than the number of types | ||
344 | /// in the @c TypeList, all types from @c First to the end of the list | ||
345 | /// are dropped. | ||
346 | /// @tparam ListT The @c TypeList | ||
347 | /// @tparam First The first index | ||
348 | /// @tparam Last The last index | ||
349 | /// @tparam Idx Internal counter for the current index | ||
350 | template<typename ListT, size_t First, size_t Last, size_t Idx=0> | ||
351 | struct TSRemoveIndicesImpl; | ||
352 | |||
353 | /// @brief Partial specialization for an empty @c TypeList | ||
354 | /// @tparam First The first index | ||
355 | /// @tparam Last The last index | ||
356 | /// @tparam Idx Internal counter for the current index | ||
357 | template<size_t First, size_t Last, size_t Idx> | ||
358 | struct TSRemoveIndicesImpl<TypeList<>, First, Last, Idx> { | ||
359 | using type = TypeList<>; | ||
360 | }; | ||
361 | |||
362 | /// @brief Partial specialization for a @c TypeList containing a single element. | ||
363 | /// @tparam T The last or only type in a @c TypeList | ||
364 | /// @tparam First The first index | ||
365 | /// @tparam Last The last index | ||
366 | /// @tparam Idx Internal counter for the current index | ||
367 | template<typename T, size_t First, size_t Last, size_t Idx> | ||
368 | struct TSRemoveIndicesImpl<TypeList<T>, First, Last, Idx> | ||
369 | { | ||
370 | private: | ||
371 | static constexpr bool Remove = Idx >= First && Idx <= Last; | ||
372 | public: | ||
373 | using type = typename std::conditional<Remove, TypeList<>, TypeList<T>>::type; | ||
374 | }; | ||
375 | |||
376 | /// @brief Partial specialization for a @c TypeList containing two or more types. | ||
377 | /// @details This implementation effectively rebuilds a @c TypeList by starting | ||
378 | /// with an empty @c TypeList and recursively defining an expanded | ||
379 | /// @c TypeList for every type (first to last), only if the type's | ||
380 | /// index does not fall within the range of indices defines by | ||
381 | /// @c First and @c Last. Recursively defines this implementation with | ||
382 | /// all but the last type. | ||
383 | /// @tparam T The currently evaluating type within a @c TypeList | ||
384 | /// @tparam Ts Remaining types in the @c TypeList | ||
385 | /// @tparam First The first index | ||
386 | /// @tparam Last The last index | ||
387 | /// @tparam Idx Internal counter for the current index | ||
388 | template<typename T, typename... Ts, size_t First, size_t Last, size_t Idx> | ||
389 | struct TSRemoveIndicesImpl<TypeList<T, Ts...>, First, Last, Idx> | ||
390 | { | ||
391 | private: | ||
392 | using ThisList = typename TSRemoveIndicesImpl<TypeList<T>, First, Last, Idx>::type; | ||
393 | using NextList = typename TSRemoveIndicesImpl<TypeList<Ts...>, First, Last, Idx+1>::type; | ||
394 | public: | ||
395 | using type = typename ThisList::template Append<NextList>; | ||
396 | }; | ||
397 | |||
398 | /// @brief Transform a @c TypeList, converting each type into a new type based | ||
399 | /// on a transformation struct @c OpT. | ||
400 | /// @details This implementation iterates through each type in a @c TypeList | ||
401 | /// and builds a new @c TypeList where each element is resolved through | ||
402 | /// a user provided converter which provides a @c Type definition. | ||
403 | /// @tparam OpT User struct to convert each type | ||
404 | /// @tparam Ts Remaining types in the @c TypeList | ||
405 | template<template <typename> class OpT, typename... Ts> struct TSTranformImpl; | ||
406 | |||
407 | /// @brief Partial specialization for an empty @c TypeList | ||
408 | /// @tparam OpT User struct to convert each type | ||
409 | template<template <typename> class OpT> | ||
410 | struct TSTranformImpl<OpT> { | ||
411 | using type = TypeList<>; | ||
412 | }; | ||
413 | |||
414 | /// @brief Implementation of TSTranformImpl. See fwd declaration for details. | ||
415 | /// @tparam OpT User struct to convert each type | ||
416 | /// @tparam Ts Remaining types in the @c TypeList | ||
417 | /// @tparam T Current type being converted | ||
418 | template<template <typename> class OpT, typename T, typename... Ts> | ||
419 | struct TSTranformImpl<OpT, T, Ts...> { | ||
420 | private: | ||
421 | using NextList = typename TSTranformImpl<OpT, Ts...>::type; | ||
422 | public: | ||
423 | // Invoke Append for each type to match the behaviour should OpT<T> be a | ||
424 | // TypeList<> | ||
425 | using type = typename TSTranformImpl<OpT>::type::template | ||
426 | Append<OpT<T>>::template | ||
427 | Append<NextList>; | ||
428 | }; | ||
429 | |||
430 | |||
431 | template<typename OpT> inline void TSForEachImpl(OpT) {} | ||
432 | template<typename OpT, typename T, typename... Ts> | ||
433 |
3/5✓ Branch 0 taken 90342 times.
✓ Branch 1 taken 50190 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
|
361464 | inline void TSForEachImpl(OpT op) { op(T()); TSForEachImpl<OpT, Ts...>(op); } |
434 | |||
435 | template<template <typename> class OpT> inline void TSForEachImpl() {} | ||
436 | template<template <typename> class OpT, typename T, typename... Ts> | ||
437 |
3/6✓ Branch 1 taken 323 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 323 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 323 times.
✗ Branch 8 not taken.
|
22023 | inline void TSForEachImpl() { OpT<T>()(); TSForEachImpl<OpT, Ts...>(); } |
438 | |||
439 | |||
440 | /// @brief Partial apply specialization for an empty @c TypeList | ||
441 | /// @tparam OpT User functor to apply to the first valid type | ||
442 | /// @tparam BaseT Type of the provided obj | ||
443 | /// @tparam T Current type | ||
444 | /// @tparam Ts Remaining types | ||
445 | template<typename OpT, typename BaseT, typename T, typename ...Ts> | ||
446 | struct TSApplyImpl { static bool apply(BaseT&, OpT&) { return false; } }; | ||
447 | |||
448 | /// @brief Apply a unary functor to a provided object only if the object | ||
449 | /// satisfies the cast requirement of isType<T> for a type in a TypeList. | ||
450 | /// @note Iteration terminates immediately on the first valid type and true | ||
451 | /// is returned. | ||
452 | /// @tparam OpT User functor to apply to the first valid type | ||
453 | /// @tparam BaseT Type of the provided obj | ||
454 | /// @tparam T Current type | ||
455 | /// @tparam Ts Remaining types | ||
456 | template<typename OpT, typename BaseT, typename T, typename ...Ts> | ||
457 | struct TSApplyImpl<OpT, BaseT, TypeList<T, Ts...>> | ||
458 | { | ||
459 | using CastT = | ||
460 | typename std::conditional<std::is_const<BaseT>::value, const T, T>::type; | ||
461 | |||
462 | 88578 | static bool apply(BaseT& obj, OpT& op) | |
463 | { | ||
464 |
14/25✓ Branch 1 taken 6624 times.
✓ Branch 2 taken 37666 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 25 times.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
✓ Branch 11 taken 1 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 1 times.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 1 times.
✗ Branch 19 not taken.
✓ Branch 21 taken 1 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 1 times.
✗ Branch 24 not taken.
✓ Branch 26 taken 1 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 1 times.
✗ Branch 29 not taken.
|
88584 | if (obj.template isType<T>()) { |
465 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
3408 | op(static_cast<CastT&>(obj)); |
466 | 13257 | return true; | |
467 | } | ||
468 | 75270 | return TSApplyImpl<OpT, BaseT, TypeList<Ts...>>::apply(obj, op); | |
469 | } | ||
470 | }; | ||
471 | |||
472 | } // namespace internal | ||
473 | |||
474 | /// @endcond | ||
475 | |||
476 | |||
477 | /// @brief A list of types (not necessarily unique) | ||
478 | /// @details Example: | ||
479 | /// @code | ||
480 | /// using MyTypes = openvdb::TypeList<int, float, int, double, float>; | ||
481 | /// @endcode | ||
482 | template<typename... Ts> | ||
483 | struct TypeList | ||
484 | { | ||
485 | /// The type of this list | ||
486 | using Self = TypeList; | ||
487 | |||
488 | /// @brief The number of types in the type list | ||
489 | static constexpr size_t Size = sizeof...(Ts); | ||
490 | |||
491 | /// @brief Access a particular element of this type list. If the index | ||
492 | /// is out of range, typelist_internal::NullType is returned. | ||
493 | template<size_t N> | ||
494 | using Get = typename typelist_internal::TSGetElementImpl<Self, N>::type; | ||
495 | using Front = Get<0>; | ||
496 | using Back = Get<Size-1>; | ||
497 | |||
498 | /// @brief True if this list contains the given type, false otherwise | ||
499 | /// @details Example: | ||
500 | /// @code | ||
501 | /// { | ||
502 | /// using IntTypes = openvdb::TypeList<Int16, Int32, Int64>; | ||
503 | /// using RealTypes = openvdb::TypeList<float, double>; | ||
504 | /// } | ||
505 | /// { | ||
506 | /// openvdb::TypeList<IntTypes>::Contains<Int32>; // true | ||
507 | /// openvdb::TypeList<RealTypes>::Contains<Int32>; // false | ||
508 | /// } | ||
509 | /// @endcode | ||
510 | template<typename T> | ||
511 | static constexpr bool Contains = typelist_internal::TSHasTypeImpl<Self, T>::Value; | ||
512 | |||
513 | /// @brief Returns the index of the first found element of the given type, -1 if | ||
514 | /// no matching element exists. | ||
515 | /// @details Example: | ||
516 | /// @code | ||
517 | /// { | ||
518 | /// using IntTypes = openvdb::TypeList<Int16, Int32, Int64>; | ||
519 | /// using RealTypes = openvdb::TypeList<float, double>; | ||
520 | /// } | ||
521 | /// { | ||
522 | /// const int64_t L1 = openvdb::TypeList<IntTypes>::Index<Int32>; // 1 | ||
523 | /// const int64_t L2 = openvdb::TypeList<RealTypes>::Index<Int32>; // -1 | ||
524 | /// } | ||
525 | /// @endcode | ||
526 | template<typename T> | ||
527 | static constexpr int64_t Index = typelist_internal::TSHasTypeImpl<Self, T>::Index; | ||
528 | |||
529 | /// @brief Remove any duplicate types from this TypeList by rotating the | ||
530 | /// next valid type left (maintains the order of other types). Optionally | ||
531 | /// combine the result with another TypeList. | ||
532 | /// @details Example: | ||
533 | /// @code | ||
534 | /// { | ||
535 | /// using Types = openvdb::TypeList<Int16, Int32, Int16, float, float, Int64>; | ||
536 | /// } | ||
537 | /// { | ||
538 | /// using UniqueTypes = Types::Unique<>; // <Int16, Int32, float, Int64> | ||
539 | /// } | ||
540 | /// @endcode | ||
541 | template<typename ListT = TypeList<>> | ||
542 | using Unique = typename typelist_internal::TSRecurseAppendUniqueImpl<ListT, Ts...>::type; | ||
543 | |||
544 | /// @brief Append types, or the members of another TypeList, to this list. | ||
545 | /// @warning Appending nested TypeList<> objects causes them to expand to | ||
546 | /// their contained list of types. | ||
547 | /// @details Example: | ||
548 | /// @code | ||
549 | /// { | ||
550 | /// using IntTypes = openvdb::TypeList<Int16, Int32, Int64>; | ||
551 | /// using RealTypes = openvdb::TypeList<float, double>; | ||
552 | /// using NumericTypes = IntTypes::Append<RealTypes>; | ||
553 | /// } | ||
554 | /// { | ||
555 | /// using IntTypes = openvdb::TypeList<Int16>::Append<Int32, Int64>; | ||
556 | /// using NumericTypes = IntTypes::Append<float>::Append<double>; | ||
557 | /// } | ||
558 | /// @endcode | ||
559 | template<typename... TypesToAppend> | ||
560 | using Append = typename typelist_internal::TSAppendImpl<Self, TypesToAppend...>::type; | ||
561 | |||
562 | /// @brief Remove all occurrences of one or more types, or the members of | ||
563 | /// another TypeList, from this list. | ||
564 | /// @details Example: | ||
565 | /// @code | ||
566 | /// { | ||
567 | /// using NumericTypes = openvdb::TypeList<float, double, Int16, Int32, Int64>; | ||
568 | /// using LongTypes = openvdb::TypeList<Int64, double>; | ||
569 | /// using ShortTypes = NumericTypes::Remove<LongTypes>; // float, Int16, Int32 | ||
570 | /// } | ||
571 | /// @endcode | ||
572 | template<typename... TypesToRemove> | ||
573 | using Remove = typename typelist_internal::TSRemoveImpl<Self, TypesToRemove...>::type; | ||
574 | |||
575 | /// @brief Remove the first element of this type list. Has no effect if the | ||
576 | /// type list is already empty. | ||
577 | /// @details Example: | ||
578 | /// @code | ||
579 | /// { | ||
580 | /// using IntTypes = openvdb::TypeList<Int16, Int32, Int64>; | ||
581 | /// using EmptyTypes = openvdb::TypeList<>; | ||
582 | /// } | ||
583 | /// { | ||
584 | /// IntTypes::PopFront; // openvdb::TypeList<Int32, Int64>; | ||
585 | /// EmptyTypes::PopFront; // openvdb::TypeList<>; | ||
586 | /// } | ||
587 | /// @endcode | ||
588 | using PopFront = typename typelist_internal::TSRemoveFirstImpl<Self>::type; | ||
589 | |||
590 | /// @brief Remove the last element of this type list. Has no effect if the | ||
591 | /// type list is already empty. | ||
592 | /// @details Example: | ||
593 | /// @code | ||
594 | /// { | ||
595 | /// using IntTypes = openvdb::TypeList<Int16, Int32, Int64>; | ||
596 | /// using EmptyTypes = openvdb::TypeList<>; | ||
597 | /// } | ||
598 | /// { | ||
599 | /// IntTypes::PopBack; // openvdb::TypeList<Int16, Int32>; | ||
600 | /// EmptyTypes::PopBack; // openvdb::TypeList<>; | ||
601 | /// } | ||
602 | /// @endcode | ||
603 | using PopBack = typename typelist_internal::TSRemoveLastImpl<Self>::type; | ||
604 | |||
605 | /// @brief Return a new list with types removed by their location within the list. | ||
606 | /// If First is equal to Last, a single element is removed (if it exists). | ||
607 | /// If First is greater than Last, the list remains unmodified. | ||
608 | /// @details Example: | ||
609 | /// @code | ||
610 | /// { | ||
611 | /// using NumericTypes = openvdb::TypeList<float, double, Int16, Int32, Int64>; | ||
612 | /// } | ||
613 | /// { | ||
614 | /// using IntTypes = NumericTypes::RemoveByIndex<0,1>; // openvdb::TypeList<Int16, Int32, Int64>; | ||
615 | /// using RealTypes = NumericTypes::RemoveByIndex<2,4>; // openvdb::TypeList<float, double>; | ||
616 | /// using RemoveFloat = NumericTypes::RemoveByIndex<0,0>; // openvdb::TypeList<double, Int16, Int32, Int64>; | ||
617 | /// } | ||
618 | /// @endcode | ||
619 | template <size_t First, size_t Last> | ||
620 | using RemoveByIndex = typename typelist_internal::TSRemoveIndicesImpl<Self, First, Last>::type; | ||
621 | |||
622 | /// @brief Transform each type of this TypeList, rebuiling a new list of | ||
623 | /// converted types. This method instantiates a user provided Opt<T> to | ||
624 | /// replace each type in the current list. | ||
625 | /// @warning Transforming types to new TypeList<> objects causes them to expand to | ||
626 | /// their contained list of types. | ||
627 | /// @details Example: | ||
628 | /// @code | ||
629 | /// { | ||
630 | /// // Templated type decl, where the type T will be subsituted for each type | ||
631 | /// // in the TypeList being transformed. | ||
632 | /// template <typename T> | ||
633 | /// using ConvertedType = typename openvdb::PromoteType<T>::Next; | ||
634 | /// | ||
635 | /// // Results in: openvdb::TypeList<Int64, double>; | ||
636 | /// using PromotedType = openvdb::TypeList<Int32, float>::Transform<ConvertedType>; | ||
637 | /// } | ||
638 | /// @endcode | ||
639 | template<template <typename> class OpT> | ||
640 | using Transform = typename typelist_internal::TSTranformImpl<OpT, Ts...>::type; | ||
641 | |||
642 | /// @brief Invoke a templated class operator on each type in this list. Use | ||
643 | /// this method if you only need access to the type for static methods. | ||
644 | /// @details Example: | ||
645 | /// @code | ||
646 | /// #include <typeinfo> | ||
647 | /// | ||
648 | /// template <typename T> | ||
649 | /// struct PintTypes() { | ||
650 | /// inline void operator()() { std::cout << typeid(T).name() << std::endl; } | ||
651 | /// }; | ||
652 | /// | ||
653 | /// using MyTypes = openvdb::TypeList<int, float, double>; | ||
654 | /// MyTypes::foreach<PintTypes>(); // "i, f, d" (exact output is compiler-dependent) | ||
655 | /// @endcode | ||
656 | /// | ||
657 | /// @note OpT must be a templated class. It is created and invoked for each | ||
658 | /// type in this list. | ||
659 | template<template <typename> class OpT> | ||
660 | 970 | static void foreach() { typelist_internal::TSForEachImpl<OpT, Ts...>(); } | |
661 | |||
662 | /// @brief Invoke a templated, unary functor on a value of each type in this list. | ||
663 | /// @details Example: | ||
664 | /// @code | ||
665 | /// #include <typeinfo> | ||
666 | /// | ||
667 | /// template<typename ListT> | ||
668 | /// void printTypeList() | ||
669 | /// { | ||
670 | /// std::string sep; | ||
671 | /// auto op = [&](auto x) { // C++14 | ||
672 | /// std::cout << sep << typeid(decltype(x)).name(); sep = ", "; }; | ||
673 | /// ListT::foreach(op); | ||
674 | /// } | ||
675 | /// | ||
676 | /// using MyTypes = openvdb::TypeList<int, float, double>; | ||
677 | /// printTypeList<MyTypes>(); // "i, f, d" (exact output is compiler-dependent) | ||
678 | /// @endcode | ||
679 | /// | ||
680 | /// @note The functor object is passed by value. Wrap it with @c std::ref | ||
681 | /// to use the same object for each type. | ||
682 | template<typename OpT> | ||
683 |
8/15✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 1 times.
✗ Branch 20 not taken.
|
5047 | static void foreach(OpT op) { typelist_internal::TSForEachImpl<OpT, Ts...>(op); } |
684 | |||
685 | /// @brief Invoke a templated, unary functor on a provide @c obj of type | ||
686 | /// @c BaseT only if said object is an applicable (derived) type | ||
687 | /// also contained in the current @c TypeList. | ||
688 | /// @details This method loops over every type in the type list and calls | ||
689 | /// an interface method on @c obj to check to see if the @c obj is | ||
690 | /// interpretable as the given type. If it is, the method static casts | ||
691 | /// @c obj to the type, invokes the provided functor with the casted type | ||
692 | /// and returns, stopping further list iteration. @c obj is expected to | ||
693 | /// supply an interface to validate the type which satisfies the | ||
694 | /// prototype: | ||
695 | /// @code | ||
696 | /// template <typename T> bool isType() | ||
697 | /// @endcode | ||
698 | /// | ||
699 | /// A full example (using dynamic_cast - see Grid/Tree implementations | ||
700 | /// for string based comparisons: | ||
701 | /// @code | ||
702 | /// struct Base { | ||
703 | /// virtual ~Base() = default; | ||
704 | /// template<typename T> bool isType() { return dynamic_cast<const T*>(this); } | ||
705 | /// }; | ||
706 | /// struct MyType1 : public Base { void print() { std::cerr << "MyType1" << std::endl; } }; | ||
707 | /// struct MyType2 : public Base { void print() { std::cerr << "MyType2" << std::endl; } }; | ||
708 | /// | ||
709 | /// using MyTypeList = TypeList<MyType1, MyType2>; | ||
710 | /// Base* getObj() { return new MyType2(); } | ||
711 | /// | ||
712 | /// std::unique_ptr<Base> obj = getObj(); | ||
713 | /// // Returns 'true', prints 'MyType2' | ||
714 | /// const bool success = | ||
715 | /// MyTypeList::apply([](const auto& type) { type.print(); }, *obj); | ||
716 | /// @endcode | ||
717 | /// | ||
718 | /// @note The functor object is passed by value. Wrap it with @c std::ref | ||
719 | /// pass by reference. | ||
720 | template<typename OpT, typename BaseT> | ||
721 | static bool apply(OpT op, BaseT& obj) { | ||
722 |
16/32✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4915 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 2 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 1 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 1 times.
✗ Branch 23 not taken.
✓ Branch 25 taken 1 times.
✗ Branch 26 not taken.
✓ Branch 28 taken 1 times.
✗ Branch 29 not taken.
✓ Branch 31 taken 1 times.
✗ Branch 32 not taken.
✓ Branch 34 taken 1 times.
✗ Branch 35 not taken.
✓ Branch 37 taken 1 times.
✗ Branch 38 not taken.
✓ Branch 40 taken 1 times.
✗ Branch 41 not taken.
✓ Branch 43 taken 1 times.
✗ Branch 44 not taken.
✓ Branch 46 taken 1 times.
✗ Branch 47 not taken.
|
6654 | return typelist_internal::TSApplyImpl<OpT, BaseT, Self>::apply(obj, op); |
723 | } | ||
724 | }; | ||
725 | |||
726 | |||
727 | } // namespace OPENVDB_VERSION_NAME | ||
728 | } // namespace openvdb | ||
729 | |||
730 | |||
731 | #endif // OPENVDB_TYPELIST_HAS_BEEN_INCLUDED | ||
732 |