1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkScaledSOADataArrayTemplate.h
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 
16 #ifndef vtkScaledSOADataArrayTemplate_txx
17 #define vtkScaledSOADataArrayTemplate_txx
18 
19 #ifdef VTK_SCALED_SOA_DATA_ARRAY_TEMPLATE_INSTANTIATING
20 #define VTK_GDA_VALUERANGE_INSTANTIATING
21 #include "vtkDataArrayPrivate.txx"
22 #undef VTK_GDA_VALUERANGE_INSTANTIATING
23 #endif
24 
25 #include "vtkScaledSOADataArrayTemplate.h"
26 
27 #include "vtkArrayIteratorTemplate.h"
28 #include "vtkBuffer.h"
29 
30 #include <cassert>
31 
32 //-----------------------------------------------------------------------------
33 template <class ValueType>
New()34 vtkScaledSOADataArrayTemplate<ValueType>* vtkScaledSOADataArrayTemplate<ValueType>::New()
35 {
36   VTK_STANDARD_NEW_BODY(vtkScaledSOADataArrayTemplate<ValueType>);
37 }
38 
39 //-----------------------------------------------------------------------------
40 template <class ValueType>
vtkScaledSOADataArrayTemplate()41 vtkScaledSOADataArrayTemplate<ValueType>::vtkScaledSOADataArrayTemplate()
42   : AoSCopy(nullptr)
43   , Scale(1)
44 {
45 }
46 
47 //-----------------------------------------------------------------------------
48 template <class ValueType>
~vtkScaledSOADataArrayTemplate()49 vtkScaledSOADataArrayTemplate<ValueType>::~vtkScaledSOADataArrayTemplate()
50 {
51   for (size_t cc = 0; cc < this->Data.size(); ++cc)
52   {
53     this->Data[cc]->Delete();
54   }
55   this->Data.clear();
56   if (this->AoSCopy)
57   {
58     this->AoSCopy->Delete();
59     this->AoSCopy = nullptr;
60   }
61 }
62 
63 //-----------------------------------------------------------------------------
64 template <class ValueType>
SetNumberOfComponents(int val)65 void vtkScaledSOADataArrayTemplate<ValueType>::SetNumberOfComponents(int val)
66 {
67   this->GenericDataArrayType::SetNumberOfComponents(val);
68   size_t numComps = static_cast<size_t>(this->GetNumberOfComponents());
69   assert(numComps >= 1);
70   while (this->Data.size() > numComps)
71   {
72     this->Data.back()->Delete();
73     this->Data.pop_back();
74   }
75   while (this->Data.size() < numComps)
76   {
77     this->Data.push_back(vtkBuffer<ValueType>::New());
78   }
79 }
80 
81 //-----------------------------------------------------------------------------
82 template <class ValueType>
NewIterator()83 vtkArrayIterator* vtkScaledSOADataArrayTemplate<ValueType>::NewIterator()
84 {
85   vtkArrayIterator* iter = vtkArrayIteratorTemplate<ValueType>::New();
86   iter->Initialize(this);
87   return iter;
88 }
89 
90 //-----------------------------------------------------------------------------
91 template <class ValueType>
ShallowCopy(vtkDataArray * other)92 void vtkScaledSOADataArrayTemplate<ValueType>::ShallowCopy(vtkDataArray* other)
93 {
94   SelfType* o = SelfType::FastDownCast(other);
95   if (o)
96   {
97     this->Size = o->Size;
98     this->MaxId = o->MaxId;
99     this->SetName(o->Name);
100     this->SetNumberOfComponents(o->NumberOfComponents);
101     this->CopyComponentNames(o);
102     this->Scale = o->Scale;
103     assert(this->Data.size() == o->Data.size());
104     for (size_t cc = 0; cc < this->Data.size(); ++cc)
105     {
106       vtkBuffer<ValueType>* thisBuffer = this->Data[cc];
107       vtkBuffer<ValueType>* otherBuffer = o->Data[cc];
108       if (thisBuffer != otherBuffer)
109       {
110         thisBuffer->Delete();
111         this->Data[cc] = otherBuffer;
112         otherBuffer->Register(nullptr);
113       }
114     }
115     this->DataChanged();
116   }
117   else
118   {
119     this->Superclass::ShallowCopy(other);
120   }
121 }
122 
123 //-----------------------------------------------------------------------------
124 template <class ValueType>
InsertTuples(vtkIdType dstStart,vtkIdType n,vtkIdType srcStart,vtkAbstractArray * source)125 void vtkScaledSOADataArrayTemplate<ValueType>::InsertTuples(
126   vtkIdType dstStart, vtkIdType n, vtkIdType srcStart, vtkAbstractArray* source)
127 {
128   // First, check for the common case of typeid(source) == typeid(this). This
129   // way we don't waste time redoing the other checks in the superclass, and
130   // can avoid doing a dispatch for the most common usage of this method.
131   SelfType* other = vtkArrayDownCast<SelfType>(source);
132   if (!other)
133   {
134     // Let the superclass handle dispatch/fallback.
135     this->Superclass::InsertTuples(dstStart, n, srcStart, source);
136     return;
137   }
138 
139   if (n == 0)
140   {
141     return;
142   }
143 
144   int numComps = this->GetNumberOfComponents();
145   if (other->GetNumberOfComponents() != numComps)
146   {
147     vtkErrorMacro("Number of components do not match: Source: "
148       << other->GetNumberOfComponents() << " Dest: " << this->GetNumberOfComponents());
149     return;
150   }
151 
152   vtkIdType maxSrcTupleId = srcStart + n - 1;
153   vtkIdType maxDstTupleId = dstStart + n - 1;
154 
155   if (maxSrcTupleId >= other->GetNumberOfTuples())
156   {
157     vtkErrorMacro("Source array too small, requested tuple at index "
158       << maxSrcTupleId << ", but there are only " << other->GetNumberOfTuples()
159       << " tuples in the array.");
160     return;
161   }
162 
163   vtkIdType newSize = (maxDstTupleId + 1) * this->NumberOfComponents;
164   if (this->Size < newSize)
165   {
166     if (!this->Resize(maxDstTupleId + 1))
167     {
168       vtkErrorMacro("Resize failed.");
169       return;
170     }
171   }
172 
173   this->MaxId = std::max(this->MaxId, newSize - 1);
174 
175   std::vector<ValueType> vals(numComps);
176   for (vtkIdType i = 0; i < n; i++)
177   {
178     other->GetTypedTuple(i + srcStart, vals.data());
179     this->SetTypedTuple(i + dstStart, vals.data()); // will automatically scale data
180   }
181 }
182 
183 //-----------------------------------------------------------------------------
184 template <class ValueType>
FillTypedComponent(int compIdx,ValueType value)185 void vtkScaledSOADataArrayTemplate<ValueType>::FillTypedComponent(int compIdx, ValueType value)
186 {
187   ValueType* buffer = this->Data[compIdx]->GetBuffer();
188   value /= this->Scale;
189   std::fill(buffer, buffer + this->GetNumberOfTuples(), value);
190 }
191 
192 //-----------------------------------------------------------------------------
193 template <class ValueType>
SetArray(int comp,ValueType * array,vtkIdType size,bool updateMaxId,bool save,int deleteMethod)194 void vtkScaledSOADataArrayTemplate<ValueType>::SetArray(
195   int comp, ValueType* array, vtkIdType size, bool updateMaxId, bool save, int deleteMethod)
196 {
197   const int numComps = this->GetNumberOfComponents();
198   if (comp >= numComps || comp < 0)
199   {
200     vtkErrorMacro("Invalid component number '"
201       << comp
202       << "' specified. "
203          "Use `SetNumberOfComponents` first to set the number of components.");
204     return;
205   }
206 
207   this->Data[comp]->SetBuffer(array, size);
208 
209   if (deleteMethod == VTK_DATA_ARRAY_DELETE)
210   {
211     this->Data[comp]->SetFreeFunction(save != 0, ::operator delete[]);
212   }
213   else if (deleteMethod == VTK_DATA_ARRAY_ALIGNED_FREE)
214   {
215 #ifdef _WIN32
216     this->Data[comp]->SetFreeFunction(save != 0, _aligned_free);
217 #else
218     this->Data[comp]->SetFreeFunction(save != 0, free);
219 #endif
220   }
221   else if (deleteMethod == VTK_DATA_ARRAY_USER_DEFINED || deleteMethod == VTK_DATA_ARRAY_FREE)
222   {
223     this->Data[comp]->SetFreeFunction(save != 0, free);
224   }
225 
226   if (updateMaxId)
227   {
228     this->Size = numComps * size;
229     this->MaxId = this->Size - 1;
230   }
231   this->DataChanged();
232 }
233 
234 //-----------------------------------------------------------------------------
235 template <class ValueType>
SetArrayFreeFunction(void (* callback)(void *))236 void vtkScaledSOADataArrayTemplate<ValueType>::SetArrayFreeFunction(void (*callback)(void*))
237 {
238   const int numComps = this->GetNumberOfComponents();
239   for (int i = 0; i < numComps; ++i)
240   {
241     this->SetArrayFreeFunction(i, callback);
242   }
243 }
244 
245 //-----------------------------------------------------------------------------
246 template <class ValueType>
SetArrayFreeFunction(int comp,void (* callback)(void *))247 void vtkScaledSOADataArrayTemplate<ValueType>::SetArrayFreeFunction(
248   int comp, void (*callback)(void*))
249 {
250   const int numComps = this->GetNumberOfComponents();
251   if (comp >= numComps || comp < 0)
252   {
253     vtkErrorMacro("Invalid component number '"
254       << comp
255       << "' specified. "
256          "Use `SetNumberOfComponents` first to set the number of components.");
257     return;
258   }
259   this->Data[comp]->SetFreeFunction(false, callback);
260 }
261 
262 //-----------------------------------------------------------------------------
263 template <class ValueType>
264 typename vtkScaledSOADataArrayTemplate<ValueType>::ValueType*
GetComponentArrayPointer(int comp)265 vtkScaledSOADataArrayTemplate<ValueType>::GetComponentArrayPointer(int comp)
266 {
267   const int numComps = this->GetNumberOfComponents();
268   if (comp >= numComps || comp < 0)
269   {
270     vtkErrorMacro("Invalid component number '" << comp << "' specified.");
271     return nullptr;
272   }
273 
274   return this->Data[comp]->GetBuffer();
275 }
276 
277 //-----------------------------------------------------------------------------
278 template <class ValueType>
AllocateTuples(vtkIdType numTuples)279 bool vtkScaledSOADataArrayTemplate<ValueType>::AllocateTuples(vtkIdType numTuples)
280 {
281   for (size_t cc = 0, max = this->Data.size(); cc < max; ++cc)
282   {
283     if (!this->Data[cc]->Allocate(numTuples))
284     {
285       return false;
286     }
287   }
288   return true;
289 }
290 
291 //-----------------------------------------------------------------------------
292 template <class ValueType>
ReallocateTuples(vtkIdType numTuples)293 bool vtkScaledSOADataArrayTemplate<ValueType>::ReallocateTuples(vtkIdType numTuples)
294 {
295   for (size_t cc = 0, max = this->Data.size(); cc < max; ++cc)
296   {
297     if (!this->Data[cc]->Reallocate(numTuples))
298     {
299       return false;
300     }
301   }
302   return true;
303 }
304 
305 //-----------------------------------------------------------------------------
306 template <class ValueType>
GetVoidPointer(vtkIdType valueIdx)307 void* vtkScaledSOADataArrayTemplate<ValueType>::GetVoidPointer(vtkIdType valueIdx)
308 {
309   // Allow warnings to be silenced:
310   const char* silence = getenv("VTK_SILENCE_GET_VOID_POINTER_WARNINGS");
311   if (!silence)
312   {
313     vtkWarningMacro(<< "GetVoidPointer called. This is very expensive for "
314                        "non-array-of-structs subclasses, as the scalar array "
315                        "must be generated for each call. Using the "
316                        "vtkGenericDataArray API with vtkArrayDispatch are "
317                        "preferred. Define the environment variable "
318                        "VTK_SILENCE_GET_VOID_POINTER_WARNINGS to silence "
319                        "this warning. Additionally, for the vtkScaledSOADataArrayTemplate "
320                        "class we also set Scale to 1 since we've scaled how "
321                        "we're storing the data in memory now. ");
322   }
323 
324   size_t numValues = this->GetNumberOfValues();
325 
326   if (!this->AoSCopy)
327   {
328     this->AoSCopy = vtkBuffer<ValueType>::New();
329   }
330 
331   if (!this->AoSCopy->Allocate(static_cast<vtkIdType>(numValues)))
332   {
333     vtkErrorMacro(<< "Error allocating a buffer of " << numValues << " '"
334                   << this->GetDataTypeAsString() << "' elements.");
335     return nullptr;
336   }
337 
338   this->ExportToVoidPointer(static_cast<void*>(this->AoSCopy->GetBuffer()));
339 
340   // This is the hacky thing with this class that we now need to set the scale
341   // to 1 since we internally are storing the memory in an unscaled manner
342   this->Scale = 1.0;
343 
344   return static_cast<void*>(this->AoSCopy->GetBuffer() + valueIdx);
345 }
346 
347 //-----------------------------------------------------------------------------
348 template <class ValueType>
ExportToVoidPointer(void * voidPtr)349 void vtkScaledSOADataArrayTemplate<ValueType>::ExportToVoidPointer(void* voidPtr)
350 {
351   vtkIdType numTuples = this->GetNumberOfTuples();
352   if (this->NumberOfComponents * numTuples == 0)
353   {
354     // Nothing to do.
355     return;
356   }
357 
358   if (!voidPtr)
359   {
360     vtkErrorMacro(<< "Buffer is nullptr.");
361     return;
362   }
363 
364   ValueType* ptr = static_cast<ValueType*>(voidPtr);
365   for (vtkIdType t = 0; t < numTuples; ++t)
366   {
367     for (int c = 0; c < this->NumberOfComponents; ++c)
368     {
369       *ptr++ = this->Data[c]->GetBuffer()[t] * this->Scale;
370     }
371   }
372 }
373 
374 #endif
375