HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UT_PackedArrayOfArrays.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: UT_PackedArrayOfArrays.h (UT Library, C++)
7  *
8  * COMMENTS: An array of arrays that is more efficiently
9  * laid out than the UT_Array<UT_Array<T> >
10  * Only allows appending, however.
11  */
12 
13 #pragma once
14 
15 #ifndef __UT_PACKED_ARRAY_OF_ARRAYS_H__
16 #define __UT_PACKED_ARRAY_OF_ARRAYS_H__
17 
18 #include "UT_API.h"
19 
20 #include "UT_Array.h"
21 #include "UT_Span.h"
22 #include "UT_IteratorRange.h"
23 #include "UT_ParallelUtil.h"
24 
25 template <typename T>
27 {
28 public:
30 
32  {
33  }
34 
35  void clear()
36  { myOffsets.clear(); myData.clear(); }
37  bool isEmpty() const
38  { return size() == 0; }
39 
40  /// Returns the number of arrays in this structure.
41  exint size() const { return SYSmax(myOffsets.size() - 1, 0); }
42  exint entries() const { return size(); }
43 
44  int64 getMemoryUsage(bool inclusive = false) const
45  {
46  return (inclusive ? sizeof(*this) : 0) +
47  myOffsets.getMemoryUsage(false) +
48  myData.getMemoryUsage(false);
49  }
50 
51  /// Adds a new array to the end of our list of arrays.
52  void append(const UT_Array<T> &arr)
53  { append(arr.array(), arr.entries()); }
54  void append(const T *data, exint len)
55  {
56  if (myOffsets.isEmpty())
57  myOffsets.append(0);
58  myData.bumpCapacity(myData.size() + len);
59  for (exint i = 0; i < len; i++)
60  myData.append(data[i]);
61  myOffsets.append(myData.entries());
62  }
63  void append(const UT_PackedArrayOfArrays<T> &arr, exint idx)
64  { append(arr.arrayData(idx), arr.arrayLen(idx)); }
65 
66  /// Appends an array of arrays to our list.
68  {
69  myOffsets.bumpCapacity(myOffsets.size() + arr.size());
70  myData.bumpCapacity(myData.size() + arr.myData.size());
71  for (exint i = 0; i < arr.entries(); i++)
72  append(arr, i);
73  }
74 
75  /// Moves an array of arrays to our list.
77  {
78  // If the array is empty just steal the other array.
79  if (isEmpty())
80  {
81  *this = std::move(arr);
82  return;
83  }
84 
85  // Otherwise we can do a move concat for the data, but the
86  // offsets need to be shifted.
87  myData.concat(std::move(arr.myData));
88 
89  myOffsets.bumpCapacity(myOffsets.size() + arr.size());
90  for (exint i = 0, n = arr.size(); i < n; ++i)
91  myOffsets.append(myOffsets.last() + arr.arrayLen(i));
92 
93  arr.myOffsets.clear();
94  }
95 
96  /// Appends a new array and returns a pointer to the resulting
97  /// data so it can be filled in.
99  {
100  if (myOffsets.isEmpty())
101  myOffsets.append(0);
102  exint base = myOffsets.last();
103  myOffsets.append(base+len);
104  myData.bumpSize(base+len);
105  return myData.array() + base;
106  }
107 
108  /// Appends new arrays in parallel using a functor to compute element
109  /// count per array.
110  ///
111  /// The functor takes the form exint(exint) or optionally
112  /// exint(exint, TLD&) where TLD is some thread-local data that can be
113  /// reused by the functor.
114  ///
115  /// Example:
116  ///
117  /// data.allocateArraysNoInit(
118  /// gdp->getNumPrimitives(),
119  /// [&](exint i)
120  /// {
121  /// return gdp->getPrimitiveVertexCount(gdp->primitiveOffset(i));
122  /// });
123  ///
124  ///
125  /// Example with TLD:
126  ///
127  /// data.allocateArraysNoInit<GA_OffsetArray>(
128  /// gdp->getNumPoints(),
129  /// [&](exint i, GA_OffsetArray &offsets)
130  /// {
131  /// gdp->getPrimitivesReferencingPoint(offsets, gdp->pointOffset(i));
132  /// return offsets.size();
133  /// });
134  template <typename TLD = void, typename FUNC>
135  T *allocateArraysNoInit(exint n, FUNC &&countfunctor)
136  {
137  if (myOffsets.isEmpty())
138  myOffsets.append(0);
139  exint base = myOffsets.last();
140  exint oldcount = myOffsets.size();
141  myOffsets.setSizeNoInit(oldcount + n);
144  [&](const UT_BlockedRange<exint> &r)
145  {
146  if constexpr (!std::is_void_v<TLD>)
147  {
148  TLD tld;
149  for (exint i = r.begin(), end = r.end(); i < end; ++i)
150  myOffsets[oldcount + i] = countfunctor(i, tld);
151  }
152  else
153  {
154  for (exint i = r.begin(), end = r.end(); i < end; ++i)
155  myOffsets[oldcount + i] = countfunctor(i);
156  }
157  });
158 
159  UT_Span<exint> tempoffsets(myOffsets.data() + oldcount, n);
161  tempoffsets, base, std::plus<exint>());
162  // Assume few calls with large n and focus on performance.
163  // setSizeNoInit rather than bumpSize.
164  myData.setSizeNoInit(myOffsets.last());
165  return myData.array() + base;
166  }
167 
168  /// From the given idxth array, return the idx_in_array element
169  const T &operator()(exint idx, exint idx_in_array) const
170  {
171  UT_ASSERT_P(idx >= 0 && idx < size());
172  exint base = myOffsets(idx);
173  UT_ASSERT_P(base+idx_in_array < myOffsets(idx+1));
174  return myData(base+idx_in_array);
175  }
176 
177  /// Extracts an array into a UT_Array.
178  void extract(UT_Array<T> &result, exint idx) const
179  {
180  UT_ASSERT_P(idx >= 0 && idx < size());
181  exint base = myOffsets(idx);
182  exint len = myOffsets(idx+1)-base;
183  result.entries(len);
184  for (exint i = 0; i < len; i++)
185  result(i) = myData(base+i);
186  }
187 
189  {
190  // This is less than equal to as it is valid to
191  // point to the final element if the corresponding
192  // array is empty!
193  UT_ASSERT_P(myOffsets(idx) <= myData.size());
194  return myData.array() + myOffsets(idx);
195  }
196  const T *arrayData(exint idx) const
197  {
198  UT_ASSERT_P(myOffsets(idx) <= myData.size());
199  return myData.array() + myOffsets(idx);
200  }
201  exint arrayLen(exint idx) const
202  {
203  return myOffsets(idx+1)-myOffsets(idx);
204  }
206  {
207  return UT_Span<const T>(arrayData(idx), arrayLen(idx));
208  }
209 
210  /// @{
211  /// Returns an iterator range for the specified array.
213  { return UTmakeRange(arrayData(idx), arrayData(idx + 1)); }
215  { return UTmakeRange(arrayData(idx), arrayData(idx + 1)); }
216  /// @}
217 
218  /// Decreases, but never expands, to the given maxsize.
219  void truncate(exint maxsize)
220  {
221  if (maxsize >= 0 && size() > maxsize)
222  {
223  if (maxsize == 0)
224  clear();
225  else
226  {
227  myOffsets.setSize(maxsize+1);
228  myData.setSize(myOffsets(maxsize));
229  }
230  }
231  }
232 
233  /// These adjust the capacity without adjusting the entries
234  /// and are useful for pre-allocing the amount when known
235  /// in advance.
236  void setDataCapacity(exint capacity)
237  { myData.setCapacity(capacity); }
239  { myData.setCapacityIfNeeded(capacity); }
240  void setArrayCapacity(exint capacity)
241  { myOffsets.setCapacity(capacity); }
243  { myOffsets.setCapacityIfNeeded(capacity); }
244 
245  /// The raw offset table stores the end of each array
246  /// in the data array.
247  /// Each array has [rawOffsets(idx) ... rawOffsets(idx+1))
248  UT_Array<exint> &rawOffsets() { return myOffsets; }
249  const UT_Array<exint> &rawOffsets() const { return myOffsets; }
250 
251  /// All of the array data is in one contiguous block.
252  UT_Array<T> &rawData() { return myData; }
253  const UT_Array<T> &rawData() const { return myData; }
254 
255 private:
256  UT_Array<exint> myOffsets;
257  UT_Array<T> myData;
258 };
259 
260 #endif
261 
#define SYSmax(a, b)
Definition: SYS_Math.h:1952
void setDataCapacity(exint capacity)
const T & operator()(exint idx, exint idx_in_array) const
From the given idxth array, return the idx_in_array element.
void truncate(exint maxsize)
Decreases, but never expands, to the given maxsize.
UT_Array< exint > & rawOffsets()
UT_IteratorRange< IterT > UTmakeRange(IterT &&b, IterT &&e)
int64 exint
Definition: SYS_Types.h:125
const UT_Array< T > & rawData() const
T * array()
Definition: UT_Array.h:863
void UTparallelForLightItems(const Range &range, const Body &body, const bool force_use_task_scope=true)
**But if you need a result
Definition: thread.h:622
UT_IteratorRange< const T * > arrayRange(exint idx) const
void append(const UT_PackedArrayOfArrays< T > &arr, exint idx)
void append(const T *data, exint len)
void setArrayCapacity(exint capacity)
const UT_Array< exint > & rawOffsets() const
GLdouble n
Definition: glcorearb.h:2008
const T * arrayData(exint idx) const
void concat(const UT_PackedArrayOfArrays< T > &arr)
Appends an array of arrays to our list.
#define UT_ASSERT_P(ZZ)
Definition: UT_Assert.h:164
GLuint GLuint end
Definition: glcorearb.h:475
UT_Array< T > & rawData()
All of the array data is in one contiguous block.
void setArrayCapacityIfNeeded(exint capacity)
long long int64
Definition: SYS_Types.h:116
UT_Span< const T > span(exint idx) const
void concat(UT_PackedArrayOfArrays< T > &&arr)
Moves an array of arrays to our list.
void extract(UT_Array< T > &result, exint idx) const
Extracts an array into a UT_Array.
exint size() const
Returns the number of arrays in this structure.
exint entries() const
Alias of size(). size() is preferred.
Definition: UT_Array.h:669
GLsizeiptr size
Definition: glcorearb.h:664
void setDataCapacityIfNeeded(exint capacity)
int64 getMemoryUsage(bool inclusive=false) const
#define UT_API_TMPL
Definition: UT_API.h:15
void append(const UT_Array< T > &arr)
Adds a new array to the end of our list of arrays.
exint arrayLen(exint idx) const
GLboolean r
Definition: glcorearb.h:1222
T * allocateArraysNoInit(exint n, FUNC &&countfunctor)
void UTparallelDeterministicPrefixSumInPlace(UT_Span< T > &array, const T identity, const Op &op, const int grain_size=1024, const bool force_use_task_scope=true)
Declare prior to use.
Definition: format.h:1821
UT_IteratorRange< T * > arrayRange(exint idx)