iMSTK
Interactive Medical Simulation Toolkit
imstkDataArray.h
1 /*
2 ** This file is part of the Interactive Medical Simulation Toolkit (iMSTK)
3 ** iMSTK is distributed under the Apache License, Version 2.0.
4 ** See accompanying NOTICE for details.
5 */
6 
7 #pragma once
8 
9 #include "imstkAbstractDataArray.h"
10 #include "imstkMath.h"
11 #include "imstkMacros.h"
12 
13 namespace imstk
14 {
21 template<typename T>
23 {
24 public:
25 
26  using ScalarType = T;
27  using ValueType = T;
28  static constexpr int NumComponents = 1;
29 
30  class iterator
31  {
32  public:
33  using self_type = iterator;
34  using value_type = T;
35  using iterator_category = std::forward_iterator_tag;
36  using difference_type = std::ptrdiff_t;
37  using pointer = T*;
38  using reference = T&;
39 
40  public:
41  iterator(pointer ptr, pointer end) : ptr_(ptr), end_(end) { }
42 
43  self_type operator++()
44  {
45  self_type i = *this;
46  ptr_++;
47 #ifdef IMSTK_CHECK_ARRAY_RANGE
48  if ((end_ - ptr_) < 0) { throw std::runtime_error("iterator past bounds"); }
49 #endif
50  return i;
51  }
52 
53  self_type operator++(int junk)
54  {
55  ptr_++;
56 #ifdef IMSTK_CHECK_ARRAY_RANGE
57  if ((end_ - ptr_) < 0) { throw std::runtime_error("iterator past bounds"); }
58 #endif
59  return *this;
60  }
61 
62  reference operator*() { return *ptr_; }
63 
64  pointer operator->() { return ptr_; }
65 
66  bool operator==(const self_type& rhs) const { return ptr_ == rhs.ptr_; }
67 
68  bool operator!=(const self_type& rhs) const { return ptr_ != rhs.ptr_; }
69 
70  private:
71  pointer ptr_;
72  pointer end_;
73  };
74 
76  {
77  public:
78  using self_type = const_iterator;
79  using value_type = T;
80  using iterator_category = std::forward_iterator_tag;
81  using difference_type = std::ptrdiff_t;
82  using pointer = T*;
83  using reference = const T&;
84 
85  public:
86  const_iterator(pointer ptr, pointer end) : ptr_(ptr), end_(end) { }
87 
88  self_type operator++()
89  {
90  self_type i = *this;
91  ptr_++;
92 #ifdef IMSTK_CHECK_ARRAY_RANGE
93  if ((end_ - ptr_) < 0) { throw std::runtime_error("iterator past bounds"); }
94 #endif
95  return i;
96  }
97 
98  self_type operator++(int junk)
99  {
100  ptr_++;
101 #ifdef IMSTK_CHECK_ARRAY_RANGE
102  if ((end_ - ptr_) < 0) { throw std::runtime_error("iterator past bounds"); }
103 #endif
104  return *this;
105  }
106 
107  reference operator*() { return *ptr_; }
108 
109  const pointer operator->() { return ptr_; }
110 
111  bool operator==(const self_type& rhs) const { return ptr_ == rhs.ptr_; }
112 
113  bool operator!=(const self_type& rhs) const { return ptr_ != rhs.ptr_; }
114 
115  private:
116  pointer ptr_;
117  pointer end_;
118  };
119 
120 public:
125  DataArray() : m_mapped(false), m_data(new T[1])
126  {
127  setType(TypeTemplateMacro(T));
128  m_capacity = 1;
129  }
130 
134  DataArray(const int size) : AbstractDataArray(size), m_mapped(false), m_data(new T[size])
135  {
136  setType(TypeTemplateMacro(T));
137  }
138 
142  template<typename U>
143  DataArray(std::initializer_list<U> list) : AbstractDataArray(static_cast<int>(list.size())), m_mapped(false), m_data(new T[list.size()])
144  {
145  int j = 0;
146  for (auto i : list)
147  {
148  m_data[j] = i;
149  j++;
150  }
151  setType(TypeTemplateMacro(T));
152  m_size = m_capacity = static_cast<int>(list.size());
153  }
154 
159  DataArray(const DataArray& other) : AbstractDataArray(other)
160  {
161  // Copy the buffer instead of the pointer
162  m_mapped = other.m_mapped;
163  m_size = other.m_size;
164  m_capacity = other.m_capacity;
165  m_scalarType = other.m_scalarType;
166  if (m_mapped)
167  {
168  m_data = other.m_data;
169  }
170  else
171  {
172  m_data = new T[m_size];
173  std::copy_n(other.m_data, m_size, m_data);
174  }
175  }
176 
177  DataArray(DataArray&& other)
178  {
179  m_mapped = other.m_mapped;
180  m_size = other.m_size;
181  m_capacity = other.m_capacity;
182  m_scalarType = other.m_scalarType;
183  m_data = other.m_data; // Take the others buffer
184  other.m_mapped = true; // The others destructor should then not delete
185  }
186 
187  ~DataArray() override
188  {
189  if (!m_mapped)
190  {
191  delete[] m_data;
192  m_data = nullptr;
193  }
194  }
195 
196 public:
200  inline void resize(const int size) override
201  {
202  // Can't resize a mapped vector
203  if (m_mapped)
204  {
205  return;
206  }
207 
208  if (size <= m_capacity)
209  {
210  m_size = size;
211  }
212  else
213  {
214  const T* oldData = m_data;
215  m_data = new T[size];
216  std::copy_n(oldData, m_size, m_data);
217  delete[] oldData;
218  m_size = m_capacity = size;
219  }
220  }
221 
225  inline void fill(const T& val) { std::fill_n(m_data, m_size, val); }
226 
230  virtual inline void squeeze()
231  {
232  const T* oldData = m_data;
233  m_data = new T[m_size];
234  std::copy_n(oldData, m_size, m_data);
235  delete[] oldData;
236  m_capacity = m_size;
237  }
238 
242  inline void push_back(const T& val)
243  {
244  // Can't push back to a mapped vector
245  if (m_mapped)
246  {
247  return;
248  }
249 
250  const int newSize = m_size + 1;
251  if (newSize > m_capacity) // If the new size exceeds capacity
252  {
253  resize(m_capacity * 2); // Conservative/copies values
254  }
255  m_size = newSize;
256  m_data[newSize - 1] = val;
257  }
258 
259  inline void push_back(const T&& val) // Move
260  {
261  // Can't push back to a mapped vector
262  if (m_mapped)
263  {
264  return;
265  }
266 
267  const int newSize = m_size + 1;
268  if (newSize > m_capacity) // If the new size exceeds capacity
269  {
270  reserve(m_capacity * 2); // Conservative/copies values
271  }
272  m_size = newSize;
273  m_data[newSize - 1] = val;
274  }
275 
279  iterator begin() { return iterator(m_data, m_data + m_size); }
280 
281  const_iterator begin() const { return const_iterator(m_data, m_data + m_size); }
282 
283  iterator end() { return iterator(m_data + m_size, m_data + m_size); }
284 
285  const_iterator end() const { return const_iterator(m_data + m_size, m_data + m_size); }
286 
287  const_iterator cbegin() const { return const_iterator(m_data, m_data + m_size); }
288 
289  const_iterator cend() const { return const_iterator(m_data + m_size, m_data + m_size); }
291 
295  inline void reserve(const int capacity) override
296  {
297  if (m_mapped) { return; }
298  if (capacity <= m_capacity) { return; }
299 
300  const int currSize = m_size;
301  resize(capacity); // Reallocate
302  m_size = currSize; // Keep current size
303  }
304 
305  inline T* getPointer() { return m_data; }
306  inline void* getVoidPointer() override { return static_cast<void*>(m_data); }
307 
308  inline T& operator[](const size_t pos)
309  {
310 #ifdef IMSTK_CHECK_ARRAY_RANGE
311  if (pos >= static_cast<size_t>(m_size)) { throw std::out_of_range("Index out of range"); }
312 #endif
313  return m_data[pos];
314  }
315 
316  inline const T& operator[](const size_t pos) const
317  {
318 #ifdef IMSTK_CHECK_ARRAY_RANGE
319  if (pos >= static_cast<size_t>(m_size)) { throw std::out_of_range("Index out of range"); }
320 #endif
321  return m_data[pos];
322  }
323 
328  inline T& at(const size_t pos)
329  {
330 #ifdef IMSTK_CHECK_ARRAY_RANGE
331  if (pos >= static_cast<size_t>(m_size)) { throw std::out_of_range("Index out of range"); }
332 #endif
333  return m_data[pos];
334  }
335 
340  inline const T& at(const size_t pos) const
341  {
342 #ifdef IMSTK_CHECK_ARRAY_RANGE
343  if (pos >= static_cast<size_t>(m_size)) { throw std::out_of_range("Index out of range"); }
344 #endif
345  return m_data[pos];
346  }
347 
351  template<typename U>
352  DataArray<T>& operator=(std::initializer_list<U> list)
353  {
354  // If previously mapped, don't delete, just overwrite
355  if (!m_mapped)
356  {
357  delete[] m_data;
358  }
359  m_data = new T[list.size()];
360  int j = 0;
361  for (auto i : list)
362  {
363  m_data[j] = i;
364  j++;
365  }
366  m_size = m_capacity = static_cast<int>(list.size());
367  m_mapped = false;
368  return *this;
369  }
370 
371  DataArray& operator=(const DataArray& other)
372  {
373  // Delegate to the appropriate functions while maintaining state
374  // No need to copy type as it's static and this will only be used
375  // for `=` of equivalent types
376  if (other.m_mapped)
377  {
378  setData(other.m_data, other.size());
379  }
380  else
381  {
382  if (m_mapped)
383  {
384  m_data = nullptr;
385  m_capacity = 0;
386  m_size = 0;
387  m_mapped = false;
388  }
389  reserve(other.size());
390  std::copy_n(other.m_data, other.m_size, m_data);
391  m_size = other.m_size;
392  }
393 
394  return *this;
395  }
396 
400  /*inline Vec2d getRange(const int component) const
401  {
402  ParallelUtils::RangeFunctor<DataArray<T, N>> pObj(vec);
403  tbb::parallel_reduce(tbb::blocked_range<size_t>(0, vec.size()), pObj);
404  return pObj.getRange();
405  return Vec2d(0.0, 0.0);
406  }*/
407 
414  inline void setData(T* ptr, const int size)
415  {
416  if (!m_mapped)
417  {
418  delete[] m_data;
419  }
420  m_mapped = true;
421  m_data = ptr;
422  m_size = m_capacity = size;
423  }
424 
425  inline virtual int getNumberOfComponents() const override { return NumComponents; }
426 
430  template<typename N>
432  {
433  if (m_mapped)
434  {
435  throw(std::runtime_error("Can't cast a mapped array"));
436  }
437  DataArray<N> result;
438  result.reserve(size());
439  for (auto& i : *this)
440  {
441  result.push_back(static_cast<N>(i));
442  }
443  return result;
444  }
445 
449  std::shared_ptr<AbstractDataArray> cast(ScalarTypeId type) override
450  {
451  if (type == AbstractDataArray::m_scalarType)
452  {
453  return std::make_shared<DataArray<T>>(*this);
454  }
455  switch (type)
456  {
457  TemplateMacro(return std::make_shared<DataArray<IMSTK_TT>>(cast<IMSTK_TT>()));
458  default:
459  throw(std::runtime_error("Unknown scalar type"));
460  }
461  }
462 
467  std::unique_ptr<DataArray<T>> clone()
468  {
469  return std::unique_ptr<DataArray<T>>(cloneImplementation());
470  }
471 
472 protected:
473 
474  bool m_mapped;
475  T* m_data;
476 
477 private:
478 
479  DataArray<T>* cloneImplementation()
480  {
481  return new DataArray<T>(*this);
482  };
483 };
484 } // namespace imstk
const T & at(const size_t pos) const
int size() const
Get number of values/tuples.
std::shared_ptr< AbstractDataArray > cast(ScalarTypeId type) override
Cast array to the IMSTK type on the abstract interface.
DataArray(const int size)
Constructs a data array.
DataArray< N > cast()
Cast array to specific c++ type.
T & at(const size_t pos)
virtual int getNumberOfComponents() const override
Returns the number of components.
virtual void squeeze()
Resize to current size.
Compound Geometry.
DataArray(std::initializer_list< U > list)
Constructs from intializer list.
void fill(const T &val)
Fill the array with the specified value.
std::unique_ptr< DataArray< T > > clone()
Polymorphic clone, shadows the declaration in the superclasss but returns own type.
This class serves as the base class of DataArray, for typeless use.
DataArray()
Constructs an empty data array DataArray will never have capacity < 1.
void reserve(const int capacity) override
Allocates extra capacity, for the number of values, conservative reallocate.
void * getVoidPointer() override
Returns void pointer to data.
void resize(const int size) override
Resize data array to hold exactly size number of values.
void push_back(const T &val)
Append the data array to hold the new value, resizes if neccesary.
iterator begin()
begin(), end() to mirror std::vector
void setData(T *ptr, const int size)
Computes the range of a component of the vectors elements.
DataArray(const DataArray &other)
Copy Constructor.
DataArray< T > & operator=(std::initializer_list< U > list)
Allow initialization from initializer list, ie: DataArray<int> arr = { 1, 2 }.
bool operator==(const Color &color_lhs, const Color &color_rhs)
Comparison operator.
Definition: imstkColor.cpp:310
Color operator*(const Color &color_lhs, const Color &color_rhs)
Multiplication operators.
Definition: imstkColor.cpp:178
Simple dynamic array implementation that also supports event posting and viewing/facade.