VTK-m  1.5
List.h
Go to the documentation of this file.
1 //============================================================================
2 // Copyright (c) Kitware, Inc.
3 // All rights reserved.
4 // See LICENSE.txt for details.
5 //
6 // This software is distributed WITHOUT ANY WARRANTY; without even
7 // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
8 // PURPOSE. See the above copyright notice for more information.
9 //============================================================================
10 #ifndef vtk_m_List_h
11 #define vtk_m_List_h
12 
13 #include <vtkm/Types.h>
14 
15 #include <vtkm/internal/brigand.hpp>
16 
17 namespace vtkm
18 {
19 
20 template <typename... Ts>
21 struct List
22 {
23 };
24 
25 namespace detail
26 {
27 
28 // This prototype is here to detect deprecated ListTag objects. When ListTags are removed, then
29 // this should be removed too.
30 struct ListRoot;
31 }
32 
33 namespace internal
34 {
35 
36 template <typename T>
37 struct IsListImpl
38 {
39  // This prototype is here to detect deprecated ListTag objects. When ListTags are removed, then
40  // this should be changed to be just std::false_type.
41  using type = std::is_base_of<vtkm::detail::ListRoot, T>;
42 };
43 
44 template <typename... Ts>
45 struct IsListImpl<vtkm::List<Ts...>>
46 {
47  using type = std::true_type;
48 };
49 
50 template <typename T>
51 using IsList = typename vtkm::internal::IsListImpl<T>::type;
52 
53 } // namespace internal
54 
60 #define VTKM_IS_LIST(type) \
61  VTKM_STATIC_ASSERT_MSG((::vtkm::internal::IsList<type>::value), \
62  "Provided type is not a valid VTK-m list type.")
63 
64 namespace detail
65 {
66 
68 struct UniversalTypeTag
69 {
70  //We never want this tag constructed, and by deleting the constructor
71  //we get an error when trying to use this class with ForEach.
72  UniversalTypeTag() = delete;
73 };
74 
75 } // namespace detail
76 
77 namespace internal
78 {
79 
80 // This is here so that the old (deprecated) `ListTag`s can convert themselves to the new
81 // `List` style and be operated on. When that deprecated functionality goes away, we can
82 // probably remove `AsList` and just operate directly on the `List`s.
83 template <typename T>
84 struct AsListImpl;
85 
86 template <typename... Ts>
87 struct AsListImpl<vtkm::List<Ts...>>
88 {
89  using type = vtkm::List<Ts...>;
90 };
91 
92 template <typename T>
93 using AsList = typename AsListImpl<T>::type;
94 }
95 
99 
104 
105 namespace detail
106 {
107 
108 template <typename T, template <typename...> class Target>
109 struct ListApplyImpl;
110 template <typename... Ts, template <typename...> class Target>
111 struct ListApplyImpl<vtkm::List<Ts...>, Target>
112 {
113  using type = Target<Ts...>;
114 };
115 // Cannot apply the universal list.
116 template <template <typename...> class Target>
117 struct ListApplyImpl<vtkm::ListUniversal, Target>;
118 
119 } // namespace detail
120 
126 template <typename List, template <typename...> class Target>
127 using ListApply = typename detail::ListApplyImpl<internal::AsList<List>, Target>::type;
128 
131 template <typename List>
132 using ListSize =
133  std::integral_constant<vtkm::IdComponent,
134  vtkm::IdComponent{ brigand::size<internal::AsList<List>>::value }>;
135 
140 template <typename List, vtkm::IdComponent Index>
141 using ListAt =
142  brigand::at<internal::AsList<List>, std::integral_constant<vtkm::IdComponent, Index>>;
143 
144 namespace detail
145 {
146 
147 // This find is roughly based on the brigand::find functionality. We don't use brigand::find
148 // because it has an apparent bug where if a list contains templated types, it trys to
149 // apply those types as predicates, which is wrong.
150 
151 template <vtkm::IdComponent NumSearched, typename Target, typename... Remaining>
152 struct FindFirstOfType;
153 
154 // Not found
155 template <vtkm::IdComponent NumSearched, typename Target>
156 struct FindFirstOfType<NumSearched, Target> : std::integral_constant<vtkm::IdComponent, -1>
157 {
158 };
159 
160 // Basic search next one
161 template <bool NextIsTarget, vtkm::IdComponent NumSearched, typename Target, typename... Remaining>
162 struct FindFirstOfCheckHead;
163 
164 template <vtkm::IdComponent NumSearched, typename Target, typename... Ts>
165 struct FindFirstOfCheckHead<true, NumSearched, Target, Ts...>
166  : std::integral_constant<vtkm::IdComponent, NumSearched>
167 {
168 };
169 
170 template <vtkm::IdComponent NumSearched, typename Target, typename Next, typename... Remaining>
171 struct FindFirstOfCheckHead<false, NumSearched, Target, Next, Remaining...>
172  : FindFirstOfCheckHead<std::is_same<Target, Next>::value, NumSearched + 1, Target, Remaining...>
173 {
174 };
175 
176 // Not found
177 template <vtkm::IdComponent NumSearched, typename Target>
178 struct FindFirstOfCheckHead<false, NumSearched, Target>
179  : std::integral_constant<vtkm::IdComponent, -1>
180 {
181 };
182 
183 template <vtkm::IdComponent NumSearched, typename Target, typename Next, typename... Remaining>
184 struct FindFirstOfType<NumSearched, Target, Next, Remaining...>
185  : FindFirstOfCheckHead<std::is_same<Target, Next>::value, NumSearched, Target, Remaining...>
186 {
187 };
188 
189 // If there are at least 6 entries, check the first 4 to quickly narrow down
190 template <bool OneInFirst4Matches, vtkm::IdComponent NumSearched, typename Target, typename... Ts>
191 struct FindFirstOfSplit4;
192 
193 template <vtkm::IdComponent NumSearched,
194  typename Target,
195  typename T0,
196  typename T1,
197  typename T2,
198  typename T3,
199  typename... Ts>
200 struct FindFirstOfSplit4<true, NumSearched, Target, T0, T1, T2, T3, Ts...>
201  : FindFirstOfCheckHead<std::is_same<Target, T0>::value, NumSearched, Target, T1, T2, T3>
202 {
203 };
204 
205 template <vtkm::IdComponent NumSearched,
206  typename Target,
207  typename T0,
208  typename T1,
209  typename T2,
210  typename T3,
211  typename T4,
212  typename... Ts>
213 struct FindFirstOfSplit4<false, NumSearched, Target, T0, T1, T2, T3, T4, Ts...>
214  : FindFirstOfCheckHead<std::is_same<Target, T4>::value, NumSearched + 4, Target, Ts...>
215 {
216 };
217 
218 template <vtkm::IdComponent NumSearched,
219  typename Target,
220  typename T0,
221  typename T1,
222  typename T2,
223  typename T3,
224  typename T4,
225  typename T5,
226  typename... Ts>
227 struct FindFirstOfType<NumSearched, Target, T0, T1, T2, T3, T4, T5, Ts...>
228  : FindFirstOfSplit4<(std::is_same<Target, T0>::value || std::is_same<Target, T1>::value ||
229  std::is_same<Target, T2>::value || std::is_same<Target, T3>::value),
230  NumSearched,
231  Target,
232  T0,
233  T1,
234  T2,
235  T3,
236  T4,
237  T5,
238  Ts...>
239 {
240 };
241 
242 // If there are at least 12 entries, check the first 8 to quickly narrow down
243 template <bool OneInFirst8Matches, vtkm::IdComponent NumSearched, typename Target, typename... Ts>
244 struct FindFirstOfSplit8;
245 
246 template <vtkm::IdComponent NumSearched,
247  typename Target,
248  typename T0,
249  typename T1,
250  typename T2,
251  typename T3,
252  typename T4,
253  typename T5,
254  typename T6,
255  typename T7,
256  typename... Ts>
257 struct FindFirstOfSplit8<true, NumSearched, Target, T0, T1, T2, T3, T4, T5, T6, T7, Ts...>
258  : FindFirstOfSplit4<(std::is_same<Target, T0>::value || std::is_same<Target, T1>::value ||
259  std::is_same<Target, T2>::value || std::is_same<Target, T3>::value),
260  NumSearched,
261  Target,
262  T0,
263  T1,
264  T2,
265  T3,
266  T4,
267  T5,
268  T6,
269  T7>
270 {
271 };
272 
273 template <vtkm::IdComponent NumSearched,
274  typename Target,
275  typename T0,
276  typename T1,
277  typename T2,
278  typename T3,
279  typename T4,
280  typename T5,
281  typename T6,
282  typename T7,
283  typename... Ts>
284 struct FindFirstOfSplit8<false, NumSearched, Target, T0, T1, T2, T3, T4, T5, T6, T7, Ts...>
285  : FindFirstOfType<NumSearched + 8, Target, Ts...>
286 {
287 };
288 
289 template <vtkm::IdComponent NumSearched,
290  typename Target,
291  typename T0,
292  typename T1,
293  typename T2,
294  typename T3,
295  typename T4,
296  typename T5,
297  typename T6,
298  typename T7,
299  typename T8,
300  typename T9,
301  typename T10,
302  typename T11,
303  typename... Ts>
304 struct FindFirstOfType<NumSearched, Target, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, Ts...>
305  : FindFirstOfSplit8<(std::is_same<Target, T0>::value || std::is_same<Target, T1>::value ||
306  std::is_same<Target, T2>::value || std::is_same<Target, T3>::value ||
307  std::is_same<Target, T4>::value || std::is_same<Target, T5>::value ||
308  std::is_same<Target, T6>::value || std::is_same<Target, T7>::value),
309  NumSearched,
310  Target,
311  T0,
312  T1,
313  T2,
314  T3,
315  T4,
316  T5,
317  T6,
318  T7,
319  T8,
320  T9,
321  T10,
322  T11,
323  Ts...>
324 {
325 };
326 
327 template <typename List, typename Target>
328 struct ListIndexOfImpl;
329 template <typename... Ts, typename Target>
330 struct ListIndexOfImpl<vtkm::List<Ts...>, Target>
331 {
332  using type = std::integral_constant<vtkm::IdComponent, FindFirstOfType<0, Target, Ts...>::value>;
333 };
334 template <typename Target>
335 struct ListIndexOfImpl<vtkm::ListUniversal, Target>
336 {
337  VTKM_STATIC_ASSERT_MSG((std::is_same<Target, void>::value && std::is_same<Target, int>::value),
338  "Cannot get indices in a universal list.");
339 };
340 
341 } // namespace detail
342 
348 template <typename List, typename T>
349 using ListIndexOf = typename detail::ListIndexOfImpl<internal::AsList<List>, T>::type;
350 
351 namespace detail
352 {
353 
354 template <typename List, typename T>
355 struct ListHasImpl
356 {
357  using type = std::integral_constant<bool, (vtkm::ListIndexOf<List, T>::value >= 0)>;
358 };
359 
360 template <typename T>
361 struct ListHasImpl<vtkm::ListUniversal, T>
362 {
363  using type = std::true_type;
364 };
365 
366 } // namespace detail
367 
372 template <typename List, typename T>
373 using ListHas = typename detail::ListHasImpl<internal::AsList<List>, T>::type;
374 
375 #if defined(VTKM_MSVC) && (_MSC_VER < 1911)
376 
377 // Alternate definition of ListAppend to get around an apparent issue with
378 // Visual Studio 2015.
379 namespace detail
380 {
381 
382 template <typename... Lists>
383 struct ListAppendImpl
384 {
385  using type = brigand::append<internal::AsList<Lists>...>;
386 };
387 
388 } // namespace detail
389 
390 template <typename... Lists>
391 using ListAppend = typename detail::ListAppendImpl<Lists...>::type;
392 
393 #else // Normal definition
394 
398 template <typename... Lists>
399 using ListAppend = brigand::append<internal::AsList<Lists>...>;
400 
401 #endif
402 
403 namespace detail
404 {
405 
406 template <bool Has, typename State, typename Element>
407 struct ListIntersectTagsChoose;
408 
409 template <typename State, typename Element>
410 struct ListIntersectTagsChoose<true, State, Element>
411 {
412  using type = brigand::push_back<State, Element>;
413 };
414 
415 template <typename State, typename Element>
416 struct ListIntersectTagsChoose<false, State, Element>
417 {
418  using type = State;
419 };
420 
421 template <class State, class Element, class List>
422 struct ListIntersectTags
423  : ListIntersectTagsChoose<vtkm::ListHas<List, Element>::value, State, Element>
424 {
425 };
426 
427 template <typename List1, typename List2>
428 struct ListIntersectImpl
429 {
430  VTKM_IS_LIST(List1);
431  VTKM_IS_LIST(List2);
432 
433  using type =
434  brigand::fold<List1,
435  vtkm::List<>,
436  ListIntersectTags<brigand::_state, brigand::_element, brigand::pin<List2>>>;
437 };
438 
439 template <typename List1>
440 struct ListIntersectImpl<List1, vtkm::ListUniversal>
441 {
442  VTKM_IS_LIST(List1);
443 
444  using type = List1;
445 };
446 template <typename List2>
447 struct ListIntersectImpl<vtkm::ListUniversal, List2>
448 {
449  VTKM_IS_LIST(List2);
450 
451  using type = List2;
452 };
453 template <>
454 struct ListIntersectImpl<vtkm::ListUniversal, vtkm::ListUniversal>
455 {
456  using type = vtkm::ListUniversal;
457 };
458 
459 } // namespace detail
460 
463 template <typename List1, typename List2>
464 using ListIntersect =
465  typename detail::ListIntersectImpl<internal::AsList<List1>, internal::AsList<List2>>::type;
466 
467 namespace detail
468 {
469 
470 template <typename T, template <typename> class Target>
471 struct ListTransformImpl;
472 template <typename... Ts, template <typename> class Target>
473 struct ListTransformImpl<vtkm::List<Ts...>, Target>
474 {
475  using type = vtkm::List<Target<Ts>...>;
476 };
477 // Cannot transform the universal list.
478 template <template <typename> class Target>
479 struct ListTransformImpl<vtkm::ListUniversal, Target>;
480 
481 } // namespace detail
482 
485 template <typename List, template <typename> class Transform>
486 using ListTransform = typename detail::ListTransformImpl<internal::AsList<List>, Transform>::type;
487 
500 template <typename List, template <typename> class Predicate>
501 using ListRemoveIf =
502  brigand::remove_if<internal::AsList<List>, brigand::bind<Predicate, brigand::_1>>;
503 
504 namespace detail
505 {
506 
507 // We want to use an initializer list as a trick to call a function once for each type, but
508 // an initializer list needs a type, so create wrapper function that returns a value.
510 template <typename Functor, typename... Args>
511 VTKM_EXEC_CONT inline bool ListForEachCallThrough(Functor&& f, Args&&... args)
512 {
513  f(std::forward<Args>(args)...);
514  return false; // Return value does not matter. Hopefully just thrown away.
515 }
516 
518 template <typename Functor, typename... Ts, typename... Args>
519 VTKM_EXEC_CONT void ListForEachImpl(Functor&& f, vtkm::List<Ts...>, Args&&... args)
520 {
522  "Cannot call ListFor on vtkm::ListUniversal.");
523  auto init_list = { ListForEachCallThrough(
524  std::forward<Functor>(f), Ts{}, std::forward<Args>(args)...)... };
525  (void)init_list;
526 }
527 
528 template <typename Functor, typename... Args>
529 VTKM_EXEC_CONT void ListForEachImpl(Functor&&, vtkm::ListEmpty, Args&&...)
530 {
531  // No types to run functor on.
532 }
533 
534 } // namespace detail
535 
539 template <typename Functor, typename List, typename... Args>
540 VTKM_EXEC_CONT void ListForEach(Functor&& f, List, Args&&... args)
541 {
542  detail::ListForEachImpl(
543  std::forward<Functor>(f), internal::AsList<List>{}, std::forward<Args>(args)...);
544 }
545 
546 namespace detail
547 {
548 
549 template <typename List1, typename List2>
550 struct ListCrossImpl
551 {
552  VTKM_IS_LIST(List1);
553  VTKM_IS_LIST(List2);
554 
555  // This is a lazy Cartesian product generator.
556  // This version was settled on as being the best default
557  // version as all compilers including Intel handle this
558  // implementation without issue for very large cross products
559  using type = brigand::reverse_fold<
562  brigand::lazy::join<brigand::lazy::transform<
563  brigand::_2,
564  brigand::defer<brigand::lazy::join<brigand::lazy::transform<
565  brigand::parent<brigand::_1>,
566  brigand::defer<brigand::bind<
567  vtkm::List,
568  brigand::lazy::push_front<brigand::_1, brigand::parent<brigand::_1>>>>>>>>>>;
569 };
570 
571 } // namespace detail
572 
577 template <typename List1, typename List2>
578 using ListCross =
579  typename detail::ListCrossImpl<internal::AsList<List1>, internal::AsList<List2>>::type;
580 
581 } // namespace vtkm
582 
583 #endif //vtk_m_List_h
vtkm::ListForEach
VTKM_EXEC_CONT void ListForEach(Functor &&f, List, Args &&... args)
For each typename represented by the list, call the functor with a default instance of that type.
Definition: List.h:540
vtkm::ListIntersect
typename detail::ListIntersectImpl< internal::AsList< List1 >, internal::AsList< List2 > >::type ListIntersect
Constructs a list containing types present in all lists.
Definition: List.h:465
vtkm
Groups connected points that have the same field value.
Definition: Algorithms.h:23
Types.h
VTKM_EXEC_CONT
#define VTKM_EXEC_CONT
Definition: ExportMacros.h:52
vtkm::IdComponent
vtkm::Int32 IdComponent
Represents a component ID (index of component in a vector).
Definition: Types.h:168
vtkm::ListHas
typename detail::ListHasImpl< internal::AsList< List >, T >::type ListHas
Checks to see if the given T is in the list pointed to by List.
Definition: List.h:373
vtkm::ListApply
typename detail::ListApplyImpl< internal::AsList< List >, Target >::type ListApply
Applies the list of types to a template.
Definition: List.h:127
vtkm::ListCross
typename detail::ListCrossImpl< internal::AsList< List1 >, internal::AsList< List2 > >::type ListCross
Generates a list that is the cross product of two input lists.
Definition: List.h:579
vtkm::ListUniversal
vtkm::List< detail::UniversalTypeTag > ListUniversal
A special tag for a list that represents holding all potential values.
Definition: List.h:103
vtkm::ListAt
brigand::at< internal::AsList< List >, std::integral_constant< vtkm::IdComponent, Index > > ListAt
Finds the type at the given index.
Definition: List.h:142
vtkm::ListAppend
brigand::append< internal::AsList< Lists >... > ListAppend
Concatinates a set of lists into a single list.
Definition: List.h:399
VTKM_STATIC_ASSERT_MSG
#define VTKM_STATIC_ASSERT_MSG(condition, message)
Definition: StaticAssert.h:18
vtkm::ListRemoveIf
brigand::remove_if< internal::AsList< List >, brigand::bind< Predicate, brigand::_1 > > ListRemoveIf
Takes an existing List and a predicate template that is applied to each type in the List.
Definition: List.h:502
vtkm::ListSize
std::integral_constant< vtkm::IdComponent, vtkm::IdComponent{ brigand::size< internal::AsList< List > >::value }> ListSize
Becomes an std::integral_constant containing the number of types in a list.
Definition: List.h:134
vtkm::ListIndexOf
typename detail::ListIndexOfImpl< internal::AsList< List >, T >::type ListIndexOf
Finds the index of a given type.
Definition: List.h:349
VTKM_IS_LIST
#define VTKM_IS_LIST(type)
Checks that the argument is a proper list.
Definition: List.h:60
vtkm::List
Definition: List.h:21
vtkm::ListTransform
typename detail::ListTransformImpl< internal::AsList< List >, Transform >::type ListTransform
Constructs a list containing all types in a source list applied to a transform template.
Definition: List.h:486
VTKM_SUPPRESS_EXEC_WARNINGS
#define VTKM_SUPPRESS_EXEC_WARNINGS
Definition: ExportMacros.h:53