@@ -112,36 +112,85 @@ struct TSHasTypeImpl<TypeList<T, Ts...>, T, Idx>
112112};
113113
114114
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
125- template <typename ListT, typename ... Ts>
126- struct TSMakeUniqueImpl {
127- using type = ListT;
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;
128181};
129182
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
138- template <typename ... Ts, typename U, typename ... Us>
139- struct TSMakeUniqueImpl <TypeList<Ts...>, U, Us...>
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...>
140190{
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;
191+ using type = typename TSAppendUniqueImpl<U,
192+ typename TSRecurseAppendUniqueImpl<Ts...>::type
193+ >::type;
145194};
146195
147196
@@ -351,6 +400,10 @@ template<typename OpT> inline void TSForEachImpl(OpT) {}
351400template <typename OpT, typename T, typename ... Ts>
352401inline void TSForEachImpl (OpT op) { op (T ()); TSForEachImpl<OpT, Ts...>(op); }
353402
403+ template <template <typename > class OpT > inline void TSForEachImpl () {}
404+ template <template <typename > class OpT , typename T, typename ... Ts>
405+ inline void TSForEachImpl () { OpT<T>()(); TSForEachImpl<OpT, Ts...>(); }
406+
354407} // namespace internal
355408
356409// / @endcond
@@ -421,7 +474,7 @@ struct TypeList
421474 // / }
422475 // / @endcode
423476 template <typename ListT = TypeList<>>
424- using Unique = typename typelist_internal::TSMakeUniqueImpl <ListT, Ts...>::type;
477+ using Unique = typename typelist_internal::TSRecurseAppendUniqueImpl <ListT, Ts...>::type;
425478
426479 // / @brief Append types, or the members of another TypeList, to this list.
427480 // / @details Example:
@@ -499,6 +552,25 @@ struct TypeList
499552 template <size_t First, size_t Last>
500553 using RemoveByIndex = typename typelist_internal::TSRemoveIndicesImpl<Self, First, Last>::type;
501554
555+ // / @brief Invoke a templated class operator on each type in this list. Use
556+ // / this method if you only need access to the type for static methods.
557+ // / @code
558+ // / #include <typeinfo>
559+ // /
560+ // / template <typename T>
561+ // / struct PintTypes() {
562+ // / inline void operator()() { std::cout << typeid(T).name() << std::endl; }
563+ // / };
564+ // /
565+ // / using MyTypes = openvdb::TypeList<int, float, double>;
566+ // / MyTypes::foreach<PintTypes>(); // "i, f, d" (exact output is compiler-dependent)
567+ // / @endcode
568+ // /
569+ // / @note OpT must be a templated class. It is created and invoked for each
570+ // / type in this list.
571+ template <template <typename > class OpT >
572+ static void foreach () { typelist_internal::TSForEachImpl<OpT, Ts...>(); }
573+
502574 // / @brief Invoke a templated, unary functor on a value of each type in this list.
503575 // / @details Example:
504576 // / @code
0 commit comments