| 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 |