1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkCellArray.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  * @class   vtkCellArray
17  * @brief   object to represent cell connectivity
18  *
19  * vtkCellArray stores dataset topologies as an explicit connectivity table
20  * listing the point ids that make up each cell.
21  *
22  * Internally, the connectivity table is represented as two arrays: Offsets and
23  * Connectivity.
24  *
25  * Offsets is an array of [numCells+1] values indicating the index in the
26  * Connectivity array where each cell's points start. The last value is always
27  * the length of the Connectivity array.
28  *
29  * The Connectivity array stores the lists of point ids for each cell.
30  *
31  * Thus, for a dataset consisting of 2 triangles, a quad, and a line, the
32  * internal arrays will appear as follows:
33  *
34  * ```
35  * Topology:
36  * ---------
37  * Cell 0: Triangle | point ids: {0, 1, 2}
38  * Cell 1: Triangle | point ids: {5, 7, 2}
39  * Cell 2: Quad     | point ids: {3, 4, 6, 7}
40  * Cell 4: Line     | point ids: {5, 8}
41  *
42  * vtkCellArray (current):
43  * -----------------------
44  * Offsets:      {0, 3, 6, 10, 12}
45  * Connectivity: {0, 1, 2, 5, 7, 2, 3, 4, 6, 7, 5, 8}
46  * ```
47  *
48  * While this class provides traversal methods (the legacy InitTraversal(),
49  * GetNextCell() methods, and the newer method GetCellAtId()) these are in
50  * general not thread-safe. Whenever possible it is preferrable to use a
51  * local thread-safe, vtkCellArrayIterator object, which can be obtained via:
52  *
53  * ```
54  * auto iter = vtk::TakeSmartPointer(cellArray->NewIterator());
55  * for (iter->GoToFirstCell(); !iter->IsDoneWithTraversal(); iter->GoToNextCell())
56  * {
57  *   // do work with iter
58  * }
59  * ```
60  * (Note however that depending on the type and structure of internal
61  * storage, a cell array iterator may be significantly slower than direct
62  * traversal over the cell array due to extra data copying. Factors of 3-4X
63  * are not uncommon. See vtkCellArrayIterator for more information. Also note
64  * that an iterator may become invalid if the internal vtkCellArray storage
65  * is modified.)
66  *
67  * Other methods are also available for allocation and memory-related
68  * management; insertion of new cells into the vtkCellArray; and limited
69  * editing operations such as replacing one cell with a new cell of the
70  * same size.
71  *
72  * The internal arrays may store either 32- or 64-bit values, though most of
73  * the API will prefer to use vtkIdType to refer to items in these
74  * arrays. This enables significant memory savings when vtkIdType is 64-bit,
75  * but 32 bits are sufficient to store all of the values in the connectivity
76  * table. Using 64-bit storage with a 32-bit vtkIdType is permitted, but
77  * values too large to fit in a 32-bit signed integer will be truncated when
78  * accessed through the API. (The particular internal storage type has
79  * implications on performance depending on vtkIdType. If the internal
80  * storage is equivalent to vtkIdType, then methods that return pointers to
81  * arrays of point ids can share the internal storage; otherwise a copy of
82  * internal memory must be performed.)
83  *
84  * Methods for managing the storage type are:
85  *
86  * - `bool IsStorage64Bit()`
87  * - `bool IsStorageShareable() // Can pointers to internal storage be shared`
88  * - `void Use32BitStorage()`
89  * - `void Use64BitStorage()`
90  * - `void UseDefaultStorage() // Depends on vtkIdType`
91  * - `bool CanConvertTo32BitStorage()`
92  * - `bool CanConvertTo64BitStorage()`
93  * - `bool CanConvertToDefaultStorage() // Depends on vtkIdType`
94  * - `bool ConvertTo32BitStorage()`
95  * - `bool ConvertTo64BitStorage()`
96  * - `bool ConvertToDefaultStorage() // Depends on vtkIdType`
97  * - `bool ConvertToSmallestStorage() // Depends on current values in arrays`
98  *
99  * Note that some legacy methods are still available that reflect the
100  * previous storage format of this data, which embedded the cell sizes into
101  * the Connectivity array:
102  *
103  * ```
104  * vtkCellArray (legacy):
105  * ----------------------
106  * Connectivity: {3, 0, 1, 2, 3, 5, 7, 2, 4, 3, 4, 6, 7, 2, 5, 8}
107  *                |--Cell 0--||--Cell 1--||----Cell 2---||--C3-|
108  * ```
109  *
110  * The methods require an external lookup table to allow random access, which
111  * was historically stored in the vtkCellTypes object. The following methods in
112  * vtkCellArray still support this style of indexing for compatibility
113  * purposes, but these are slow as they must perform some complex computations
114  * to convert the old "location" into the new "offset" and should be avoided.
115  * These methods (and their modern equivalents) are:
116  *
117  * - GetCell (Prefer GetCellAtId)
118  * - GetInsertLocation (Prefer GetNumberOfCells)
119  * - GetTraversalLocation (Prefer GetTraversalCellId, or better, NewIterator)
120  * - SetTraversalLocation (Prefer SetTraversalLocation, or better, NewIterator)
121  * - ReverseCell (Prefer ReverseCellAtId)
122  * - ReplaceCell (Prefer ReplaceCellAtId)
123  * - SetCells (Use ImportLegacyFormat, or SetData)
124  * - GetData (Use ExportLegacyFormat, or Get[Offsets|Connectivity]Array[|32|64])
125  *
126  * Some other legacy methods were completely removed, such as GetPointer() /
127  * WritePointer(), since they are cannot be effectively emulated under the
128  * current design. If external code needs to support both the old and new
129  * version of the vtkCellArray API, the VTK_CELL_ARRAY_V2 preprocessor
130  * definition may be used to detect which API is being compiled against.
131  *
132  * @sa vtkCellTypes vtkCellLinks
133  */
134 
135 #ifndef vtkCellArray_h
136 #define vtkCellArray_h
137 
138 #include "vtkCommonDataModelModule.h" // For export macro
139 #include "vtkObject.h"
140 
141 #include "vtkAOSDataArrayTemplate.h" // Needed for inline methods
142 #include "vtkCell.h"                 // Needed for inline methods
143 #include "vtkDataArrayRange.h"       // Needed for inline methods
144 #include "vtkFeatures.h"             // for VTK_USE_MEMKIND
145 #include "vtkSmartPointer.h"         // For vtkSmartPointer
146 #include "vtkTypeInt32Array.h"       // Needed for inline methods
147 #include "vtkTypeInt64Array.h"       // Needed for inline methods
148 #include "vtkTypeList.h"             // Needed for ArrayList definition
149 
150 #include <cassert>          // for assert
151 #include <initializer_list> // for API
152 #include <type_traits>      // for std::is_same
153 #include <utility>          // for std::forward
154 
155 /**
156  * @def VTK_CELL_ARRAY_V2
157  * @brief This preprocessor definition indicates that the updated vtkCellArray
158  * is being used. It may be used to conditionally switch between old and new
159  * API when both must be supported.
160  *
161  * For example:
162  *
163  * ```
164  * vtkIdType npts;
165  *
166  * #ifdef VTK_CELL_ARRAY_V2
167  * const vtkIdType *pts;
168  * #else // VTK_CELL_ARRAY_V2
169  * vtkIdType *pts'
170  * #endif // VTK_CELL_ARRAY_V2
171  *
172  * cellArray->GetCell(legacyLocation, npts, pts);
173  * ```
174  */
175 #define VTK_CELL_ARRAY_V2
176 
177 class vtkCellArrayIterator;
178 class vtkIdTypeArray;
179 
180 class VTKCOMMONDATAMODEL_EXPORT vtkCellArray : public vtkObject
181 {
182 public:
183   using ArrayType32 = vtkTypeInt32Array;
184   using ArrayType64 = vtkTypeInt64Array;
185 
186   ///@{
187   /**
188    * Standard methods for instantiation, type information, and
189    * printing.
190    */
191   static vtkCellArray* New();
192   vtkTypeMacro(vtkCellArray, vtkObject);
193   void PrintSelf(ostream& os, vtkIndent indent) override;
194   void PrintDebug(ostream& os);
195   ///@}
196 
197   /**
198    * List of possible array types used for storage. May be used with
199    * vtkArrayDispatch::Dispatch[2]ByArray to process internal arrays.
200    * Both the Connectivity and Offset arrays are guaranteed to have the same
201    * type.
202    *
203    * @sa vtkCellArray::Visit() for a simpler mechanism.
204    */
205   using StorageArrayList = vtkTypeList::Create<ArrayType32, ArrayType64>;
206 
207   /**
208    * List of possible ArrayTypes that are compatible with internal storage.
209    * Single component AOS-layout arrays holding one of these types may be
210    * passed to the method SetData to setup the cell array state.
211    *
212    * This can be used with vtkArrayDispatch::DispatchByArray, etc to
213    * check input arrays before assigning them to a cell array.
214    */
215   using InputArrayList =
216     typename vtkTypeList::Unique<vtkTypeList::Create<vtkAOSDataArrayTemplate<int>,
217       vtkAOSDataArrayTemplate<long>, vtkAOSDataArrayTemplate<long long>>>::Result;
218 
219   /**
220    * Allocate memory.
221    *
222    * This currently allocates both the offsets and connectivity arrays to @a sz.
223    *
224    * @note It is preferrable to use AllocateEstimate(numCells, maxCellSize)
225    * or AllocateExact(numCells, connectivitySize) instead.
226    */
227   vtkTypeBool Allocate(vtkIdType sz, vtkIdType vtkNotUsed(ext) = 1000)
228   {
229     return this->AllocateExact(sz, sz) ? 1 : 0;
230   }
231 
232   /**
233    * @brief Pre-allocate memory in internal data structures. Does not change
234    * the number of cells, only the array capacities. Existing data is NOT
235    * preserved.
236    * @param numCells The number of expected cells in the dataset.
237    * @param maxCellSize The number of points per cell to allocate memory for.
238    * @return True if allocation succeeds.
239    * @sa Squeeze AllocateExact AllocateCopy
240    */
AllocateEstimate(vtkIdType numCells,vtkIdType maxCellSize)241   bool AllocateEstimate(vtkIdType numCells, vtkIdType maxCellSize)
242   {
243     return this->AllocateExact(numCells, numCells * maxCellSize);
244   }
245 
246   /**
247    * @brief Pre-allocate memory in internal data structures. Does not change
248    * the number of cells, only the array capacities. Existing data is NOT
249    * preserved.
250    * @param numCells The number of expected cells in the dataset.
251    * @param connectivitySize The total number of pointIds stored for all cells.
252    * @return True if allocation succeeds.
253    * @sa Squeeze AllocateEstimate AllocateCopy
254    */
255   bool AllocateExact(vtkIdType numCells, vtkIdType connectivitySize);
256 
257   /**
258    * @brief Pre-allocate memory in internal data structures to match the used
259    * size of the input vtkCellArray. Does not change
260    * the number of cells, only the array capacities. Existing data is NOT
261    * preserved.
262    * @param other The vtkCellArray to use as a reference.
263    * @return True if allocation succeeds.
264    * @sa Squeeze AllocateEstimate AllocateExact
265    */
AllocateCopy(vtkCellArray * other)266   bool AllocateCopy(vtkCellArray* other)
267   {
268     return this->AllocateExact(other->GetNumberOfCells(), other->GetNumberOfConnectivityIds());
269   }
270 
271   /**
272    * @brief ResizeExact() resizes the internal structures to hold @a numCells
273    * total cell offsets and @a connectivitySize total pointIds. Old data is
274    * preserved, and newly-available memory is not initialized.
275    *
276    * @warning For advanced use only. You probably want an Allocate method.
277    *
278    * @return True if allocation succeeds.
279    */
280   bool ResizeExact(vtkIdType numCells, vtkIdType connectivitySize);
281 
282   /**
283    * Free any memory and reset to an empty state.
284    */
285   void Initialize();
286 
287   /**
288    * Reuse list. Reset to initial state without freeing memory.
289    */
290   void Reset();
291 
292   /**
293    * Reclaim any extra memory while preserving data.
294    *
295    * @sa ConvertToSmallestStorage
296    */
297   void Squeeze();
298 
299   /**
300    * Check that internal storage is consistent and in a valid state.
301    *
302    * Specifically, this function returns true if and only if:
303    * - The offset and connectivity arrays have exactly one component.
304    * - The offset array has at least one value and starts at 0.
305    * - The offset array values never decrease.
306    * - The connectivity array has as many entries as the last value in the
307    *   offset array.
308    */
309   bool IsValid();
310 
311   /**
312    * Get the number of cells in the array.
313    */
GetNumberOfCells()314   vtkIdType GetNumberOfCells() const
315   {
316     if (this->Storage.Is64Bit())
317     {
318       return this->Storage.GetArrays64().Offsets->GetNumberOfValues() - 1;
319     }
320     else
321     {
322       return this->Storage.GetArrays32().Offsets->GetNumberOfValues() - 1;
323     }
324   }
325 
326   /**
327    * Get the number of elements in the offsets array. This will be the number of
328    * cells + 1.
329    */
GetNumberOfOffsets()330   vtkIdType GetNumberOfOffsets() const
331   {
332     if (this->Storage.Is64Bit())
333     {
334       return this->Storage.GetArrays64().Offsets->GetNumberOfValues();
335     }
336     else
337     {
338       return this->Storage.GetArrays32().Offsets->GetNumberOfValues();
339     }
340   }
341 
342   /**
343    * Get the size of the connectivity array that stores the point ids.
344    * @note Do not confuse this with the deprecated
345    * GetNumberOfConnectivityEntries(), which refers to the legacy memory
346    * layout.
347    */
GetNumberOfConnectivityIds()348   vtkIdType GetNumberOfConnectivityIds() const
349   {
350     if (this->Storage.Is64Bit())
351     {
352       return this->Storage.GetArrays64().Connectivity->GetNumberOfValues();
353     }
354     else
355     {
356       return this->Storage.GetArrays32().Connectivity->GetNumberOfValues();
357     }
358   }
359 
360   /**
361    * @brief NewIterator returns a new instance of vtkCellArrayIterator that
362    * is initialized to point at the first cell's data. The caller is responsible
363    * for Delete()'ing the object.
364    */
365   VTK_NEWINSTANCE vtkCellArrayIterator* NewIterator();
366 
367 #ifndef __VTK_WRAP__ // The wrappers have issues with some of these templates
368   /**
369    * Set the internal data arrays to the supplied offsets and connectivity
370    * arrays.
371    *
372    * Note that the input arrays may be copied and not used directly. To avoid
373    * copying, use vtkIdTypeArray, vtkCellArray::ArrayType32, or
374    * vtkCellArray::ArrayType64.
375    *
376    * @{
377    */
378   void SetData(vtkTypeInt32Array* offsets, vtkTypeInt32Array* connectivity);
379   void SetData(vtkTypeInt64Array* offsets, vtkTypeInt64Array* connectivity);
380   void SetData(vtkIdTypeArray* offsets, vtkIdTypeArray* connectivity);
381   void SetData(vtkAOSDataArrayTemplate<int>* offsets, vtkAOSDataArrayTemplate<int>* connectivity);
382   void SetData(vtkAOSDataArrayTemplate<long>* offsets, vtkAOSDataArrayTemplate<long>* connectivity);
383   void SetData(
384     vtkAOSDataArrayTemplate<long long>* offsets, vtkAOSDataArrayTemplate<long long>* connectivity);
385   /**@}*/
386 #endif // __VTK_WRAP__
387 
388   /**
389    * Sets the internal arrays to the supplied offsets and connectivity arrays.
390    *
391    * This is a convenience method, and may fail if the following conditions
392    * are not met:
393    *
394    * - Both arrays must be of the same type.
395    * - The array type must be one of the types in InputArrayList.
396    *
397    * If invalid arrays are passed in, an error is logged and the function
398    * will return false.
399    */
400   bool SetData(vtkDataArray* offsets, vtkDataArray* connectivity);
401 
402   /**
403    * Sets the internal arrays to the supported connectivity array with an
404    * offsets array automatically generated given the fixed cells size.
405    *
406    * This is a convenience method, and may fail if the following conditions
407    * are not met:
408    *
409    * - The `connectivity` array must be one of the types in InputArrayList.
410    * - The `connectivity` array size must be a multiple of `cellSize`.
411    *
412    * If invalid arrays are passed in, an error is logged and the function
413    * will return false.
414    */
415   bool SetData(vtkIdType cellSize, vtkDataArray* connectivity);
416 
417   /**
418    * @return True if the internal storage is using 64 bit arrays. If false,
419    * the storage is using 32 bit arrays.
420    */
IsStorage64Bit()421   bool IsStorage64Bit() const { return this->Storage.Is64Bit(); }
422 
423   /**
424    * @return True if the internal storage can be shared as a
425    * pointer to vtkIdType, i.e., the type and organization of internal
426    * storage is such that copying of data can be avoided, and instead
427    * a pointer to vtkIdType can be used.
428    */
IsStorageShareable()429   bool IsStorageShareable() const
430   {
431     if (this->Storage.Is64Bit())
432     {
433       return this->Storage.GetArrays64().ValueTypeIsSameAsIdType;
434     }
435     else
436     {
437       return this->Storage.GetArrays32().ValueTypeIsSameAsIdType;
438     }
439   }
440 
441   /**
442    * Initialize internal data structures to use 32- or 64-bit storage.
443    * If selecting default storage, the storage depends on the VTK_USE_64BIT_IDS
444    * setting.
445    *
446    * All existing data is erased.
447    * @{
448    */
449   void Use32BitStorage();
450   void Use64BitStorage();
451   void UseDefaultStorage();
452   /**@}*/
453 
454   /**
455    * Check if the existing data can safely be converted to use 32- or 64- bit
456    * storage. Ensures that all values can be converted to the target storage
457    * without truncating.
458    * If selecting default storage, the storage depends on the VTK_USE_64BIT_IDS
459    * setting.
460    * @{
461    */
462   bool CanConvertTo32BitStorage() const;
463   bool CanConvertTo64BitStorage() const;
464   bool CanConvertToDefaultStorage() const;
465   /**@}*/
466 
467   /**
468    * Convert internal data structures to use 32- or 64-bit storage.
469    *
470    * If selecting default storage, the storage depends on the VTK_USE_64BIT_IDS
471    * setting.
472    *
473    * If selecting smallest storage, the data is checked to see what the smallest
474    * safe storage for the existing data is, and then converts to it.
475    *
476    * Existing data is preserved.
477    *
478    * @return True on success, false on failure. If this algorithm fails, the
479    * cell array will be in an unspecified state.
480    *
481    * @{
482    */
483   bool ConvertTo32BitStorage();
484   bool ConvertTo64BitStorage();
485   bool ConvertToDefaultStorage();
486   bool ConvertToSmallestStorage();
487   /**@}*/
488 
489   /**
490    * Return the array used to store cell offsets. The 32/64 variants are only
491    * valid when IsStorage64Bit() returns the appropriate value.
492    * @{
493    */
GetOffsetsArray()494   vtkDataArray* GetOffsetsArray()
495   {
496     if (this->Storage.Is64Bit())
497     {
498       return this->GetOffsetsArray64();
499     }
500     else
501     {
502       return this->GetOffsetsArray32();
503     }
504   }
GetOffsetsArray32()505   ArrayType32* GetOffsetsArray32() { return this->Storage.GetArrays32().Offsets; }
GetOffsetsArray64()506   ArrayType64* GetOffsetsArray64() { return this->Storage.GetArrays64().Offsets; }
507   /**@}*/
508 
509   /**
510    * Return the array used to store the point ids that define the cells'
511    * connectivity. The 32/64 variants are only valid when IsStorage64Bit()
512    * returns the appropriate value.
513    * @{
514    */
GetConnectivityArray()515   vtkDataArray* GetConnectivityArray()
516   {
517     if (this->Storage.Is64Bit())
518     {
519       return this->GetConnectivityArray64();
520     }
521     else
522     {
523       return this->GetConnectivityArray32();
524     }
525   }
GetConnectivityArray32()526   ArrayType32* GetConnectivityArray32() { return this->Storage.GetArrays32().Connectivity; }
GetConnectivityArray64()527   ArrayType64* GetConnectivityArray64() { return this->Storage.GetArrays64().Connectivity; }
528   /**@}*/
529 
530   /**
531    * Check if all cells have the same number of vertices.
532    *
533    * The return value is coded as:
534    * * -1 = heterogeneous
535    * * 0 = Cell array empty
536    * * n (positive integer) = homogeneous array of cell size n
537    */
538   vtkIdType IsHomogeneous();
539 
540   /**
541    * @warning This method is not thread-safe. Consider using the NewIterator()
542    * iterator instead.
543    *
544    * InitTraversal() initializes the traversal of the list of cells.
545    *
546    * @note This method is not thread-safe and has tricky syntax to use
547    * correctly. Prefer the use of vtkCellArrayIterator (see NewIterator()).
548    */
549   void InitTraversal();
550 
551   /**
552    * @warning This method is not thread-safe. Consider using the NewIterator()
553    * iterator instead.
554    *
555    * GetNextCell() gets the next cell in the list. If end of list
556    * is encountered, 0 is returned. A value of 1 is returned whenever
557    * npts and pts have been updated without error.
558    *
559    * Do not modify the returned @a pts pointer, as it may point to shared
560    * memory.
561    *
562    * @note This method is not thread-safe and has tricky syntax to use
563    * correctly. Prefer the use of vtkCellArrayIterator (see NewIterator()).
564    */
565   int GetNextCell(vtkIdType& npts, vtkIdType const*& pts) VTK_SIZEHINT(pts, npts);
566 
567   /**
568    * @warning This method is not thread-safe. Consider using the NewIterator()
569    * iterator instead.
570    *
571    * GetNextCell() gets the next cell in the list. If end of list is
572    * encountered, 0 is returned.
573    *
574    * @note This method is not thread-safe and has tricky syntax to use
575    * correctly. Prefer the use of vtkCellArrayIterator (see NewIterator()).
576    */
577   int GetNextCell(vtkIdList* pts);
578 
579   /**
580    * Return the point ids for the cell at @a cellId.
581    *
582    * @warning Subsequent calls to this method may invalidate previous call
583    * results if the internal storage type is not the same as vtkIdType and
584    * cannot be shared through the @a cellPoints pointer. In other words, the
585    * method may not be thread safe. Check if shareable (using
586    * IsStorageShareable()), or use a vtkCellArrayIterator to guarantee thread
587    * safety.
588    */
589   void GetCellAtId(vtkIdType cellId, vtkIdType& cellSize, vtkIdType const*& cellPoints)
590     VTK_SIZEHINT(cellPoints, cellSize) VTK_EXPECTS(0 <= cellId && cellId < GetNumberOfCells());
591 
592   /**
593    * Return the point ids for the cell at @a cellId. This always copies
594    * the cell ids (i.e., the list of points @a pts into the supplied
595    * vtkIdList). This method is thread safe.
596    */
597   void GetCellAtId(vtkIdType cellId, vtkIdList* pts)
598     VTK_EXPECTS(0 <= cellId && cellId < GetNumberOfCells());
599 
600   /**
601    * Return the size of the cell at @a cellId.
602    */
603   vtkIdType GetCellSize(const vtkIdType cellId) const;
604 
605   /**
606    * Insert a cell object. Return the cell id of the cell.
607    */
608   vtkIdType InsertNextCell(vtkCell* cell);
609 
610   /**
611    * Create a cell by specifying the number of points and an array of point
612    * id's.  Return the cell id of the cell.
613    */
614   vtkIdType InsertNextCell(vtkIdType npts, const vtkIdType* pts) VTK_SIZEHINT(pts, npts);
615 
616   /**
617    * Create a cell by specifying a list of point ids. Return the cell id of
618    * the cell.
619    */
620   vtkIdType InsertNextCell(vtkIdList* pts);
621 
622   /**
623    * Overload that allows `InsertNextCell({0, 1, 2})` syntax.
624    *
625    * @warning This approach is useful for testing, but beware that trying to
626    * pass a single value (eg. `InsertNextCell({3})`) will call the
627    * `InsertNextCell(int)` overload instead.
628    */
InsertNextCell(const std::initializer_list<vtkIdType> & cell)629   vtkIdType InsertNextCell(const std::initializer_list<vtkIdType>& cell)
630   {
631     return this->InsertNextCell(static_cast<vtkIdType>(cell.size()), cell.begin());
632   }
633 
634   /**
635    * Create cells by specifying a count of total points to be inserted, and
636    * then adding points one at a time using method InsertCellPoint(). If you
637    * don't know the count initially, use the method UpdateCellCount() to
638    * complete the cell. Return the cell id of the cell.
639    */
640   vtkIdType InsertNextCell(int npts);
641 
642   /**
643    * Used in conjunction with InsertNextCell(npts) to add another point
644    * to the list of cells.
645    */
646   void InsertCellPoint(vtkIdType id);
647 
648   /**
649    * Used in conjunction with InsertNextCell(int npts) and InsertCellPoint() to
650    * update the number of points defining the cell.
651    */
652   void UpdateCellCount(int npts);
653 
654   /**
655    * Get/Set the current cellId for traversal.
656    *
657    * @note This method is not thread-safe and has tricky syntax to use
658    * correctly. Prefer the use of vtkCellArrayIterator (see NewIterator()).
659    * @{
660    */
661   vtkIdType GetTraversalCellId();
662   void SetTraversalCellId(vtkIdType cellId);
663   /**@}*/
664 
665   /**
666    * Reverses the order of the point ids for the specified cell.
667    */
668   void ReverseCellAtId(vtkIdType cellId) VTK_EXPECTS(0 <= cellId && cellId < GetNumberOfCells());
669 
670   /**
671    * Replaces the point ids for the specified cell with the supplied list.
672    *
673    * @warning This can ONLY replace the cell if the size does not change.
674    * Attempting to change cell size through this method will have undefined
675    * results.
676    * @{
677    */
678   void ReplaceCellAtId(vtkIdType cellId, vtkIdList* list);
679   void ReplaceCellAtId(vtkIdType cellId, vtkIdType cellSize, const vtkIdType* cellPoints)
680     VTK_EXPECTS(0 <= cellId && cellId < GetNumberOfCells()) VTK_SIZEHINT(cellPoints, cellSize);
681   /**@}*/
682 
683   /**
684    * Overload that allows `ReplaceCellAtId(cellId, {0, 1, 2})` syntax.
685    *
686    * @warning This can ONLY replace the cell if the size does not change.
687    * Attempting to change cell size through this method will have undefined
688    * results.
689    */
ReplaceCellAtId(vtkIdType cellId,const std::initializer_list<vtkIdType> & cell)690   void ReplaceCellAtId(vtkIdType cellId, const std::initializer_list<vtkIdType>& cell)
691   {
692     return this->ReplaceCellAtId(cellId, static_cast<vtkIdType>(cell.size()), cell.begin());
693   }
694 
695   /**
696    * Returns the size of the largest cell. The size is the number of points
697    * defining the cell.
698    */
699   int GetMaxCellSize();
700 
701   /**
702    * Perform a deep copy (no reference counting) of the given cell array.
703    */
704   void DeepCopy(vtkCellArray* ca);
705 
706   /**
707    * Shallow copy @a ca into this cell array.
708    */
709   void ShallowCopy(vtkCellArray* ca);
710 
711   /**
712    * Append cells from src into this. Point ids are offset by @a pointOffset.
713    */
714   void Append(vtkCellArray* src, vtkIdType pointOffset = 0);
715 
716   /**
717    * Fill @a data with the old-style vtkCellArray data layout, e.g.
718    *
719    * ```
720    * { n0, p0_0, p0_1, ..., p0_n, n1, p1_0, p1_1, ..., p1_n, ... }
721    * ```
722    *
723    * where `n0` is the number of points in cell 0, and `pX_Y` is the Y'th point
724    * in cell X.
725    */
726   void ExportLegacyFormat(vtkIdTypeArray* data);
727 
728   /**
729    * Import an array of data with the legacy vtkCellArray layout, e.g.:
730    *
731    * ```
732    * { n0, p0_0, p0_1, ..., p0_n, n1, p1_0, p1_1, ..., p1_n, ... }
733    * ```
734    *
735    * where `n0` is the number of points in cell 0, and `pX_Y` is the Y'th point
736    * in cell X.
737    * @{
738    */
739   void ImportLegacyFormat(vtkIdTypeArray* data);
740   void ImportLegacyFormat(const vtkIdType* data, vtkIdType len) VTK_SIZEHINT(data, len);
741   /** @} */
742 
743   /**
744    * Append an array of data with the legacy vtkCellArray layout, e.g.:
745    *
746    * ```
747    * { n0, p0_0, p0_1, ..., p0_n, n1, p1_0, p1_1, ..., p1_n, ... }
748    * ```
749    *
750    * where `n0` is the number of points in cell 0, and `pX_Y` is the Y'th point
751    * in cell X.
752    * @{
753    */
754   void AppendLegacyFormat(vtkIdTypeArray* data, vtkIdType ptOffset = 0);
755   void AppendLegacyFormat(const vtkIdType* data, vtkIdType len, vtkIdType ptOffset = 0)
756     VTK_SIZEHINT(data, len);
757   /** @} */
758 
759   /**
760    * Return the memory in kibibytes (1024 bytes) consumed by this cell array. Used to
761    * support streaming and reading/writing data. The value returned is
762    * guaranteed to be greater than or equal to the memory required to
763    * actually represent the data represented by this object. The
764    * information returned is valid only after the pipeline has
765    * been updated.
766    */
767   unsigned long GetActualMemorySize() const;
768 
769   // The following code is used to support
770 
771   // The wrappers get understandably confused by some of the template code below
772 #ifndef __VTK_WRAP__
773 
774   // Holds connectivity and offset arrays of the given ArrayType.
775   template <typename ArrayT>
776   struct VisitState
777   {
778     using ArrayType = ArrayT;
779     using ValueType = typename ArrayType::ValueType;
780     using CellRangeType = decltype(vtk::DataArrayValueRange<1>(std::declval<ArrayType>()));
781 
782     // We can't just use is_same here, since binary compatible representations
783     // (e.g. int and long) are distinct types. Instead, ensure that ValueType
784     // is a signed integer the same size as vtkIdType.
785     // If this value is true, ValueType pointers may be safely converted to
786     // vtkIdType pointers via reinterpret cast.
787     static constexpr bool ValueTypeIsSameAsIdType = std::is_integral<ValueType>::value &&
788       std::is_signed<ValueType>::value && (sizeof(ValueType) == sizeof(vtkIdType));
789 
GetOffsetsVisitState790     ArrayType* GetOffsets() { return this->Offsets; }
GetOffsetsVisitState791     const ArrayType* GetOffsets() const { return this->Offsets; }
792 
GetConnectivityVisitState793     ArrayType* GetConnectivity() { return this->Connectivity; }
GetConnectivityVisitState794     const ArrayType* GetConnectivity() const { return this->Connectivity; }
795 
796     vtkIdType GetNumberOfCells() const;
797 
798     vtkIdType GetBeginOffset(vtkIdType cellId) const;
799 
800     vtkIdType GetEndOffset(vtkIdType cellId) const;
801 
802     vtkIdType GetCellSize(vtkIdType cellId) const;
803 
804     CellRangeType GetCellRange(vtkIdType cellId);
805 
806     friend class vtkCellArray;
807 
808   protected:
VisitStateVisitState809     VisitState()
810     {
811       this->Connectivity = vtkSmartPointer<ArrayType>::New();
812       this->Offsets = vtkSmartPointer<ArrayType>::New();
813       this->Offsets->InsertNextValue(0);
814       if (vtkObjectBase::GetUsingMemkind())
815       {
816         this->IsInMemkind = true;
817       }
818     }
819     ~VisitState() = default;
newVisitState820     void* operator new(size_t nSize)
821     {
822       void* r;
823 #ifdef VTK_USE_MEMKIND
824       r = vtkObjectBase::GetCurrentMallocFunction()(nSize);
825 #else
826       r = malloc(nSize);
827 #endif
828       return r;
829     }
deleteVisitState830     void operator delete(void* p)
831     {
832 #ifdef VTK_USE_MEMKIND
833       VisitState* a = static_cast<VisitState*>(p);
834       if (a->IsInMemkind)
835       {
836         vtkObjectBase::GetAlternateFreeFunction()(p);
837       }
838       else
839       {
840         free(p);
841       }
842 #else
843       free(p);
844 #endif
845     }
846 
847     vtkSmartPointer<ArrayType> Connectivity;
848     vtkSmartPointer<ArrayType> Offsets;
849 
850   private:
851     VisitState(const VisitState&) = delete;
852     VisitState& operator=(const VisitState&) = delete;
853     bool IsInMemkind = false;
854   };
855 
856 private: // Helpers that allow Visit to return a value:
857   template <typename Functor, typename... Args>
858   using GetReturnType = decltype(
859     std::declval<Functor>()(std::declval<VisitState<ArrayType32>&>(), std::declval<Args>()...));
860 
861   template <typename Functor, typename... Args>
862   struct ReturnsVoid : std::is_same<GetReturnType<Functor, Args...>, void>
863   {
864   };
865 
866 public:
867   /**
868    * @warning Advanced use only.
869    *
870    * The Visit methods allow efficient bulk modification of the vtkCellArray
871    * internal arrays by dispatching a functor with the current storage arrays.
872    * The simplest functor is of the form:
873    *
874    * ```
875    * // Functor definition:
876    * struct Worker
877    * {
878    *   template <typename CellStateT>
879    *   void operator()(CellStateT &state)
880    *   {
881    *     // Do work on state object
882    *   }
883    * };
884    *
885    * // Functor usage:
886    * vtkCellArray *cellArray = ...;
887    * cellArray->Visit(Worker{});
888    * ```
889    *
890    * where `state` is an instance of the vtkCellArray::VisitState<ArrayT> class,
891    * instantiated for the current storage type of the cell array. See that
892    * class for usage details.
893    *
894    * The functor may also:
895    * - Return a value from `operator()`
896    * - Pass additional arguments to `operator()`
897    * - Hold state.
898    *
899    * A more advanced functor that does these things is shown below, along
900    * with its usage. This functor scans a range of cells and returns the largest
901    * cell's id:
902    *
903    * ```
904    * struct FindLargestCellInRange
905    * {
906    *   template <typename CellStateT>
907    *   vtkIdType operator()(CellStateT &state,
908    *                        vtkIdType rangeBegin,
909    *                        vtkIdType rangeEnd)
910    *   {
911    *     vtkIdType largest = rangeBegin;
912    *     vtkIdType largestSize = state.GetCellSize(rangeBegin);
913    *     ++rangeBegin;
914    *     for (; rangeBegin < rangeEnd; ++rangeBegin)
915    *     {
916    *       const vtkIdType curSize = state.GetCellSize(rangeBegin);
917    *       if (curSize > largestSize)
918    *       {
919    *         largest = rangeBegin;
920    *         largestSize = curSize;
921    *       }
922    *     }
923    *
924    *     return largest;
925    *   }
926    * };
927    *
928    * // Usage:
929    * // Scan cells in range [128, 1024) and return the id of the largest.
930    * vtkCellArray cellArray = ...;
931    * vtkIdType largest = cellArray->Visit(FindLargestCellInRange{},
932    *                                      128, 1024);
933    * ```
934    * @{
935    */
936   template <typename Functor, typename... Args,
937     typename = typename std::enable_if<ReturnsVoid<Functor, Args...>::value>::type>
Visit(Functor && functor,Args &&...args)938   void Visit(Functor&& functor, Args&&... args)
939   {
940     if (this->Storage.Is64Bit())
941     {
942       // If you get an error on the next line, a call to Visit(functor, Args...)
943       // is being called with arguments that do not match the functor's call
944       // signature. See the Visit documentation for details.
945       functor(this->Storage.GetArrays64(), std::forward<Args>(args)...);
946     }
947     else
948     {
949       // If you get an error on the next line, a call to Visit(functor, Args...)
950       // is being called with arguments that do not match the functor's call
951       // signature. See the Visit documentation for details.
952       functor(this->Storage.GetArrays32(), std::forward<Args>(args)...);
953     }
954   }
955 
956   template <typename Functor, typename... Args,
957     typename = typename std::enable_if<ReturnsVoid<Functor, Args...>::value>::type>
Visit(Functor && functor,Args &&...args)958   void Visit(Functor&& functor, Args&&... args) const
959   {
960     if (this->Storage.Is64Bit())
961     {
962       // If you get an error on the next line, a call to Visit(functor, Args...)
963       // is being called with arguments that do not match the functor's call
964       // signature. See the Visit documentation for details.
965       functor(this->Storage.GetArrays64(), std::forward<Args>(args)...);
966     }
967     else
968     {
969       // If you get an error on the next line, a call to Visit(functor, Args...)
970       // is being called with arguments that do not match the functor's call
971       // signature. See the Visit documentation for details.
972       functor(this->Storage.GetArrays32(), std::forward<Args>(args)...);
973     }
974   }
975 
976   template <typename Functor, typename... Args,
977     typename = typename std::enable_if<!ReturnsVoid<Functor, Args...>::value>::type>
Visit(Functor && functor,Args &&...args)978   GetReturnType<Functor, Args...> Visit(Functor&& functor, Args&&... args)
979   {
980     if (this->Storage.Is64Bit())
981     {
982       // If you get an error on the next line, a call to Visit(functor, Args...)
983       // is being called with arguments that do not match the functor's call
984       // signature. See the Visit documentation for details.
985       return functor(this->Storage.GetArrays64(), std::forward<Args>(args)...);
986     }
987     else
988     {
989       // If you get an error on the next line, a call to Visit(functor, Args...)
990       // is being called with arguments that do not match the functor's call
991       // signature. See the Visit documentation for details.
992       return functor(this->Storage.GetArrays32(), std::forward<Args>(args)...);
993     }
994   }
995   template <typename Functor, typename... Args,
996     typename = typename std::enable_if<!ReturnsVoid<Functor, Args...>::value>::type>
Visit(Functor && functor,Args &&...args)997   GetReturnType<Functor, Args...> Visit(Functor&& functor, Args&&... args) const
998   {
999     if (this->Storage.Is64Bit())
1000     {
1001       // If you get an error on the next line, a call to Visit(functor, Args...)
1002       // is being called with arguments that do not match the functor's call
1003       // signature. See the Visit documentation for details.
1004       return functor(this->Storage.GetArrays64(), std::forward<Args>(args)...);
1005     }
1006     else
1007     {
1008       // If you get an error on the next line, a call to Visit(functor, Args...)
1009       // is being called with arguments that do not match the functor's call
1010       // signature. See the Visit documentation for details.
1011       return functor(this->Storage.GetArrays32(), std::forward<Args>(args)...);
1012     }
1013   }
1014 
1015   /** @} */
1016 
1017 #endif // __VTK_WRAP__
1018 
1019   //=================== Begin Legacy Methods ===================================
1020   // These should be deprecated at some point as they are confusing or very slow
1021 
1022   /**
1023    * Set the number of cells in the array.
1024    * DO NOT do any kind of allocation, advanced use only.
1025    *
1026    * @note This call has no effect.
1027    */
1028   virtual void SetNumberOfCells(vtkIdType);
1029 
1030   /**
1031    * Utility routines help manage memory of cell array. EstimateSize()
1032    * returns a value used to initialize and allocate memory for array based
1033    * on number of cells and maximum number of points making up cell.  If
1034    * every cell is the same size (in terms of number of points), then the
1035    * memory estimate is guaranteed exact. (If not exact, use Squeeze() to
1036    * reclaim any extra memory.)
1037    *
1038    * @note This method was often misused (e.g. called alone and then
1039    * discarding the result). Use AllocateEstimate directly instead.
1040    */
1041   vtkIdType EstimateSize(vtkIdType numCells, int maxPtsPerCell);
1042 
1043   /**
1044    * Get the size of the allocated connectivity array.
1045    *
1046    * @warning This returns the allocated capacity of the internal arrays as a
1047    * number of elements, NOT the number of elements in use.
1048    *
1049    * @note Method incompatible with current internal storage.
1050    */
1051   vtkIdType GetSize();
1052 
1053   /**
1054    * Return the size of the array that would be returned from
1055    * ExportLegacyFormat().
1056    *
1057    * @note Method incompatible with current internal storage.
1058    */
1059   vtkIdType GetNumberOfConnectivityEntries();
1060 
1061   /**
1062    * Internal method used to retrieve a cell given a legacy offset location.
1063    *
1064    * @warning Subsequent calls to this method may invalidate previous call
1065    * results.
1066    *
1067    * @note The location-based API is now a super-slow compatibility layer.
1068    * Prefer GetCellAtId.
1069    */
1070   void GetCell(vtkIdType loc, vtkIdType& npts, const vtkIdType*& pts)
1071     VTK_EXPECTS(0 <= loc && loc < GetNumberOfConnectivityEntries()) VTK_SIZEHINT(pts, npts);
1072 
1073   /**
1074    * Internal method used to retrieve a cell given a legacy offset location.
1075    *
1076    * @note The location-based API is now a super-slow compatibility layer.
1077    * Prefer GetCellAtId.
1078    */
1079   void GetCell(vtkIdType loc, vtkIdList* pts)
1080     VTK_EXPECTS(0 <= loc && loc < GetNumberOfConnectivityEntries());
1081 
1082   /**
1083    * Computes the current legacy insertion location within the internal array.
1084    * Used in conjunction with GetCell(int loc,...).
1085    *
1086    * @note The location-based API is now a super-slow compatibility layer.
1087    */
1088   vtkIdType GetInsertLocation(int npts);
1089 
1090   /**
1091    * Get/Set the current traversal legacy location.
1092    *
1093    * @note The location-based API is now a super-slow compatibility layer.
1094    * Prefer Get/SetTraversalCellId.
1095    * @{
1096    */
1097   vtkIdType GetTraversalLocation();
1098   vtkIdType GetTraversalLocation(vtkIdType npts);
1099   void SetTraversalLocation(vtkIdType loc);
1100   /**@}*/
1101 
1102   /**
1103    * Special method inverts ordering of cell at the specified legacy location.
1104    * Must be called carefully or the cell topology may be corrupted.
1105    *
1106    * @note The location-based API is now a super-slow compatibility layer.
1107    * Prefer ReverseCellAtId;
1108    */
1109   void ReverseCell(vtkIdType loc) VTK_EXPECTS(0 <= loc && loc < GetNumberOfConnectivityEntries());
1110 
1111   /**
1112    * Replace the point ids of the cell at the legacy location with a different
1113    * list of point ids. Calling this method does not mark the vtkCellArray as
1114    * modified. This is the responsibility of the caller and may be done after
1115    * multiple calls to ReplaceCell. This call does not support changing the
1116    * number of points in the cell -- the caller must ensure that the target
1117    * cell has npts points.
1118    *
1119    * @note The location-based API is now a super-slow compatibility layer.
1120    * Prefer ReplaceCellAtId.
1121    */
1122   void ReplaceCell(vtkIdType loc, int npts, const vtkIdType pts[])
1123     VTK_EXPECTS(0 <= loc && loc < GetNumberOfConnectivityEntries()) VTK_SIZEHINT(pts, npts);
1124 
1125   /**
1126    * Define multiple cells by providing a connectivity list. The list is in
1127    * the form (npts,p0,p1,...p(npts-1), repeated for each cell). Be careful
1128    * using this method because it discards the old cells, and anything
1129    * referring these cells becomes invalid (for example, if BuildCells() has
1130    * been called see vtkPolyData).  The traversal location is reset to the
1131    * beginning of the list; the insertion location is set to the end of the
1132    * list.
1133    *
1134    * @warning The vtkCellArray will not hold a reference to `cells`. This
1135    * function merely calls ImportLegacyFormat.
1136    *
1137    * @note Use ImportLegacyFormat or SetData instead.
1138    */
1139   void SetCells(vtkIdType ncells, vtkIdTypeArray* cells);
1140 
1141   /**
1142    * Return the underlying data as a data array.
1143    *
1144    * @warning The returned array is not the actual internal representation used
1145    * by vtkCellArray. Modifications to the returned array will not change the
1146    * vtkCellArray's topology.
1147    *
1148    * @note Use ExportLegacyFormat, or GetOffsetsArray/GetConnectivityArray
1149    * instead.
1150    */
1151   vtkIdTypeArray* GetData();
1152 
1153   //=================== End Legacy Methods =====================================
1154 
1155   friend class vtkCellArrayIterator;
1156 
1157 protected:
1158   vtkCellArray();
1159   ~vtkCellArray() override;
1160 
1161   // Encapsulates storage of the internal arrays as a discriminated union
1162   // between 32-bit and 64-bit storage.
1163   struct Storage
1164   {
1165     // Union type that switches 32 and 64 bit array storage
1166     union ArraySwitch {
1167       ArraySwitch() = default;  // handled by Storage
1168       ~ArraySwitch() = default; // handle by Storage
1169       VisitState<ArrayType32>* Int32;
1170       VisitState<ArrayType64>* Int64;
1171     };
1172 
StorageStorage1173     Storage()
1174     {
1175 #ifdef VTK_USE_MEMKIND
1176       this->Arrays =
1177         static_cast<ArraySwitch*>(vtkObjectBase::GetCurrentMallocFunction()(sizeof(ArraySwitch)));
1178 #else
1179       this->Arrays = new ArraySwitch;
1180 #endif
1181 
1182       // Default to the compile-time setting:
1183 #ifdef VTK_USE_64BIT_IDS
1184 
1185       this->Arrays->Int64 = new VisitState<ArrayType64>;
1186       this->StorageIs64Bit = true;
1187 
1188 #else // VTK_USE_64BIT_IDS
1189 
1190       this->Arrays->Int32 = new VisitState<ArrayType32>;
1191       this->StorageIs64Bit = false;
1192 
1193 #endif // VTK_USE_64BIT_IDS
1194 #ifdef VTK_USE_MEMKIND
1195       if (vtkObjectBase::GetUsingMemkind())
1196       {
1197         this->IsInMemkind = true;
1198       }
1199 #else
1200       (void)this->IsInMemkind; // comp warning workaround
1201 #endif
1202     }
1203 
~StorageStorage1204     ~Storage()
1205     {
1206       if (this->StorageIs64Bit)
1207       {
1208         this->Arrays->Int64->~VisitState();
1209         delete this->Arrays->Int64;
1210       }
1211       else
1212       {
1213         this->Arrays->Int32->~VisitState();
1214         delete this->Arrays->Int32;
1215       }
1216 #ifdef VTK_USE_MEMKIND
1217       if (this->IsInMemkind)
1218       {
1219         vtkObjectBase::GetAlternateFreeFunction()(this->Arrays);
1220       }
1221       else
1222       {
1223         free(this->Arrays);
1224       }
1225 #else
1226       delete this->Arrays;
1227 #endif
1228     }
1229 
1230     // Switch the internal arrays to be 32-bit. Any old data is lost. Returns
1231     // true if the storage changes.
Use32BitStorageStorage1232     bool Use32BitStorage()
1233     {
1234       if (!this->StorageIs64Bit)
1235       {
1236         return false;
1237       }
1238 
1239       this->Arrays->Int64->~VisitState();
1240       delete this->Arrays->Int64;
1241       this->Arrays->Int32 = new VisitState<ArrayType32>;
1242       this->StorageIs64Bit = false;
1243 
1244       return true;
1245     }
1246 
1247     // Switch the internal arrays to be 64-bit. Any old data is lost. Returns
1248     // true if the storage changes.
Use64BitStorageStorage1249     bool Use64BitStorage()
1250     {
1251       if (this->StorageIs64Bit)
1252       {
1253         return false;
1254       }
1255 
1256       this->Arrays->Int32->~VisitState();
1257       delete this->Arrays->Int32;
1258       this->Arrays->Int64 = new VisitState<ArrayType64>;
1259       this->StorageIs64Bit = true;
1260 
1261       return true;
1262     }
1263 
1264     // Returns true if the storage is currently configured to be 64 bit.
Is64BitStorage1265     bool Is64Bit() const { return this->StorageIs64Bit; }
1266 
1267     // Get the VisitState for 32-bit arrays
GetArrays32Storage1268     VisitState<ArrayType32>& GetArrays32()
1269     {
1270       assert(!this->StorageIs64Bit);
1271       return *this->Arrays->Int32;
1272     }
1273 
GetArrays32Storage1274     const VisitState<ArrayType32>& GetArrays32() const
1275     {
1276       assert(!this->StorageIs64Bit);
1277       return *this->Arrays->Int32;
1278     }
1279 
1280     // Get the VisitState for 64-bit arrays
GetArrays64Storage1281     VisitState<ArrayType64>& GetArrays64()
1282     {
1283       assert(this->StorageIs64Bit);
1284       return *this->Arrays->Int64;
1285     }
1286 
GetArrays64Storage1287     const VisitState<ArrayType64>& GetArrays64() const
1288     {
1289       assert(this->StorageIs64Bit);
1290       return *this->Arrays->Int64;
1291     }
1292 
1293   private:
1294     // Access restricted to ensure proper union construction/destruction thru
1295     // API.
1296     ArraySwitch* Arrays;
1297     bool StorageIs64Bit;
1298     bool IsInMemkind = false;
1299   };
1300 
1301   Storage Storage;
1302   vtkNew<vtkIdList> TempCell;
1303   vtkIdType TraversalCellId{ 0 };
1304 
1305   vtkNew<vtkIdTypeArray> LegacyData; // For GetData().
1306 
1307 private:
1308   vtkCellArray(const vtkCellArray&) = delete;
1309   void operator=(const vtkCellArray&) = delete;
1310 };
1311 
1312 template <typename ArrayT>
GetNumberOfCells()1313 vtkIdType vtkCellArray::VisitState<ArrayT>::GetNumberOfCells() const
1314 {
1315   return this->Offsets->GetNumberOfValues() - 1;
1316 }
1317 
1318 template <typename ArrayT>
GetBeginOffset(vtkIdType cellId)1319 vtkIdType vtkCellArray::VisitState<ArrayT>::GetBeginOffset(vtkIdType cellId) const
1320 {
1321   return static_cast<vtkIdType>(this->Offsets->GetValue(cellId));
1322 }
1323 
1324 template <typename ArrayT>
GetEndOffset(vtkIdType cellId)1325 vtkIdType vtkCellArray::VisitState<ArrayT>::GetEndOffset(vtkIdType cellId) const
1326 {
1327   return static_cast<vtkIdType>(this->Offsets->GetValue(cellId + 1));
1328 }
1329 
1330 template <typename ArrayT>
GetCellSize(vtkIdType cellId)1331 vtkIdType vtkCellArray::VisitState<ArrayT>::GetCellSize(vtkIdType cellId) const
1332 {
1333   return this->GetEndOffset(cellId) - this->GetBeginOffset(cellId);
1334 }
1335 
1336 template <typename ArrayT>
1337 typename vtkCellArray::VisitState<ArrayT>::CellRangeType
GetCellRange(vtkIdType cellId)1338 vtkCellArray::VisitState<ArrayT>::GetCellRange(vtkIdType cellId)
1339 {
1340   return vtk::DataArrayValueRange<1>(
1341     this->GetConnectivity(), this->GetBeginOffset(cellId), this->GetEndOffset(cellId));
1342 }
1343 
1344 namespace vtkCellArray_detail
1345 {
1346 
1347 struct InsertNextCellImpl
1348 {
1349   // Insert full cell
1350   template <typename CellStateT>
operatorInsertNextCellImpl1351   vtkIdType operator()(CellStateT& state, const vtkIdType npts, const vtkIdType pts[])
1352   {
1353     using ValueType = typename CellStateT::ValueType;
1354     auto* conn = state.GetConnectivity();
1355     auto* offsets = state.GetOffsets();
1356 
1357     const vtkIdType cellId = offsets->GetNumberOfValues() - 1;
1358 
1359     offsets->InsertNextValue(static_cast<ValueType>(conn->GetNumberOfValues() + npts));
1360 
1361     for (vtkIdType i = 0; i < npts; ++i)
1362     {
1363       conn->InsertNextValue(static_cast<ValueType>(pts[i]));
1364     }
1365 
1366     return cellId;
1367   }
1368 
1369   // Just update offset table (for incremental API)
1370   template <typename CellStateT>
operatorInsertNextCellImpl1371   vtkIdType operator()(CellStateT& state, const vtkIdType npts)
1372   {
1373     using ValueType = typename CellStateT::ValueType;
1374     auto* conn = state.GetConnectivity();
1375     auto* offsets = state.GetOffsets();
1376 
1377     const vtkIdType cellId = offsets->GetNumberOfValues() - 1;
1378 
1379     offsets->InsertNextValue(static_cast<ValueType>(conn->GetNumberOfValues() + npts));
1380 
1381     return cellId;
1382   }
1383 };
1384 
1385 // for incremental API:
1386 struct UpdateCellCountImpl
1387 {
1388   template <typename CellStateT>
operatorUpdateCellCountImpl1389   void operator()(CellStateT& state, const vtkIdType npts)
1390   {
1391     using ValueType = typename CellStateT::ValueType;
1392 
1393     auto* offsets = state.GetOffsets();
1394     const ValueType cellBegin = offsets->GetValue(offsets->GetMaxId() - 1);
1395     offsets->SetValue(offsets->GetMaxId(), static_cast<ValueType>(cellBegin + npts));
1396   }
1397 };
1398 
1399 struct GetCellSizeImpl
1400 {
1401   template <typename CellStateT>
operatorGetCellSizeImpl1402   vtkIdType operator()(CellStateT& state, const vtkIdType cellId)
1403   {
1404     return state.GetCellSize(cellId);
1405   }
1406 };
1407 
1408 struct GetCellAtIdImpl
1409 {
1410   template <typename CellStateT>
operatorGetCellAtIdImpl1411   void operator()(CellStateT& state, const vtkIdType cellId, vtkIdList* ids)
1412   {
1413     using ValueType = typename CellStateT::ValueType;
1414 
1415     const auto cellPts = state.GetCellRange(cellId);
1416 
1417     ids->SetNumberOfIds(cellPts.size());
1418     vtkIdType* idPtr = ids->GetPointer(0);
1419 
1420     for (ValueType ptId : cellPts)
1421     {
1422       *idPtr++ = static_cast<vtkIdType>(ptId);
1423     }
1424   }
1425 
1426   // SFINAE helper to check if a VisitState's connectivity array's memory
1427   // can be used as a vtkIdType*.
1428   template <typename CellStateT>
1429   struct CanShareConnPtr
1430   {
1431   private:
1432     using ValueType = typename CellStateT::ValueType;
1433     using ArrayType = typename CellStateT::ArrayType;
1434     using AOSArrayType = vtkAOSDataArrayTemplate<ValueType>;
1435     static constexpr bool ValueTypeCompat = CellStateT::ValueTypeIsSameAsIdType;
1436     static constexpr bool ArrayTypeCompat = std::is_base_of<AOSArrayType, ArrayType>::value;
1437 
1438   public:
1439     static constexpr bool value = ValueTypeCompat && ArrayTypeCompat;
1440   };
1441 
1442   template <typename CellStateT>
operatorGetCellAtIdImpl1443   typename std::enable_if<CanShareConnPtr<CellStateT>::value, void>::type operator()(
1444     CellStateT& state, const vtkIdType cellId, vtkIdType& cellSize, vtkIdType const*& cellPoints,
1445     vtkIdList* vtkNotUsed(temp))
1446   {
1447     const vtkIdType beginOffset = state.GetBeginOffset(cellId);
1448     const vtkIdType endOffset = state.GetEndOffset(cellId);
1449     cellSize = endOffset - beginOffset;
1450     // This is safe, see CanShareConnPtr helper above.
1451     cellPoints = reinterpret_cast<vtkIdType*>(state.GetConnectivity()->GetPointer(beginOffset));
1452   }
1453 
1454   template <typename CellStateT>
operatorGetCellAtIdImpl1455   typename std::enable_if<!CanShareConnPtr<CellStateT>::value, void>::type operator()(
1456     CellStateT& state, const vtkIdType cellId, vtkIdType& cellSize, vtkIdType const*& cellPoints,
1457     vtkIdList* temp)
1458   {
1459     using ValueType = typename CellStateT::ValueType;
1460 
1461     const auto cellPts = state.GetCellRange(cellId);
1462     cellSize = cellPts.size();
1463 
1464     // ValueType differs from vtkIdType, so we have to copy into a temporary
1465     // buffer:
1466     temp->SetNumberOfIds(cellSize);
1467     vtkIdType* tempPtr = temp->GetPointer(0);
1468     for (ValueType ptId : cellPts)
1469     {
1470       *tempPtr++ = static_cast<vtkIdType>(ptId);
1471     }
1472 
1473     cellPoints = temp->GetPointer(0);
1474   }
1475 };
1476 
1477 struct ResetImpl
1478 {
1479   template <typename CellStateT>
operatorResetImpl1480   void operator()(CellStateT& state)
1481   {
1482     state.GetOffsets()->Reset();
1483     state.GetConnectivity()->Reset();
1484     state.GetOffsets()->InsertNextValue(0);
1485   }
1486 };
1487 
1488 } // end namespace vtkCellArray_detail
1489 
1490 //----------------------------------------------------------------------------
InitTraversal()1491 inline void vtkCellArray::InitTraversal()
1492 {
1493   this->TraversalCellId = 0;
1494 }
1495 
1496 //----------------------------------------------------------------------------
GetNextCell(vtkIdType & npts,vtkIdType const * & pts)1497 inline int vtkCellArray::GetNextCell(vtkIdType& npts, vtkIdType const*& pts) VTK_SIZEHINT(pts, npts)
1498 {
1499   if (this->TraversalCellId < this->GetNumberOfCells())
1500   {
1501     this->GetCellAtId(this->TraversalCellId, npts, pts);
1502     ++this->TraversalCellId;
1503     return 1;
1504   }
1505 
1506   npts = 0;
1507   pts = nullptr;
1508   return 0;
1509 }
1510 
1511 //----------------------------------------------------------------------------
GetNextCell(vtkIdList * pts)1512 inline int vtkCellArray::GetNextCell(vtkIdList* pts)
1513 {
1514   if (this->TraversalCellId < this->GetNumberOfCells())
1515   {
1516     this->GetCellAtId(this->TraversalCellId, pts);
1517     ++this->TraversalCellId;
1518     return 1;
1519   }
1520 
1521   pts->Reset();
1522   return 0;
1523 }
1524 //----------------------------------------------------------------------------
GetCellSize(const vtkIdType cellId)1525 inline vtkIdType vtkCellArray::GetCellSize(const vtkIdType cellId) const
1526 {
1527   return this->Visit(vtkCellArray_detail::GetCellSizeImpl{}, cellId);
1528 }
1529 
1530 //----------------------------------------------------------------------------
GetCellAtId(vtkIdType cellId,vtkIdType & cellSize,vtkIdType const * & cellPoints)1531 inline void vtkCellArray::GetCellAtId(vtkIdType cellId, vtkIdType& cellSize,
1532   vtkIdType const*& cellPoints) VTK_SIZEHINT(cellPoints, cellSize)
1533 {
1534   this->Visit(vtkCellArray_detail::GetCellAtIdImpl{}, cellId, cellSize, cellPoints, this->TempCell);
1535 }
1536 
1537 //----------------------------------------------------------------------------
GetCellAtId(vtkIdType cellId,vtkIdList * pts)1538 inline void vtkCellArray::GetCellAtId(vtkIdType cellId, vtkIdList* pts)
1539 {
1540   this->Visit(vtkCellArray_detail::GetCellAtIdImpl{}, cellId, pts);
1541 }
1542 
1543 //----------------------------------------------------------------------------
InsertNextCell(vtkIdType npts,const vtkIdType * pts)1544 inline vtkIdType vtkCellArray::InsertNextCell(vtkIdType npts, const vtkIdType* pts)
1545   VTK_SIZEHINT(pts, npts)
1546 {
1547   return this->Visit(vtkCellArray_detail::InsertNextCellImpl{}, npts, pts);
1548 }
1549 
1550 //----------------------------------------------------------------------------
InsertNextCell(int npts)1551 inline vtkIdType vtkCellArray::InsertNextCell(int npts)
1552 {
1553   return this->Visit(vtkCellArray_detail::InsertNextCellImpl{}, npts);
1554 }
1555 
1556 //----------------------------------------------------------------------------
InsertCellPoint(vtkIdType id)1557 inline void vtkCellArray::InsertCellPoint(vtkIdType id)
1558 {
1559   if (this->Storage.Is64Bit())
1560   {
1561     using ValueType = typename ArrayType64::ValueType;
1562     this->Storage.GetArrays64().Connectivity->InsertNextValue(static_cast<ValueType>(id));
1563   }
1564   else
1565   {
1566     using ValueType = typename ArrayType32::ValueType;
1567     this->Storage.GetArrays32().Connectivity->InsertNextValue(static_cast<ValueType>(id));
1568   }
1569 }
1570 
1571 //----------------------------------------------------------------------------
UpdateCellCount(int npts)1572 inline void vtkCellArray::UpdateCellCount(int npts)
1573 {
1574   this->Visit(vtkCellArray_detail::UpdateCellCountImpl{}, npts);
1575 }
1576 
1577 //----------------------------------------------------------------------------
InsertNextCell(vtkIdList * pts)1578 inline vtkIdType vtkCellArray::InsertNextCell(vtkIdList* pts)
1579 {
1580   return this->Visit(
1581     vtkCellArray_detail::InsertNextCellImpl{}, pts->GetNumberOfIds(), pts->GetPointer(0));
1582 }
1583 
1584 //----------------------------------------------------------------------------
InsertNextCell(vtkCell * cell)1585 inline vtkIdType vtkCellArray::InsertNextCell(vtkCell* cell)
1586 {
1587   vtkIdList* pts = cell->GetPointIds();
1588   return this->Visit(
1589     vtkCellArray_detail::InsertNextCellImpl{}, pts->GetNumberOfIds(), pts->GetPointer(0));
1590 }
1591 
1592 //----------------------------------------------------------------------------
Reset()1593 inline void vtkCellArray::Reset()
1594 {
1595   this->Visit(vtkCellArray_detail::ResetImpl{});
1596 }
1597 
1598 #endif // vtkCellArray.h
1599