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