1 //============================================================================
2 //  Copyright (c) Kitware, Inc.
3 //  All rights reserved.
4 //  See LICENSE.txt for details.
5 //  This software is distributed WITHOUT ANY WARRANTY; without even
6 //  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
7 //  PURPOSE.  See the above copyright notice for more information.
8 //
9 //  Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
10 //  Copyright 2014 UT-Battelle, LLC.
11 //  Copyright 2014 Los Alamos National Security.
12 //
13 //  Under the terms of Contract DE-NA0003525 with NTESS,
14 //  the U.S. Government retains certain rights in this software.
15 //
16 //  Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
17 //  Laboratory (LANL), the U.S. Government retains certain rights in
18 //  this software.
19 //============================================================================
20 
21 #ifndef vtk_m_internal_ListTagDetail_h
22 #define vtk_m_internal_ListTagDetail_h
23 
24 #if !defined(vtk_m_ListTag_h) && !defined(VTKM_TEST_HEADER_BUILD)
25 #error ListTagDetail.h must be included from ListTag.h
26 #endif
27 
28 #include <vtkm/Types.h>
29 #include <vtkm/internal/brigand.hpp>
30 
31 namespace vtkm
32 {
33 namespace detail
34 {
35 
36 //-----------------------------------------------------------------------------
37 
38 /// Base class that all ListTag classes inherit from. Helps identify lists
39 /// in macros like VTKM_IS_LIST_TAG.
40 ///
41 struct ListRoot
42 {
43 };
44 
45 template <class... T>
46 using ListBase = brigand::list<T...>;
47 
48 /// list value that is used to represent a list actually matches all values
49 struct UniversalTag
50 {
51   //We never want this tag constructed, and by deleting the constructor
52   //we get an error when trying to use this class with ForEach.
53   UniversalTag() = delete;
54 };
55 
56 //-----------------------------------------------------------------------------
57 template <typename ListTag1, typename ListTag2>
58 struct ListJoin
59 {
60   using type = brigand::append<ListTag1, ListTag2>;
61 };
62 
63 template <typename ListTag>
64 struct ListJoin<vtkm::detail::ListBase<vtkm::detail::UniversalTag>, ListTag>
65 {
66   using type = vtkm::detail::ListBase<vtkm::detail::UniversalTag>;
67 };
68 
69 template <typename ListTag>
70 struct ListJoin<ListTag, vtkm::detail::ListBase<vtkm::detail::UniversalTag>>
71 {
72   using type = vtkm::detail::ListBase<vtkm::detail::UniversalTag>;
73 };
74 
75 //-----------------------------------------------------------------------------
76 template <typename Type, typename List>
77 struct ListContainsImpl;
78 
79 //-----------------------------------------------------------------------------
80 template <typename Type>
81 struct ListContainsImpl<Type, brigand::empty_sequence>
82 {
83   static constexpr bool value = false;
84 };
85 
86 //-----------------------------------------------------------------------------
87 template <typename Type>
88 struct ListContainsImpl<Type, brigand::list<vtkm::detail::UniversalTag>>
89 {
90   static constexpr bool value = true;
91 };
92 
93 //-----------------------------------------------------------------------------
94 template <typename Type, typename T1>
95 struct ListContainsImpl<Type, brigand::list<T1>>
96 {
97   static constexpr bool value = std::is_same<Type, T1>::value;
98 };
99 
100 //-----------------------------------------------------------------------------
101 template <typename Type, typename T1, typename T2>
102 struct ListContainsImpl<Type, brigand::list<T1, T2>>
103 {
104   static constexpr bool value = std::is_same<Type, T1>::value || std::is_same<Type, T2>::value;
105 };
106 
107 //-----------------------------------------------------------------------------
108 template <typename Type, typename T1, typename T2, typename T3>
109 struct ListContainsImpl<Type, brigand::list<T1, T2, T3>>
110 {
111   static constexpr bool value =
112     std::is_same<Type, T1>::value || std::is_same<Type, T2>::value || std::is_same<Type, T3>::value;
113 };
114 
115 //-----------------------------------------------------------------------------
116 template <typename Type, typename T1, typename T2, typename T3, typename T4>
117 struct ListContainsImpl<Type, brigand::list<T1, T2, T3, T4>>
118 {
119   static constexpr bool value = std::is_same<Type, T1>::value || std::is_same<Type, T2>::value ||
120     std::is_same<Type, T3>::value || std::is_same<Type, T4>::value;
121 };
122 
123 //-----------------------------------------------------------------------------
124 template <typename Type, typename List>
125 struct ListContainsImpl
126 {
127   using find_result = brigand::find<List, std::is_same<brigand::_1, Type>>;
128   using size = brigand::size<find_result>;
129   static constexpr bool value = (size::value != 0);
130 };
131 
132 //-----------------------------------------------------------------------------
133 template <class T, class U, class ListTag>
134 struct intersect_tags
135 {
136   using has_u = ListContainsImpl<U, ListTag>;
137   using type = typename std::conditional<has_u::value, brigand::push_back<T, U>, T>::type;
138 };
139 
140 //-----------------------------------------------------------------------------
141 template <typename ListTag1, typename ListTag2>
142 struct ListIntersect
143 {
144   using type =
145     brigand::fold<ListTag1,
146                   brigand::list<>,
147                   intersect_tags<brigand::_state, brigand::_element, brigand::pin<ListTag2>>>;
148 };
149 
150 template <typename ListTag>
151 struct ListIntersect<vtkm::detail::ListBase<vtkm::detail::UniversalTag>, ListTag>
152 {
153   using type = ListTag;
154 };
155 
156 template <typename ListTag>
157 struct ListIntersect<ListTag, vtkm::detail::ListBase<vtkm::detail::UniversalTag>>
158 {
159   using type = ListTag;
160 };
161 
162 template <typename SameListTag>
163 struct ListIntersect<SameListTag, SameListTag>
164 {
165   using type = SameListTag;
166 };
167 
168 template <typename Functor, typename... Args>
169 VTKM_CONT void ListForEachImpl(Functor&&, brigand::list<>, Args&&...)
170 {
171 }
172 
173 template <typename Functor, typename T1, typename... Args>
174 VTKM_CONT void ListForEachImpl(Functor&& f, brigand::list<T1>, Args&&... args)
175 {
176   f(T1{}, std::forward<Args>(args)...);
177 }
178 
179 template <typename Functor, typename T1, typename T2, typename... Args>
180 VTKM_CONT void ListForEachImpl(Functor&& f, brigand::list<T1, T2>, Args&&... args)
181 {
182   f(T1{}, std::forward<Args>(args)...);
183   f(T2{}, std::forward<Args>(args)...);
184 }
185 
186 template <typename Functor, typename T1, typename T2, typename T3, typename... Args>
187 VTKM_CONT void ListForEachImpl(Functor&& f, brigand::list<T1, T2, T3>, Args&&... args)
188 {
189   f(T1{}, std::forward<Args>(args)...);
190   f(T2{}, std::forward<Args>(args)...);
191   f(T3{}, std::forward<Args>(args)...);
192 }
193 
194 template <typename Functor,
195           typename T1,
196           typename T2,
197           typename T3,
198           typename T4,
199           typename... ArgTypes,
200           typename... Args>
201 VTKM_CONT void ListForEachImpl(Functor&& f,
202                                brigand::list<T1, T2, T3, T4, ArgTypes...>&&,
203                                Args&&... args)
204 {
205   f(T1{}, std::forward<Args>(args)...);
206   f(T2{}, std::forward<Args>(args)...);
207   f(T3{}, std::forward<Args>(args)...);
208   f(T4{}, std::forward<Args>(args)...);
209   ListForEachImpl(
210     std::forward<Functor>(f), brigand::list<ArgTypes...>{}, std::forward<Args>(args)...);
211 }
212 
213 template <typename R1, typename R2>
214 struct ListCrossProductImpl
215 {
216   // This is a lazy Cartesian product generator.
217   // This version was settled on as being the best default
218   // version as all compilers including Intel handle this
219   // implementation without issue for very large cross products
220   using type = brigand::reverse_fold<
221     brigand::list<R1, R2>,
222     brigand::list<brigand::list<>>,
223     brigand::lazy::join<brigand::lazy::transform<
224       brigand::_2,
225       brigand::defer<brigand::lazy::join<brigand::lazy::transform<
226         brigand::parent<brigand::_1>,
227         brigand::defer<brigand::bind<
228           brigand::list,
229           brigand::lazy::push_front<brigand::_1, brigand::parent<brigand::_1>>>>>>>>>>;
230 };
231 
232 //-----------------------------------------------------------------------------
233 template <typename List, typename Type>
234 struct ListAppendUniqueImpl
235 {
236   using type = typename std::conditional<ListContainsImpl<Type, List>::value,
237                                          List,
238                                          typename ListJoin<List, ListBase<Type>>::type>::type;
239 };
240 
241 } // namespace detail
242 
243 //-----------------------------------------------------------------------------
244 /// A basic tag for a list of typenames. This struct can be subclassed
245 /// and still behave like a list tag.
246 template <typename... ArgTypes>
247 struct ListTagBase : detail::ListRoot
248 {
249   using list = detail::ListBase<ArgTypes...>;
250 };
251 }
252 
253 #endif //vtk_m_internal_ListTagDetail_h
254