@@ -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
@@ -425,7 +474,7 @@ struct TypeList
425474 // / }
426475 // / @endcode
427476 template <typename ListT = TypeList<>>
428- using Unique = typename typelist_internal::TSMakeUniqueImpl <ListT, Ts...>::type;
477+ using Unique = typename typelist_internal::TSRecurseAppendUniqueImpl <ListT, Ts...>::type;
429478
430479 // / @brief Append types, or the members of another TypeList, to this list.
431480 // / @details Example:
0 commit comments