OpenVDB 9.0.0
TypeList.h
Go to the documentation of this file.
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
20namespace openvdb {
22namespace OPENVDB_VERSION_NAME {
23
24/// @cond OPENVDB_DOCS_INTERNAL
25
26template<typename... Ts> struct TypeList; // forward declaration
27
28namespace 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.
34struct 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
43template<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
48template<typename... Ts, size_t Idx>
49struct 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
58template<typename... Ts, size_t Idx>
59struct 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
77template <typename ListT, typename T, size_t=0>
78struct 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
85template <typename T, size_t Idx>
86struct 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
98template <typename U, typename T, typename... Ts, size_t Idx>
99struct 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
107template <typename T, typename... Ts, size_t Idx>
108struct 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 Remove any duplicate types from a @c TypeList.
116/// @details This implementation effectively rebuilds a @c TypeList by starting
117/// with an empty @c TypeList and recursively defining an expanded
118/// @c TypeList for every type (first to last), only if the type does
119/// not already exist in the new @c TypeList. This has the effect of
120/// dropping all but the first of duplicate types.
121/// @note Each type must define a new instantiation of this object.
122/// @tparam ListT The starting @c TypeList, usually (but not limited to) an
123/// empty @c TypeList
124/// @tparam Ts The list of types to make unique
125template <typename ListT, typename... Ts>
126struct TSMakeUniqueImpl {
127 using type = ListT;
128};
129
130/// @brief Partial specialization for type packs, where by the next type @c U
131/// is checked in the existing type set @c Ts for duplication. If the
132/// type does not exist, it is added to the new @c TypeList definition,
133/// otherwise it is dropped. In either case, this class is recursively
134/// defined with the remaining types @c Us.
135/// @tparam Ts Current types in the @c TypeList
136/// @tparam U Type to check for duplication in @c Ts
137/// @tparam Us Remaining types
138template <typename... Ts, typename U, typename... Us>
139struct TSMakeUniqueImpl<TypeList<Ts...>, U, Us...>
140{
141 using type = typename std::conditional<
142 TSHasTypeImpl<TypeList<Ts...>, U>::Value,
143 typename TSMakeUniqueImpl<TypeList<Ts...>, Us...>::type,
144 typename TSMakeUniqueImpl<TypeList<Ts..., U>, Us...>::type >::type;
145};
146
147
148/// @brief Append any number of types to a @c TypeList
149/// @details Defines a new @c TypeList with the provided types appended
150/// @tparam ListT The @c TypeList to append to
151/// @tparam Ts Types to append
152template<typename ListT, typename... Ts> struct TSAppendImpl;
153
154/// @brief Partial specialization for a @c TypeList with a list of zero or more
155/// types to append
156/// @tparam Ts Current types within the @c TypeList
157/// @tparam OtherTs Other types to append
158template<typename... Ts, typename... OtherTs>
159struct TSAppendImpl<TypeList<Ts...>, OtherTs...> {
160 using type = TypeList<Ts..., OtherTs...>;
161};
162
163/// @brief Partial specialization for a @c TypeList with another @c TypeList.
164/// Appends the other TypeList's members.
165/// @tparam Ts Types within the first @c TypeList
166/// @tparam OtherTs Types within the second @c TypeList
167template<typename... Ts, typename... OtherTs>
168struct TSAppendImpl<TypeList<Ts...>, TypeList<OtherTs...>> {
169 using type = TypeList<Ts..., OtherTs...>;
170};
171
172
173/// @brief Remove all occurrences of type T from a @c TypeList
174/// @details Defines a new @c TypeList with the provided types removed
175/// @tparam ListT The @c TypeList
176/// @tparam T Type to remove
177template<typename ListT, typename T> struct TSEraseImpl;
178
179/// @brief Partial specialization for an empty @c TypeList
180/// @tparam T Type to remove, has no effect
181template<typename T>
182struct TSEraseImpl<TypeList<>, T> { using type = TypeList<>; };
183
184/// @brief Partial specialization where the currently evaluating type in a
185/// @c TypeList matches the type to remove. Recursively defines this
186/// implementation with the remaining types.
187/// @tparam Ts Unpacked types within the @c TypeList
188/// @tparam T Type to remove
189template<typename... Ts, typename T>
190struct TSEraseImpl<TypeList<T, Ts...>, T> {
191 using type = typename TSEraseImpl<TypeList<Ts...>, T>::type;
192};
193
194/// @brief Partial specialization where the currently evaluating type @c T2 in
195/// a @c TypeList does not match the type to remove @c T. Recursively
196/// defines this implementation with the remaining types.
197/// @tparam T2 Current type within the @c TypeList, which does not match @c T
198/// @tparam Ts Other types within the @c TypeList
199/// @tparam T Type to remove
200template<typename T2, typename... Ts, typename T>
201struct TSEraseImpl<TypeList<T2, Ts...>, T> {
202 using type = typename TSAppendImpl<TypeList<T2>,
203 typename TSEraseImpl<TypeList<Ts...>, T>::type>::type;
204};
205
206/// @brief Front end implementation to call TSEraseImpl which removes all
207/// occurrences of a type from a @c TypeList. This struct handles the
208/// case where the type to remove is another @c TypeList, in which case
209/// all types in the second @c TypeList are removed from the first.
210/// @tparam ListT The @c TypeList
211/// @tparam Ts Types in the @c TypeList
212template<typename ListT, typename... Ts> struct TSRemoveImpl;
213
214/// @brief Partial specialization when there are no types in the @c TypeList.
215/// @tparam ListT The @c TypeList
216template<typename ListT>
217struct TSRemoveImpl<ListT> { using type = ListT; };
218
219/// @brief Partial specialization when the type to remove @c T is not another
220/// @c TypeList. @c T is removed from the @c TypeList.
221/// @tparam ListT The @c TypeList
222/// @tparam T Type to remove
223/// @tparam Ts Types in the @c TypeList
224template<typename ListT, typename T, typename... Ts>
225struct TSRemoveImpl<ListT, T, Ts...> {
226 using type = typename TSRemoveImpl<typename TSEraseImpl<ListT, T>::type, Ts...>::type;
227};
228
229/// @brief Partial specialization when the type to remove is another
230/// @c TypeList. All types within the other type list are removed from
231/// the first list.
232/// @tparam ListT The @c TypeList
233/// @tparam Ts Types from the second @c TypeList to remove from the first
234template<typename ListT, typename... Ts>
235struct TSRemoveImpl<ListT, TypeList<Ts...>> {
236 using type = typename TSRemoveImpl<ListT, Ts...>::type;
237};
238
239/// @brief Remove the first element of a type list. If the list is empty,
240/// nothing is done. This base configuration handles the empty list.
241/// @note Much cheaper to instantiate than TSRemoveIndicesImpl
242/// @tparam T The @c TypeList
243template<typename T>
244struct TSRemoveFirstImpl {
245 using type = TypeList<>;
246};
247
248/// @brief Partial specialization for removing the first type of a @c TypeList
249/// when the list is not empty i.e. does that actual work.
250/// @tparam T The first type in the @c TypeList.
251/// @tparam Ts Remaining types in the @c TypeList
252template<typename T, typename... Ts>
253struct TSRemoveFirstImpl<TypeList<T, Ts...>> {
254 using type = TypeList<Ts...>;
255};
256
257
258/// @brief Remove the last element of a type list. If the list is empty,
259/// nothing is done. This base configuration handles the empty list.
260/// @note Cheaper to instantiate than TSRemoveIndicesImpl
261/// @tparam T The @c TypeList
262template<typename T>
263struct TSRemoveLastImpl { using type = TypeList<>; };
264
265/// @brief Partial specialization for removing the last type of a @c TypeList.
266/// This instance is instantiated when the @c TypeList contains a
267/// single type, or the primary struct which recursively removes types
268/// (see below) hits the last type. Evaluates the last type to the empty
269/// list (see above).
270/// @tparam T The last type in the @c TypeList
271template<typename T>
272struct TSRemoveLastImpl<TypeList<T>> : TSRemoveLastImpl<T> {};
273
274/// @brief Partial specialization for removing the last type of a @c TypeList
275/// with a type list size of two or more. Recursively defines this
276/// implementation with the remaining types, effectively rebuilding the
277/// @c TypeList until the last type is hit, which is dropped.
278/// @tparam T The current type in the @c TypeList
279/// @tparam Ts Remaining types in the @c TypeList
280template<typename T, typename... Ts>
281struct TSRemoveLastImpl<TypeList<T, Ts...>>
282{
283 using type =
284 typename TypeList<T>::template
285 Append<typename TSRemoveLastImpl<TypeList<Ts...>>::type>;
286};
287
288
289/// @brief Remove a number of types from a @c TypeList based on a @c First and
290/// @c Last index.
291/// @details Both indices are inclusive, such that when <tt>First == Last</tt>
292/// a single type is removed (assuming the index exists). If
293/// <tt>Last < First</tt>, nothing is done. Any indices which do not
294/// exist are ignored. If @c Last is greater than the number of types
295/// in the @c TypeList, all types from @c First to the end of the list
296/// are dropped.
297/// @tparam ListT The @c TypeList
298/// @tparam First The first index
299/// @tparam Last The last index
300/// @tparam Idx Internal counter for the current index
301template<typename ListT, size_t First, size_t Last, size_t Idx=0>
302struct TSRemoveIndicesImpl;
303
304/// @brief Partial specialization for an empty @c TypeList
305/// @tparam First The first index
306/// @tparam Last The last index
307/// @tparam Idx Internal counter for the current index
308template<size_t First, size_t Last, size_t Idx>
309struct TSRemoveIndicesImpl<TypeList<>, First, Last, Idx> {
310 using type = TypeList<>;
311};
312
313/// @brief Partial specialization for a @c TypeList containing a single element.
314/// @tparam T The last or only type in a @c TypeList
315/// @tparam First The first index
316/// @tparam Last The last index
317/// @tparam Idx Internal counter for the current index
318template<typename T, size_t First, size_t Last, size_t Idx>
319struct TSRemoveIndicesImpl<TypeList<T>, First, Last, Idx>
320{
321private:
322 static constexpr bool Remove = Idx >= First && Idx <= Last;
323public:
324 using type = typename std::conditional<Remove, TypeList<>, TypeList<T>>::type;
325};
326
327/// @brief Partial specialization for a @c TypeList containing two or more types.
328/// @details This implementation effectively rebuilds a @c TypeList by starting
329/// with an empty @c TypeList and recursively defining an expanded
330/// @c TypeList for every type (first to last), only if the type's
331/// index does not fall within the range of indices defines by
332/// @c First and @c Last. Recursively defines this implementation with
333/// all but the last type.
334/// @tparam T The currently evaluating type within a @c TypeList
335/// @tparam Ts Remaining types in the @c TypeList
336/// @tparam First The first index
337/// @tparam Last The last index
338/// @tparam Idx Internal counter for the current index
339template<typename T, typename... Ts, size_t First, size_t Last, size_t Idx>
340struct TSRemoveIndicesImpl<TypeList<T, Ts...>, First, Last, Idx>
341{
342private:
343 using ThisList = typename TSRemoveIndicesImpl<TypeList<T>, First, Last, Idx>::type;
344 using NextList = typename TSRemoveIndicesImpl<TypeList<Ts...>, First, Last, Idx+1>::type;
345public:
346 using type = typename ThisList::template Append<NextList>;
347};
348
349
350template<typename OpT> inline void TSForEachImpl(OpT) {}
351template<typename OpT, typename T, typename... Ts>
352inline void TSForEachImpl(OpT op) { op(T()); TSForEachImpl<OpT, Ts...>(op); }
353
354} // namespace internal
355
356/// @endcond
357
358
359/// @brief A list of types (not necessarily unique)
360/// @details Example:
361/// @code
362/// using MyTypes = openvdb::TypeList<int, float, int, double, float>;
363/// @endcode
364template<typename... Ts>
366{
367 /// The type of this list
368 using Self = TypeList;
369
370 /// @brief The number of types in the type list
371 static constexpr size_t Size = sizeof...(Ts);
372
373 /// @brief Access a particular element of this type list. If the index
374 /// is out of range, typelist_internal::NullType is returned.
375 template<size_t N>
376 using Get = typename typelist_internal::TSGetElementImpl<Self, N>::type;
377 using Front = Get<0>;
378 using Back = Get<Size-1>;
379
380 /// @brief True if this list contains the given type, false otherwise
381 /// @details Example:
382 /// @code
383 /// {
384 /// using IntTypes = openvdb::TypeList<Int16, Int32, Int64>;
385 /// using RealTypes = openvdb::TypeList<float, double>;
386 /// }
387 /// {
388 /// openvdb::TypeList<IntTypes>::Contains<Int32>; // true
389 /// openvdb::TypeList<RealTypes>::Contains<Int32>; // false
390 /// }
391 /// @endcode
392 template<typename T>
393 static constexpr bool Contains = typelist_internal::TSHasTypeImpl<Self, T>::Value;
394
395 /// @brief Returns the index of the first found element of the given type, -1 if
396 /// no matching element exists.
397 /// @details Example:
398 /// @code
399 /// {
400 /// using IntTypes = openvdb::TypeList<Int16, Int32, Int64>;
401 /// using RealTypes = openvdb::TypeList<float, double>;
402 /// }
403 /// {
404 /// const int64_t L1 = openvdb::TypeList<IntTypes>::Index<Int32>; // 1
405 /// const int64_t L2 = openvdb::TypeList<RealTypes>::Index<Int32>; // -1
406 /// }
407 /// @endcode
408 template<typename T>
410
411 /// @brief Remove any duplicate types from this TypeList by rotating the
412 /// next valid type left (maintains the order of other types). Optionally
413 /// combine the result with another TypeList.
414 /// @details Example:
415 /// @code
416 /// {
417 /// using Types = openvdb::TypeList<Int16, Int32, Int16, float, float, Int64>;
418 /// }
419 /// {
420 /// using UniqueTypes = Types::Unique<>; // <Int16, Int32, float, Int64>
421 /// }
422 /// @endcode
423 template<typename ListT = TypeList<>>
424 using Unique = typename typelist_internal::TSMakeUniqueImpl<ListT, Ts...>::type;
425
426 /// @brief Append types, or the members of another TypeList, to this list.
427 /// @details Example:
428 /// @code
429 /// {
430 /// using IntTypes = openvdb::TypeList<Int16, Int32, Int64>;
431 /// using RealTypes = openvdb::TypeList<float, double>;
432 /// using NumericTypes = IntTypes::Append<RealTypes>;
433 /// }
434 /// {
435 /// using IntTypes = openvdb::TypeList<Int16>::Append<Int32, Int64>;
436 /// using NumericTypes = IntTypes::Append<float>::Append<double>;
437 /// }
438 /// @endcode
439 template<typename... TypesToAppend>
440 using Append = typename typelist_internal::TSAppendImpl<Self, TypesToAppend...>::type;
441
442 /// @brief Remove all occurrences of one or more types, or the members of
443 /// another TypeList, from this list.
444 /// @details Example:
445 /// @code
446 /// {
447 /// using NumericTypes = openvdb::TypeList<float, double, Int16, Int32, Int64>;
448 /// using LongTypes = openvdb::TypeList<Int64, double>;
449 /// using ShortTypes = NumericTypes::Remove<LongTypes>; // float, Int16, Int32
450 /// }
451 /// @endcode
452 template<typename... TypesToRemove>
453 using Remove = typename typelist_internal::TSRemoveImpl<Self, TypesToRemove...>::type;
454
455 /// @brief Remove the first element of this type list. Has no effect if the
456 /// type list is already empty.
457 /// @details Example:
458 /// @code
459 /// {
460 /// using IntTypes = openvdb::TypeList<Int16, Int32, Int64>;
461 /// using EmptyTypes = openvdb::TypeList<>;
462 /// }
463 /// {
464 /// IntTypes::PopFront; // openvdb::TypeList<Int32, Int64>;
465 /// EmptyTypes::PopFront; // openvdb::TypeList<>;
466 /// }
467 /// @endcode
468 using PopFront = typename typelist_internal::TSRemoveFirstImpl<Self>::type;
469
470 /// @brief Remove the last element of this type list. Has no effect if the
471 /// type list is already empty.
472 /// @details Example:
473 /// @code
474 /// {
475 /// using IntTypes = openvdb::TypeList<Int16, Int32, Int64>;
476 /// using EmptyTypes = openvdb::TypeList<>;
477 /// }
478 /// {
479 /// IntTypes::PopBack; // openvdb::TypeList<Int16, Int32>;
480 /// EmptyTypes::PopBack; // openvdb::TypeList<>;
481 /// }
482 /// @endcode
483 using PopBack = typename typelist_internal::TSRemoveLastImpl<Self>::type;
484
485 /// @brief Return a new list with types removed by their location within the list.
486 /// If First is equal to Last, a single element is removed (if it exists).
487 /// If First is greater than Last, the list remains unmodified.
488 /// @details Example:
489 /// @code
490 /// {
491 /// using NumericTypes = openvdb::TypeList<float, double, Int16, Int32, Int64>;
492 /// }
493 /// {
494 /// using IntTypes = NumericTypes::RemoveByIndex<0,1>; // openvdb::TypeList<Int16, Int32, Int64>;
495 /// using RealTypes = NumericTypes::RemoveByIndex<2,4>; // openvdb::TypeList<float, double>;
496 /// using RemoveFloat = NumericTypes::RemoveByIndex<0,0>; // openvdb::TypeList<double, Int16, Int32, Int64>;
497 /// }
498 /// @endcode
499 template <size_t First, size_t Last>
500 using RemoveByIndex = typename typelist_internal::TSRemoveIndicesImpl<Self, First, Last>::type;
501
502 /// @brief Invoke a templated, unary functor on a value of each type in this list.
503 /// @details Example:
504 /// @code
505 /// #include <typeinfo>
506 ///
507 /// template<typename ListT>
508 /// void printTypeList()
509 /// {
510 /// std::string sep;
511 /// auto op = [&](auto x) { // C++14
512 /// std::cout << sep << typeid(decltype(x)).name(); sep = ", "; };
513 /// ListT::foreach(op);
514 /// }
515 ///
516 /// using MyTypes = openvdb::TypeList<int, float, double>;
517 /// printTypeList<MyTypes>(); // "i, f, d" (exact output is compiler-dependent)
518 /// @endcode
519 ///
520 /// @note The functor object is passed by value. Wrap it with @c std::ref
521 /// to use the same object for each type.
522 template<typename OpT>
523 static void foreach(OpT op) { typelist_internal::TSForEachImpl<OpT, Ts...>(op); }
524};
525
526
527} // namespace OPENVDB_VERSION_NAME
528} // namespace openvdb
529
530
531#endif // OPENVDB_TYPELIST_HAS_BEEN_INCLUDED
Index32 Index
Definition: Types.h:54
Definition: Exceptions.h:13
Definition: Coord.h:586
A list of types (not necessarily unique)
Definition: TypeList.h:366
typename typelist_internal::TSRemoveImpl< Self, TypesToRemove... >::type Remove
Remove all occurrences of one or more types, or the members of another TypeList, from this list.
Definition: TypeList.h:453
Get< 0 > Front
Definition: TypeList.h:377
Get< Size-1 > Back
Definition: TypeList.h:378
typename typelist_internal::TSGetElementImpl< Self, N >::type Get
Access a particular element of this type list. If the index is out of range, typelist_internal::NullT...
Definition: TypeList.h:376
typename typelist_internal::TSRemoveIndicesImpl< Self, First, Last >::type RemoveByIndex
Return a new list with types removed by their location within the list. If First is equal to Last,...
Definition: TypeList.h:500
typename typelist_internal::TSRemoveFirstImpl< Self >::type PopFront
Remove the first element of this type list. Has no effect if the type list is already empty.
Definition: TypeList.h:468
typename typelist_internal::TSRemoveLastImpl< Self >::type PopBack
Remove the last element of this type list. Has no effect if the type list is already empty.
Definition: TypeList.h:483
typename typelist_internal::TSAppendImpl< Self, TypesToAppend... >::type Append
Append types, or the members of another TypeList, to this list.
Definition: TypeList.h:440
typename typelist_internal::TSMakeUniqueImpl< ListT, Ts... >::type Unique
Remove any duplicate types from this TypeList by rotating the next valid type left (maintains the ord...
Definition: TypeList.h:424
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:116
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:202