HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UT_Array.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_Array.h (UT Library, C++)
7  *
8  * COMMENTS: This is the array class implementation used by
9  * almost everything in the codebase.
10  * Please be careful if you need to change it!
11  *
12  * RELATION TO THE STL:
13  *
14  * Use UT_Array instead of std::vector
15  *
16  * EXCEPTION: T is not known to be bitwise copyable (trivially
17  * relocatable)
18  *
19  * Examples of types T that cannot be copied bitwise:
20  * - A smart pointer class that uses reference linking (instead
21  * of reference counting)
22  * - A container with a fixed buffer optimization like
23  * UT_WorkBuffer or UT_SmallArray.
24  *
25  * Specific example: Don't use T = std::function< U >.
26  *
27  * For a more comprehensive table of which STL types are not
28  * trivially relocatable, see
29  * https://quuxplusone.github.io/blog/2019/02/20/p1144-what-types-are-relocatable/
30  *
31  * Reasoning to not use std::vector:
32  *
33  * - Performance: std::vector’s growth factor tends to be doubling,
34  * which pessimizes memory use.
35  * std::vector cannot detect trivially relocatable types,
36  * so it can’t use realloc nor memcpy to move data as quickly
37  * as UT_Array can.
38  *
39  * - Aesthetics: std::vector<float> tries to pretend to be float*,
40  * with [] indexing.
41  * This is dangerous as distinguishing value from pointer is
42  * rather important. Using () indexing makes this clear (and
43  * allows higher dimensional indexing).
44  *
45  */
46 
47 #pragma once
48 
49 #ifndef __UT_ARRAY_H_INCLUDED__
50 #define __UT_ARRAY_H_INCLUDED__
51 
52 #include "UT_API.h"
53 #include "UT_ArrayHelp.h"
54 #include "UT_Assert.h"
55 #include "UT_ContainerPrinter.h"
56 #include "UT_IteratorRange.h"
57 #include "UT_Permute.h"
58 #include "UT_LabeledCapacity.h"
59 
60 #include <SYS/SYS_Compiler.h>
61 #include <SYS/SYS_Deprecated.h>
62 #include <SYS/SYS_Inline.h>
63 #include <SYS/SYS_Types.h>
64 #include <SYS/SYS_TypeTraits.h>
65 #include <SYS/SYS_TypeDecorate.h>
66 
67 #include <algorithm>
68 #include <initializer_list>
69 #include <iterator>
70 #include <type_traits>
71 #include <utility>
72 
73 #include <string.h>
74 
75 // Enable this to encode labeled capacity using a wrapper class rather than
76 // directly as an integer type. This allows the compiler to catch cases
77 // where the numeric value of the encoding which includes the label bit
78 // is accidentally used directly as a capacity value.
79 #undef UT_ARRAY_STRICT_LABELED_CAPACITY
80 
81 // Constructor tags for UT_Array
82 struct UT_ArrayCT
83 {
84  static constexpr struct ExternalCapacity{} EXTERNAL_CAPACITY{};
85  static constexpr struct ExternalMove{} EXTERNAL_MOVE{};
86  static constexpr struct GeneralizedMove{} GENERALIZED_MOVE{};
87 };
88 
89 template <typename T>
90 class UT_Array
91 {
92 public:
93  typedef T value_type;
94 
95  typedef int (*Comparator)(const T *, const T *);
96 
97  /// Copy constructor. It duplicates the data.
98  /// It's marked explicit so that it's not accidentally passed by value.
99  /// You can always pass by reference and then copy it, if needed.
100  /// If you have a line like:
101  /// UT_Array<int> a = otherarray;
102  /// and it really does need to copy instead of referencing,
103  /// you can rewrite it as:
104  /// UT_Array<int> a(otherarray);
105  explicit UT_Array(const UT_Array<T> &a);
106 
107  /// Move constructor. Steals the working data from the original.
108  UT_Array(UT_Array<T> &&a) noexcept;
109 
110  /// Construct based on given capacity and size
111  UT_Array(const exint capacity, const exint size);
112 
113  /// Construct based on given capacity with a size of 0
114  explicit UT_Array(const exint capacity = 0);
115 
116  /// Construct with the contents of an initializer list
117  /// If you are wondering why we mark this as explicit...
118  /// Imagine you have the following:
119  /// void foo(int i); // 1
120  /// void foo(UT_Array<int>); // 2
121  /// Without explicit you can do this
122  /// foo({1})
123  /// and function 1 will be called when you probably meant
124  /// for function 2 to be called.
125  explicit UT_Array(std::initializer_list<T> init);
126 
127  ~UT_Array();
128 
129  void swap(UT_Array<T> &other);
130 
131  /// Append an element to the current elements and return its index in the
132  /// array, or insert the element at a specified position; if necessary,
133  /// insert() grows the array to accommodate the element. The insert
134  /// methods use the assignment operator '=' to place the element into the
135  /// right spot; be aware that '=' works differently on objects and pointers.
136  /// The test for duplicates uses the logical equal operator '=='; as with
137  /// '=', the behaviour of the equality operator on pointers versus objects
138  /// is not the same.
139  /// Use the subscript operators instead of insert() if you are appending
140  /// to the array, or if you don't mind overwriting the element already
141  /// inserted at the given index.
142  exint append() { return insert(mySize); }
143  exint append(const T &t) { return appendImpl(t); }
144  exint append(T &&t) { return appendImpl(std::move(t)); }
145  exint append(const T &t, bool check_dup)
146  {
147  exint idx;
148  if (check_dup && ((idx = find(t)) != -1))
149  return idx;
150  return append(t);
151  }
152  void append(const T *pt, exint count);
153  void appendMultiple(const T &t, exint count);
155  exint insert(const T &t, exint i)
156  { return insertImpl(t, i); }
158  { return insertImpl(std::move(t), i); }
159 
160  /// Adds a new element to the array (resizing if necessary) and forwards
161  /// the given arguments to T's constructor.
162  /// NOTE: Unlike append(), the arguments cannot reference any existing
163  /// elements in the array. Checking for and handling such cases would
164  /// remove most of the performance gain versus append(T(...)). Debug builds
165  /// will assert that the arguments are valid.
166  template <typename... S>
167  exint emplace_back(S&&... s);
168 
169 protected:
170 
171  // The constructors below create a UT_Array with an external data buffer
172  // that's not allocated by UT_Array itself.
173  // This is used by UT_SmallArray to create UT_Array superclass objects
174  // that have a nonheap data buffer, created on the stack.
175 
176  explicit UT_Array(
177  const UT_ArrayCT::ExternalCapacity,
178  T *external_data,
179  const exint external_capacity
180  );
181 
182  explicit UT_Array(
183  const UT_ArrayCT::ExternalMove,
184  T *external_data,
185  const exint external_capacity,
186  UT_Array&& a
187  );
188 
189 private:
190 
191  // Move construct a UT_Array that uses (data, capacity) as its buffer.
192  // This constructor works both for an externally provided
193  // buffer (e.g., the UT_SmallArray case) and
194  // for a heap buffer that's allocated and owned by UT_Array itself.
195  explicit UT_Array(
196  const UT_ArrayCT::GeneralizedMove,
197  T *data,
198  const exint capacity,
199  UT_Array&& a
200  );
201 
202  // Equivalent to std::less without bringing in <functional>
203  template <typename Y>
204  struct Less
205  {
206  constexpr bool operator()(const Y &left, const Y &right) const noexcept
207  {
208  return left < right;
209  }
210  };
211 
212  // SFINAE constraint for bool comparators to avoid ambiguity
213  template <typename F>
214  using IsBoolComp = decltype(std::declval<F>()(std::declval<T>(),
215  std::declval<T>()),
216  void());
217 
218 public:
219  /// Assuming the array is sorted, it inserts item t maintaining the sorted
220  /// state of the array. It returns the index of the inserted item.
221  /// @note This is O(N^2) behaviour if you call it in a loop! Do not use.
222  /// @{
223  SYS_DEPRECATED_HDK(13.0)
225 
226  template <typename ComparatorBool = Less<T>,
227  typename = IsBoolComp<ComparatorBool>>
228  SYS_DEPRECATED_HDK(13.0)
229  exint sortedInsert(const T &t, ComparatorBool is_less = {});
230  /// @}
231 
232  SYS_DEPRECATED_HDK(13.0)
234  { return uniqueSortedInsertImpl(t, compare); }
235 
236  template <typename ComparatorBool = Less<T>,
237  typename = IsBoolComp<ComparatorBool>>
238  SYS_DEPRECATED_HDK(13.0)
239  exint uniqueSortedInsert(const T &t, ComparatorBool is_less = {});
240 
241  SYS_DEPRECATED_HDK(13.0)
243  { return uniqueSortedInsertImpl(std::move(t), compare); }
244 
245  /// Convenience method to perform binary search of a ascending sorted array
246  /// with no duplicates. Returns the index of the specified item, -1 if not
247  /// found.
248  template <typename ComparatorBool = Less<T>,
249  typename = IsBoolComp<ComparatorBool>>
250  exint uniqueSortedFind(const T &item,
251  ComparatorBool is_less = {}) const;
252 
253  SYS_DEPRECATED_HDK_REPLACE(19.5, "Use ComparatorBool variant")
254  exint uniqueSortedFind(const T &item, Comparator compare) const;
255 
256  /// Merge the given array into us.
257  /// If direction is -1, then it assumes us and 'other' are both already
258  /// sorted in descending order. Similarly, +1 means ascending.
259  /// If allow_dups is false, then it further assumes that both arrays have no
260  /// duplicates and will produce a result that also has no duplicates.
261  /// More work will be needed if you want allow_dups to mean remove duplicates
262  template <typename ComparatorBool = Less<T>>
263  void merge(const UT_Array<T> &other, int direction,
264  bool allow_dups, ComparatorBool is_less = {});
265 
266  template <typename ComparatorBool = Less<T>,
267  typename = IsBoolComp<ComparatorBool>>
268  bool hasSortedSubset(const UT_Array<T> &other,
269  ComparatorBool is_less = {}) const;
270 
271  template <typename ComparatorBool = Less<T>,
272  typename = IsBoolComp<ComparatorBool>>
273  void sortedUnion(
274  const UT_Array<T> &other,
275  ComparatorBool is_less = {});
276  template <typename ComparatorBool = Less<T>,
277  typename = IsBoolComp<ComparatorBool>>
278  void sortedUnion(
279  const UT_Array<T> &other,
281  ComparatorBool is_less = {}) const;
282  template <typename ComparatorBool = Less<T>,
283  typename = IsBoolComp<ComparatorBool>>
284  void sortedIntersection(
285  const UT_Array<T> &other,
286  ComparatorBool is_less = {});
287  template <typename ComparatorBool = Less<T>,
288  typename = IsBoolComp<ComparatorBool>>
289  void sortedIntersection(
290  const UT_Array<T> &other,
291  UT_Array<T> &result,
292  ComparatorBool is_less = {}) const;
293  template <typename ComparatorBool = Less<T>,
294  typename = IsBoolComp<ComparatorBool>>
295  void sortedSetDifference(
296  const UT_Array<T> &other,
297  ComparatorBool is_less = {});
298  template <typename ComparatorBool = Less<T>,
299  typename = IsBoolComp<ComparatorBool>>
300  void sortedSetDifference(
301  const UT_Array<T> &other,
302  UT_Array<T> &result,
303  ComparatorBool is_less = {}) const;
304 
305  SYS_DEPRECATED_REPLACE(19.5, "Use ComparatorBool variant")
306  bool hasSortedSubset(const UT_Array<T> &other,
307  Comparator compare) const;
308  SYS_DEPRECATED_REPLACE(19.5, "Use ComparatorBool variant")
309  void sortedUnion(
310  const UT_Array<T> &other,
312  SYS_DEPRECATED_REPLACE(19.5, "Use ComparatorBool variant")
313  void sortedUnion(
314  const UT_Array<T> &other,
315  UT_Array<T> &result,
316  Comparator compare) const;
317  SYS_DEPRECATED_REPLACE(19.5, "Use ComparatorBool variant")
318  void sortedIntersection(
319  const UT_Array<T> &other,
320  Comparator compare);
321  SYS_DEPRECATED_REPLACE(19.5, "Use ComparatorBool variant")
322  void sortedIntersection(
323  const UT_Array<T> &other,
324  UT_Array<T> &result,
325  Comparator compare) const;
326  SYS_DEPRECATED_REPLACE(19.5, "Use ComparatorBool variant")
327  void sortedSetDifference(
328  const UT_Array<T> &other,
329  Comparator compare);
330  SYS_DEPRECATED_REPLACE(19.5, "Use ComparatorBool variant")
331  void sortedSetDifference(
332  const UT_Array<T> &other,
333  UT_Array<T> &result,
334  Comparator compare) const;
335 
336  /// Assuming the array is already a heap, it inserts item t maintaining
337  /// the heap. It returns the index of the inserted item.
338  exint heapPush(const T &t, Comparator compare);
339 
340  /// Assuming the array is already a heap, extracts the top (maximum)
341  /// element from the heap and returns it.
342  T heapPop(Comparator compare);
343 
344  /// Assuming the array is already a heap, return the top (maximum)
345  /// element.
346  const T & heapMax() const
347  {
348  UT_ASSERT_P(mySize > 0);
349  return myData[0];
350  }
351 
352  /// Takes another T array and concatenate it onto my end
353  exint concat(const UT_Array<T> &a);
354  /// Takes another T array and concatenate it onto my end
355  exint concat(UT_Array<T> &&a) noexcept;
356 
357  /// Insert an element "count" times at the given index. Return the index.
359 
360  /// An alias for unique element insertion at a certain index. Also used by
361  /// the other insertion methods.
362  exint insertAt(const T &t, exint index)
363  { return insertImpl(t, index); }
364 
365  /// Return true if given index is valid.
367  { return (index >= 0 && index < mySize); }
368 
369  /// Remove one element from the array given the element itself or its
370  /// position in the list, and fill the gap by shifting the elements down
371  /// by one position. Return the index of the element remove or -1 if
372  /// the value was not found.
373  template <typename S>
374  exint findAndRemove(const S &s);
376  {
377  return isValidIndex(index) ? removeAt(index) : -1;
378  }
380  {
381  if (mySize)
382  {
383  exint idx = --mySize;
384  destroyElement(myData[idx]);
385  }
386  }
387 
388  /// Remove the range [begin_i,end_i) of elements from the array.
389  /// begin_i is the start index.
390  /// end_i is the index to stop at, and isn't inclusive.
391  void removeRange(exint begin_i, exint end_i);
392 
393  /// Remove the range [begin_i, end_i) of elements from this array and place
394  /// them in the dest array, shrinking/growing the dest array as necessary.
395  /// begin_i is the start index,
396  /// end_i is index to stop at, and isn't inclusive.
397  void extractRange(exint begin_i, exint end_i,
398  UT_Array<T>& dest);
399 
400  /// Removes all matching elements from the list, shuffling down and changing
401  /// the size appropriately.
402  /// Returns the number of elements left.
403  template <typename IsEqual>
404  exint removeIf(IsEqual is_equal);
405 
406  /// Remove all matching elements. Also sets the capacity of the array.
407  template <typename IsEqual>
408  void collapseIf(IsEqual is_equal)
409  {
410  removeIf(is_equal);
411  setCapacity(size());
412  }
413 
414  /// Move how_many objects starting at index src_idx to dst_idx;
415  /// This method will remove the elements at [src_idx, src_idx+how_many) and
416  /// then insert them at dst_idx. This method can be used in place of
417  /// the old shift() operation.
418  void move(exint src_idx, exint dst_idx, exint how_many);
419 
420  /// Cyclically shifts the entire array by how_many
421  void cycle(exint how_many);
422 
423  /// Quickly set the array to a single value.
424  void constant(const T &v);
425  /// Zeros the array if a POD type, else trivial constructs if a class type.
426  void zero();
427 
428  /// Search for s linearly using the '==' operator, starting at index start.
429  /// @returns the index of the matching element or (exint)-1.
430  template <typename S>
431  exint find(const S &s, exint start = 0) const;
432 
433  /// Search for t via binary search using the function specified in the
434  /// parameter list, assuming the array is already sorted with respect to
435  /// compare.
436  /// @returns the index of the matching element or (exint)-1.
437  exint sortedFind(const T &t, Comparator compare) const;
438 
439  /// Reverses the array by swapping elements in mirrored locations.
440  void reverse();
441 
442  /// The fastest search possible, which does pointer arithmetic to find the
443  /// index of the element. WARNING: index() does no out-of-bounds checking.
444  /// @{
445  exint index(const T &t) const { return &t - myData; }
446  exint safeIndex(const T &t) const
447  {
448  return (&t >= myData && &t < (myData + mySize))
449  ? &t - myData : -1;
450  }
451  /// @}
452 
453  /// Sort using std::sort with bool comparator. Defaults to operator<().
454  template <typename ComparatorBool = Less<T>,
455  typename = IsBoolComp<ComparatorBool>>
456  void sort(ComparatorBool is_less = {})
457  {
458  std::sort(myData, myData + mySize, is_less);
459  }
460 
461  /// Sort the array using a comparison function that you must provide. t1 and
462  /// t2 are pointers to Thing. The comparison function uses strcmp()
463  /// semantics (i.e. -1 if less than, 0 if equal, 1 if greater).
464  SYS_DEPRECATED_HDK_REPLACE(19.5, "Use ComparatorBool variant")
466 
467  /// Sort using std::sort. The ComparatorBool uses the less-than semantics
468  template <typename ComparatorBool,
469  typename = IsBoolComp<ComparatorBool>>
470  SYS_DEPRECATED_REPLACE(19.5, "Use sort(ComparatorBool) overload")
471  void stdsort(ComparatorBool is_less)
472  {
473  std::sort(myData, myData + mySize, is_less);
474  }
475 
476  /// stableSort is both stable, so keeps equal elements in the same
477  /// order (note this is very useful for compatibility between
478  /// compilers) and templated.
479  /// Either use a bool sort function or make a utility class with
480  /// bool operator()(const T a, const T b)
481  /// the utility class lets you bind data to avoid globals.
482  /// The comparator returns true if a must occur before b in the list.
483  /// For sorting ascending, this is a less than operation.
484  template<typename ComparatorBool = Less<T>>
485  void stableSort(ComparatorBool is_less = {})
486  {
487  // No-op for small/empty arrays, avoiding out of
488  // bounds assert on array()
489  if (size() < 2)
490  return;
491 
492  std::stable_sort(array(), array() + size(), is_less);
493  }
494  /// Like stableSort, but operates on a subset of the array.
495  template<typename ComparatorBool>
496  void stableSortRange(ComparatorBool is_less,
497  exint start, exint end)
498  {
499  // No-op for small/empty arrays or ranges, avoiding out of
500  // bounds assert on array()
501  if (end < 0)
502  end = size();
503  if (start < 0)
504  start = 0;
505  if (end < start + 2)
506  return;
507 
508  std::stable_sort(array() + start, array() + end, is_less);
509  }
510 
511  /// Comparator class for stableSortIndices
512  template <typename I, typename V, typename ComparatorBool>
514  {
515  public:
517  const ComparatorBool &compare)
518  : myValues(values)
519  , myCompare(compare)
520  {}
521  inline bool operator()(I a, I b) const
522  { return myCompare(myValues(a), myValues(b)); }
523  private:
524  const UT_Array<V> &myValues;
525  const ComparatorBool &myCompare;
526  };
527 
528  /// Sort indices array by the values indexed into this array using a
529  /// stable sorting algorithm. To reorder the array in such a way
530  /// that it would be sorted, or another array to be reordered the
531  /// same way, include UT_Permute.h and use:
532  /// UTinversePermute(values.getArray(), indices.getArray(),
533  /// values.size());
534  /// The ComparatorBool uses the less-than semantics.
535  /// I must be an integer type.
536  template <typename I, typename ComparatorBool>
538  ComparatorBool is_less) const
539  {
540  IndexedCompare<I, T, ComparatorBool> compare(*this, is_less);
541  std::stable_sort(indices.getArray(),
542  indices.getArray() + indices.size(), compare);
543  }
544 
545  /// Create an index array from 0..n-1 into this array and sort
546  /// it with stableSortIndices.
547  /// The index array will be resized & rebuilt by this.
548  template <typename I, typename ComparatorBool>
550  ComparatorBool is_less) const
551  {
552  indices.setSizeNoInit(size());
553  for (exint i = 0; i < size(); i++)
554  indices(i) = i;
555  stableSortIndices(indices, is_less);
556  }
557 
558  /// Sorts this array by an external key array. We assume a 1:1
559  /// corespondence between our own elements and those of the key
560  /// array. The comparator should be defined on the key type.
561  template <typename K, typename ComparatorBool>
562  void stableSortByKey(const UT_Array<K> &keys, ComparatorBool is_less)
563  {
564  UT_ASSERT(keys.size() == size());
565  if (keys.size() != size())
566  return;
568  keys.stableArgSort(indices, is_less);
569  UTinversePermute(getArray(), indices.getArray(), size());
570  }
571 
572  /// Assuming this array is sorted, remove all duplicate elements.
573  /// Returns the number of elements removed.
575 
576  /// Assuming this array is sorted, remove all duplicate elements using the
577  /// given binary predicate.
578  /// Returns the number of elements removed
579  template <typename CompareEqual>
580  exint sortedRemoveDuplicatesIf(CompareEqual compare_equal);
581 
582  /// Sort and then remove duplicates.
583  /// By default, operator<() is used but if you supply a custom comparator,
584  /// ensure that equal elements are adjacent after sorting.
585  /// Returns the number of elements removed.
586  template<typename ComparatorBool = Less<T>>
587  exint sortAndRemoveDuplicates(ComparatorBool is_less = {})
588  {
589  stableSort(is_less);
590  return sortedRemoveDuplicates();
591  }
592 
593  /// Partitions the array into values greater than or less than
594  /// the Nth element, returns the resulting partition number.
595  /// idx == 0 will get the minimum value, idx == size()-1 the
596  /// maximum value. This does modify this array!
597  template <typename ComparatorBool = Less<T>>
598  T selectNthLargest(exint idx, ComparatorBool is_less = {});
599 
600  /// Set the capacity of the array, i.e. grow it or shrink it. The
601  /// function copies the data after reallocating space for the array.
602  void setCapacity(exint new_capacity);
603  void setCapacityIfNeeded(exint min_capacity)
604  {
605  if (capacity() < min_capacity)
606  setCapacity(min_capacity);
607  }
608  /// If the capacity is smaller than min_capacity, expand the array
609  /// to at least min_capacity and to at least a constant factor of the
610  /// array's previous capacity, to avoid having a linear number of
611  /// reallocations in a linear number of calls to bumpCapacity.
612  void bumpCapacity(exint min_capacity)
613  {
614  if (capacity() >= min_capacity)
615  return;
616  // The following 4 lines are just
617  // SYSmax(min_capacity, UTbumpAlloc(capacity())), avoiding SYSmax
618  exint bumped = UTbumpAlloc(capacity());
619  exint new_capacity = min_capacity;
620  if (bumped > min_capacity)
621  new_capacity = bumped;
622  setCapacity(new_capacity);
623  }
624 
625  /// First bumpCapacity to ensure that there's space for newsize,
626  /// expanding either not at all or by at least a constant factor
627  /// of the array's previous capacity,
628  /// then set the size to newsize.
629  void bumpSize(exint newsize)
630  {
631  bumpCapacity(newsize);
632  setSize(newsize);
633  }
634  /// NOTE: bumpEntries() will be deprecated in favour of bumpSize() in a
635  /// future version.
636  void bumpEntries(exint newsize)
637  {
638  bumpSize(newsize);
639  }
640 
641  /// Query the capacity, i.e. the allocated length of the array.
642  /// NOTE: capacity() >= size().
643  exint capacity() const;
644  /// Query the size, i.e. the number of occupied elements in the array.
645  /// NOTE: capacity() >= size().
646  exint size() const { return mySize; }
647  /// Alias of size(). size() is preferred.
648  exint entries() const { return mySize; }
649  /// Returns true iff there are no occupied elements in the array.
650  bool isEmpty() const { return mySize==0; }
651 
652  /// Returns the amount of memory used by this UT_Array.
653  /// If inclusive is false, it only counts the memory of the array.
654  /// This is often necessary to avoid double-counting, e.g. if this
655  /// UT_Array is a member variable of a class whose memory is already
656  /// being counted by the caller.
657  int64 getMemoryUsage(bool inclusive=false) const
658  {
659  return (inclusive ? sizeof(*this) : 0) + capacity()*sizeof(T); // NOLINT
660  }
661 
662  /// Set the size, the number of occupied elements in the array.
663  /// NOTE: This will not do bumpCapacity, so if you call this
664  /// n times to increase the size, it may take
665  /// n^2 time.
666  void setSize(exint newsize)
667  {
668  if (newsize < 0)
669  newsize = 0;
670  if (newsize == mySize)
671  return;
672  setCapacityIfNeeded(newsize);
673  if (mySize > newsize)
674  destroyRange(myData + newsize, mySize - newsize);
675  else // newsize > mySize
676  constructRange(myData + mySize, newsize - mySize);
677  mySize = newsize;
678  }
679  void setSizeIfNeeded(exint minsize)
680  {
681  if (size() >= minsize)
682  return;
683  setSize(minsize);
684  }
685  /// Alias of setSize(). setSize() is preferred.
686  void entries(exint newsize)
687  {
688  setSize(newsize);
689  }
690  /// Set the size, but unlike setSize(newsize), this function
691  /// will not initialize new POD elements to zero. Non-POD data types
692  /// will still have their constructors called.
693  /// This function is faster than setSize(ne) if you intend to fill in
694  /// data for all elements.
695  void setSizeNoInit(exint newsize)
696  {
697  if (newsize < 0)
698  newsize = 0;
699  if (newsize == mySize)
700  return;
701  setCapacityIfNeeded(newsize);
702  if (mySize > newsize)
703  destroyRange(myData + newsize, mySize - newsize);
704  else if (!isPOD()) // newsize > mySize
705  constructRange(myData + mySize, newsize - mySize);
706  mySize = newsize;
707  }
708 
709  /// shrinks the capacity to the current size
710  void shrinkToFit()
711  {
712  // TODO: be more intelligent here
713  setCapacity(size());
714  }
715  /// convenience method to set size and shrink-to-fit in a single call
716  void setSizeAndShrink(exint new_size)
717  {
718  setSize(new_size);
719  shrinkToFit();
720  }
721 
722  /// Decreases, but never expands, to the given maxsize.
723  void truncate(exint maxsize)
724  {
725  if (maxsize >= 0 && size() > maxsize)
726  setSize(maxsize);
727  }
728  /// Resets list to an empty list.
729  void clear()
730  {
731  // Don't call setSize(0) since it supports growing the array
732  // which requires a default constructor. Avoiding it allows
733  // this to be used on types that lack a default constructor.
734  destroyRange(myData, mySize);
735  mySize = 0;
736  }
737 
738  /// Assign array a to this array by copying each of a's elements with
739  /// memcpy for POD types, and with copy construction for class types.
741 
742  /// Replace the contents with those from the initializer_list ilist
743  UT_Array<T> & operator=(std::initializer_list<T> ilist);
744 
745  /// Move the contents of array a to this array.
747 
748  /// Compare two array and return true if they are equal and false otherwise.
749  /// Two elements are checked against each other using operator '==' or
750  /// compare() respectively.
751  /// NOTE: The capacities of the arrays are not checked when
752  /// determining whether they are equal.
753  bool operator==(const UT_Array<T> &a) const;
754  bool operator!=(const UT_Array<T> &a) const;
755 
756 
757  template <typename ComparatorBool,
758  typename = IsBoolComp<ComparatorBool>>
759  bool isEqual(const UT_Array<T> &a, ComparatorBool is_equal) const;
760 
761  SYS_DEPRECATED_REPLACE(20.5, "Use ComparatorBool variant")
762  int isEqual(const UT_Array<T> &a, Comparator compare) const;
763 
764  /// Subscript operator
765  /// NOTE: This does NOT do any bounds checking unless paranoid
766  /// asserts are enabled.
767  T & operator()(exint i)
768  {
769  UT_ASSERT_P(i >= 0 && i < mySize);
770  return myData[i];
771  }
772  /// Const subscript operator
773  /// NOTE: This does NOT do any bounds checking unless paranoid
774  /// asserts are enabled.
775  const T & operator()(exint i) const
776  {
777  UT_ASSERT_P(i >= 0 && i < mySize);
778  return myData[i];
779  }
780 
781  /// Subscript operator
782  /// NOTE: This does NOT do any bounds checking unless paranoid
783  /// asserts are enabled.
785  {
786  UT_ASSERT_P(i >= 0 && i < mySize);
787  return myData[i];
788  }
789  /// Const subscript operator
790  /// NOTE: This does NOT do any bounds checking unless paranoid
791  /// asserts are enabled.
792  const T & operator[](exint i) const
793  {
794  UT_ASSERT_P(i >= 0 && i < mySize);
795  return myData[i];
796  }
797 
798  /// forcedRef(exint) will grow the array if necessary, initializing any
799  /// new elements to zero for POD types and default constructing for
800  /// class types.
802  {
803  UT_ASSERT_P(i >= 0);
804  if (i >= mySize)
805  bumpSize(i+1);
806  return myData[i];
807  }
808 
809  /// forcedGet(exint) does NOT grow the array, and will return default
810  /// objects for out of bound array indices.
811  T forcedGet(exint i) const
812  {
813  return (i >= 0 && i < mySize) ? myData[i] : T();
814  }
815 
816  T & last()
817  {
818  UT_ASSERT_P(mySize);
819  return myData[mySize-1];
820  }
821  const T & last() const
822  {
823  UT_ASSERT_P(mySize);
824  return myData[mySize-1];
825  }
826 
827  /// Apply a user-defined function to each element of the array
828  /// as int as the function returns zero. If apply_func returns
829  /// 1, apply() stops traversing the list and returns the current
830  /// index; otherwise, apply() returns the size.
831  exint apply(int (*apply_func)(T &t, void *d), void *d);
832 
833  template <typename BinaryOp>
834  T accumulate(const T &init_value, BinaryOp add) const;
835 
836  T * getArray() const { return myData; }
837  const T * getRawArray() const { return myData; }
838 
839  T * array() { return myData; }
840  const T * array() const { return myData; }
841 
842  T * data() { return myData; }
843  const T * data() const { return myData; }
844 
845  /// This method allows you to swap in a new raw T array, which must be
846  /// the same size as capacity(). Use caution with this method.
847  T * aliasArray(T *newdata)
848  { T *data = myData; myData = newdata; return data; }
849 
850  template <typename IT, bool FORWARD>
852  {
853  public:
854  using iterator_category = std::random_access_iterator_tag;
855  using value_type = T;
857  using pointer = IT*;
858  using reference = IT&;
859 
860  // Note: When we drop gcc 4.4 support and allow range-based for
861  // loops, we should also drop atEnd(), which means we can drop
862  // myEnd here.
863  base_iterator() : myCurrent(nullptr), myEnd(nullptr) {}
864 
865  // Allow iterator to const_iterator conversion
866  template<typename EIT>
868  : myCurrent(src.myCurrent), myEnd(src.myEnd) {}
869 
871  { return FORWARD ? myCurrent : myCurrent - 1; }
872 
874  { return FORWARD ? *myCurrent : myCurrent[-1]; }
875 
876  reference item() const
877  { return FORWARD ? *myCurrent : myCurrent[-1]; }
878 
880  { return FORWARD ? myCurrent[n] : myCurrent[-n - 1]; }
881 
882  /// Pre-increment operator
884  {
885  if (FORWARD) ++myCurrent; else --myCurrent;
886  return *this;
887  }
888  /// Post-increment operator
890  {
891  base_iterator tmp = *this;
892  if (FORWARD) ++myCurrent; else --myCurrent;
893  return tmp;
894  }
895  /// Pre-decrement operator
897  {
898  if (FORWARD) --myCurrent; else ++myCurrent;
899  return *this;
900  }
901  /// Post-decrement operator
903  {
904  base_iterator tmp = *this;
905  if (FORWARD) --myCurrent; else ++myCurrent;
906  return tmp;
907  }
908 
910  {
911  if (FORWARD)
912  myCurrent += n;
913  else
914  myCurrent -= n;
915  return *this;
916  }
918  {
919  if (FORWARD)
920  return base_iterator(myCurrent + n, myEnd);
921  else
922  return base_iterator(myCurrent - n, myEnd);
923  }
924 
926  { return (*this) += (-n); }
928  { return (*this) + (-n); }
929 
930  bool atEnd() const { return myCurrent == myEnd; }
931  void advance() { this->operator++(); }
932 
933  // Comparators
934  template<typename ITR, bool FR>
936  { return myCurrent == r.myCurrent; }
937 
938  template<typename ITR, bool FR>
940  { return myCurrent != r.myCurrent; }
941 
942  template<typename ITR>
943  bool operator<(const base_iterator<ITR, FORWARD> &r) const
944  {
945  if (FORWARD)
946  return myCurrent < r.myCurrent;
947  else
948  return r.myCurrent < myCurrent;
949  }
950 
951  template<typename ITR>
953  {
954  if (FORWARD)
955  return myCurrent > r.myCurrent;
956  else
957  return r.myCurrent > myCurrent;
958  }
959 
960  template<typename ITR>
961  bool operator<=(const base_iterator<ITR, FORWARD> &r) const
962  {
963  if (FORWARD)
964  return myCurrent <= r.myCurrent;
965  else
966  return r.myCurrent <= myCurrent;
967  }
968 
969  template<typename ITR>
971  {
972  if (FORWARD)
973  return myCurrent >= r.myCurrent;
974  else
975  return r.myCurrent >= myCurrent;
976  }
977 
978  // Difference operator for std::distance
979  template<typename ITR>
981  {
982  if (FORWARD)
983  return exint(myCurrent - r.myCurrent);
984  else
985  return exint(r.myCurrent - myCurrent);
986  }
987 
988 
989  protected:
990  friend class UT_Array<T>;
991  base_iterator(IT *c, IT *e) : myCurrent(c), myEnd(e) {}
992  private:
993 
994  IT *myCurrent;
995  IT *myEnd;
996  };
997 
998  typedef base_iterator<T, true> iterator;
999  typedef base_iterator<const T, true> const_iterator;
1000  typedef base_iterator<T, false> reverse_iterator;
1001  typedef base_iterator<const T, false> const_reverse_iterator;
1002  typedef const_iterator traverser; // For backward compatibility
1003 
1004  /// Begin iterating over the array. The contents of the array may be
1005  /// modified during the traversal.
1007  {
1008  return iterator(myData, myData + mySize);
1009  }
1010  /// End iterator.
1012  {
1013  return iterator(myData + mySize,
1014  myData + mySize);
1015  }
1016 
1017  /// Begin iterating over the array. The array may not be modified during
1018  /// the traversal.
1020  {
1021  return const_iterator(myData, myData + mySize);
1022  }
1023  /// End const iterator. Consider using it.atEnd() instead.
1025  {
1026  return const_iterator(myData + mySize,
1027  myData + mySize);
1028  }
1029 
1030  /// Begin iterating over the array in reverse.
1032  {
1033  return reverse_iterator(myData + mySize,
1034  myData);
1035  }
1036  /// End reverse iterator.
1038  {
1039  return reverse_iterator(myData, myData);
1040  }
1041  /// Begin iterating over the array in reverse.
1043  {
1044  return const_reverse_iterator(myData + mySize,
1045  myData);
1046  }
1047  /// End reverse iterator. Consider using it.atEnd() instead.
1049  {
1050  return const_reverse_iterator(myData, myData);
1051  }
1052 
1054  { return UT_IteratorRange<iterator>(begin(), end()); }
1056  { return UT_IteratorRange<const_iterator>(begin(), end()); }
1057 
1062 
1063  /// Remove item specified by the reverse_iterator.
1065  {
1066  removeAt(&it.item() - myData);
1067  }
1068 
1069 
1070  /// Very dangerous methods to share arrays.
1071  /// The array is not aware of the sharing, so ensure you clear
1072  /// out the array prior a destructor or setCapacity operation.
1074  {
1075  myData = src.myData;
1076  myCapacity = labelExternal( src.capacity() );
1077  mySize = src.mySize;
1078  }
1079  void unsafeShareData(T *src, exint srcsize)
1080  {
1081  myData = src;
1082  myCapacity = labelExternal( srcsize );
1083  mySize = srcsize;
1084  }
1086  {
1087  myData = src;
1088  mySize = size;
1089  myCapacity = labelExternal( capacity );
1090  }
1092  {
1093  myData = nullptr;
1094  myCapacity = labelExternal( 0 );
1095  mySize = 0;
1096  }
1097 
1098  /// Returns true if the data used by the array was allocated on the heap.
1099  inline bool isHeapBuffer() const
1100  {
1101  return isHeapBuffer(myData);
1102  }
1103 
1104 protected:
1105  // Check whether T may have a constructor, destructor, or copy
1106  // constructor. This test is conservative in that some POD types will
1107  // not be recognized as POD by this function. To mark your type as POD,
1108  // use the SYS_DECLARE_IS_POD() macro in SYS_TypeDecorate.h.
1109  static constexpr SYS_FORCE_INLINE bool isPOD()
1110  {
1111  return SYS_IsPod_v< T >;
1112  }
1113 
1114  /// Implements both append(const T &) and append(T &&) via perfect
1115  /// forwarding. Unlike the variadic emplace_back(), its argument may be a
1116  /// reference to another element in the array.
1117  template <typename S>
1118  exint appendImpl(S &&s);
1119 
1120  /// Similar to appendImpl() but for insertion.
1121  template <typename S>
1122  exint insertImpl(S &&s, exint index);
1123 
1124  template <typename S>
1125  SYS_DEPRECATED_HDK(13.0)
1127 
1128  /// In debug builds, verifies that the arguments to emplace_back() will not
1129  /// be invalidated when realloc() is called.
1130  template <typename First, typename... Rest>
1131  void validateEmplaceArgs(First &&first, Rest&&... rest) const
1132  {
1134  static_cast<const void *>(&first) <
1135  static_cast<const void *>(myData) ||
1136  static_cast<const void *>(&first) >=
1137  static_cast<const void *>(myData + mySize),
1138  "Argument cannot reference an existing element in the array.");
1139 
1140  validateEmplaceArgs(std::forward<Rest>(rest)...);
1141  }
1142 
1143  /// Base case for validateEmplaceArgs().
1144  void validateEmplaceArgs() const
1145  {
1146  }
1147 
1148  // Construct the given type
1149  template <typename... S>
1150  static void construct(T &dst, S&&... s)
1151  {
1152  new (&dst) T(std::forward<S>(s)...);
1153  }
1154 
1155  // Copy construct the given type
1156  static void copyConstruct(T &dst, const T &src)
1157  {
1158  if constexpr( SYS_IsPod_v< T > )
1159  {
1160  dst = src;
1161  }
1162  else // constexpr
1163  {
1164  new (&dst) T(src);
1165  }
1166  }
1167 
1168 private:
1169  /// Equivalent to std::back_insert_iterator, but using the append() method
1170  /// for UT_Array. This is useful for appending to an array via STL
1171  /// algorithms that have an output iterator
1172  class AppendIterator
1173  {
1174  public:
1175  using iterator_category = std::output_iterator_tag;
1176  using value_type = void;
1177  using difference_type = void;
1178  using pointer = void;
1179  using reference = void;
1180 
1181  explicit AppendIterator(UT_Array<T> &arr) : myArray(&arr) {}
1182 
1183  /// @{
1184  /// Append the value when the iterator is assigned to.
1185  AppendIterator &operator=(const T &val)
1186  {
1187  myArray->append(val);
1188  return *this;
1189  }
1190 
1191  AppendIterator &operator=(T &&val)
1192  {
1193  myArray->append(std::move(val));
1194  return *this;
1195  }
1196  /// @}
1197 
1198  /// @{
1199  /// This iterator does not move, and dereferencing just returns itself.
1200  AppendIterator &operator*() { return *this; }
1201  AppendIterator &operator++() { return *this; }
1202  AppendIterator operator++(int) { return *this; }
1203  /// @}
1204 
1205  private:
1206  UT_Array<T> *myArray;
1207  };
1208 
1209 #ifdef UT_ARRAY_STRICT_LABELED_CAPACITY
1210  using LabeledCapacity = UT_LabeledCapacity;
1211 #else
1212  using LabeledCapacity = UT_LabeledCapacityRep;
1213 #endif
1214 
1215  /// Pointer to the array of elements of type T
1216  T *myData;
1217 
1218  /// The number of elements for which we have allocated memory
1219  LabeledCapacity myCapacity;
1220 
1221  /// The actual number of valid elements in the array
1222  exint mySize;
1223 
1224  // Create a Capacity that's labeled as owned by this UT_Array
1225  static LabeledCapacity labelOwned(const exint capacity) noexcept;
1226 
1227  // Create a Capacity that's labeled as external (not owned by this UT_Array)
1228  static LabeledCapacity labelExternal(const exint capacity) noexcept;
1229 
1230  // All memory allocations, reallocations and deallocations in UT_Array's
1231  // implementation go through the three functions
1232  // allocateArray, reallocateArray, deallocateArray below.
1233  // These functions make no calls to constructors/destructors.
1234 
1235  // Return an array with given capacity for elements of type T.
1236  // PRE: capacity > 0
1237  static T *allocateArray(const exint capacity) noexcept;
1238 
1239  // Return an array with given capacity for elements of type T.
1240  // reusing the passed-in 'data' if possible.
1241  // PRE: capacity > 0
1242  static T *reallocateArray(T *data, const exint capacity) noexcept;
1243 
1244  // NOTE: This will work correctly with data == nullptr
1245  static void deallocateArray(T *data) noexcept;
1246 
1247  // Identify whether 'data' is a heap buffer.
1248  // 'data' is decided to be a heap buffer when it is not
1249  // located at the first memory location after this UT_Array object
1250  // (a trick used by UT_SmallArray).
1251  // If a call to 'allocateArray' happens to return the first memory
1252  // location after this UT_Array object, then isHeapBuffer ends up false.
1253  // To avoid this, a second allocation should then by attempted,
1254  // see 'allocateArrayHeapIdentifiable' below.
1255  bool isHeapBuffer(T* data) const;
1256 
1257  // Like allocateArray, except ensure that the returned array 'data'
1258  // is NOT located at the end of this UT_Array object, so that
1259  // isHeapBuffer( data) is true.
1260  // PRE: capacity > 0
1261  T *allocateArrayHeapIdentifiable(const exint capacity);
1262 
1263  //
1264  // Construct/destroy elements and ranges.
1265  // For POD types, construct* fills T objects with zeroes,
1266  // and destroy* does nothing.
1267  // For non-POD types, construct* calls the regular constructor
1268  // (by way of placement new), and destroy* calls the regular destructor.
1269  //
1270 
1271  static void constructElement(T &dst);
1272  static void constructRange(T *dst, exint n);
1273 
1274  static void destroyElement(T &dst) noexcept;
1275  static void destroyRange([[maybe_unused]] T *dst, exint n) noexcept;
1276 
1277  //
1278  // About relocation:
1279  // Relocating [ src, src + n ) to [ dst, dst + n ) should be equivalent
1280  // to the following:
1281  // For each i in [ 0, n ):
1282  // 1. move construct dst[ i ] from src[ i ]
1283  // 2. destroy src[ i ]
1284  //
1285  // The trivial relocation macros and traits defined in SYS_TypeDecorate.h
1286  // and SYS_TypeTraits.h can be used to indicate for which types T
1287  // bitwise copying is equivalent to the above construct and destroy steps.
1288  //
1289 
1290  // The below "standardRelocate" methods relocate
1291  // [ src, src + n ) to [ dst, dst + n ) by invoking
1292  // T's move constructor and destructor.
1293 
1294  // Relocate elements in increasing order 0, 1, ..., n - 1
1295  static void standardRelocateIncreasing(T *dst, T *src, exint n);
1296 
1297  // Relocate elements in decreasing order n - 1,, ..., 1, 0
1298  static void standardRelocateDecreasing(T *dst, T *src, exint n);
1299 
1300  // For use in cases where the source and destination ranges may overlap:
1301  // Relocate in increasing order if dst < src and
1302  // relocate in decreasing order if src < dst.
1303  static void standardRelocate(T *dst, T *src, exint n);
1304 
1305  //
1306  // The below "bitwiseRelocate" methods relocate
1307  // [ src, src + n ) to [ dst, dst +n ) using memcpy and memmove,
1308  // and do not invoke destructors afterwards.
1309  //
1310 
1311  // PRE:
1312  // * both 'dst' and 'src' are valid (not null)
1313  static void bitwiseRelocate(T *dst, const T *src, exint n) noexcept;
1314 
1315  // PRE:
1316  // * both 'dst' and 'src' are valid (not null)
1317  // * [ dst, dst + n ) and [ src, src + n ) don't overlap
1318  static void bitwiseRelocateNonoverlapping(
1319  T *dst,
1320  const T *src,
1321  exint n) noexcept;
1322 
1323  //
1324  // The below relocate, copy and swap methods decide whether to use
1325  // standard or bitwise copying at compile time, based on traits.
1326  // Only these are the versions should be called directly by
1327  // the rest of the UT_Array implementation.
1328  //
1329 
1330  // For trivially relocatable types, bitwise copy [ src, src + n )
1331  // onto [ dst, dst + n ) instead.
1332  static void relocate(T *dst, T *src, exint n);
1333 
1334  // Version of relocate with a stronger precondition that is
1335  // exploited for potentially faster computation:
1336  // PRE: [ dst, dst + n ) and [ src, src + n ) don't overlap
1337  static void relocateNonoverlapping(T *dst, T *src, exint n);
1338 
1339  // PRE: dst < src
1340  static void relocateIncreasing(T *dst, T *src, exint n);
1341 
1342  // PRE: dst > src
1343  static void relocateDecreasing(T *dst, T *src, exint n);
1344 
1345  // copyNonoverlapping is similar to relocateNonoverlapping,
1346  // with the following to differences:
1347  // * Each value is copy constructed into its destination (not moved)
1348  // * The source values are not destroyed (no destructor invoked)
1349  // PRE: [ dst, dst + n ) and [ src, src + n ) don't overlap
1350  static void copyNonoverlapping(T *dst, const T *src, exint n);
1351 
1352  // swapNonoverlapping is equivalent to the following:
1353  // For each i in [ 0, n ): swap dst[ i ] and src[ i ]
1354  static void swapNonoverlapping(T *dst, T *src, exint n);
1355 
1356  // The guts of the remove() methods.
1357  exint removeAt(exint index);
1358 
1359  // Convert the current object's buffer from a non-heap buffer
1360  // to a heap buffer of given capacity
1361  // PRE: *this has a non-heap buffer
1362  // 'capacity' should be at least the size
1363  // POST: *this has a heap buffer with given capacity,
1364  // and its initial size elements are the same as before the call
1365  void convertToHeapBuffer(const exint capacity);
1366 
1367  template<typename OS, typename S>
1368  friend OS &operator<<(OS &os, const UT_Array<S> &d);
1369 
1370  /// Friend specialization of std::swap() to use UT_String::swap()
1371  /// @internal This is needed because standard std::swap() implementations
1372  /// will try to copy the UT_String objects, causing hardened strings to
1373  /// become weak.
1374  friend void swap(UT_Array<T>& a, UT_Array<T>& b) { a.swap(b); }
1375 };
1376 
1377 // Suppress UT_Array<UT_StringHolder> instantations to avoid duplicate symbols
1378 // when UT_Array<UT_StringHolder> is used with UT_StringArray which derives
1379 // from it.
1380 class UT_StringHolder;
1382 
1383 // Assigns src to dest, using the default C++ conversion operator.
1384 template <typename T, typename S>
1385 void
1387 {
1388  exint n = src.size();
1389  dest.setCapacity(n);
1390  dest.setSize(n);
1391  for (exint i = 0; i < n; i++)
1392  dest(i) = T(src(i));
1393 }
1394 template <typename T, typename S>
1395 void
1397 {
1398  dest.setCapacity(n);
1399  dest.setSize(n);
1400  for (exint i = 0; i < n; i++)
1401  dest(i) = T(src[i]);
1402 }
1403 template <typename T, typename S>
1404 void
1406 {
1407  // We assume here that dest has enough memory for src.size()
1408  exint n = src.size();
1409  for (exint i = 0; i < n; i++)
1410  dest[i] = T(src(i));
1411 }
1412 template <typename T, typename S>
1413 void
1414 UTconvertArray(T *dest, const S *src, int64 n)
1415 {
1416  // We assume here that dest has enough memory for n elements
1417  for (int64 i = 0; i < n; i++)
1418  dest[i] = T(src[i]);
1419 }
1420 
1421 #include "UT_ArrayImpl.h"
1422 
1423 
1424 template<typename OS, typename S>
1425 inline OS &
1426 operator<<(OS &os, const UT_Array<S> &d)
1427 {
1428  os << "UT_Array" << UT_ContainerPrinter<UT_Array<S> >(d);
1429  return os;
1430 }
1431 
1432 // Overload for custom formatting of a UT_StringArray with UTformat.
1433 template <typename T> UT_API size_t
1434 format(char *buffer, size_t bufsize, const UT_Array<T> &v);
1435 
1436 /// Unlike UT_Array::getMemoryUsage(), this also calls getMemoryUsage() on the
1437 /// its elements
1438 template <template <typename> class ArrayT, typename T>
1439 static inline int64
1440 UTarrayDeepMemoryUsage(const ArrayT<T> &arr, bool inclusive)
1441 {
1442  int64 mem = inclusive ? sizeof(arr) : 0;
1443  mem += arr.getMemoryUsage(false);
1444  for (auto &&item : arr)
1445  mem += item.getMemoryUsage(false);
1446  return mem;
1447 }
1448 
1449 /// Utility to sort array using operator<
1450 template <typename T>
1451 static inline void
1452 UTsort(UT_Array<T> &arr)
1453 {
1454  arr.sort([](const T &a, const T &b) { return a < b; });
1455 }
1456 
1457 /// Utility to sort array using operator< and remove duplicates
1458 template <typename T>
1459 static inline void
1460 UTsortAndRemoveDuplicates(UT_Array<T> &arr)
1461 {
1462  arr.sortAndRemoveDuplicates([](const T &a, const T &b) { return a < b; });
1463 }
1464 
1465 // For UT::ArraySet.
1466 namespace UT
1467 {
1468 template <typename T>
1469 struct DefaultClearer;
1470 
1471 template <typename T>
1473 {
1474  static void clear(UT_Array<T> &v) { v.setCapacity(0); }
1475  static bool isClear(const UT_Array<T> &v) { return v.capacity() == 0; }
1476  static void clearConstruct(UT_Array<T> *p)
1477  {
1478  new ((void *)p) UT_Array<T>();
1479  }
1480  static const bool clearNeedsDestruction = false;
1481 };
1482 } // namespace UT
1483 
1484 //
1485 // Trivial relocation is not safe for UT_Array:
1486 // UT_SmallArray, which has a fixed-buffer optimization inherits from UT_Array.
1487 // At compile time, it cannot be known whether a UT_Array object is a
1488 // UT_SmallArray object.
1489 // For this reason alone, it cannot be safe to use trivial relocation on UT_Array.
1490 //
1491 // In addition to that, UT_Array is currently not safe for trivial relocation
1492 // even if UT_SmallArray didn't get used anywhere, due to the isHeapBuffer() test,
1493 // which may incorrectly return false after a UT_Array with a heap buffer gets
1494 // trivially relocated (making it adjacent in memory to its myData).
1495 //
1496 template <typename T>
1498 
1499 //
1500 // Trivial relocation is not safe for std::string since most implementations
1501 // use a small buffer optimization (aka SBO).
1502 //
1503 #if defined(MBSD) || defined(_LIBCPP_VERSION)
1504  #include <iosfwd>
1505  template <typename CharT, typename Traits, typename Allocator>
1507 #elif defined(__GLIBCXX__)
1508  #include <bits/stringfwd.h>
1509  template <typename CharT, typename Traits, typename Allocator>
1511 #else
1512  namespace std { template <class,class,class> class basic_string; }
1513  template <typename CharT, typename Traits, typename Allocator>
1515 #endif
1516 
1517 #endif // __UT_ARRAY_H_INCLUDED__
reference operator*() const
Definition: UT_Array.h:873
base_iterator & operator++()
Pre-increment operator.
Definition: UT_Array.h:883
base_iterator & operator--()
Pre-decrement operator.
Definition: UT_Array.h:896
T & last()
Definition: UT_Array.h:816
exint insert(T &&t, exint i)
Definition: UT_Array.h:157
GLint first
Definition: glcorearb.h:405
IndexedCompare(const UT_Array< V > &values, const ComparatorBool &compare)
Definition: UT_Array.h:516
typedef int(APIENTRYP RE_PFNGLXSWAPINTERVALSGIPROC)(int)
const T & operator[](exint i) const
Definition: UT_Array.h:792
exint append(const T &t)
Definition: UT_Array.h:143
const T * data() const
Definition: UT_Array.h:843
void merge(const UT_Array< T > &other, int direction, bool allow_dups, ComparatorBool is_less={})
const T * getRawArray() const
Definition: UT_Array.h:837
bool isHeapBuffer() const
Returns true if the data used by the array was allocated on the heap.
Definition: UT_Array.h:1099
pointer operator->() const
Definition: UT_Array.h:870
base_iterator operator+(exint n) const
Definition: UT_Array.h:917
GLenum GLuint GLsizei bufsize
Definition: glcorearb.h:1818
void validateEmplaceArgs() const
Base case for validateEmplaceArgs().
Definition: UT_Array.h:1144
GLsizei GLenum const void * indices
Definition: glcorearb.h:406
std::make_unsigned_t< exint > UT_LabeledCapacityRep
bool operator!=(const UT_Array< T > &a) const
void stableSort(ComparatorBool is_less={})
Definition: UT_Array.h:485
void bumpCapacity(exint min_capacity)
Definition: UT_Array.h:612
void setSizeIfNeeded(exint minsize)
Definition: UT_Array.h:679
exint insertImpl(S &&s, exint index)
Similar to appendImpl() but for insertion.
void
Definition: png.h:1083
GLint left
Definition: glcorearb.h:2005
SYS_FORCE_INLINE void removeLast()
Definition: UT_Array.h:379
const GLdouble * v
Definition: glcorearb.h:837
void unsafeShareData(T *src, exint size, exint capacity)
Definition: UT_Array.h:1085
exint findAndRemove(const S &s)
void shrinkToFit()
shrinks the capacity to the current size
Definition: UT_Array.h:710
UT_Array< T > & operator=(const UT_Array< T > &a)
IMF_EXPORT IMATH_NAMESPACE::V3f direction(const IMATH_NAMESPACE::Box2i &dataWindow, const IMATH_NAMESPACE::V2f &pixelPosition)
GLuint start
Definition: glcorearb.h:475
void extractRange(exint begin_i, exint end_i, UT_Array< T > &dest)
void collapseIf(IsEqual is_equal)
Remove all matching elements. Also sets the capacity of the array.
Definition: UT_Array.h:408
T * aliasArray(T *newdata)
Definition: UT_Array.h:847
void setSizeNoInit(exint newsize)
Definition: UT_Array.h:695
bool isValidIndex(exint index) const
Return true if given index is valid.
Definition: UT_Array.h:366
#define SYS_DEPRECATED_HDK_REPLACE(__V__, __R__)
void zero()
Zeros the array if a POD type, else trivial constructs if a class type.
base_iterator< const T, false > const_reverse_iterator
Definition: UT_Array.h:1001
GLdouble right
Definition: glad.h:2817
friend void swap(UT_Array< T > &a, UT_Array< T > &b)
Definition: UT_Array.h:1374
UT_API size_t format(char *buffer, size_t bufsize, const UT_Array< T > &v)
exint uniqueSortedFind(const T &item, ComparatorBool is_less={}) const
Definition: UT_ArrayImpl.h:899
int64 exint
Definition: SYS_Types.h:125
void move(exint src_idx, exint dst_idx, exint how_many)
const_iterator begin() const
Definition: UT_Array.h:1019
int64 getMemoryUsage(bool inclusive=false) const
Definition: UT_Array.h:657
void bumpEntries(exint newsize)
Definition: UT_Array.h:636
const T & heapMax() const
Definition: UT_Array.h:346
GLboolean GLboolean GLboolean GLboolean a
Definition: glcorearb.h:1222
void cycle(exint how_many)
Cyclically shifts the entire array by how_many.
GLdouble s
Definition: glad.h:3009
exint removeIndex(exint index)
Definition: UT_Array.h:375
T * array()
Definition: UT_Array.h:839
static constexpr struct UT_ArrayCT::GeneralizedMove GENERALIZED_MOVE
const_reverse_iterator rend() const
End reverse iterator. Consider using it.atEnd() instead.
Definition: UT_Array.h:1048
#define UT_API
Definition: UT_API.h:14
void setCapacity(exint new_capacity)
static constexpr SYS_FORCE_INLINE bool isPOD()
Definition: UT_Array.h:1109
exint concat(const UT_Array< T > &a)
Takes another T array and concatenate it onto my end.
Definition: UT_ArrayImpl.h:982
exint append(const T &t, bool check_dup)
Definition: UT_Array.h:145
**But if you need a result
Definition: thread.h:613
#define UT_ASSERT_MSG_P(ZZ,...)
Definition: UT_Assert.h:158
exint index(const T &t) const
Definition: UT_Array.h:445
bool operator>=(const base_iterator< ITR, FORWARD > &r) const
Definition: UT_Array.h:970
exint uniqueSortedInsert(const T &t, Comparator compare)
Definition: UT_Array.h:233
reference item() const
Definition: UT_Array.h:876
exint find(const S &s, exint start=0) const
static bool isClear(const UT_Array< T > &v)
Definition: UT_Array.h:1475
void unsafeClearData()
Definition: UT_Array.h:1091
exint size() const
Definition: UT_Array.h:646
void setSize(exint newsize)
Definition: UT_Array.h:666
bool operator==(const base_iterator< ITR, FR > &r) const
Definition: UT_Array.h:935
void sortedUnion(const UT_Array< T > &other, ComparatorBool is_less={})
base_iterator operator-(exint n) const
Definition: UT_Array.h:927
void bumpSize(exint newsize)
Definition: UT_Array.h:629
bool operator>(const base_iterator< ITR, FORWARD > &r) const
Definition: UT_Array.h:952
void setSizeAndShrink(exint new_size)
convenience method to set size and shrink-to-fit in a single call
Definition: UT_Array.h:716
base_iterator< T, false > reverse_iterator
Definition: UT_Array.h:1000
void unsafeShareData(T *src, exint srcsize)
Definition: UT_Array.h:1079
exint append(T &&t)
Definition: UT_Array.h:144
#define SYS_DEPRECATED_REPLACE(__V__, __R__)
exint operator-(const base_iterator< ITR, FORWARD > &r) const
Definition: UT_Array.h:980
exint sortAndRemoveDuplicates(ComparatorBool is_less={})
Definition: UT_Array.h:587
CompareResults OIIO_API compare(const ImageBuf &A, const ImageBuf &B, float failthresh, float warnthresh, ROI roi={}, int nthreads=0)
const_reverse_iterator rbegin() const
Begin iterating over the array in reverse.
Definition: UT_Array.h:1042
exint safeIndex(const T &t) const
Definition: UT_Array.h:446
GLdouble n
Definition: glcorearb.h:2008
void stableSortByKey(const UT_Array< K > &keys, ComparatorBool is_less)
Definition: UT_Array.h:562
Definition: core.h:760
exint apply(int(*apply_func)(T &t, void *d), void *d)
reverse_iterator rbegin()
Begin iterating over the array in reverse.
Definition: UT_Array.h:1031
exint emplace_back(S &&...s)
Definition: UT_ArrayImpl.h:769
static void construct(T &dst, S &&...s)
Definition: UT_Array.h:1150
void entries(exint newsize)
Alias of setSize(). setSize() is preferred.
Definition: UT_Array.h:686
exint uniqueSortedInsertImpl(S &&s, Comparator compare)
Definition: UT_ArrayImpl.h:853
T & operator[](exint i)
Definition: UT_Array.h:784
const T & operator()(exint i) const
Definition: UT_Array.h:775
void sort(ComparatorBool is_less={})
Sort using std::sort with bool comparator. Defaults to operator<().
Definition: UT_Array.h:456
reference operator[](exint n) const
Definition: UT_Array.h:879
#define UT_ASSERT_P(ZZ)
Definition: UT_Assert.h:155
exint insertAt(const T &t, exint index)
Definition: UT_Array.h:362
T accumulate(const T &init_value, BinaryOp add) const
GLuint GLuint end
Definition: glcorearb.h:475
#define SYS_FORCE_INLINE
Definition: SYS_Inline.h:45
exint capacity() const
Definition: UT_ArrayImpl.h:143
base_iterator< T, true > iterator
Definition: UT_Array.h:998
static void clearConstruct(UT_Array< T > *p)
Definition: UT_Array.h:1476
exint sortedInsert(const T &t, Comparator compare)
Definition: UT_ArrayImpl.h:819
UT_IteratorRange< reverse_iterator > rrange()
Definition: UT_Array.h:1058
exint insert(const T &t, exint i)
Definition: UT_Array.h:155
exint appendImpl(S &&s)
Definition: UT_ArrayImpl.h:746
base_iterator(const base_iterator< EIT, FORWARD > &src)
Definition: UT_Array.h:867
void appendMultiple(const T &t, exint count)
Definition: UT_ArrayImpl.h:795
iterator begin()
Definition: UT_Array.h:1006
IMATH_HOSTDEVICE constexpr Color4< T > operator*(S a, const Color4< T > &v) IMATH_NOEXCEPT
Reverse multiplication: S * Color4.
Definition: ImathColor.h:732
long long int64
Definition: SYS_Types.h:116
base_iterator(IT *c, IT *e)
Definition: UT_Array.h:991
void stableSortRange(ComparatorBool is_less, exint start, exint end)
Like stableSort, but operates on a subset of the array.
Definition: UT_Array.h:496
static constexpr struct UT_ArrayCT::ExternalCapacity EXTERNAL_CAPACITY
T forcedGet(exint i) const
Definition: UT_Array.h:811
static void copyConstruct(T &dst, const T &src)
Definition: UT_Array.h:1156
void setCapacityIfNeeded(exint min_capacity)
Definition: UT_Array.h:603
#define SYS_DEPRECATED_HDK(__V__)
exint removeIf(IsEqual is_equal)
const_iterator end() const
End const iterator. Consider using it.atEnd() instead.
Definition: UT_Array.h:1024
base_iterator & operator-=(exint n)
Definition: UT_Array.h:925
exint sortedRemoveDuplicates()
void sortedSetDifference(const UT_Array< T > &other, ComparatorBool is_less={})
GLboolean GLboolean GLboolean b
Definition: glcorearb.h:1222
void unsafeShareData(UT_Array< T > &src)
Definition: UT_Array.h:1073
reverse_iterator rend()
End reverse iterator.
Definition: UT_Array.h:1037
exint append()
Definition: UT_Array.h:142
GLdouble t
Definition: glad.h:2397
bool atEnd() const
Definition: UT_Array.h:930
bool operator()(I a, I b) const
Definition: UT_Array.h:521
bool operator!=(const base_iterator< ITR, FR > &r) const
Definition: UT_Array.h:939
exint sortedRemoveDuplicatesIf(CompareEqual compare_equal)
exint entries() const
Alias of size(). size() is preferred.
Definition: UT_Array.h:648
T selectNthLargest(exint idx, ComparatorBool is_less={})
base_iterator & operator+=(exint n)
Definition: UT_Array.h:909
GLsizeiptr size
Definition: glcorearb.h:664
GLenum GLenum dst
Definition: glcorearb.h:1793
void stdsort(ComparatorBool is_less)
Sort using std::sort. The ComparatorBool uses the less-than semantics.
Definition: UT_Array.h:471
#define SYS_DECLARE_IS_NOT_TR_TEMPLATE(...)
Version for class template.
T value_type
Definition: UT_Array.h:93
GLenum void ** pointer
Definition: glcorearb.h:810
static constexpr struct UT_ArrayCT::ExternalMove EXTERNAL_MOVE
GLenum GLsizei GLsizei GLint * values
Definition: glcorearb.h:1602
T * data()
Definition: UT_Array.h:842
GLuint index
Definition: glcorearb.h:786
bool isEqual(const UT_Array< T > &a, ComparatorBool is_equal) const
base_iterator operator--(int)
Post-decrement operator.
Definition: UT_Array.h:902
const T & last() const
Definition: UT_Array.h:821
GLuint GLfloat * val
Definition: glcorearb.h:1608
const T * array() const
Definition: UT_Array.h:840
static void clear(UT_Array< T > &v)
Definition: UT_Array.h:1474
int(* Comparator)(const T *, const T *)
Definition: UT_Array.h:95
UT_EXTERN_TEMPLATE(UT_Array< UT_StringHolder >)
base_iterator< const T, true > const_iterator
Definition: UT_Array.h:999
void stableArgSort(UT_Array< I > &indices, ComparatorBool is_less) const
Definition: UT_Array.h:549
void truncate(exint maxsize)
Decreases, but never expands, to the given maxsize.
Definition: UT_Array.h:723
void constant(const T &v)
Quickly set the array to a single value.
void removeItem(const reverse_iterator &it)
Remove item specified by the reverse_iterator.
Definition: UT_Array.h:1064
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:156
void sortedIntersection(const UT_Array< T > &other, ComparatorBool is_less={})
void UTconvertArray(UT_Array< T > &dest, const UT_Array< S > &src)
Definition: UT_Array.h:1386
Comparator class for stableSortIndices.
Definition: UT_Array.h:513
ImageBuf OIIO_API add(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
GLboolean r
Definition: glcorearb.h:1222
UT_Array(const UT_Array< T > &a)
Definition: UT_ArrayImpl.h:519
T & forcedRef(exint i)
Definition: UT_Array.h:801
void clear()
Resets list to an empty list.
Definition: UT_Array.h:729
void stableSortIndices(UT_Array< I > &indices, ComparatorBool is_less) const
Definition: UT_Array.h:537
UT_IteratorRange< iterator > range()
Definition: UT_Array.h:1053
UT_IteratorRange< const_iterator > range() const
Definition: UT_Array.h:1055
that also have some descendant prim *whose name begins with which in turn has a child named baz where *the predicate and *a name There is also one special expression reference
const_iterator traverser
Definition: UT_Array.h:1002
T & operator()(exint i)
Definition: UT_Array.h:767
GA_API const UT_StringHolder rest
T heapPop(Comparator compare)
Definition: UT_ArrayImpl.h:945
std::random_access_iterator_tag iterator_category
Definition: UT_Array.h:854
exint heapPush(const T &t, Comparator compare)
Definition: UT_ArrayImpl.h:928
void sort(I begin, I end, const Pred &pred)
Definition: pugixml.cpp:7334
void reverse()
Reverses the array by swapping elements in mirrored locations.
T * getArray() const
Definition: UT_Array.h:836
exint multipleInsert(exint index, exint count)
Insert an element "count" times at the given index. Return the index.
void removeRange(exint begin_i, exint end_i)
base_iterator operator++(int)
Post-increment operator.
Definition: UT_Array.h:889
void swap(UT_Array< T > &other)
Definition: UT_ArrayImpl.h:676
exint insert(exint index)
Definition: UT_ArrayImpl.h:721
bool hasSortedSubset(const UT_Array< T > &other, ComparatorBool is_less={}) const
GLint GLsizei count
Definition: glcorearb.h:405
Definition: format.h:895
iterator end()
End iterator.
Definition: UT_Array.h:1011
UT_IteratorRange< const_reverse_iterator > rrange() const
Definition: UT_Array.h:1060
GLenum src
Definition: glcorearb.h:1793
bool isEmpty() const
Returns true iff there are no occupied elements in the array.
Definition: UT_Array.h:650
bool operator==(const UT_Array< T > &a) const
exint sortedFind(const T &t, Comparator compare) const