# GetPointer vs ValueRange for typed data arrays

**URL:** <https://discourse.vtk.org/t/getpointer-vs-valuerange-for-typed-data-arrays/4826>\
**Category:** Development\
**Created:** [December 15, 2020, 2:50pm UTC](https://discourse.vtk.org/t/getpointer-vs-valuerange-for-typed-data-arrays/4826 "2020-12-15T14:50:09Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![jaswantp](https://discourse.vtk.org/user_avatar/discourse.vtk.org/jaswantp/32/10046_2.png) [@jaswantp](https://discourse.vtk.org/u/jaswantp)\
**Post date:** [December 15, 2020, 2:50pm UTC](https://discourse.vtk.org/t/getpointer-vs-valuerange-for-typed-data-arrays/4826/1 "2020-12-15T14:50:09Z")

</div>

I’m using `vtkIdTypeArray` to implement a half-edge data structure for 2D meshes. Once the faces are prepared, the connectivity and offsets array will be sent to `vtkCellArray` with (`vtkCellArray::SetData(vtkIdTypeArray*, vtkIdTypeArray*)`).

I’m stuck b/w certain syntactic/API choices. It would help to get an expert opinion before I choose one over the other.

Internally, the `struct` uses API of said data arrays. But, I want to access member data-arrays through traditional `operator[]`. Now, I have two options: 1. `Ranges`, 2. `GetPointer()`.

Also right after any `Resize`/`InsertTypedComponent` these _proxy_-like accessors are invalid, so I’ve to revalidate them.

Ex: Build 2-D meshes with half-edge data-structure and fill a `vtkCellArray`

```auto
struct HalfEdgeMesh
{
  HalfEdgeMesh() 
    : m_Conn(vtkIdTypeArray::New())
    , m_Offsts(vtkIdTypeArray::New())
    , m_HalfEdges(vtkIdTypeArray::New())
  {}

   // vtkCellArray will assume ownership, so no need to invoke GC rn.
  ~HalfEdgeMesh() {m_Conn->FastDelete(); m_Offsts->FastDelete(); ...}

  // to simplify access, provide public pointers.
  vtkIdType* polys
  vtkIdType* offsets
  vtkIdType* halfEdges
   
  void Allocate(vtkIdType maxPolys) {...}
  void Insert(vtkIdType* verts, vtkIdType* hedges) {...} 
  void FillUp(vtkCellArray* polys) { polys->SetData(m_Conn, m_Offsts); }
  void Link(vtkIdType hedge1, vtkIdType hedge2){...}
  void Size() {...}
 
private:
  vtkIdTypeArray* m_Conn;
  vtkIdTypeArray* m_Offsts;
  vtkIdTypeArray* m_HalfEdges;

protected:
  // must call this post-allocation or post-resize
  // in methods `Allocate`, `Insert` and `Link`
  void __revalidate_mem_accessors() {...}
};

```

Possible implementations of `__revalidate_mem_accessors`:

1. This looks _weird_. Each line makes 4 assertions and is the one suggested by docs. 😕

```auto
{
  polys = vtk::DataArrayValueRange<1>(m_Conn).begin();
  offsets = vtk::DataArrayValueRange<1>(m_Offsts).begin();
  halfEdges= vtk::DataArrayValueRange<1>(m_HalfEdges).begin();
}

```

1. This is _simple_ and _readable_. It has minimal overhead; zero assertions, zero range checks.

```auto
{
  polys = m_Conn->GetPointer(0);
  offsets = m_Offsts->GetPointer(0);
  halfEdges= m_HalfEdges->GetPointer(0);
}

```

Also, the functions `Insert` and `Link` are called in very tight loops that need to be performant. Which would be better? Is this a bad design?

I’m aware that exposing non-const public pointers is scary but I use this in a translation unit where I am the sole user of this `struct`.

Posting after a mini panic-attack when I found [this](https://vtk.org/doc/nightly/html/classvtkAOSDataArrayTemplate.html#a73bfa031ba2d6ced70205c22639b1ee8) in the documentation for `GetPointer`.

> Get the address of a particular data index.  
> Performs no checks to verify that the memory has been allocated etc. Use of this method is  
> discouraged, as newer arrays require a deep-copy of the array data in order to return a suitable  
> pointer. See [vtkArrayDispatch](https://vtk.org/doc/nightly/html/classvtkArrayDispatch.html) for a safer  
> alternative for fast data access.

Will that mean `GetPointer` will soon be `deprecated` in coming releases?  
It would be great for typed data-arrays to retain this method.

Edit: code typos

---

<div class="post-metadata">

**Author:** ![AllisonVacanti](https://discourse.vtk.org/user_avatar/discourse.vtk.org/allisonvacanti/32/2396_2.png) [@AllisonVacanti](https://discourse.vtk.org/u/AllisonVacanti)\
**Post date:** [December 16, 2020, 6:36am UTC](https://discourse.vtk.org/t/getpointer-vs-valuerange-for-typed-data-arrays/4826/2 "2020-12-16T06:36:11Z")

</div>

tl;dr: Just storing the `vtk::DataArrayValueRange<1>(array)` object directly instead of the iterator (no `begin()`) will also provide `operator[]` access and is a bit cleaner. The range/iterator approaches provide additional runtime safety checks only in debugging builds. When building in release mode, identical assembly is emitted for the ranges and the pointer versions and performance is the same.

Now – since I love to get longwinded when talking about data models, a more detailed answer follows 😃

This is what I would use:

```auto
// Deduce range type
using RangeType = decltype(
  vtk::DataArrayValueRange<1>(std::declval<vtkIdTypeArray*>()));

// Declare variable
RangeType polys;

// Initialize
polys = vtk::DataArrayValueRange<1>(m_Conn);

```

> This looks _weird_ . Each line makes 4 assertions and is the one suggested by docs.

Weird is subjective I suppose 🙂 C++ has changed a lot over the years, and admittedly the newer syntaxes post-C++11 feel like a completely different language compared with the “C with classes” style from 1994, when most of the core VTK classes were originally written. It takes some adjustment.

The docs suggest this approach because the assertions are your friends – they catch bugs early and don’t affect performance unless you’re building in `Debug` mode, in which case testing and correctness are the goals of the build, not peak performance. You can also define `VTK_DEBUG_RANGE_ITERATORS` to get even more correctness checks to help track down trickier problems, again at the cost of performance. Alternatively, you can instead define `VTK_ALWAYS_OPTIMIZE_ARRAY_ITERATORS` to opt out of the checks and enable optimizations for the ranges/iterators in debug mode, which should help recover a significant amount of performance.

But performance is never impacted where it matters: using ranges and iterators in `Release` mode generally produces the exact same assembly as using a raw pointer. Towards the end of [this blog post](https://blog.kitware.com/c11-for-range-support-in-vtk/) I summarized a series of benchmarks on the tight loop iteration performance of ranges vs raw pointers. If you’re using a typed `vtkIdTypeArray` to create the ranges, the relevant results will be the 3rd and 4th bar charts in that post comparing the `vtkAOSDataArrayTemplate` results. There’s virtually no difference between the `Pointer` vs the `Range`/`Iterator` benchmarks, all are within noise. Whether you write:

```auto
  const ValueType *data = array->GetPointer(0);
  ValueType sum{0};
  for (vtk::ValueIdType v = 0; v < numValues; ++v)
  {
    sum += *data++;
  }

```

or

```auto
  const auto range = vtk::DataArrayValueRange<TupleSize>(array);
  APIType sum{0};
  for (const auto& value : range)
  {
    sum += value;
  }

```

will have no impact on performance in a release build, but the second version helps catch bugs in debugging builds.

The sources are [here](https://gitlab.kitware.com/allisonvacanti/vtkBenchmark/blob/master/RangeIters.cxx) if you’re curious what the implementations of the other benchmarks look like.

> the functions `Insert` and `Link` are called in very tight loops that need to be performant. Which would be better? Is this a bad design?

I wouldn’t say it’s a bad design, but calling either of those in a loop is going to be bad for performance. Both allocate memory, and those allocations are expensive. The `Insert` method is especially troublesome – it’s branchy, and every call will execute a lot of extra instructions to check whether the array needs reallocation. Not to mention the fact that its behavior is completely different and surprising compared to any other container’s `insert` methods 😅 Use it cautiously, and read the docs for that one carefully!

Ideally, you’ll want to pre-allocate memory whenever possible and keep allocations/invalidations to an absolute minimum. There are three scenarios, in order from best performance to worst:

1. The exact final size of the array is known. Do a single allocation before the tight loop that exactly fits the data. Use Range APIs to make sure that your calculated size is correct and detect accesses beyond the predicted size when debugging.
2. The exact size is unknown, but has a known upper bound. Same as above, but preallocate the upper bound and then `Resize` to the final size once it is known.
3. Worst case: nothing is known about the final size of the array. Pre-allocate a reasonable guess at the final size with `Allocate` (which increases capacity without increasing the actual number of valid values) and then fill with `InsertNextValue` to make sure the array is grown as-needed. Finish up with `Squeeze` if you want to release any excess memory (this will also invalidate pointers/ranges, btw).

> Will that mean `GetPointer` will soon be `deprecated` in coming releases?

No. Subclasses of `vtkAOSDataArrayTemplate<T>` (including `vtkIdTypeArray`) will always provide the typed `GetPointer` method. At one point I was pushing to deprecate `GetVoidPointer` in the generic levels of the array hierarchy, since that’s a real can of worms after the SOA-layout arrays were added. But I don’t think there’s been much interest in continuing that effort since I stopped working on VTK.

Also – unrelated, but as a heads up,

> `__revalidate_mem_accessors`

Identifiers containing double underscores are reserved by compiler vendors. It’s best to avoid them.

---

<div class="post-metadata">

**Author:** ![jaswantp](https://discourse.vtk.org/user_avatar/discourse.vtk.org/jaswantp/32/10046_2.png) [@jaswantp](https://discourse.vtk.org/u/jaswantp)\
**Post date:** [December 16, 2020, 7:33am UTC](https://discourse.vtk.org/t/getpointer-vs-valuerange-for-typed-data-arrays/4826/3 "2020-12-16T07:33:27Z")

</div>

Hi, Thanks for your reply.

> [@AllisonVacanti](#):
>
> tl;dr: Just storing the `vtk::DataArrayValueRange<1>(array)` object directly instead of the iterator (no `begin()`) will also provide `operator[]` access and is a bit cleaner

Sweet.

> [@AllisonVacanti](#):
>
> There’s virtually no difference between the `Pointer` vs the `Range`/`Iterator` benchmarks, all are within noise.

Yes!

> [@AllisonVacanti](#):
>
> The `Insert` method is especially troublesome – it’s branchy, and every call will execute a lot of extra instructions to check whether the array needs reallocation. Not to mention the fact that its behavior is completely different and surprising compared to any other container’s `insert` methods

Right, so much to ensure `MaxId` is appropriate. I dealt with worst-case scenarios by resizing the array beforehand followed by successive `InsertTypedComponent`. I found this to be better than naive calls to `InsertTypedComponent`. That’s the least I could do. 🤷‍♂️

> [@AllisonVacanti](#):
>
> but calling either of those in a loop is going to be bad for performance.

In worst-case it is bad. In my use, almost always, I have a rough estimate of the upper bound.

It’s the cases when the rough estimate is a poor one… Such scenarios will require `Ranges` to be revalidated. But I think I can get around that by querying `MaxId` and revalidate only if required.

> [@AllisonVacanti](#):
>
> Identifiers containing double underscores are reserved by compiler vendors. It’s best to avoid them.

Ah, ok. Thanks for pointing that out.

> [@AllisonVacanti](#):
>
> No. Subclasses of `vtkAOSDataArrayTemplate<T>` (including `vtkIdTypeArray`) will always provide the typed `GetPointer` method. At one point I was pushing to deprecate `GetVoidPointer` in the generic levels of the array hierarchy, since that’s a real can of worms after the SOA-layout arrays were added. But I don’t think there’s been much interest in continuing that effort since I stopped working on VTK.

Good. You improved the data-access part of this library. Most of the stuff I do in VTK is impossible without your contributions. Thank you 😅
