OpenVDB 13.0.1
Loading...
Searching...
No Matches
TypeList.h
Go to the documentation of this file.
1// Copyright Contributors to the OpenVDB Project
2// SPDX-License-Identifier: Apache-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/// We should usually not be decorating public API functions with attributes
21/// such as always_inline. However many compilers are notoriously bad at
22/// inlining recursive template loops with default inline settings. The
23/// TypeList and TupleList metaprogram constructs heavily use this C++ feature
24/// and the performance difference can be substantial, even for very small
25/// lists. You can disable this behaviour by setting the define:
26/// OPENVDB_TYPELIST_NO_FORCE_INLINE
27/// This will disable the force inling on public API methods in this file.
28#ifdef OPENVDB_TYPELIST_NO_FORCE_INLINE
29#define OPENVDB_TYPELIST_FORCE_INLINE inline
30#else
31#define OPENVDB_TYPELIST_FORCE_INLINE OPENVDB_FORCE_INLINE
32#endif
33
34namespace openvdb {
36namespace OPENVDB_VERSION_NAME {
37
38/// @cond OPENVDB_DOCS_INTERNAL
39
40// forward declarations
41template<typename... Ts> struct TypeList;
42template<typename... Ts> struct TupleList;
43
44namespace typelist_internal {
45
46// Implementation details of @c TypeList
47
48/// @brief Dummy struct, used as the return type from invalid or out-of-range
49/// @c TypeList queries.
50struct NullType {};
51
52
53/// @brief Type resolver for index queries
54/// @details Defines a type at a given location within a @c TypeList or the
55/// @c NullType if the index is out-of-range. The last template
56/// parameter is used to determine if the index is in range.
57/// @tparam ListT The @c TypeList
58/// @tparam Idx The index of the type to get
59template<typename ListT, size_t Idx, typename = void> struct TSGetElementImpl;
60
61/// @brief Partial specialization for valid (in range) index queries.
62/// @tparam Ts Unpacked types from a @c TypeList
63/// @tparam Idx The index of the type to get
64template<typename... Ts, size_t Idx>
65struct TSGetElementImpl<TypeList<Ts...>, Idx,
66 typename std::enable_if<(Idx < sizeof...(Ts) && sizeof...(Ts))>::type> {
67 using type = typename std::tuple_element<Idx, std::tuple<Ts...>>::type;
68};
69
70/// @brief Partial specialization for invalid index queries (i.e. out-of-range
71/// indices such as @c TypeList<Int32>::Get<1>). Defines the NullType.
72/// @tparam Ts Unpacked types from a @c TypeList
73/// @tparam Idx The index of the type to get
74template<typename... Ts, size_t Idx>
75struct TSGetElementImpl<TypeList<Ts...>, Idx,
76 typename std::enable_if<!(Idx < sizeof...(Ts) && sizeof...(Ts))>::type> {
77 using type = NullType;
78};
79
80
81/// @brief Search for a given type within a @c TypeList.
82/// @details If the type is found, a @c bool constant @c Value is set to true
83/// and an @c int64_t @c Index points to the location of the type. If
84/// multiple versions of the types exist, the value of @c Index is
85/// always the location of the first matching type. If the type is not
86/// found, @c Value is set to false and @c Index is set to -1.
87/// @note This implementation is recursively defined until the type is found
88/// or until the end of the list is reached. The last template argument
89/// is used as an internal counter to track the current index being
90/// evaluated.
91/// @tparam ListT The @c TypeList
92/// @tparam T The type to find
93template <typename ListT, typename T, size_t=0>
94struct TSHasTypeImpl;
95
96/// @brief Partial specialization on an empty @c TypeList, instantiated when
97/// @c TSHasTypeImpl has been invoked with an empty @c TypeList or when
98/// a recursive search reaches the end of a @c TypeList.
99/// @tparam T The type to find
100/// @tparam Idx Current index
101template <typename T, size_t Idx>
102struct TSHasTypeImpl<TypeList<>, T, Idx> {
103 static constexpr bool Value = false;
104 static constexpr int64_t Index = -1;
105};
106
107/// @brief Partial specialization on a @c TypeList which still contains types,
108/// but the current type being evaluated @c U does not match the given
109/// type @C T.
110/// @tparam U The current type being evaluated within the @c TypeList
111/// @tparam T The type to find
112/// @tparam Ts Remaining types
113/// @tparam Idx Current index
114template <typename U, typename T, typename... Ts, size_t Idx>
115struct TSHasTypeImpl<TypeList<U, Ts...>, T, Idx> :
116 TSHasTypeImpl<TypeList<Ts...>, T, Idx+1> {};
117
118/// @brief Partial specialization on a @c TypeList where @c T matches the
119/// current type (i.e. the type has been found).
120/// @tparam T The type to find
121/// @tparam Ts Remaining types
122/// @tparam Idx Current index
123template <typename T, typename... Ts, size_t Idx>
124struct TSHasTypeImpl<TypeList<T, Ts...>, T, Idx>
125{
126 static constexpr bool Value = true;
127 static constexpr int64_t Index = static_cast<int64_t>(Idx);
128};
129
130
131/// @brief Similar to TsAppendImpl but only appends types to a list if the
132/// type does not alreay exist in the list.
133/// @details Defines a new @c TypeList with non-unique types appended
134/// @tparam U Type to append
135/// @tparam ListT The @c TypeList to append to
136template <typename U, typename ListT,
137 bool ListContainsType = TSHasTypeImpl<ListT, U>::Value>
138struct TSAppendUniqueImpl;
139
140/// @brief Partial specialization where the currently evaluating type @c U in
141/// a @c TypeList already exists in the list. Returns the unmodified list.
142/// @tparam U Type to append
143/// @tparam Ts Other types within the @c TypeList
144template <typename U, typename... Ts>
145struct TSAppendUniqueImpl<U, TypeList<Ts...>, true> {
146private:
147 using RemovedU = typename TypeList<Ts...>::template Remove<U>;
148public:
149 /// @note It's simpler to remove the current type U and append the rest by
150 /// just having "using type = TypeList<Ts...>". However this ends up with
151 /// with keeping the last seen type rather than the first which this
152 /// method historically did. e.g:
153 /// TypeList<float, int, float>::Unique<> can become:
154 /// a) TypeList<float, int> currently
155 /// b) TypeList<int, float> if we used the afformentioned technique
156 /// Might be useful to have both? Complexity in (a) is currently linear so
157 /// this shouldn't be a problem, but be careful this doesn't change.
158 //using type = TypeList<Ts...>;
159 using type = typename TypeList<U>::template Append<RemovedU>;
160};
161
162/// @brief Partial specialization where the currently evaluating type @c U in
163/// a @c TypeList does not exists in the list. Returns the appended list.
164/// @tparam U Type to append
165/// @tparam Ts Other types within the @c TypeList
166template <typename U, typename... Ts>
167struct TSAppendUniqueImpl<U, TypeList<Ts...>, false> {
168 using type = TypeList<U, Ts...>;
169};
170
171/// @brief Reconstruct a @c TypeList containing only unique types.
172/// @details This implementation effectively rebuilds a @c TypeList by
173/// starting with an empty @c TypeList and recursively defining an expanded
174/// @c TypeList for every type (first to last), only if the type does not
175/// already exist in the new @c TypeList. This has the effect of dropping all
176/// but the first of duplicate types.
177/// @warning This implementation previously used an embdedded std::conditional
178/// which resulted in drastically slow compilation times. If you're changing
179/// this implementation make sure to profile compile times with larger lists.
180/// @tparam Ts Types within the @c TypeList
181template <typename... Ts>
182struct TSRecurseAppendUniqueImpl;
183
184/// @brief Terminate type recursion when the end of a @c TypeList is reached.
185template <>
186struct TSRecurseAppendUniqueImpl<> {
187 using type = TypeList<>;
188};
189
190/// @brief Merge and unpack an initial @c TypeList from the first argument if
191/// such a @c TypeList has been provided.
192/// @tparam Ts Types within the first @c TypeList
193/// @tparam OtherTs Other types
194template <typename... Ts, typename... OtherTs>
195struct TSRecurseAppendUniqueImpl<TypeList<Ts...>, OtherTs...> {
196 using type = typename TSRecurseAppendUniqueImpl<OtherTs..., Ts...>::type;
197};
198
199/// @brief Recursively call TSRecurseAppendUniqueImpl with each type in the
200/// provided @c TypeLists, rebuilding a new list with only the unique set
201/// of types.
202/// @tparam U Next type to check for uniqueness and append
203/// @tparam Ts Remaining types within the @c TypeList
204template <typename U, typename... Ts>
205struct TSRecurseAppendUniqueImpl<U, Ts...>
206{
207 using type = typename TSAppendUniqueImpl<U,
208 typename TSRecurseAppendUniqueImpl<Ts...>::type
209 >::type;
210};
211
212
213/// @brief Append any number of types to a @c TypeList
214/// @details Defines a new @c TypeList with the provided types appended
215/// @tparam ListT The @c TypeList to append to
216/// @tparam Ts Types to append
217template<typename ListT, typename... Ts> struct TSAppendImpl;
218
219/// @brief Partial specialization for a @c TypeList with a list of zero or more
220/// types to append
221/// @tparam Ts Current types within the @c TypeList
222/// @tparam OtherTs Other types to append
223template<typename... Ts, typename... OtherTs>
224struct TSAppendImpl<TypeList<Ts...>, OtherTs...> {
225 using type = TypeList<Ts..., OtherTs...>;
226};
227
228/// @brief Partial specialization for a @c TypeList with another @c TypeList.
229/// Appends the other TypeList's members.
230/// @tparam Ts Types within the first @c TypeList
231/// @tparam OtherTs Types within the second @c TypeList
232template<typename... Ts, typename... OtherTs>
233struct TSAppendImpl<TypeList<Ts...>, TypeList<OtherTs...>> {
234 using type = TypeList<Ts..., OtherTs...>;
235};
236
237
238/// @brief Remove all occurrences of type T from a @c TypeList
239/// @details Defines a new @c TypeList with the provided types removed
240/// @tparam ListT The @c TypeList
241/// @tparam T Type to remove
242template<typename ListT, typename T> struct TSEraseImpl;
243
244/// @brief Partial specialization for an empty @c TypeList
245/// @tparam T Type to remove, has no effect
246template<typename T>
247struct TSEraseImpl<TypeList<>, T> { using type = TypeList<>; };
248
249/// @brief Partial specialization where the currently evaluating type in a
250/// @c TypeList matches the type to remove. Recursively defines this
251/// implementation with the remaining types.
252/// @tparam Ts Unpacked types within the @c TypeList
253/// @tparam T Type to remove
254template<typename... Ts, typename T>
255struct TSEraseImpl<TypeList<T, Ts...>, T> {
256 using type = typename TSEraseImpl<TypeList<Ts...>, T>::type;
257};
258
259/// @brief Partial specialization where the currently evaluating type @c T2 in
260/// a @c TypeList does not match the type to remove @c T. Recursively
261/// defines this implementation with the remaining types.
262/// @tparam T2 Current type within the @c TypeList, which does not match @c T
263/// @tparam Ts Other types within the @c TypeList
264/// @tparam T Type to remove
265template<typename T2, typename... Ts, typename T>
266struct TSEraseImpl<TypeList<T2, Ts...>, T> {
267 using type = typename TSAppendImpl<TypeList<T2>,
268 typename TSEraseImpl<TypeList<Ts...>, T>::type>::type;
269};
270
271/// @brief Front end implementation to call TSEraseImpl which removes all
272/// occurrences of a type from a @c TypeList. This struct handles the
273/// case where the type to remove is another @c TypeList, in which case
274/// all types in the second @c TypeList are removed from the first.
275/// @tparam ListT The @c TypeList
276/// @tparam Ts Types in the @c TypeList
277template<typename ListT, typename... Ts> struct TSRemoveImpl;
278
279/// @brief Partial specialization when there are no types in the @c TypeList.
280/// @tparam ListT The @c TypeList
281template<typename ListT>
282struct TSRemoveImpl<ListT> { using type = ListT; };
283
284/// @brief Partial specialization when the type to remove @c T is not another
285/// @c TypeList. @c T is removed from the @c TypeList.
286/// @tparam ListT The @c TypeList
287/// @tparam T Type to remove
288/// @tparam Ts Types in the @c TypeList
289template<typename ListT, typename T, typename... Ts>
290struct TSRemoveImpl<ListT, T, Ts...> {
291 using type = typename TSRemoveImpl<typename TSEraseImpl<ListT, T>::type, Ts...>::type;
292};
293
294/// @brief Partial specialization when the type to remove is another
295/// @c TypeList. All types within the other type list are removed from
296/// the first list.
297/// @tparam ListT The @c TypeList
298/// @tparam Ts Types from the second @c TypeList to remove from the first
299template<typename ListT, typename... Ts>
300struct TSRemoveImpl<ListT, TypeList<Ts...>> {
301 using type = typename TSRemoveImpl<ListT, Ts...>::type;
302};
303
304/// @brief Remove the first element of a type list. If the list is empty,
305/// nothing is done. This base configuration handles the empty list.
306/// @note Much cheaper to instantiate than TSRemoveIndicesImpl
307/// @tparam T The @c TypeList
308template<typename T>
309struct TSRemoveFirstImpl {
310 using type = TypeList<>;
311};
312
313/// @brief Partial specialization for removing the first type of a @c TypeList
314/// when the list is not empty i.e. does that actual work.
315/// @tparam T The first type in the @c TypeList.
316/// @tparam Ts Remaining types in the @c TypeList
317template<typename T, typename... Ts>
318struct TSRemoveFirstImpl<TypeList<T, Ts...>> {
319 using type = TypeList<Ts...>;
320};
321
322
323/// @brief Remove the last element of a type list. If the list is empty,
324/// nothing is done. This base configuration handles the empty list.
325/// @note Cheaper to instantiate than TSRemoveIndicesImpl
326/// @tparam T The @c TypeList
327template<typename T>
328struct TSRemoveLastImpl { using type = TypeList<>; };
329
330/// @brief Partial specialization for removing the last type of a @c TypeList.
331/// This instance is instantiated when the @c TypeList contains a
332/// single type, or the primary struct which recursively removes types
333/// (see below) hits the last type. Evaluates the last type to the empty
334/// list (see above).
335/// @tparam T The last type in the @c TypeList
336template<typename T>
337struct TSRemoveLastImpl<TypeList<T>> : TSRemoveLastImpl<T> {};
338
339/// @brief Partial specialization for removing the last type of a @c TypeList
340/// with a type list size of two or more. Recursively defines this
341/// implementation with the remaining types, effectively rebuilding the
342/// @c TypeList until the last type is hit, which is dropped.
343/// @tparam T The current type in the @c TypeList
344/// @tparam Ts Remaining types in the @c TypeList
345template<typename T, typename... Ts>
346struct TSRemoveLastImpl<TypeList<T, Ts...>>
347{
348 using type =
349 typename TypeList<T>::template
350 Append<typename TSRemoveLastImpl<TypeList<Ts...>>::type>;
351};
352
353
354/// @brief Remove a number of types from a @c TypeList based on a @c First and
355/// @c Last index.
356/// @details Both indices are inclusive, such that when <tt>First == Last</tt>
357/// a single type is removed (assuming the index exists). If
358/// <tt>Last < First</tt>, nothing is done. Any indices which do not
359/// exist are ignored. If @c Last is greater than the number of types
360/// in the @c TypeList, all types from @c First to the end of the list
361/// are dropped.
362/// @tparam ListT The @c TypeList
363/// @tparam First The first index
364/// @tparam Last The last index
365/// @tparam Idx Internal counter for the current index
366template<typename ListT, size_t First, size_t Last, size_t Idx=0>
367struct TSRemoveIndicesImpl;
368
369/// @brief Partial specialization for an empty @c TypeList
370/// @tparam First The first index
371/// @tparam Last The last index
372/// @tparam Idx Internal counter for the current index
373template<size_t First, size_t Last, size_t Idx>
374struct TSRemoveIndicesImpl<TypeList<>, First, Last, Idx> {
375 using type = TypeList<>;
376};
377
378/// @brief Partial specialization for a @c TypeList containing a single element.
379/// @tparam T The last or only type in a @c TypeList
380/// @tparam First The first index
381/// @tparam Last The last index
382/// @tparam Idx Internal counter for the current index
383template<typename T, size_t First, size_t Last, size_t Idx>
384struct TSRemoveIndicesImpl<TypeList<T>, First, Last, Idx>
385{
386private:
387 static constexpr bool Remove = Idx >= First && Idx <= Last;
388public:
389 using type = typename std::conditional<Remove, TypeList<>, TypeList<T>>::type;
390};
391
392/// @brief Partial specialization for a @c TypeList containing two or more types.
393/// @details This implementation effectively rebuilds a @c TypeList by starting
394/// with an empty @c TypeList and recursively defining an expanded
395/// @c TypeList for every type (first to last), only if the type's
396/// index does not fall within the range of indices defines by
397/// @c First and @c Last. Recursively defines this implementation with
398/// all but the last type.
399/// @tparam T The currently evaluating type within a @c TypeList
400/// @tparam Ts Remaining types in the @c TypeList
401/// @tparam First The first index
402/// @tparam Last The last index
403/// @tparam Idx Internal counter for the current index
404template<typename T, typename... Ts, size_t First, size_t Last, size_t Idx>
405struct TSRemoveIndicesImpl<TypeList<T, Ts...>, First, Last, Idx>
406{
407private:
408 using ThisList = typename TSRemoveIndicesImpl<TypeList<T>, First, Last, Idx>::type;
409 using NextList = typename TSRemoveIndicesImpl<TypeList<Ts...>, First, Last, Idx+1>::type;
410public:
411 using type = typename ThisList::template Append<NextList>;
412};
413
414/// @brief Transform a @c TypeList, converting each type into a new type based
415/// on a transformation struct @c OpT.
416/// @details This implementation iterates through each type in a @c TypeList
417/// and builds a new @c TypeList where each element is resolved through
418/// a user provided converter which provides a @c Type definition.
419/// @tparam OpT User struct to convert each type
420/// @tparam Ts Remaining types in the @c TypeList
421template<template <typename> class OpT, typename... Ts> struct TSTranformImpl;
422
423/// @brief Partial specialization for an empty @c TypeList
424/// @tparam OpT User struct to convert each type
425template<template <typename> class OpT>
426struct TSTranformImpl<OpT> {
427 using type = TypeList<>;
428};
429
430/// @brief Implementation of TSTranformImpl. See fwd declaration for details.
431/// @tparam OpT User struct to convert each type
432/// @tparam Ts Remaining types in the @c TypeList
433/// @tparam T Current type being converted
434template<template <typename> class OpT, typename T, typename... Ts>
435struct TSTranformImpl<OpT, T, Ts...> {
436private:
437 using NextList = typename TSTranformImpl<OpT, Ts...>::type;
438public:
439 // Invoke Append for each type to match the behaviour should OpT<T> be a
440 // TypeList<>
441 using type = typename TSTranformImpl<OpT>::type::template
442 Append<OpT<T>>::template
443 Append<NextList>;
444};
445
446/// @brief Partial apply specialization for an empty @c TypeList
447/// @tparam OpT User functor to apply to the first valid type
448/// @tparam BaseT Type of the provided obj
449/// @tparam T Current type
450/// @tparam Ts Remaining types
451template<typename OpT, typename BaseT, typename T, typename ...Ts>
452struct TSApplyImpl { static bool apply(BaseT&, OpT&) { return false; } };
453
454/// @brief Apply a unary functor to a provided object only if the object
455/// satisfies the cast requirement of isType<T> for a type in a TypeList.
456/// @note Iteration terminates immediately on the first valid type and true
457/// is returned.
458/// @tparam OpT User functor to apply to the first valid type
459/// @tparam BaseT Type of the provided obj
460/// @tparam T Current type
461/// @tparam Ts Remaining types
462template<typename OpT, typename BaseT, typename T, typename ...Ts>
463struct TSApplyImpl<OpT, BaseT, TypeList<T, Ts...>>
464{
465 using CastT =
466 typename std::conditional<std::is_const<BaseT>::value, const T, T>::type;
467
468 static bool apply(BaseT& obj, OpT& op)
469 {
470 if (obj.template isType<T>()) {
471 op(static_cast<CastT&>(obj));
472 return true;
473 }
474 return TSApplyImpl<OpT, BaseT, TypeList<Ts...>>::apply(obj, op);
475 }
476};
477
478template<template <typename> class OpT> inline void TSForEachImpl() {}
479template<template <typename> class OpT, typename T, typename... Ts>
480inline void TSForEachImpl() { OpT<T>()(); TSForEachImpl<OpT, Ts...>(); }
481
482template<typename OpT> inline void TSForEachImpl(OpT) {}
483template<typename OpT, typename T, typename... Ts>
484constexpr OPENVDB_FORCE_INLINE void TSForEachImpl(OpT op) {
485 op(T()); TSForEachImpl<OpT, Ts...>(op);
486}
487
488///////////////////////////////////////////////////////////////////////////////
489
490// Implementation details of @c TupleList
491
492template<size_t Iter, size_t End, typename OpT, typename TupleT>
493constexpr OPENVDB_FORCE_INLINE void TSForEachImpl(
494 [[maybe_unused]] OpT op,
495 [[maybe_unused]] TupleT& tup)
496{
497 if constexpr(Iter<End) {
498 op(std::get<Iter>(tup));
499 TSForEachImpl<Iter+1, End, OpT, TupleT>(op, tup);
500 }
501}
502
503template<typename OpT, size_t Iter, size_t End>
504constexpr OPENVDB_FORCE_INLINE void TSForEachIndexImpl([[maybe_unused]] OpT op)
505{
506 if constexpr(Iter<End) {
507 op(std::integral_constant<std::size_t, Iter>());
508 TSForEachIndexImpl<OpT, Iter+1, End>(op);
509 }
510}
511
512template<typename OpT, typename RetT, size_t Iter, size_t End>
513constexpr OPENVDB_FORCE_INLINE RetT TSEvalFirstIndex([[maybe_unused]] OpT op, const RetT def)
514{
515 if constexpr(Iter<End) {
516 if (auto ret = op(std::integral_constant<std::size_t, Iter>())) return ret;
517 return TSEvalFirstIndex<OpT, RetT, Iter+1, End>(op, def);
518 }
519 else return def;
520}
521
522template<class Pred, class OpT, typename TupleT, size_t Iter, size_t End>
523constexpr OPENVDB_FORCE_INLINE
524void TSEvalFirstPredImpl(
525 [[maybe_unused]] Pred pred,
526 [[maybe_unused]] OpT op,
527 [[maybe_unused]] TupleT& tup)
528{
529 if constexpr (Iter<End) {
530 constexpr auto Idx = std::integral_constant<std::size_t, Iter>();
531 if (pred(Idx)) op(std::get<Idx>(tup));
532 else TSEvalFirstPredImpl<Pred, OpT, TupleT, Iter+1, End>(pred, op, tup);
533 }
534}
535
536template<class Pred, class OpT, typename TupleT, typename RetT, size_t Iter, size_t End>
537constexpr OPENVDB_FORCE_INLINE
538RetT TSEvalFirstPredImpl(
539 [[maybe_unused]] Pred pred,
540 [[maybe_unused]] OpT op,
541 [[maybe_unused]] TupleT& tup,
542 RetT def)
543{
544 if constexpr (Iter<End) {
545 constexpr auto Idx = std::integral_constant<std::size_t, Iter>();
546 if (pred(Idx)) return op(std::get<Idx>(tup));
547 else return TSEvalFirstPredImpl
548 <Pred, OpT, TupleT, RetT, Iter+1, End>(pred, op, tup, def);
549 }
550 else return def;
551}
552
553} // namespace internal
554
555/// @endcond
556
557template<size_t Start, size_t End, typename OpT>
559{
560 typelist_internal::TSForEachIndexImpl<OpT, Start, End>(op);
561}
562
563template<size_t Start, size_t End, typename OpT, typename RetT>
564OPENVDB_TYPELIST_FORCE_INLINE RetT evalFirstIndex(OpT op, const RetT def = RetT())
565{
566 return typelist_internal::TSEvalFirstIndex<OpT, RetT, Start, End>(op, def);
567}
568
569/// @brief A list of types (not necessarily unique)
570/// @details Example:
571/// @code
572/// using MyTypes = openvdb::TypeList<int, float, int, double, float>;
573/// @endcode
574template<typename... Ts>
576{
577 /// The type of this list
578 using Self = TypeList;
579
580 using AsTupleList = TupleList<Ts...>;
581
582 /// @brief The number of types in the type list
583 static constexpr size_t Size = sizeof...(Ts);
584
585 /// @brief Access a particular element of this type list. If the index
586 /// is out of range, typelist_internal::NullType is returned.
587 template<size_t N>
588 using Get = typename typelist_internal::TSGetElementImpl<Self, N>::type;
589 using Front = Get<0>;
590 using Back = Get<Size-1>;
591
592 /// @brief True if this list contains the given type, false otherwise
593 /// @details Example:
594 /// @code
595 /// {
596 /// using IntTypes = openvdb::TypeList<Int16, Int32, Int64>;
597 /// using RealTypes = openvdb::TypeList<float, double>;
598 /// }
599 /// {
600 /// openvdb::TypeList<IntTypes>::Contains<Int32>; // true
601 /// openvdb::TypeList<RealTypes>::Contains<Int32>; // false
602 /// }
603 /// @endcode
604 template<typename T>
605 static constexpr bool Contains = typelist_internal::TSHasTypeImpl<Self, T>::Value;
606
607 /// @brief Returns the index of the first found element of the given type, -1 if
608 /// no matching element exists.
609 /// @details Example:
610 /// @code
611 /// {
612 /// using IntTypes = openvdb::TypeList<Int16, Int32, Int64>;
613 /// using RealTypes = openvdb::TypeList<float, double>;
614 /// }
615 /// {
616 /// const int64_t L1 = openvdb::TypeList<IntTypes>::Index<Int32>; // 1
617 /// const int64_t L2 = openvdb::TypeList<RealTypes>::Index<Int32>; // -1
618 /// }
619 /// @endcode
620 template<typename T>
621 static constexpr int64_t Index = typelist_internal::TSHasTypeImpl<Self, T>::Index;
622
623 /// @brief Remove any duplicate types from this TypeList by rotating the
624 /// next valid type left (maintains the order of other types). Optionally
625 /// combine the result with another TypeList.
626 /// @details Example:
627 /// @code
628 /// {
629 /// using Types = openvdb::TypeList<Int16, Int32, Int16, float, float, Int64>;
630 /// }
631 /// {
632 /// using UniqueTypes = Types::Unique<>; // <Int16, Int32, float, Int64>
633 /// }
634 /// @endcode
635 template<typename ListT = TypeList<>>
636 using Unique = typename typelist_internal::TSRecurseAppendUniqueImpl<ListT, Ts...>::type;
637
638 /// @brief Append types, or the members of another TypeList, to this list.
639 /// @warning Appending nested TypeList<> objects causes them to expand to
640 /// their contained list of types.
641 /// @details Example:
642 /// @code
643 /// {
644 /// using IntTypes = openvdb::TypeList<Int16, Int32, Int64>;
645 /// using RealTypes = openvdb::TypeList<float, double>;
646 /// using NumericTypes = IntTypes::Append<RealTypes>;
647 /// }
648 /// {
649 /// using IntTypes = openvdb::TypeList<Int16>::Append<Int32, Int64>;
650 /// using NumericTypes = IntTypes::Append<float>::Append<double>;
651 /// }
652 /// @endcode
653 template<typename... TypesToAppend>
654 using Append = typename typelist_internal::TSAppendImpl<Self, TypesToAppend...>::type;
655
656 /// @brief Remove all occurrences of one or more types, or the members of
657 /// another TypeList, from this list.
658 /// @details Example:
659 /// @code
660 /// {
661 /// using NumericTypes = openvdb::TypeList<float, double, Int16, Int32, Int64>;
662 /// using LongTypes = openvdb::TypeList<Int64, double>;
663 /// using ShortTypes = NumericTypes::Remove<LongTypes>; // float, Int16, Int32
664 /// }
665 /// @endcode
666 template<typename... TypesToRemove>
667 using Remove = typename typelist_internal::TSRemoveImpl<Self, TypesToRemove...>::type;
668
669 /// @brief Remove the first element of this type list. Has no effect if the
670 /// type list is already empty.
671 /// @details Example:
672 /// @code
673 /// {
674 /// using IntTypes = openvdb::TypeList<Int16, Int32, Int64>;
675 /// using EmptyTypes = openvdb::TypeList<>;
676 /// }
677 /// {
678 /// IntTypes::PopFront; // openvdb::TypeList<Int32, Int64>;
679 /// EmptyTypes::PopFront; // openvdb::TypeList<>;
680 /// }
681 /// @endcode
682 using PopFront = typename typelist_internal::TSRemoveFirstImpl<Self>::type;
683
684 /// @brief Remove the last element of this type list. Has no effect if the
685 /// type list is already empty.
686 /// @details Example:
687 /// @code
688 /// {
689 /// using IntTypes = openvdb::TypeList<Int16, Int32, Int64>;
690 /// using EmptyTypes = openvdb::TypeList<>;
691 /// }
692 /// {
693 /// IntTypes::PopBack; // openvdb::TypeList<Int16, Int32>;
694 /// EmptyTypes::PopBack; // openvdb::TypeList<>;
695 /// }
696 /// @endcode
697 using PopBack = typename typelist_internal::TSRemoveLastImpl<Self>::type;
698
699 /// @brief Return a new list with types removed by their location within the list.
700 /// If First is equal to Last, a single element is removed (if it exists).
701 /// If First is greater than Last, the list remains unmodified.
702 /// @details Example:
703 /// @code
704 /// {
705 /// using NumericTypes = openvdb::TypeList<float, double, Int16, Int32, Int64>;
706 /// }
707 /// {
708 /// using IntTypes = NumericTypes::RemoveByIndex<0,1>; // openvdb::TypeList<Int16, Int32, Int64>;
709 /// using RealTypes = NumericTypes::RemoveByIndex<2,4>; // openvdb::TypeList<float, double>;
710 /// using RemoveFloat = NumericTypes::RemoveByIndex<0,0>; // openvdb::TypeList<double, Int16, Int32, Int64>;
711 /// }
712 /// @endcode
713 template <size_t First, size_t Last>
714 using RemoveByIndex = typename typelist_internal::TSRemoveIndicesImpl<Self, First, Last>::type;
715
716 /// @brief Transform each type of this TypeList, rebuiling a new list of
717 /// converted types. This method instantiates a user provided Opt<T> to
718 /// replace each type in the current list.
719 /// @warning Transforming types to new TypeList<> objects causes them to expand to
720 /// their contained list of types.
721 /// @details Example:
722 /// @code
723 /// {
724 /// // Templated type decl, where the type T will be subsituted for each type
725 /// // in the TypeList being transformed.
726 /// template <typename T>
727 /// using ConvertedType = typename openvdb::PromoteType<T>::Next;
728 ///
729 /// // Results in: openvdb::TypeList<Int64, double>;
730 /// using PromotedType = openvdb::TypeList<Int32, float>::Transform<ConvertedType>;
731 /// }
732 /// @endcode
733 template<template <typename> class OpT>
734 using Transform = typename typelist_internal::TSTranformImpl<OpT, Ts...>::type;
735
736 /// @brief Invoke a templated class operator on each type in this list. Use
737 /// this method if you only need access to the type for static methods.
738 /// @details Example:
739 /// @code
740 /// #include <typeinfo>
741 ///
742 /// template <typename T>
743 /// struct PintTypes() {
744 /// inline void operator()() { std::cout << typeid(T).name() << std::endl; }
745 /// };
746 ///
747 /// using MyTypes = openvdb::TypeList<int, float, double>;
748 /// MyTypes::foreach<PintTypes>(); // "i, f, d" (exact output is compiler-dependent)
749 /// @endcode
750 ///
751 /// @note OpT must be a templated class. It is created and invoked for each
752 /// type in this list.
753 template<template <typename> class OpT>
754 static OPENVDB_TYPELIST_FORCE_INLINE void foreach() {
755 typelist_internal::TSForEachImpl<OpT, Ts...>();
756 }
757
758 /// @brief Invoke a templated, unary functor on a value of each type in this list.
759 /// @details Example:
760 /// @code
761 /// #include <typeinfo>
762 ///
763 /// template<typename ListT>
764 /// void printTypeList()
765 /// {
766 /// std::string sep;
767 /// auto op = [&](auto x) { // C++14
768 /// std::cout << sep << typeid(decltype(x)).name(); sep = ", "; };
769 /// ListT::foreach(op);
770 /// }
771 ///
772 /// using MyTypes = openvdb::TypeList<int, float, double>;
773 /// printTypeList<MyTypes>(); // "i, f, d" (exact output is compiler-dependent)
774 /// @endcode
775 ///
776 /// @note The functor object is passed by value. Wrap it with @c std::ref
777 /// to use the same object for each type.
778 template<typename OpT>
779 static OPENVDB_TYPELIST_FORCE_INLINE void foreach(OpT op) {
780 typelist_internal::TSForEachImpl<OpT, Ts...>(op);
781 }
782
783 template<typename OpT>
787
788 template<typename OpT, typename RetT>
789 static OPENVDB_TYPELIST_FORCE_INLINE RetT foreachIndex(OpT op, RetT def) {
790 return foreachIndex<OpT, RetT, 0, Size>(op, def);
791 }
792
793 /// @brief Invoke a templated, unary functor on a provide @c obj of type
794 /// @c BaseT only if said object is an applicable (derived) type
795 /// also contained in the current @c TypeList.
796 /// @details This method loops over every type in the type list and calls
797 /// an interface method on @c obj to check to see if the @c obj is
798 /// interpretable as the given type. If it is, the method static casts
799 /// @c obj to the type, invokes the provided functor with the casted type
800 /// and returns, stopping further list iteration. @c obj is expected to
801 /// supply an interface to validate the type which satisfies the
802 /// prototype:
803 /// @code
804 /// template <typename T> bool isType()
805 /// @endcode
806 ///
807 /// A full example (using dynamic_cast - see Grid/Tree implementations
808 /// for string based comparisons:
809 /// @code
810 /// struct Base {
811 /// virtual ~Base() = default;
812 /// template<typename T> bool isType() { return dynamic_cast<const T*>(this); }
813 /// };
814 /// struct MyType1 : public Base { void print() { std::cerr << "MyType1" << std::endl; } };
815 /// struct MyType2 : public Base { void print() { std::cerr << "MyType2" << std::endl; } };
816 ///
817 /// using MyTypeList = TypeList<MyType1, MyType2>;
818 /// Base* getObj() { return new MyType2(); }
819 ///
820 /// std::unique_ptr<Base> obj = getObj();
821 /// // Returns 'true', prints 'MyType2'
822 /// const bool success =
823 /// MyTypeList::apply([](const auto& type) { type.print(); }, *obj);
824 /// @endcode
825 ///
826 /// @note The functor object is passed by value. Wrap it with @c std::ref
827 /// pass by reference.
828 template<typename OpT, typename BaseT>
829 static OPENVDB_TYPELIST_FORCE_INLINE bool apply(OpT op, BaseT& obj) {
830 return typelist_internal::TSApplyImpl<OpT, BaseT, Self>::apply(obj, op);
831 }
832};
833
834/// @brief A trivial wrapper around a std::tuple but with compatible TypeList
835/// methods. Importantly can be instatiated from a TypeList and implements a
836/// similar ::foreach interface
837/// @warning Some member methods here run on actual instances of types in the
838/// list. As such, it's unlikely that they can always be resolved at compile
839/// time (unlike methods in TypeList). Compilers are notriously bad at
840/// automatically inlining recursive/nested template instations (without fine
841/// tuning inline options to the frontend) so the public API of this class is
842/// marked as force inlined. You can disable this behaviour by defining:
843/// OPENVDB_TYPELIST_NO_FORCE_INLINE
844/// before including this header. Note however that the ValueAccessor uses
845/// this API and disabling force inlining can cause significant performance
846/// degredation.
847template<typename... Ts>
849{
850 using AsTypeList = TypeList<Ts...>;
851 using TupleT = std::tuple<Ts...>;
852
853 TupleList() = default;
854 TupleList(Ts&&... args) : mTuple(std::forward<Ts>(args)...) {}
855
856 constexpr auto size() { return std::tuple_size_v<TupleT>; }
857 constexpr TupleT& tuple() { return mTuple; }
858 constexpr TupleT& tuple() const { return mTuple; }
859
860 template <size_t Idx> constexpr auto& get() { return std::get<Idx>(mTuple); }
861 template <size_t Idx> constexpr auto& get() const { return std::get<Idx>(mTuple); }
862
863 /// @brief Run a function on each type instance in the underlying
864 /// std::tuple. Effectively calls op(std::get<I>(mTuple)) where
865 /// I = [0,Size). Does not support returning a value.
866 ///
867 /// @param op Function to run on each type
868 /// @details Example:
869 /// @code
870 /// {
871 /// using Types = openvdb::TypeList<Int32, float, std::string>;
872 /// }
873 /// {
874 /// Types::AsTupleList tuple(Int32(1), float(3.3), std::string("foo"));
875 /// tuple.foreach([](auto value) { std::cout << value << ' '; }); // prints '1 3.3 foo'
876 /// }
877 /// @endcode
878 template<typename OpT>
879 OPENVDB_TYPELIST_FORCE_INLINE constexpr void foreach(OpT op) {
880 typelist_internal::TSForEachImpl<0, AsTypeList::Size>(op, mTuple);
881 }
882
883 /// @brief Run a function on the first element in the underlying
884 /// std::tuple that satisfies the provided predicate. Effectively
885 /// calls op(std::get<I>(mTuple)) when pred(I) returns true, then exits,
886 /// where I = [0,Size). Does not support returning a value.
887 /// @note This is mainly useful to avoid the overhead of calling std::get<I>
888 /// on every element when only a single unknown element needs processing.
889 ///
890 /// @param pred Predicate to run on each index, should return true/false
891 /// @param op Function to run on the first element that satisfies pred
892 /// @details Example:
893 /// @code
894 /// {
895 /// using Types = openvdb::TypeList<Int32, float, std::string>;
896 /// }
897 /// {
898 /// Types::AsTupleList tuple(Int32(1), float(3.3), std::string("foo"));
899 /// bool runtimeFlags[tuple.size()] = { .... } // some runtime flags
900 /// tuple.foreach(
901 /// [&](auto Idx) { return runtimeFlags[Idx]; },
902 /// [](auto value) { std::cout << value << std::endl; }
903 /// );
904 /// }
905 /// @endcode
906 template<class Pred, class OpT>
908 {
909 typelist_internal::TSEvalFirstPredImpl
910 <Pred, OpT, TupleT, 0, AsTypeList::Size>
911 (pred, op, mTuple);
912 }
913
914 /// @brief Run a function on the first element in the underlying
915 /// std::tuple that satisfies the provided predicate. Effectively
916 /// calls op(std::get<I>(mTuple)) when pred(I) returns true, then exits,
917 /// where I = [0,Size). Supports returning a value, but a default return
918 /// value must be provided.
919 ///
920 /// @param pred Predicate to run on each index, should return true/false
921 /// @param op Function to run on the first element that satisfies pred
922 /// @param def Default return value
923 /// @details Example:
924 /// @code
925 /// {
926 /// using Types = openvdb::TypeList<Int32, float, std::string>;
927 /// }
928 /// {
929 /// Types::AsTupleList tuple(Int32(1), float(3.3), std::string("foo"));
930 /// // returns 3
931 /// auto size = tuple.foreach(
932 /// [](auto Idx) { return std::is_same<std::string, Types::template Get<Idx>>::value; },
933 /// [](auto value) { return value.size(); },
934 /// -1
935 /// );
936 /// }
937 /// @endcode
938 template<class Pred, class OpT, typename RetT>
939 OPENVDB_TYPELIST_FORCE_INLINE RetT evalFirstPred(Pred pred, OpT op, RetT def)
940 {
941 return typelist_internal::TSEvalFirstPredImpl
942 <Pred, OpT, TupleT, RetT, 0, AsTypeList::Size>
943 (pred, op, mTuple, def);
944 }
945
946private:
947 TupleT mTuple;
948};
949
950/// @brief Specilization of an empty TupleList. Required due to constructor
951/// selection.
952template<>
953struct TupleList<>
954{
956 using TupleT = std::tuple<>;
957
958 TupleList() = default;
959
960 constexpr auto size() { return std::tuple_size_v<TupleT>; }
961 inline TupleT& tuple() { return mTuple; }
962 inline const TupleT& tuple() const { return mTuple; }
963
964 template <size_t Idx> inline constexpr auto& get() { return std::get<Idx>(mTuple); }
965 template <size_t Idx> inline constexpr auto& get() const { return std::get<Idx>(mTuple); }
966
967 template<typename OpT> constexpr void foreach(OpT) {}
968 template<class Pred, class OpT> constexpr void evalFirstPred(Pred, OpT) {}
969 template<class Pred, class OpT, typename RetT>
970 constexpr RetT evalFirstPred(Pred, OpT, RetT def) { return def; }
971
972private:
973 TupleT mTuple;
974};
975
976} // namespace OPENVDB_VERSION_NAME
977} // namespace openvdb
978
979
980#endif // OPENVDB_TYPELIST_HAS_BEEN_INCLUDED
#define OPENVDB_FORCE_INLINE
Definition Platform.h:126
#define OPENVDB_TYPELIST_FORCE_INLINE
Definition TypeList.h:31
OPENVDB_FORCE_INLINE auto foreachIndex(OpT op)
Definition TypeList.h:558
OPENVDB_FORCE_INLINE RetT evalFirstIndex(OpT op, const RetT def=RetT())
Definition TypeList.h:564
Definition Exceptions.h:13
Definition Coord.h:590
std::tuple<> TupleT
Definition TypeList.h:956
constexpr void evalFirstPred(Pred, OpT)
Definition TypeList.h:968
TupleT & tuple()
Definition TypeList.h:961
const TupleT & tuple() const
Definition TypeList.h:962
constexpr auto & get()
Definition TypeList.h:964
constexpr auto size()
Definition TypeList.h:960
constexpr auto & get() const
Definition TypeList.h:965
constexpr RetT evalFirstPred(Pred, OpT, RetT def)
Definition TypeList.h:970
TypeList<> AsTypeList
Definition TypeList.h:955
A trivial wrapper around a std::tuple but with compatible TypeList methods. Importantly can be instat...
Definition TypeList.h:849
std::tuple< Ts... > TupleT
Definition TypeList.h:851
constexpr TupleT & tuple()
Definition TypeList.h:857
constexpr auto & get()
Definition TypeList.h:860
constexpr auto size()
Definition TypeList.h:856
OPENVDB_FORCE_INLINE RetT evalFirstPred(Pred pred, OpT op, RetT def)
Run a function on the first element in the underlying std::tuple that satisfies the provided predicat...
Definition TypeList.h:939
OPENVDB_FORCE_INLINE void evalFirstPred(Pred pred, OpT op)
Run a function on the first element in the underlying std::tuple that satisfies the provided predicat...
Definition TypeList.h:907
constexpr TupleT & tuple() const
Definition TypeList.h:858
TupleList(Ts &&... args)
Definition TypeList.h:854
constexpr auto & get() const
Definition TypeList.h:861
TypeList< Ts... > AsTypeList
Definition TypeList.h:850
A list of types (not necessarily unique)
Definition TypeList.h:576
static constexpr bool Contains
Definition TypeList.h:605
typename typelist_internal::TSRemoveImpl< Self, TypesToRemove... >::type Remove
Definition TypeList.h:667
static constexpr int64_t Index
Definition TypeList.h:621
Get< 0 > Front
Definition TypeList.h:589
Get< Size-1 > Back
Definition TypeList.h:590
typename typelist_internal::TSGetElementImpl< Self, N >::type Get
Definition TypeList.h:588
typename typelist_internal::TSRemoveIndicesImpl< Self, First, Last >::type RemoveByIndex
Definition TypeList.h:714
typename typelist_internal::TSRecurseAppendUniqueImpl< ListT, Ts... >::type Unique
Definition TypeList.h:636
typename typelist_internal::TSRemoveFirstImpl< Self >::type PopFront
Definition TypeList.h:682
TupleList< Ts... > AsTupleList
Definition TypeList.h:580
static constexpr size_t Size
Definition TypeList.h:583
static OPENVDB_FORCE_INLINE void foreachIndex(OpT op)
Definition TypeList.h:784
typename typelist_internal::TSTranformImpl< OpT, Ts... >::type Transform
Definition TypeList.h:734
static OPENVDB_FORCE_INLINE RetT foreachIndex(OpT op, RetT def)
Definition TypeList.h:789
static OPENVDB_FORCE_INLINE bool apply(OpT op, BaseT &obj)
Invoke a templated, unary functor on a provide obj of type BaseT only if said object is an applicable...
Definition TypeList.h:829
typename typelist_internal::TSRemoveLastImpl< Self >::type PopBack
Definition TypeList.h:697
typename typelist_internal::TSAppendImpl< Self, TypesToAppend... >::type Append
Definition TypeList.h:654
TypeList Self
Definition TypeList.h:578
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition version.h.in:121
#define OPENVDB_USE_VERSION_NAMESPACE
Definition version.h.in:218