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 #ifndef vtk_m_cont_ArrayHandleConcatenate_h
23 #define vtk_m_cont_ArrayHandleConcatenate_h
24 
25 #include <vtkm/cont/ArrayHandle.h>
26 
27 namespace vtkm
28 {
29 namespace cont
30 {
31 namespace internal
32 {
33 
34 template <typename PortalType1, typename PortalType2>
35 class VTKM_ALWAYS_EXPORT ArrayPortalConcatenate
36 {
37 public:
38   using ValueType = typename PortalType1::ValueType;
39 
40   VTKM_SUPPRESS_EXEC_WARNINGS
41   VTKM_EXEC_CONT
ArrayPortalConcatenate()42   ArrayPortalConcatenate()
43     : portal1()
44     , portal2()
45   {
46   }
47 
48   VTKM_EXEC_CONT
ArrayPortalConcatenate(const PortalType1 & p1,const PortalType2 & p2)49   ArrayPortalConcatenate(const PortalType1& p1, const PortalType2& p2)
50     : portal1(p1)
51     , portal2(p2)
52   {
53   }
54 
55   // Copy constructor
56   template <typename OtherP1, typename OtherP2>
ArrayPortalConcatenate(const ArrayPortalConcatenate<OtherP1,OtherP2> & src)57   VTKM_EXEC_CONT ArrayPortalConcatenate(const ArrayPortalConcatenate<OtherP1, OtherP2>& src)
58     : portal1(src.GetPortal1())
59     , portal2(src.GetPortal2())
60   {
61   }
62 
63   VTKM_EXEC_CONT
GetNumberOfValues()64   vtkm::Id GetNumberOfValues() const
65   {
66     return this->portal1.GetNumberOfValues() + this->portal2.GetNumberOfValues();
67   }
68 
69   VTKM_EXEC_CONT
Get(vtkm::Id index)70   ValueType Get(vtkm::Id index) const
71   {
72     if (index < this->portal1.GetNumberOfValues())
73       return this->portal1.Get(index);
74     else
75       return this->portal2.Get(index - this->portal1.GetNumberOfValues());
76   }
77 
78   VTKM_EXEC_CONT
Set(vtkm::Id index,const ValueType & value)79   void Set(vtkm::Id index, const ValueType& value) const
80   {
81     if (index < this->portal1.GetNumberOfValues())
82       this->portal1.Set(index, value);
83     else
84       this->portal2.Set(index - this->portal1.GetNumberOfValues(), value);
85   }
86 
87   VTKM_EXEC_CONT
GetPortal1()88   const PortalType1& GetPortal1() const { return this->portal1; }
89 
90   VTKM_EXEC_CONT
GetPortal2()91   const PortalType2& GetPortal2() const { return this->portal2; }
92 
93 private:
94   PortalType1 portal1;
95   PortalType2 portal2;
96 }; // class ArrayPortalConcatenate
97 
98 } // namespace internal
99 
100 template <typename ArrayHandleType1, typename ArrayHandleType2>
101 class StorageTagConcatenate
102 {
103 };
104 
105 namespace internal
106 {
107 
108 template <typename ArrayHandleType1, typename ArrayHandleType2>
109 class Storage<typename ArrayHandleType1::ValueType,
110               StorageTagConcatenate<ArrayHandleType1, ArrayHandleType2>>
111 {
112 public:
113   using ValueType = typename ArrayHandleType1::ValueType;
114   using PortalType = ArrayPortalConcatenate<typename ArrayHandleType1::PortalControl,
115                                             typename ArrayHandleType2::PortalControl>;
116   using PortalConstType = ArrayPortalConcatenate<typename ArrayHandleType1::PortalConstControl,
117                                                  typename ArrayHandleType2::PortalConstControl>;
118 
119   VTKM_CONT
Storage()120   Storage()
121     : valid(false)
122   {
123   }
124 
125   VTKM_CONT
Storage(const ArrayHandleType1 & a1,const ArrayHandleType2 & a2)126   Storage(const ArrayHandleType1& a1, const ArrayHandleType2& a2)
127     : array1(a1)
128     , array2(a2)
129     , valid(true){};
130 
131   VTKM_CONT
GetPortalConst()132   PortalConstType GetPortalConst() const
133   {
134     VTKM_ASSERT(this->valid);
135     return PortalConstType(this->array1.GetPortalConstControl(),
136                            this->array2.GetPortalConstControl());
137   }
138 
139   VTKM_CONT
GetPortal()140   PortalType GetPortal()
141   {
142     VTKM_ASSERT(this->valid);
143     return PortalType(this->array1.GetPortalControl(), this->array2.GetPortalControl());
144   }
145 
146   VTKM_CONT
GetNumberOfValues()147   vtkm::Id GetNumberOfValues() const
148   {
149     VTKM_ASSERT(this->valid);
150     return this->array1.GetNumberOfValues() + this->array2.GetNumberOfValues();
151   }
152 
153   VTKM_CONT
Allocate(vtkm::Id vtkmNotUsed (numberOfValues))154   void Allocate(vtkm::Id vtkmNotUsed(numberOfValues))
155   {
156     throw vtkm::cont::ErrorInternal("ArrayHandleConcatenate should not be allocated explicitly. ");
157   }
158 
159   VTKM_CONT
Shrink(vtkm::Id numberOfValues)160   void Shrink(vtkm::Id numberOfValues)
161   {
162     VTKM_ASSERT(this->valid);
163     if (numberOfValues < this->array1.GetNumberOfValues())
164     {
165       this->array1.Shrink(numberOfValues);
166       this->array2.Shrink(0);
167     }
168     else
169       this->array2.Shrink(numberOfValues - this->array1.GetNumberOfValues());
170   }
171 
172   VTKM_CONT
ReleaseResources()173   void ReleaseResources()
174   {
175     VTKM_ASSERT(this->valid);
176     this->array1.ReleaseResources();
177     this->array2.ReleaseResources();
178   }
179 
180   VTKM_CONT
GetArray1()181   const ArrayHandleType1& GetArray1() const
182   {
183     VTKM_ASSERT(this->valid);
184     return this->array1;
185   }
186 
187   VTKM_CONT
GetArray2()188   const ArrayHandleType2& GetArray2() const
189   {
190     VTKM_ASSERT(this->valid);
191     return this->array2;
192   }
193 
194 private:
195   ArrayHandleType1 array1;
196   ArrayHandleType2 array2;
197   bool valid;
198 }; // class Storage
199 
200 template <typename ArrayHandleType1, typename ArrayHandleType2, typename Device>
201 class ArrayTransfer<typename ArrayHandleType1::ValueType,
202                     StorageTagConcatenate<ArrayHandleType1, ArrayHandleType2>,
203                     Device>
204 {
205 public:
206   using ValueType = typename ArrayHandleType1::ValueType;
207 
208 private:
209   using StorageTag = StorageTagConcatenate<ArrayHandleType1, ArrayHandleType2>;
210   using StorageType = vtkm::cont::internal::Storage<ValueType, StorageTag>;
211 
212 public:
213   using PortalControl = typename StorageType::PortalType;
214   using PortalConstControl = typename StorageType::PortalConstType;
215 
216   using PortalExecution =
217     ArrayPortalConcatenate<typename ArrayHandleType1::template ExecutionTypes<Device>::Portal,
218                            typename ArrayHandleType2::template ExecutionTypes<Device>::Portal>;
219   using PortalConstExecution =
220     ArrayPortalConcatenate<typename ArrayHandleType1::template ExecutionTypes<Device>::PortalConst,
221                            typename ArrayHandleType2::template ExecutionTypes<Device>::PortalConst>;
222 
223   VTKM_CONT
ArrayTransfer(StorageType * storage)224   ArrayTransfer(StorageType* storage)
225     : array1(storage->GetArray1())
226     , array2(storage->GetArray2())
227   {
228   }
229 
230   VTKM_CONT
GetNumberOfValues()231   vtkm::Id GetNumberOfValues() const
232   {
233     return this->array1.GetNumberOfValues() + this->array2.GetNumberOfValues();
234   }
235 
236   VTKM_CONT
PrepareForInput(bool vtkmNotUsed (updateData))237   PortalConstExecution PrepareForInput(bool vtkmNotUsed(updateData))
238   {
239     return PortalConstExecution(this->array1.PrepareForInput(Device()),
240                                 this->array2.PrepareForInput(Device()));
241   }
242 
243   VTKM_CONT
PrepareForInPlace(bool vtkmNotUsed (updateData))244   PortalExecution PrepareForInPlace(bool vtkmNotUsed(updateData))
245   {
246     return PortalExecution(this->array1.PrepareForInPlace(Device()),
247                            this->array2.PrepareForInPlace(Device()));
248   }
249 
250   VTKM_CONT
PrepareForOutput(vtkm::Id vtkmNotUsed (numberOfValues))251   PortalExecution PrepareForOutput(vtkm::Id vtkmNotUsed(numberOfValues))
252   {
253     throw vtkm::cont::ErrorInternal("ArrayHandleConcatenate is derived and read-only. ");
254   }
255 
256   VTKM_CONT
RetrieveOutputData(StorageType * vtkmNotUsed (storage))257   void RetrieveOutputData(StorageType* vtkmNotUsed(storage)) const
258   {
259     // not need to implement
260   }
261 
262   VTKM_CONT
Shrink(vtkm::Id numberOfValues)263   void Shrink(vtkm::Id numberOfValues)
264   {
265     if (numberOfValues < this->array1.GetNumberOfValues())
266     {
267       this->array1.Shrink(numberOfValues);
268       this->array2.Shrink(0);
269     }
270     else
271       this->array2.Shrink(numberOfValues - this->array1.GetNumberOfValues());
272   }
273 
274   VTKM_CONT
ReleaseResources()275   void ReleaseResources()
276   {
277     this->array1.ReleaseResourcesExecution();
278     this->array2.ReleaseResourcesExecution();
279   }
280 
281 private:
282   ArrayHandleType1 array1;
283   ArrayHandleType2 array2;
284 };
285 }
286 }
287 } // namespace vtkm::cont::internal
288 
289 namespace vtkm
290 {
291 namespace cont
292 {
293 
294 template <typename ArrayHandleType1, typename ArrayHandleType2>
295 class ArrayHandleConcatenate
296   : public vtkm::cont::ArrayHandle<typename ArrayHandleType1::ValueType,
297                                    StorageTagConcatenate<ArrayHandleType1, ArrayHandleType2>>
298 {
299 public:
300   VTKM_ARRAY_HANDLE_SUBCLASS(
301     ArrayHandleConcatenate,
302     (ArrayHandleConcatenate<ArrayHandleType1, ArrayHandleType2>),
303     (vtkm::cont::ArrayHandle<typename ArrayHandleType1::ValueType,
304                              StorageTagConcatenate<ArrayHandleType1, ArrayHandleType2>>));
305 
306 protected:
307   using StorageType = vtkm::cont::internal::Storage<ValueType, StorageTag>;
308 
309 public:
310   VTKM_CONT
ArrayHandleConcatenate(const ArrayHandleType1 & array1,const ArrayHandleType2 & array2)311   ArrayHandleConcatenate(const ArrayHandleType1& array1, const ArrayHandleType2& array2)
312     : Superclass(StorageType(array1, array2))
313   {
314   }
315 };
316 
317 template <typename ArrayHandleType1, typename ArrayHandleType2>
make_ArrayHandleConcatenate(const ArrayHandleType1 & array1,const ArrayHandleType2 & array2)318 VTKM_CONT ArrayHandleConcatenate<ArrayHandleType1, ArrayHandleType2> make_ArrayHandleConcatenate(
319   const ArrayHandleType1& array1,
320   const ArrayHandleType2& array2)
321 {
322   return ArrayHandleConcatenate<ArrayHandleType1, ArrayHandleType2>(array1, array2);
323 }
324 }
325 } // namespace vtkm::cont
326 
327 //=============================================================================
328 // Specializations of serialization related classes
329 namespace vtkm
330 {
331 namespace cont
332 {
333 
334 template <typename AH1, typename AH2>
335 struct TypeString<vtkm::cont::ArrayHandleConcatenate<AH1, AH2>>
336 {
337   static VTKM_CONT const std::string& Get()
338   {
339     static std::string name =
340       "AH_Concatenate<" + TypeString<AH1>::Get() + "," + TypeString<AH2>::Get() + ">";
341     return name;
342   }
343 };
344 
345 template <typename AH1, typename AH2>
346 struct TypeString<
347   vtkm::cont::ArrayHandle<typename AH1::ValueType, vtkm::cont::StorageTagConcatenate<AH1, AH2>>>
348   : TypeString<vtkm::cont::ArrayHandleConcatenate<AH1, AH2>>
349 {
350 };
351 }
352 } // vtkm::cont
353 
354 namespace diy
355 {
356 
357 template <typename AH1, typename AH2>
358 struct Serialization<vtkm::cont::ArrayHandleConcatenate<AH1, AH2>>
359 {
360 private:
361   using Type = vtkm::cont::ArrayHandleConcatenate<AH1, AH2>;
362   using BaseType = vtkm::cont::ArrayHandle<typename Type::ValueType, typename Type::StorageTag>;
363 
364 public:
365   static VTKM_CONT void save(BinaryBuffer& bb, const BaseType& obj)
366   {
367     auto storage = obj.GetStorage();
368     diy::save(bb, storage.GetArray1());
369     diy::save(bb, storage.GetArray2());
370   }
371 
372   static VTKM_CONT void load(BinaryBuffer& bb, BaseType& obj)
373   {
374     AH1 array1;
375     AH2 array2;
376 
377     diy::load(bb, array1);
378     diy::load(bb, array2);
379 
380     obj = vtkm::cont::make_ArrayHandleConcatenate(array1, array2);
381   }
382 };
383 
384 template <typename AH1, typename AH2>
385 struct Serialization<
386   vtkm::cont::ArrayHandle<typename AH1::ValueType, vtkm::cont::StorageTagConcatenate<AH1, AH2>>>
387   : Serialization<vtkm::cont::ArrayHandleConcatenate<AH1, AH2>>
388 {
389 };
390 } // diy
391 
392 #endif //vtk_m_cont_ArrayHandleConcatenate_h
393