1 //=============================================================================
2 //
3 //  Copyright (c) Kitware, Inc.
4 //  All rights reserved.
5 //  See LICENSE.txt for details.
6 //
7 //  This software is distributed WITHOUT ANY WARRANTY; without even
8 //  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
9 //  PURPOSE.  See the above copyright notice for more information.
10 //
11 //  Copyright 2015 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
12 //  Copyright 2015 UT-Battelle, LLC.
13 //  Copyright 2015 Los Alamos National Security.
14 //
15 //  Under the terms of Contract DE-NA0003525 with NTESS,
16 //  the U.S. Government retains certain rights in this software.
17 //  Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
18 //  Laboratory (LANL), the U.S. Government retains certain rights in
19 //  this software.
20 //
21 //=============================================================================
22 
23 #ifndef vtk_m_cont_ArrayHandleReverse_h
24 #define vtk_m_cont_ArrayHandleReverse_h
25 
26 #include <vtkm/cont/ArrayHandle.h>
27 #include <vtkm/cont/ErrorBadType.h>
28 #include <vtkm/cont/ErrorBadValue.h>
29 
30 namespace vtkm
31 {
32 namespace cont
33 {
34 
35 namespace internal
36 {
37 
38 template <typename PortalType>
39 class VTKM_ALWAYS_EXPORT ArrayPortalReverse
40 {
41 public:
42   using ValueType = typename PortalType::ValueType;
43 
44   VTKM_EXEC_CONT
ArrayPortalReverse()45   ArrayPortalReverse()
46     : portal()
47   {
48   }
49 
50   VTKM_EXEC_CONT
ArrayPortalReverse(const PortalType & p)51   ArrayPortalReverse(const PortalType& p)
52     : portal(p)
53   {
54   }
55 
56   template <typename OtherPortal>
ArrayPortalReverse(const ArrayPortalReverse<OtherPortal> & src)57   VTKM_EXEC_CONT ArrayPortalReverse(const ArrayPortalReverse<OtherPortal>& src)
58     : portal(src.GetPortal())
59   {
60   }
61 
62   VTKM_EXEC_CONT
GetNumberOfValues()63   vtkm::Id GetNumberOfValues() const { return this->portal.GetNumberOfValues(); }
64 
65   VTKM_EXEC_CONT
Get(vtkm::Id index)66   ValueType Get(vtkm::Id index) const
67   {
68     return this->portal.Get(portal.GetNumberOfValues() - index - 1);
69   }
70 
71   VTKM_EXEC_CONT
Set(vtkm::Id index,const ValueType & value)72   void Set(vtkm::Id index, const ValueType& value) const
73   {
74     this->portal.Set(portal.GetNumberOfValues() - index - 1, value);
75   }
76 
77 private:
78   PortalType portal;
79 };
80 }
81 
82 template <typename ArrayHandleType>
83 class StorageTagReverse
84 {
85 };
86 
87 namespace internal
88 {
89 
90 template <typename ArrayHandleType>
91 class Storage<typename ArrayHandleType::ValueType, StorageTagReverse<ArrayHandleType>>
92 {
93 public:
94   using ValueType = typename ArrayHandleType::ValueType;
95   using PortalType = ArrayPortalReverse<typename ArrayHandleType::PortalControl>;
96   using PortalConstType = ArrayPortalReverse<typename ArrayHandleType::PortalConstControl>;
97 
98   VTKM_CONT
Storage()99   Storage()
100     : Array()
101   {
102   }
103 
104   VTKM_CONT
Storage(const ArrayHandleType & a)105   Storage(const ArrayHandleType& a)
106     : Array(a)
107   {
108   }
109 
110 
111   VTKM_CONT
GetPortalConst()112   PortalConstType GetPortalConst() const
113   {
114     return PortalConstType(this->Array.GetPortalConstControl());
115   }
116 
117   VTKM_CONT
GetPortal()118   PortalType GetPortal() { return PortalType(this->Array.GetPortalControl()); }
119 
120   VTKM_CONT
GetNumberOfValues()121   vtkm::Id GetNumberOfValues() const { return this->Array.GetNumberOfValues(); }
122 
123   VTKM_CONT
Allocate(vtkm::Id numberOfValues)124   void Allocate(vtkm::Id numberOfValues) { return this->Array.Allocate(numberOfValues); }
125 
126   VTKM_CONT
Shrink(vtkm::Id numberOfValues)127   void Shrink(vtkm::Id numberOfValues) { return this->Array.Shrink(numberOfValues); }
128 
129   VTKM_CONT
ReleaseResources()130   void ReleaseResources()
131   {
132     // This request is ignored since it is asking to release the resources
133     // of the delegate array, which may be used elsewhere. Should the behavior
134     // be different?
135   }
136 
137   VTKM_CONT
GetArray()138   const ArrayHandleType& GetArray() const { return this->Array; }
139 
140 private:
141   ArrayHandleType Array;
142 }; // class storage
143 
144 template <typename ArrayHandleType, typename Device>
145 class ArrayTransfer<typename ArrayHandleType::ValueType, StorageTagReverse<ArrayHandleType>, Device>
146 {
147 public:
148   using ValueType = typename ArrayHandleType::ValueType;
149 
150 private:
151   using StorageTag = StorageTagReverse<ArrayHandleType>;
152   using StorageType = vtkm::cont::internal::Storage<ValueType, StorageTag>;
153 
154 public:
155   using PortalControl = typename StorageType::PortalType;
156   using PortalConstControl = typename StorageType::PortalConstType;
157 
158   using PortalExecution =
159     ArrayPortalReverse<typename ArrayHandleType::template ExecutionTypes<Device>::Portal>;
160   using PortalConstExecution =
161     ArrayPortalReverse<typename ArrayHandleType::template ExecutionTypes<Device>::PortalConst>;
162 
163   VTKM_CONT
ArrayTransfer(StorageType * storage)164   ArrayTransfer(StorageType* storage)
165     : Array(storage->GetArray())
166   {
167   }
168 
169   VTKM_CONT
GetNumberOfValues()170   vtkm::Id GetNumberOfValues() const { return this->Array.GetNumberOfValues(); }
171 
172   VTKM_CONT
PrepareForInput(bool vtkmNotUsed (updateData))173   PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData))
174   {
175     return PortalConstExecution(this->Array.PrepareForInput(Device()));
176   }
177 
178   VTKM_CONT
PrepareForInPlace(bool vtkmNotUsed (updateData))179   PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData))
180   {
181     return PortalExecution(this->Array.PrepareForInPlace(Device()));
182   }
183 
184   VTKM_CONT
PrepareForOutput(vtkm::Id numberOfValues)185   PortalExecution PrepareForOutput(vtkm::Id numberOfValues)
186   {
187     return PortalExecution(this->Array.PrepareForOutput(numberOfValues, Device()));
188   }
189 
190   VTKM_CONT
RetrieveOutputData(StorageType * vtkmNotUsed (storage))191   void RetrieveOutputData(StorageType* vtkmNotUsed(storage)) const
192   {
193     // not need to implement
194   }
195 
196   VTKM_CONT
Shrink(vtkm::Id numberOfValues)197   void Shrink(vtkm::Id numberOfValues) { this->Array.Shrink(numberOfValues); }
198 
199   VTKM_CONT
ReleaseResources()200   void ReleaseResources() { this->Array.ReleaseResourcesExecution(); }
201 
202 private:
203   ArrayHandleType Array;
204 };
205 
206 } // namespace internal
207 
208 /// \brief Reverse the order of an array, on demand.
209 ///
210 /// ArrayHandleReverse is a specialization of ArrayHandle. Given an ArrayHandle,
211 /// it creates a new handle that returns the elements of the array in reverse
212 /// order (i.e. from end to beginning).
213 ///
214 template <typename ArrayHandleType>
215 class ArrayHandleReverse : public vtkm::cont::ArrayHandle<typename ArrayHandleType::ValueType,
216                                                           StorageTagReverse<ArrayHandleType>>
217 
218 {
219 public:
220   VTKM_ARRAY_HANDLE_SUBCLASS(ArrayHandleReverse,
221                              (ArrayHandleReverse<ArrayHandleType>),
222                              (vtkm::cont::ArrayHandle<typename ArrayHandleType::ValueType,
223                                                       StorageTagReverse<ArrayHandleType>>));
224 
225 protected:
226   using StorageType = vtkm::cont::internal::Storage<ValueType, StorageTag>;
227 
228 public:
ArrayHandleReverse(const ArrayHandleType & handle)229   ArrayHandleReverse(const ArrayHandleType& handle)
230     : Superclass(handle)
231   {
232   }
233 };
234 
235 /// make_ArrayHandleReverse is convenience function to generate an
236 /// ArrayHandleReverse.
237 ///
238 template <typename HandleType>
make_ArrayHandleReverse(const HandleType & handle)239 VTKM_CONT ArrayHandleReverse<HandleType> make_ArrayHandleReverse(const HandleType& handle)
240 {
241   return ArrayHandleReverse<HandleType>(handle);
242 }
243 }
244 } // namespace vtkm::cont
245 
246 //=============================================================================
247 // Specializations of serialization related classes
248 namespace vtkm
249 {
250 namespace cont
251 {
252 
253 template <typename AH>
254 struct TypeString<vtkm::cont::ArrayHandleReverse<AH>>
255 {
256   static VTKM_CONT const std::string& Get()
257   {
258     static std::string name = "AH_Reverse<" + TypeString<AH>::Get() + ">";
259     return name;
260   }
261 };
262 
263 template <typename AH>
264 struct TypeString<
265   vtkm::cont::ArrayHandle<typename AH::ValueType, vtkm::cont::StorageTagReverse<AH>>>
266   : TypeString<vtkm::cont::ArrayHandleReverse<AH>>
267 {
268 };
269 }
270 } // vtkm::cont
271 
272 namespace diy
273 {
274 
275 template <typename AH>
276 struct Serialization<vtkm::cont::ArrayHandleReverse<AH>>
277 {
278 private:
279   using Type = vtkm::cont::ArrayHandleReverse<AH>;
280   using BaseType = vtkm::cont::ArrayHandle<typename Type::ValueType, typename Type::StorageTag>;
281 
282 public:
283   static VTKM_CONT void save(BinaryBuffer& bb, const BaseType& obj)
284   {
285     diy::save(bb, obj.GetStorage().GetArray());
286   }
287 
288   static VTKM_CONT void load(BinaryBuffer& bb, BaseType& obj)
289   {
290     AH array;
291     diy::load(bb, array);
292     obj = vtkm::cont::make_ArrayHandleReverse(array);
293   }
294 };
295 
296 template <typename AH>
297 struct Serialization<
298   vtkm::cont::ArrayHandle<typename AH::ValueType, vtkm::cont::StorageTagReverse<AH>>>
299   : Serialization<vtkm::cont::ArrayHandleReverse<AH>>
300 {
301 };
302 
303 } // diy
304 
305 #endif // vtk_m_cont_ArrayHandleReverse_h
306