HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UT_RLEArray.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_RLEArray.h (GT Library, C++)
7  *
8  * COMMENTS:
9  */
10 
11 #ifndef __UT_RLEArray__
12 #define __UT_RLEArray__
13 
14 #include "UT_API.h"
15 #include "UT_SmallArray.h"
16 #include "UT_Debug.h"
17 #include <algorithm>
18 #include <iterator>
19 #include <utility>
20 
21 class UT_JSONWriter;
22 
23 /// Appending elements to this array will build up a run-length encoded
24 /// compressed array. Random access may not be fast.
25 template <typename T>
27 {
28 public:
29  using value_type = T;
30 
31  struct Run
32  {
33  Run()
34  : myArray()
35  , myRepeat(0)
36  , myStartIndex(0)
37  {
38  }
39  Run(const T &item, exint repeat, exint start_index)
40  : myArray()
41  , mySingle(item)
42  , myRepeat(repeat)
43  , myStartIndex(start_index)
44  {
45  }
46 
47  SYS_FORCE_INLINE bool isEmpty() const { return myRepeat == 0; }
48  SYS_FORCE_INLINE bool isRun() const { return myRepeat >= 0; }
50  {
51  UT_ASSERT(myRepeat >= 0);
52  return myRepeat;
53  }
55  {
56  return myRepeat >= 0 ? myRepeat : myArray.size();
57  }
58  SYS_FORCE_INLINE exint startIndex() const { return myStartIndex; }
59  SYS_FORCE_INLINE exint endIndex() const { return myStartIndex + size(); }
60  SYS_FORCE_INLINE const T &arrayItem(exint idx) const
61  {
62  return myRepeat >= 0 ? mySingle : myArray[idx];
63  }
64  SYS_FORCE_INLINE const T &operator[](exint idx) const
65  {
66  if (isRun())
67  {
68  UT_ASSERT_P(idx < myRepeat && myArray.size() == 0);
69  return mySingle;
70  }
71  return myArray[idx];
72  }
73 
74  SYS_FORCE_INLINE void appendRun(exint num=1) { myRepeat += num; }
75  SYS_FORCE_INLINE void appendSequence(const T &item)
76  {
77  UT_ASSERT(!isRun());
78  myArray.append(item);
79  }
80 
82  {
83  UT_ASSERT(myRepeat > 0 && myArray.size() == 0);
84  myArray.appendMultiple(mySingle, myRepeat);
85  myArray.append(item);
86  myRepeat = -1;
87  }
88 
89  /// Return the number of items at the end of the sequence which match
90  /// the item.
91  SYS_FORCE_INLINE exint matchesAtEnd(const T &item) const
92  {
93  UT_ASSERT(!isRun() && myArray.size() > 0);
94  for (exint i = myArray.size(); i-- > 0; )
95  {
96  if (myArray[i] != item)
97  return (myArray.size() - 1) - i;
98  }
99  return myArray.size();
100  }
102  {
103  UT_ASSERT(!isRun() && myArray.size() > n);
104  myArray.setSize(myArray.size() - n);
105  UT_ASSERT(myArray.size());
106  }
108  {
109  myStartIndex += n;
110  UT_ASSERT_P(myStartIndex >= 0);
111  }
112 
114  {
115  return myArray.getMemoryUsage() + sizeof(exint) + sizeof(T);
116  }
117 
118  private:
119  // The small array is big enough to hold a single item
120  UT_Array<T> myArray;
121  T mySingle;
122  exint myRepeat;
123  exint myStartIndex;
124  };
125 
127  : myRuns()
128  , mySize(0)
129  {
130  }
132  : myRuns()
133  , mySize(0)
134  {
135  for (exint i = 0; i < size; ++i)
136  append(data[i]);
137  }
139  : myRuns()
140  , mySize(0)
141  {
142  for (auto &&item : arr)
143  append(item);
144  }
145 
146  SYS_FORCE_INLINE bool isEmpty() const { return mySize == 0; }
147  SYS_FORCE_INLINE exint size() const { return mySize; }
148  SYS_FORCE_INLINE exint numRuns() const { return myRuns.size(); }
149  SYS_FORCE_INLINE const Run &run(exint i) const { return myRuns(i); }
151  {
152  mySize = 0;
153  myRuns.clear();
154  }
155 
156  /// This is a slow way of computing the size of the array but can be used
157  /// for debugging.
159  {
160  exint n = 0;
161  for (auto &&run : myRuns)
162  n += run.size();
163  return n;
164  }
165 
167  {
168  exint mem = 0;
169  for (auto &&run : myRuns)
170  mem += run.getMemoryUsage();
171  return mem + myRuns.getMemoryUsage() + sizeof(exint);
172  }
173 
174  // Test whether the array has a single value for the entire array
176  {
177  return myRuns.size() == 1 && myRuns[0].isRun();
178  }
180  {
181  return myRuns[0].arrayItem(0);
182  }
183 
184  /// Note that finding an item is O(log(N)) - where N is the number of runs
185  SYS_FORCE_INLINE const T &findItem(exint idx) const
186  {
187  UT_ASSERT_P(idx >= 0 && idx < mySize);
188  auto &&it = std::lower_bound(myRuns.begin(), myRuns.end(), idx,
189  [](const Run &run, exint value)
190  {
191  // Return true if the run's end index is less
192  // than or equal to the value we're searching
193  // for (the run is earlier in the list than
194  // the one we're looking for).
195  return run.endIndex() <= value;
196  });
197  return (*it)[idx - (*it).startIndex()];
198  }
199 
200  SYS_FORCE_INLINE void appendRun(const T &item, exint n)
201  {
202  if (n == 0)
203  return;
204  if (n < 3)
205  {
206  for (exint i = 0; i < n; ++i)
207  append(item);
208  return;
209  }
210  if (myRuns.size()
211  && myRuns.last().isRun()
212  && item == myRuns.last().arrayItem(0))
213  {
214  myRuns.last().appendRun(n);
215  }
216  else
217  {
218  newRun(item, n);
219  }
220  mySize += n;
221  }
222 
223  /// Move and concatenate another UT_RLEArray at the end.
225  {
226  UT_ASSERT_P(this != &src);
227  if (src.mySize == 0)
228  return;
229 
230  // If this array was empty, just steal.
231  if (mySize == 0)
232  {
233  myRuns = std::move(src.myRuns);
234  mySize = src.mySize;
235  src.mySize = 0;
236  return;
237  }
238 
239  // Shift the start index for the new runs.
240  for (auto &&run : src.myRuns)
241  run.shiftStartIndex(mySize);
242 
243  mySize += src.mySize;
244  src.mySize = 0;
245 
246  // Merge with our last run if the new array starts with the same.
247  const bool merge_runs = myRuns.last().isRun() && src.myRuns[0].isRun()
248  && myRuns.last().arrayItem(0)
249  == src.myRuns[0].arrayItem(0);
250  if (merge_runs)
251  {
252  myRuns.last().appendRun(src.myRuns[0].runSize());
253 
254  myRuns.bumpCapacity(myRuns.size() + src.myRuns.size() - 1);
255  for (exint i = 1, n = src.myRuns.size(); i < n; ++i)
256  myRuns.append(std::move(src.myRuns[i]));
257 
258  src.myRuns.clear();
259  }
260  else
261  {
262  myRuns.concat(std::move(src.myRuns));
263  }
264  }
265 
266  SYS_FORCE_INLINE void append(const T &item)
267  {
268  if (mySize == 0)
269  {
270  // First item
271  newRun(item, 1);
272  }
273  else
274  {
275  Run &last = myRuns.last();
276  if (last.isRun())
277  {
278  if (item == last.arrayItem(0))
279  last.appendRun(1);
280  else
281  {
282  if (last.runSize() > 2)
283  {
284  // If we have a run that's over 2 items, we start a new run
285  newRun(item, 1);
286  }
287  else
288  {
289  // Convert the current run into a squence instead of a run
290  last.convertToSequence(item);
291  }
292  }
293  }
294  else
295  {
296  exint n = last.matchesAtEnd(item);
297  if (n >= 3)
298  {
299  last.removeItemsFromEnd(n);
300  newRun(item, n+1);
301  myRuns.last().shiftStartIndex(-n);
302  }
303  else
304  {
305  last.appendSequence(item);
306  }
307  }
308  }
309  mySize++;
310  }
311 
312  class iterator
313  {
314  public:
315  using iterator_category = std::forward_iterator_tag;
316  using value_type = exint;
317  using difference_type = std::ptrdiff_t;
318  using pointer = value_type*;
320 
322  : myArray(nullptr)
323  , myRunIndex(0)
324  , myRunOffset(0)
325  {
326  }
327 
328  const T &item() const
329  {
330  return myArray->run(myRunIndex)[myRunOffset];
331  }
332  const T &operator*() const { return item(); }
333 
334  bool operator==(const iterator &i) const
335  {
336  return myArray == i.myArray
337  && myRunIndex == i.myRunIndex
338  && myRunOffset == i.myRunOffset;
339  }
340  bool operator!=(const iterator &i) const
341  {
342  return !(*this == i);
343  }
344  bool atEnd() const
345  {
346  return myRunIndex >= myArray->numRuns();
347  }
348  iterator &operator++() { advance(); return *this; }
349  void rewind()
350  {
351  if (myArray)
352  {
353  myRunIndex = 0;
354  myRunOffset = 0;
355  }
356  }
357  void advance()
358  {
359  myRunOffset++;
360  if (myRunOffset >= myArray->run(myRunIndex).size())
361  {
362  // Advance to the next run
363  myRunIndex++;
364  myRunOffset = 0;
365  }
366  }
367  private:
368  iterator(const UT_RLEArray<T> &array, bool end)
369  : myArray(&array)
370  , myRunIndex(end ? array.numRuns() : 0)
371  , myRunOffset(0)
372  {
373  }
374  const UT_RLEArray<T> *myArray;
375  exint myRunIndex; // Index into array of runs
376  exint myRunOffset; // Index into run's items
377  friend class UT_RLEArray<T>;
378  };
379  using const_iterator = iterator;
380 
381  SYS_FORCE_INLINE iterator begin() const { return iterator(*this, false); }
382  SYS_FORCE_INLINE iterator end() const { return iterator(*this, true); }
383 
384 private:
385  SYS_FORCE_INLINE void newRun(const T &item, exint size)
386  {
387  myRuns.emplace_back(item, size, mySize);
388  }
390  exint mySize;
391 };
392 
393 #endif
value_type & reference
Definition: UT_RLEArray.h:319
iterator & operator++()
Definition: UT_RLEArray.h:348
SYS_FORCE_INLINE exint numRuns() const
Definition: UT_RLEArray.h:148
SYS_FORCE_INLINE void appendRun(exint num=1)
Definition: UT_RLEArray.h:74
SYS_FORCE_INLINE bool isEmpty() const
Definition: UT_RLEArray.h:47
GLsizei const GLfloat * value
Definition: glcorearb.h:824
std::ptrdiff_t difference_type
Definition: UT_RLEArray.h:317
SYS_FORCE_INLINE void concat(UT_RLEArray< T > &&src)
Move and concatenate another UT_RLEArray at the end.
Definition: UT_RLEArray.h:224
const T & operator*() const
Definition: UT_RLEArray.h:332
int64 exint
Definition: SYS_Types.h:125
SYS_FORCE_INLINE exint matchesAtEnd(const T &item) const
Definition: UT_RLEArray.h:91
SYS_FORCE_INLINE void append(const T &item)
Definition: UT_RLEArray.h:266
Class which writes ASCII or binary JSON streams.
Definition: UT_JSONWriter.h:39
SYS_FORCE_INLINE const Run & run(exint i) const
Definition: UT_RLEArray.h:149
value_type * pointer
Definition: UT_RLEArray.h:318
SYS_FORCE_INLINE const T & uniformItem() const
Definition: UT_RLEArray.h:179
bool operator==(const iterator &i) const
Definition: UT_RLEArray.h:334
UT_RLEArray(const UT_Array< T > &arr)
Definition: UT_RLEArray.h:138
SYS_FORCE_INLINE void appendRun(const T &item, exint n)
Definition: UT_RLEArray.h:200
GLdouble n
Definition: glcorearb.h:2008
SYS_FORCE_INLINE bool isUniform() const
Definition: UT_RLEArray.h:175
SYS_FORCE_INLINE exint size() const
Definition: UT_RLEArray.h:54
SYS_FORCE_INLINE void clear()
Definition: UT_RLEArray.h:150
#define UT_ASSERT_P(ZZ)
Definition: UT_Assert.h:164
SYS_FORCE_INLINE void appendSequence(const T &item)
Definition: UT_RLEArray.h:75
UT_RLEArray(const T *data, exint size)
Definition: UT_RLEArray.h:131
GLuint GLuint end
Definition: glcorearb.h:475
const T & item() const
Definition: UT_RLEArray.h:328
#define SYS_FORCE_INLINE
Definition: SYS_Inline.h:45
SYS_FORCE_INLINE bool isEmpty() const
Definition: UT_RLEArray.h:146
std::forward_iterator_tag iterator_category
Definition: UT_RLEArray.h:315
SYS_FORCE_INLINE exint size() const
Definition: UT_RLEArray.h:147
SYS_FORCE_INLINE exint getMemoryUsage() const
Definition: UT_RLEArray.h:113
SYS_FORCE_INLINE iterator begin() const
Definition: UT_RLEArray.h:381
SYS_FORCE_INLINE const T & operator[](exint idx) const
Definition: UT_RLEArray.h:64
SYS_FORCE_INLINE void convertToSequence(const T &item)
Definition: UT_RLEArray.h:81
SYS_FORCE_INLINE iterator end() const
Definition: UT_RLEArray.h:382
SYS_FORCE_INLINE exint getMemoryUsage() const
Definition: UT_RLEArray.h:166
std::string OIIO_UTIL_API repeat(string_view str, int n)
Repeat a string formed by concatenating str n times.
__hostdev__ uint64_t last(uint32_t i) const
Definition: NanoVDB.h:5976
GLsizeiptr size
Definition: glcorearb.h:664
SYS_FORCE_INLINE void removeItemsFromEnd(exint n)
Definition: UT_RLEArray.h:101
SYS_FORCE_INLINE exint startIndex() const
Definition: UT_RLEArray.h:58
SYS_FORCE_INLINE const T & arrayItem(exint idx) const
Definition: UT_RLEArray.h:60
bool operator!=(const iterator &i) const
Definition: UT_RLEArray.h:340
SYS_FORCE_INLINE exint countSize() const
Definition: UT_RLEArray.h:158
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:165
SYS_FORCE_INLINE exint endIndex() const
Definition: UT_RLEArray.h:59
SYS_FORCE_INLINE bool isRun() const
Definition: UT_RLEArray.h:48
bool atEnd() const
Definition: UT_RLEArray.h:344
SYS_FORCE_INLINE exint runSize() const
Definition: UT_RLEArray.h:49
Run(const T &item, exint repeat, exint start_index)
Definition: UT_RLEArray.h:39
SYS_FORCE_INLINE const T & findItem(exint idx) const
Note that finding an item is O(log(N)) - where N is the number of runs.
Definition: UT_RLEArray.h:185
Definition: format.h:1821
SYS_FORCE_INLINE void shiftStartIndex(exint n)
Definition: UT_RLEArray.h:107
GLenum src
Definition: glcorearb.h:1793