HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UT_ArrayImpl.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: Utility Library (C++)
7  *
8  * COMMENTS:
9  * This is meant to be included by UT_Array.h and includes
10  * the template implementations needed by external code.
11  */
12 
13 #pragma once
14 
15 #ifndef __UT_ARRAYIMPL_H_INCLUDED__
16 #define __UT_ARRAYIMPL_H_INCLUDED__
17 
18 #include "UT_ArrayHelp.h"
19 #include "UT_Assert.h"
20 #include "UT_Compare.h"
21 #include "UT_Swap.h"
22 #include <VM/VM_Math.h>
23 #include <SYS/SYS_Math.h>
24 #include <SYS/SYS_TypeTraits.h>
25 #include <SYS/SYS_Pragma.h>
26 
27 #include <algorithm>
28 #include <utility>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 
33 // Increasing safety levels for relocation
34 #define UT_RELOCATION_SAFETY_NONE 0
35 #define UT_RELOCATION_SAFETY_PATCHY 1
36 #define UT_RELOCATION_SAFETY_PERMISSIVE 2
37 #define UT_RELOCATION_SAFETY_NORMAL 3
38 #define UT_RELOCATION_SAFETY_MAXIMUM 4
39 
40 // Set current level
41 #define UT_RELOCATION_SAFETY_LEVEL UT_RELOCATION_SAFETY_PATCHY
42 
43 
44 #if (UT_RELOCATION_SAFETY_LEVEL >= UT_RELOCATION_SAFETY_MAXIMUM)
45 
46 // Use trivial relocation for no types at all
47 template< typename T >
49 
50 #elif (UT_RELOCATION_SAFETY_LEVEL >= UT_RELOCATION_SAFETY_NORMAL)
51 
52 // Use trivial relocation only for types that are explicitly declared safe
53 template< typename T >
55 
56 #elif (UT_RELOCATION_SAFETY_LEVEL >= UT_RELOCATION_SAFETY_PERMISSIVE)
57 
58 // Use trivial relocation for types that are explicitly declared safe
59 // and for types that must use it because of legacy code
60 template< typename T >
63  SYS_IsTriviallyRelocatable< T >::value ||
64  LegacyTrivialRelocationNoCV< std::remove_cv_t< T > >::value
65  >
66 {};
67 
68 #elif (UT_RELOCATION_SAFETY_LEVEL >= UT_RELOCATION_SAFETY_PATCHY)
69 
70 // Use trivial relocation for types that are not explicitly declared unsafe
71 // and for types that must use it due to legacy code.
72 template< typename T >
75  ( ! UnsafeTrivialRelocationNoCV< std::remove_cv_t< T > >::value ) ||
76  LegacyTrivialRelocationNoCV< std::remove_cv_t< T > >::value
77  >
78 {
79  // If T is explicitly marked as unsafe using UnsafeTrivialRelocationNoCV,
80  // then it cannot be explicitly marked as safe
81  static_assert(
82  ( ! UnsafeTrivialRelocationNoCV< std::remove_cv_t< T > >::value ) ||
84  "Not trivially relocatable"
85  );
86 };
87 
88 #else // if (UT_RELOCATION_SAFETY_LEVEL >= UT_RELOCATION_SAFETY_NONE)
89 
90 // No safety at all: each type used with UT_Array is bitwise copied,
91 // regardless of whether it is safe to do so.
92 // This is the situation of Houdini 19.5.
93 template< typename T >
95 
96 #endif
97 
98 template< typename T >
100 
101 template <typename T>
102 typename UT_Array<T>::LabeledCapacity
103 UT_Array<T>::labelOwned(const exint capacity) noexcept
104 {
105  UT_ASSERT_P( capacity >= 0 );
106 
107 #ifdef UT_ARRAY_STRICT_LABELED_CAPACITY
108 
109  return ownedLabeledCapacity( capacity );
110 
111 #else
112 
113  UT_ASSERT_P( ( capacity & LABELED_CAPACITY_MASK_VALUE ) == capacity );
114 
115  // Don't set the external bit:
116  return capacity;
117 
118 #endif
119 }
120 
121 template <typename T>
122 typename UT_Array<T>::LabeledCapacity
123 UT_Array<T>::labelExternal(const exint capacity) noexcept
124 {
125  UT_ASSERT_P( capacity >= 0 );
126 
127 #ifdef UT_ARRAY_STRICT_LABELED_CAPACITY
128 
129  return externalLabeledCapacity( capacity );
130 
131 #else
132 
133  UT_ASSERT_P( ( capacity & LABELED_CAPACITY_MASK_VALUE ) == capacity );
134 
135  // Set the external bit:
136  return capacity | LABELED_CAPACITY_FLAG_EXTERNAL;
137 
138 #endif
139 }
140 
141 template <typename T>
142 exint
144 {
145 #ifdef UT_ARRAY_STRICT_LABELED_CAPACITY
146 
147  return capacityValue( myCapacity );
148 
149 #else
150 
151  return myCapacity & LABELED_CAPACITY_MASK_VALUE;
152 
153 #endif
154 }
155 
156 template <typename T>
157 T *
158 UT_Array<T>::allocateArray(const exint capacity) noexcept
159 {
160  constexpr auto elem_size = sizeof(T); // NOLINT
161 
162  UT_ASSERT( capacity > 0 );
163 
166  //TODO: Replace this C-style cast with a static_cast
167  return (T *)malloc( capacity * elem_size );
169 }
170 
171 template <typename T>
172 T *
173 UT_Array<T>::reallocateArray(T *data, const exint capacity) noexcept
174 {
175  constexpr auto elem_size = sizeof(T); // NOLINT
176 
177  UT_ASSERT( capacity > 0 );
178 
181  //TODO: Replace this C-style cast with a static_cast
182  return (T *)realloc( data, capacity * elem_size );
184 }
185 
186 template <typename T>
187 bool
188 UT_Array<T>::isHeapBuffer(T* data) const
189 {
190  return (data != (T *)(((char*)this) + sizeof(*this)));
191 }
192 
193 template <typename T>
194 T *
196 {
197  UT_ASSERT( capacity > 0 );
198 
199  T *data = allocateArray(capacity);
200 
201  // Avoid degenerate case if we happen to be aliased the wrong way
202  if (!isHeapBuffer(data))
203  {
204  // `data` points to the end of us which erroneously causes
205  // isHeapBuffer() to incorrectly identify us as a small buffer instead
206  // of a heap buffer. Retry the allocation. Since `data` is still
207  // occupied, the new allocation's address cannot be at our end anymore.
208  T *prev = data;
209  data = allocateArray(capacity);
210 
211  deallocateArray(prev);
212  }
213 
214  return data;
215 }
216 
217 template <typename T>
218 void
219 UT_Array<T>::deallocateArray(T *p) noexcept
220 {
224  free(p);
226 }
227 
228 template <typename T>
229 void SYS_FORCE_INLINE UT_Array<T>::constructElement(T &dst)
230 {
231  if constexpr( ! SYS_IsPod_v< T > )
232  {
233  new (&dst) T();
234  }
235  else
236  {
237  //TODO: Eliminate C-style cast:
238  memset((void *)&dst, 0, sizeof(T));
239  }
240 }
241 
242 template <typename T>
243 void UT_Array<T>::constructRange(T *dst, exint n)
244 {
245  if constexpr( ! SYS_IsPod_v< T > )
246  {
247  for (exint i = 0; i < n; i++)
248  {
249  new (&dst[i]) T();
250  }
251  }
252  else if (n == 1)
253  {
254  // Special case for n == 1. If the size parameter
255  // passed to memset is known at compile time, this
256  // function call will be inlined. This results in
257  // much faster performance than a real memset
258  // function call which is required in the case
259  // below, where n is not known until runtime.
260  // This makes calls to append() much faster.
261 
262  //TODO: Eliminate C-style cast:
263  memset((void *)dst, 0, sizeof(T));
264  }
265  else
266  {
267  //TODO: Eliminate C-style cast:
268  memset((void *)dst, 0, sizeof(T) * n);
269  }
270 }
271 
272 template <typename T>
273 SYS_FORCE_INLINE void UT_Array<T>::destroyElement(T &dst) noexcept
274 {
275  if constexpr( ! SYS_IsPod_v< T > )
276  {
277  dst.~T();
278  }
279 }
280 
281 template <typename T>
282 void UT_Array<T>::destroyRange([[maybe_unused]] T *dst, exint n) noexcept
283 {
284  if constexpr( ! SYS_IsPod_v< T > )
285  {
286  for (exint i = 0; i < n; i++)
287  {
288  dst[i].~T();
289  }
290  }
291 }
292 
293 template <typename T>
294 void
295 UT_Array<T>::standardRelocateIncreasing(T *const dst, T *const src, exint n)
296 {
297  for( exint i = 0; i != n; ++i )
298  {
299  new( dst + i ) T{ std::move( src[ i ] ) };
300  src[ i ].~T();
301  }
302 }
303 
304 template <typename T>
305 void
306 UT_Array<T>::standardRelocateDecreasing(T *const dst, T *const src, exint n)
307 {
308  for( exint i = n - 1; i >= 0; --i )
309  {
310  new( dst + i ) T{ std::move( src[ i ] ) };
311  src[ i ].~T();
312  }
313 }
314 
315 template <typename T>
316 void
317 UT_Array<T>::standardRelocate(T *const dst, T *const src, exint n)
318 {
319  if( dst < src )
320  {
321  standardRelocateIncreasing( dst, src, n );
322  }
323  else if( src < dst )
324  {
325  standardRelocateDecreasing( dst, src, n );
326  }
327 }
328 
329 // Return whether the ranges [ a, a + n ) and [ b, b + n ) overlap
330 template <typename T>
331 constexpr bool
332 UTareOverlapping( const T*const a, const T*const b, exint n ) noexcept
333 {
334  return ! (
335  ( b >= a + n ) ||
336  ( a >= b + n )
337  );
338 }
339 
340 template <typename T>
341 void
342 UT_Array<T>::bitwiseRelocate(T *const dst, const T *const src, exint n) noexcept
343 {
344  UT_ASSERT( dst != nullptr );
345  UT_ASSERT( src != nullptr );
346  UT_ASSERT( n >= 0 );
347 
348  //TODO: Eliminate these C-style casts;
349  // they cause undefined behavior and
350  // hide compiler warnings that indicate potential problems in our code base
351  ::memmove( (void*)dst, (const void*)src, n * sizeof(T) ); // NOLINT
352 }
353 
354 template <typename T>
355 void
357  T *const dst,
358  const T *const src,
359  exint n) noexcept
360 {
361  UT_ASSERT( dst != nullptr );
362  UT_ASSERT( src != nullptr );
363  UT_ASSERT( n >= 0 );
364  UT_ASSERT( ! UTareOverlapping( dst, src, n ) );
365 
366  //TODO: Eliminate these C-style casts;
367  // they cause undefined behavior and
368  // hide compiler warnings that indicate potential problems in our code base
369  ::memcpy( (void*)dst, (const void*)src, n * sizeof(T) ); // NOLINT
370 }
371 
372 template <typename T>
373 void
374 UT_Array<T>::relocateNonoverlapping(T *const dst, T *const src, exint n)
375 {
376  UT_ASSERT( n >= 0 );
377  UT_ASSERT( ! UTareOverlapping( dst, src, n ) );
378 
379  if constexpr( SYS_UseTrivialRelocation_v< T > )
380  {
381  if( n > 0 )
382  {
383  UT_ASSERT( dst != nullptr );
384  UT_ASSERT( src != nullptr );
385 
386  bitwiseRelocateNonoverlapping( dst, src, n );
387  }
388  }
389  else // constexpr
390  {
391  standardRelocateIncreasing( dst, src, n );
392  }
393 }
394 
395 template <typename T>
396 void UT_Array<T>::relocateIncreasing(T *dst, T *src, exint n)
397 {
398  if constexpr( SYS_UseTrivialRelocation_v< T > )
399  {
400  if( n > 0 )
401  {
402  UT_ASSERT( dst != nullptr );
403  UT_ASSERT( src != nullptr );
404 
405  bitwiseRelocate( dst, src, n );
406  }
407  }
408  else // constexpr
409  {
410  standardRelocateIncreasing( dst, src, n );
411  }
412 }
413 
414 template <typename T>
415 void UT_Array<T>::relocateDecreasing(T *dst, T *src, exint n)
416 {
417  if constexpr( SYS_UseTrivialRelocation_v< T > )
418  {
419  if( n > 0 )
420  {
421  UT_ASSERT( dst != nullptr );
422  UT_ASSERT( src != nullptr );
423 
424  bitwiseRelocate( dst, src, n );
425  }
426  }
427  else // constexpr
428  {
429  standardRelocateDecreasing( dst, src, n );
430  }
431 }
432 
433 template <typename T>
434 void
435 UT_Array<T>::relocate(T *const dst, T *const src, exint n)
436 {
437  UT_ASSERT( n >= 0 );
438 
439  if constexpr( SYS_UseTrivialRelocation_v< T > )
440  {
441  if( n > 0 )
442  {
443  UT_ASSERT( dst != nullptr );
444  UT_ASSERT( src != nullptr );
445 
446  bitwiseRelocate( dst, src, n );
447  }
448  }
449  else // constexpr
450  {
451  standardRelocate( dst, src, n );
452  }
453 }
454 
455 template <typename T>
456 void
457 UT_Array<T>::swapNonoverlapping(T *const dst, T *const src, exint n)
458 {
459  UT_ASSERT( n >= 0 );
460  UT_ASSERT( ! UTareOverlapping( dst, src, n ) );
461 
462  if constexpr( SYS_UseTrivialRelocation_v< T > )
463  {
464  if( n > 0 )
465  {
466  UT_ASSERT( dst != nullptr );
467  UT_ASSERT( src != nullptr );
468 
469  //TODO: bitwiseSwapNonoverlapping( dst, src, n )
470  {
471  char* bytes_dst{ reinterpret_cast< char* >( dst ) };
472  char* bytes_src{ reinterpret_cast< char* >( src ) };
473 
474  const auto num_bytes{ n * sizeof( T ) };
475  for( exint b = 0; b != num_bytes; ++b )
476  {
477  UTswap( bytes_dst[ b ], bytes_src[ b ] );
478  }
479  }
480  }
481  }
482  else // constexpr
483  {
484  for( exint i = 0; i != n; ++i )
485  {
486  T t{ std::move( src[ i ] ) };
487 
488  src[ i ].~T();
489  new( src + i ) T{ std::move( dst[ i ] ) };
490 
491  dst[ i ].~T();
492  new( dst + i ) T{ std::move( t ) };
493  }
494  }
495 }
496 
497 template <typename T>
498 void
499 UT_Array<T>::copyNonoverlapping(T *dst, const T *src, exint n)
500 {
501  if constexpr( SYS_IsPod_v< T > )
502  {
503  if (n > 0)
504  {
505  bitwiseRelocateNonoverlapping(dst, src, n);
506  }
507  }
508  else // constexpr
509  {
510  for (exint i = 0; i < n; i++)
511  {
512  new ( dst + i ) T{ src[i] };
513  }
514  }
515 }
516 
517 template <typename T>
518 inline
520  : myCapacity(labelOwned(a.size())), mySize(a.size())
521 {
522  if (a.size() > 0)
523  {
524  myData = allocateArrayHeapIdentifiable(a.size());
525  copyNonoverlapping(myData, a.array(), a.size());
526  }
527  else
528  {
529  myData = nullptr;
530  }
531 }
532 
533 template <typename T>
534 inline
535 UT_Array<T>::UT_Array(std::initializer_list<T> init)
536  : myCapacity(labelOwned(init.size())), mySize(init.size())
537 {
538  if (init.size() > 0)
539  {
540  myData = allocateArrayHeapIdentifiable(init.size());
541  copyNonoverlapping(myData, init.begin(), init.size());
542  }
543  else
544  {
545  myData = nullptr;
546  }
547 }
548 
549 template <typename T>
550 inline
552  UT_Array{ UT_ArrayCT::GENERALIZED_MOVE, nullptr, 0, std::move( a ) }
553 {
554 }
555 
556 template <typename T>
557 inline
558 UT_Array<T>::UT_Array(const exint capacity, const exint size) :
559  myData{ capacity ? allocateArrayHeapIdentifiable(capacity) : nullptr },
560  myCapacity{ labelOwned(capacity) },
561  mySize{ (capacity < size) ? capacity : size }
562 {
563  UT_ASSERT(capacity >= size);
564  constructRange(myData, mySize);
565 }
566 
567 template <typename T>
568 inline
569 UT_Array<T>::UT_Array(const exint capacity) :
570  myData{ capacity ? allocateArrayHeapIdentifiable(capacity) : nullptr },
571  myCapacity{ labelOwned(capacity) },
572  mySize{ 0 }
573 {
574 }
575 
576 template <typename T>
577 inline
579 {
580  destroyRange(myData, mySize);
581  mySize = 0;
582 
583  if (isHeapBuffer())
584  {
585  deallocateArray(myData);
586  return;
587  }
588 
589  myData = nullptr;
590 
591  myCapacity = labelOwned(0);
592 }
593 
594 template <typename T>
596  const UT_ArrayCT::ExternalCapacity,
597  T *external_data,
598  const exint external_capacity
599 ) :
600  myData{ external_data },
601  myCapacity{ labelExternal(external_capacity) },
602  mySize{ 0 }
603 {
604 }
605 
606 template <typename T>
608  const UT_ArrayCT::ExternalMove,
609  T *external_data,
610  const exint external_capacity,
611  UT_Array&& a
612 ) :
613  UT_Array{ UT_ArrayCT::GENERALIZED_MOVE, external_data, external_capacity, std::move( a ) }
614 {
615 }
616 
617 template <typename T>
619  const UT_ArrayCT::GeneralizedMove,
620  T *external_data,
621  const exint external_capacity,
622  UT_Array&& a
623 ) :
624  myData{ external_data },
625  myCapacity{ labelExternal(external_capacity) },
626  mySize{ 0 }
627 {
628  if( ! a.isHeapBuffer() )
629  {
630  if( a.mySize > external_capacity )
631  {
632  myData = allocateArrayHeapIdentifiable(a.mySize);
633  myCapacity = labelOwned(a.mySize);
634  }
635 
636  relocateNonoverlapping(myData, a.myData, a.mySize);
637  mySize = std::exchange( a.mySize, 0 );
638 
639  return;
640  }
641 
642  myData = std::exchange( a.myData, nullptr );
643  myCapacity = std::exchange( a.myCapacity, labelOwned(0) );
644 
645  mySize = std::exchange( a.mySize, 0 );
646 }
647 
648 template <typename T>
649 void UT_Array<T>::convertToHeapBuffer(const exint capacity)
650 {
651  UT_ASSERT(!isHeapBuffer());
652  UT_ASSERT(mySize<=capacity);
653 
654  T *heap_data{ nullptr };
655 
656  if( capacity > 0 )
657  {
658  heap_data = allocateArray(capacity);
659  relocateNonoverlapping(heap_data, myData, mySize);
660  }
661 
662  myData = heap_data;
663  myCapacity = labelOwned(capacity);
664 
665  // Because we were a nonheap buffer before the call,
666  // it is for impossible myData to have been allocated exactly
667  // at the end of the UT_Array part.
668  // That part of memory is already occupied by UT_SmallArray.
669  // So there is no chance of *this being incorrectly identified
670  // as a nonheap buffer.
671  UT_ASSERT(isHeapBuffer());
672 }
673 
674 template <typename T>
675 inline void
677 {
678  if(
679  ( ( ! isHeapBuffer() ) || ( ! other.isHeapBuffer() ) ) &&
680  ( ( other.mySize <= capacity() ) && ( mySize <= other.capacity() ) )
681  )
682  {
683  // Optimization that applies when one or both
684  // UT_Array objects are nonheap buffers:
685  // As long as each array has the capacity to store the contents of
686  // the other, the elements can be swapped individually.
687  // This avoids the need to convert any nonheap buffer to a heap buffer.
688 
689  swapNonoverlapping( myData, other.myData, SYSmin( mySize, other.mySize ) );
690 
691  if( mySize < other.mySize )
692  {
693  relocateNonoverlapping( myData + mySize, other.myData + mySize, other.mySize - mySize );
694  }
695  else if( other.mySize < mySize )
696  {
697  relocateNonoverlapping( other.myData + other.mySize, myData + other.mySize, mySize - other.mySize );
698  }
699  }
700  else
701  {
702  if( ! isHeapBuffer() )
703  {
704  convertToHeapBuffer( capacity() );
705  }
706 
707  if( ! other.isHeapBuffer() )
708  {
709  other.convertToHeapBuffer( other.capacity() );
710  }
711 
712  UTswap(myData, other.myData);
713  UTswap(myCapacity, other.myCapacity);
714  }
715 
716  UTswap(mySize, other.mySize);
717 }
718 
719 template <typename T>
720 inline exint
722 {
723  if (index >= mySize)
724  {
725  bumpCapacity(index + 1);
726 
727  constructRange(myData + mySize, index - mySize + 1);
728 
729  mySize = index+1;
730  return index;
731  }
732  bumpCapacity(mySize + 1);
733 
734  UT_ASSERT_P(index >= 0);
735  relocateDecreasing(myData + index + 1, myData + index, mySize-index);
736 
737  constructElement(myData[index]);
738 
739  mySize++;
740  return index;
741 }
742 
743 template <typename T>
744 template <typename S>
745 inline exint
747 {
748  if (mySize == capacity())
749  {
750  exint idx = safeIndex(s);
751 
752  // NOTE: UTbumpAlloc always returns a strictly larger value.
753  setCapacity(UTbumpAlloc(capacity()));
754  if (idx >= 0)
755  construct(myData[mySize], std::forward<S>(myData[idx]));
756  else
757  construct(myData[mySize], std::forward<S>(s));
758  }
759  else
760  {
761  construct(myData[mySize], std::forward<S>(s));
762  }
763  return mySize++;
764 }
765 
766 template <typename T>
767 template <typename... S>
768 inline exint
770 {
771 #if UT_ASSERT_LEVEL >= UT_ASSERT_LEVEL_PARANOID
772  validateEmplaceArgs(std::forward<S>(s)...);
773 #endif
774 
775  if (mySize == capacity())
776  {
777  setCapacity(UTbumpAlloc(capacity()));
778  }
779 
780  construct(myData[mySize], std::forward<S>(s)...);
781  return mySize++;
782 }
783 
784 template <typename T>
785 inline void
787 {
788  bumpCapacity(mySize + count);
789  copyNonoverlapping(myData + mySize, pt, count);
790  mySize += count;
791 }
792 
793 template <typename T>
794 inline void
796 {
797  UT_ASSERT_P(count >= 0);
798  if (count <= 0)
799  return;
800  if (mySize + count >= capacity())
801  {
802  exint tidx = safeIndex(t);
803 
804  bumpCapacity(mySize + count);
805 
806  for (exint i = 0; i < count; i++)
807  copyConstruct(myData[mySize+i], tidx >= 0 ? myData[tidx] : t);
808  }
809  else
810  {
811  for (exint i = 0; i < count; i++)
812  copyConstruct(myData[mySize+i], t);
813  }
814  mySize += count;
815 }
816 
817 template <typename T>
818 inline exint
819 UT_Array<T>::sortedInsert(const T &t, Comparator compare)
820 {
821  return sortedInsert(t, UTcompareLess(compare));
822 }
823 
824 template <typename T>
825 template <typename ComparatorBool, typename>
826 inline exint
827 UT_Array<T>::sortedInsert(const T &t, ComparatorBool is_less)
828 {
829  exint low, mid, high;
830 
831  low = 0;
832  high = size() - 1;
833  while (low <= high)
834  {
835  mid = (low + high) / 2;
836  if (is_less(t, myData[mid]))
837  high = mid - 1;
838  else if (is_less(myData[mid], t))
839  low = mid + 1;
840  else
841  {
842  insertAt(t, mid);
843  return mid;
844  }
845  }
846  insertAt(t, low);
847  return low;
848 }
849 
850 template <typename T>
851 template <typename S>
852 inline exint
854 {
855  exint low, mid, high;
856 
857  low = 0;
858  high = size() - 1;
859  while (low <= high)
860  {
861  mid = (low + high) / 2;
862  if (compare(&s, &myData[mid]) < 0)
863  high = mid - 1;
864  else if (compare(&s, &myData[mid]) > 0)
865  low = mid + 1;
866  else
867  return (exint)mid;
868  }
869  insertImpl(std::forward<S>(s), low);
870  return low;
871 }
872 
873 template <typename T>
874 template <typename ComparatorBool, typename>
875 inline exint
876 UT_Array<T>::uniqueSortedInsert(const T &t, ComparatorBool is_less)
877 {
878  exint low, mid, high;
879 
880  low = 0;
881  high = size() - 1;
882  while (low <= high)
883  {
884  mid = (low + high) / 2;
885  if (t == myData[mid])
886  return (exint)mid;
887  else if (is_less(t, myData[mid]))
888  high = mid - 1;
889  else
890  low = mid + 1;
891  }
892  insertAt(t, low);
893  return low;
894 }
895 
896 template <typename T>
897 template <typename ComparatorBool, typename>
898 inline exint
899 UT_Array<T>::uniqueSortedFind(const T &item, ComparatorBool is_less) const
900 {
901  exint len = size();
902  exint idx = 0;
903 
904  while(len > 0)
905  {
906  exint h = len / 2;
907  if (is_less(myData[idx + h], item))
908  {
909  idx += h + 1;
910  len -= h + 1;
911  }
912  else
913  len = h;
914  }
915 
916  return (idx != size() && !is_less(item, myData[idx])) ? idx : -1;
917 }
918 
919 template <typename T>
920 inline exint
921 UT_Array<T>::uniqueSortedFind(const T &item, Comparator compare) const
922 {
923  return uniqueSortedFind(item, UTcompareLess(compare));
924 }
925 
926 template <typename T>
927 inline exint
928 UT_Array<T>::heapPush(const T &t, Comparator compare)
929 {
930  UT_ASSERT(safeIndex(t) < 0);
931  exint i = append(t);
932 
933  // walk up towards the root restoring the heap condition
934  while( i > 0 && compare(&myData[(i - 1) / 2], &t) < 0 )
935  {
936  myData[i] = myData[(i - 1) / 2];
937  i = (i - 1) / 2;
938  }
939  myData[i] = t;
940  return i;
941 }
942 
943 template <typename T>
944 inline T
946 {
947  UT_ASSERT_P(mySize > 0);
948 
949  T result = myData[0];
950  // move last item into the newly created hole
951  myData[0] = myData[mySize - 1];
952  removeAt(mySize - 1);
953  // percolate down until the heap condition is restored
954  exint idx = 0;
955  for(;;)
956  {
957  exint largest = idx;
958 
959  // test heap condition with left child
960  exint cidx = 2 * idx + 1;
961  if( cidx < mySize && compare(&myData[largest], &myData[cidx]) < 0 )
962  largest = cidx;
963  // test heap condition with right child
964  ++cidx;
965  if( cidx < mySize && compare(&myData[largest], &myData[cidx]) < 0 )
966  largest = cidx;
967  if( largest == idx )
968  {
969  // heap condition has been restored
970  break;
971  }
972 
973  UTswap(myData[idx], myData[largest]);
974  idx = largest;
975  }
976 
977  return result;
978 }
979 
980 template <typename T>
981 inline exint
983 {
984  bumpCapacity(mySize + a.mySize);
985  copyNonoverlapping(myData + mySize, a.myData, a.mySize);
986  mySize += a.mySize;
987 
988  return mySize;
989 }
990 
991 template <typename T>
992 inline exint
994 {
995  // If this array was empty, we can just steal from the other array.
996  if (mySize == 0)
997  {
998  operator=(std::move(a));
999  return mySize;
1000  }
1001 
1002  const exint n = a.mySize;
1003  bumpCapacity(mySize + n);
1004  relocateNonoverlapping(myData + mySize, a.myData, n);
1005  mySize += n;
1006  a.mySize = 0;
1007 
1008  return mySize;
1009 }
1010 
1011 template <typename T>
1012 inline exint
1014 {
1015  exint end_index = beg_index + count;
1016 
1017  if (beg_index >= mySize)
1018  {
1019  bumpCapacity(end_index);
1020 
1021  constructRange(myData + mySize, end_index - mySize);
1022 
1023  mySize = end_index;
1024  return beg_index;
1025  }
1026  bumpCapacity(mySize+count);
1027 
1028  relocateDecreasing(myData + end_index, myData + beg_index, mySize-beg_index);
1029  mySize += count;
1030 
1031  constructRange(myData + beg_index, count);
1032 
1033  return beg_index;
1034 }
1035 
1036 template <typename T>
1037 template <typename S>
1038 inline exint
1040 {
1041  if (index == mySize)
1042  {
1043  // This case avoids an extraneous call to constructRange()
1044  // which the compiler may not optimize out.
1045  (void) appendImpl(std::forward<S>(s));
1046  }
1047  else if (index > mySize)
1048  {
1049  exint src_i = safeIndex(s);
1050 
1051  bumpCapacity(index + 1);
1052 
1053  constructRange(myData + mySize, index - mySize);
1054 
1055  if (src_i >= 0)
1056  construct(myData[index], std::forward<S>(myData[src_i]));
1057  else
1058  construct(myData[index], std::forward<S>(s));
1059 
1060  mySize = index + 1;
1061  }
1062  else // (index < mySize)
1063  {
1064  exint src_i = safeIndex(s);
1065 
1066  bumpCapacity(mySize + 1);
1067 
1068  relocateDecreasing(myData + index + 1, myData + index, mySize-index);
1069 
1070  if (src_i >= index)
1071  ++src_i;
1072 
1073  if (src_i >= 0)
1074  construct(myData[index], std::forward<S>(myData[src_i]));
1075  else
1076  construct(myData[index], std::forward<S>(s));
1077 
1078  ++mySize;
1079  }
1080 
1081  return index;
1082 }
1083 
1084 template <typename T>
1085 template <typename S>
1086 inline exint
1088 {
1089  exint idx = find(s);
1090  return (idx < 0) ? -1 : removeAt((exint)idx);
1091 }
1092 
1093 template <typename T>
1094 inline exint
1096 {
1097  destroyElement(myData[idx]);
1098  if (idx != --mySize)
1099  {
1100  relocateIncreasing(myData + idx, myData + idx + 1, mySize - idx);
1101  }
1102 
1103  return idx;
1104 }
1105 
1106 template <typename T>
1107 inline void
1109 {
1110  UT_ASSERT(begin_i <= end_i);
1111  UT_ASSERT(end_i <= mySize);
1112 
1113  const exint nelements = end_i - begin_i;
1114  if (nelements <= 0)
1115  {
1116  return;
1117  }
1118 
1119  destroyRange(myData + begin_i, nelements);
1120  relocateIncreasing(myData + begin_i, myData + end_i, mySize - end_i);
1121  mySize -= nelements;
1122 }
1123 
1124 template <typename T>
1125 inline void
1127 {
1128  UT_ASSERT_P(begin_i >= 0);
1129  UT_ASSERT_P(begin_i <= end_i);
1130  UT_ASSERT_P(end_i <= size());
1131  UT_ASSERT(this != &dest);
1132 
1133  exint nelements = end_i - begin_i;
1134 
1135  // grow the raw array if necessary.
1136  dest.setCapacityIfNeeded(nelements);
1137 
1138  if( nelements > 0 )
1139  {
1140  relocate(dest.myData, myData + begin_i, nelements);
1141  }
1142  dest.mySize = nelements;
1143 
1144  // we just asserted this was true, but just in case
1145  if (this != &dest)
1146  {
1147  if (end_i < size())
1148  {
1149  if( nelements > 0 )
1150  {
1151  relocateIncreasing(myData + begin_i, myData + end_i, mySize - end_i);
1152  }
1153  }
1154  mySize -= nelements;
1155  if (mySize<0)
1156  mySize=0;
1157  }
1158 }
1159 
1160 template <typename T>
1161 inline void
1162 UT_Array<T>::move(exint src_idx, exint dst_idx, exint how_many)
1163 {
1164  // Make sure all the parameters are valid.
1165  if (src_idx < 0)
1166  src_idx = 0;
1167  if (dst_idx < 0)
1168  dst_idx = 0;
1169  // If we are told to move a set of elements that would extend beyond the
1170  // end of the current array, trim the group.
1171  if (src_idx + how_many > size())
1172  how_many = size() - src_idx;
1173  // If the dst_idx would have us move the source beyond the end of the
1174  // current array, move the dst_idx back.
1175  if (dst_idx + how_many > size())
1176  dst_idx = size() - how_many;
1177  if (src_idx != dst_idx && how_many > 0)
1178  {
1179  exint savelen = SYSabs(src_idx - dst_idx);
1180 
1181  T* tmp = allocateArray(savelen);
1182 
1183  if (src_idx > dst_idx && how_many > 0)
1184  {
1185  // We're moving the group backwards. Save all the stuff that
1186  // we would overwrite, plus everything beyond that to the
1187  // start of the source group. Then move the source group, then
1188  // tack the saved data onto the end of the moved group.
1189  relocateNonoverlapping(tmp, &myData[dst_idx], savelen);
1190  relocate(&myData[dst_idx], &myData[src_idx], how_many);
1191  relocateNonoverlapping(&myData[dst_idx + how_many], tmp, savelen);
1192  }
1193  if (src_idx < dst_idx && how_many > 0)
1194  {
1195  // We're moving the group forwards. Save from the end of the
1196  // group being moved to the end of the where the destination
1197  // group will end up. Then copy the source to the destination.
1198  // Then move back up to the original source location and drop
1199  // in our saved data.
1200  relocateNonoverlapping(tmp, &myData[src_idx + how_many], savelen);
1201  relocate(&myData[dst_idx], &myData[src_idx], how_many);
1202  relocateNonoverlapping(&myData[src_idx], tmp, savelen);
1203  }
1204 
1205  deallocateArray(tmp);
1206  }
1207 }
1208 
1209 template <typename T>
1210 template <typename IsEqual>
1211 inline exint
1212 UT_Array<T>::removeIf(IsEqual is_equal)
1213 {
1214  // Move dst to the first element to remove.
1215  exint dst;
1216  for (dst = 0; dst < mySize; dst++)
1217  {
1218  if (is_equal(myData[dst]))
1219  break;
1220  }
1221  // Now start looking at all the elements past the first one to remove.
1222  for (exint idx = dst+1; idx < mySize; idx++)
1223  {
1224  if (!is_equal(myData[idx]))
1225  {
1226  UT_ASSERT(idx != dst);
1227  myData[dst] = std::move(myData[idx]);
1228  dst++;
1229  }
1230  // On match, ignore.
1231  }
1232 
1233  // Don't call setSize(dst) since it supports growing the array which
1234  // requires a default constructor. Avoiding it allows this to be used on
1235  // types that lack a default constructor.
1236  destroyRange(myData + dst, mySize - dst);
1237  mySize = dst;
1238 
1239  return mySize;
1240 }
1241 
1242 template <typename T>
1243 inline void
1245 {
1246  exint numShift; // The number of items we shift
1247  exint remaining; // mySize - numShift
1248 
1249  if (how_many == 0 || mySize < 1)
1250  return;
1251 
1252  numShift = how_many % (exint)mySize;
1253  if (numShift < 0) numShift += mySize;
1254  remaining = mySize - numShift;
1255 
1256  if( numShift == 0 )
1257  {
1258  return;
1259  }
1260 
1261  T* tmp = allocateArray(numShift);
1262 
1263  relocate(tmp, myData + remaining, numShift);
1264  relocate(myData + numShift, myData, remaining);
1265  relocate(myData + 0, tmp, numShift);
1266 
1267  deallocateArray(tmp);
1268 }
1269 
1270 template <typename T>
1271 inline void
1273 {
1274  for (exint i = 0; i < mySize; i++)
1275  {
1276  myData[i] = value;
1277  }
1278 }
1279 
1280 // This constant() specialization needs to be declared here and implemented
1281 // in UT_Array.C.
1282 template <>
1284 
1285 template <typename T>
1286 inline void
1288 {
1289  if constexpr( SYS_IsPod_v< T > )
1290  {
1291  ::memset((void *)myData, 0, mySize*sizeof(T)); // NOLINT
1292  }
1293  else // constexpr
1294  {
1295  constructRange(myData, mySize);
1296  }
1297 }
1298 
1299 template <typename T>
1300 template <typename S>
1301 inline exint
1302 UT_Array<T>::find(const S &s, exint start) const
1303 {
1304  const T *end = myData + mySize;
1305  for (const T *p = myData + start; p < end; ++p)
1306  if (*p == s)
1307  return (p - myData);
1308  return -1;
1309 }
1310 
1311 template <typename T>
1312 exint
1313 UT_Array<T>::sortedFind(const T &t, Comparator compare) const
1314 {
1315  T *found;
1316 
1317  if( mySize == 0 ) return -1;
1318 
1319  // NOLINTNEXTLINE
1320  found = (T *)::bsearch(&t, myData, mySize, sizeof(T),
1321  (ut_ptr_compare_func_t)compare);
1322  return found ? (found - myData) : -1;
1323 }
1324 
1325 template <typename T>
1326 inline void
1328 {
1329  exint n = mySize / 2;
1330  for (exint i = 0; i < n; i++ )
1331  UTswap(myData[i], myData[mySize-1-i]);
1332 }
1333 
1334 template <typename T>
1335 inline void
1337 {
1338  std::sort(myData, myData + mySize, UTcompareLess(compare));
1339 }
1340 
1341 template <typename T>
1342 template <typename ComparatorBool>
1343 inline T
1344 UT_Array<T>::selectNthLargest(exint idx, ComparatorBool is_less)
1345 {
1346  // The idea of returning doesn't make sense if we have
1347  // an empty array.
1348  UT_ASSERT(size() > 0);
1349  if (size() == 0)
1350  return T();
1351 
1352  idx = SYSclamp(idx, (exint)0, (exint)(size())-1);
1353 
1354  UTnth_element(myData, &myData[idx], &myData[size()], is_less);
1355 
1356  return myData[idx];
1357 }
1358 
1359 template <typename T>
1360 inline void
1362 {
1363  // Do nothing when new capacity is the same as the current
1364  if (new_capacity == capacity())
1365  {
1366  return;
1367  }
1368 
1369  // Special case for non-heap buffers
1370  if (!isHeapBuffer())
1371  {
1372  if (new_capacity < mySize)
1373  {
1374  // Destroy the extra elements without changing capacity()
1375  destroyRange(myData + new_capacity, mySize - new_capacity);
1376  mySize = new_capacity;
1377  }
1378  else if (new_capacity > capacity())
1379  {
1380  convertToHeapBuffer(new_capacity);
1381  }
1382  else
1383  {
1384  // Keep capacity unchanged in this case
1385  UT_ASSERT_P(new_capacity >= mySize && new_capacity <= capacity());
1386  }
1387  return;
1388  }
1389 
1390  if (new_capacity == 0)
1391  {
1392  if (myData)
1393  {
1394  destroyRange(myData, mySize);
1395  deallocateArray(myData);
1396  }
1397  myData = nullptr;
1398  myCapacity = labelOwned(0);
1399  mySize = 0;
1400  return;
1401  }
1402 
1403  if (new_capacity < mySize)
1404  {
1405  destroyRange(myData + new_capacity, mySize - new_capacity);
1406  mySize = new_capacity;
1407  }
1408 
1409  if (myData)
1410  {
1411  if constexpr( SYS_UseTrivialRelocation_v< T > )
1412  {
1413  myData = reallocateArray(myData, new_capacity);
1414  }
1415  else // constexpr
1416  {
1417  T *prev = myData;
1418  myData = allocateArray(new_capacity);
1419  if (mySize > 0)
1420  {
1421  relocateNonoverlapping(myData, prev, mySize);
1422  }
1423 
1424  deallocateArray(prev);
1425  }
1426  }
1427  else
1428  {
1429  myData = allocateArray(new_capacity);
1430  }
1431 
1432  // Avoid degenerate case if we happen to be aliased the wrong way
1433  if (!isHeapBuffer())
1434  {
1435  // `myData` points to the end of us which erroneously causes
1436  // isHeapBuffer() to incorrectly identify us as a small buffer instead
1437  // of a heap buffer. Retry the allocation. Since `myData` is still
1438  // occupied, the new allocation's address cannot be at our end anymore.
1439  T *prev = myData;
1440  myData = allocateArray(new_capacity);
1441  if (mySize > 0)
1442  {
1443  relocateNonoverlapping(myData, prev, mySize);
1444  }
1445 
1446  deallocateArray(prev);
1447  }
1448 
1449  myCapacity = labelOwned(new_capacity);
1450  UT_ASSERT(myData);
1451 }
1452 
1453 template <typename T>
1454 inline UT_Array<T> &
1456 {
1457  if (this == &a)
1458  {
1459  return *this;
1460  }
1461 
1462  UT_Array t{ a };
1463  swap( t );
1464 
1465  return *this;
1466 }
1467 
1468 template <typename T>
1469 inline UT_Array<T> &
1470 UT_Array<T>::operator=(std::initializer_list<T> a)
1471 {
1472  const exint new_size = a.size();
1473 
1474  // Grow the raw array if necessary.
1475  setCapacityIfNeeded(new_size);
1476 
1477  // Make sure destructors and constructors are called on all elements
1478  // being removed/added.
1479  destroyRange(myData, mySize);
1480 
1481  copyNonoverlapping(myData, a.begin(), new_size);
1482 
1483  mySize = new_size;
1484 
1485  return *this;
1486 }
1487 
1488 template <typename T>
1489 inline UT_Array<T> &
1491 {
1492  // Satisfy requirement that if 'a' has a heap buffer,
1493  // then *this has to have a heap buffer as well.
1494  if((!isHeapBuffer()) && a.isHeapBuffer())
1495  {
1496  destroyRange(myData, mySize);
1497  mySize = 0;
1498  convertToHeapBuffer(0);
1499  }
1500 
1501  UT_Array t{ std::move( a ) };
1502  swap( t );
1503 
1504  return *this;
1505 }
1506 
1507 
1508 template <typename T>
1509 inline bool
1511 {
1512  if (this == &a) return true;
1513  if (mySize != a.size()) return false;
1514  for (exint i = 0; i < mySize; i++)
1515  if (!(myData[i] == a(i))) return false;
1516  return true;
1517 }
1518 
1519 template <typename T>
1520 inline bool
1522 {
1523  return (!operator==(a));
1524 }
1525 
1526 template <typename T>
1527 inline int
1528 UT_Array<T>::isEqual(const UT_Array<T> &a, Comparator compare) const
1529 {
1530  if (this == &a) return 1;
1531  if (mySize != a.size()) return 0;
1532  for (exint i = 0; i < mySize; i++)
1533  {
1534  T v2 = a(i);
1535  if (compare(&myData[i], &v2)) return 0;
1536  }
1537  return 1;
1538 }
1539 
1540 template <typename T>
1541 inline exint
1542 UT_Array<T>::apply(int (*apply_func)(T &t, void *d), void *d)
1543 {
1544  exint i;
1545  for (i = 0; i < mySize; i++)
1546  {
1547  if (apply_func(myData[i], d))
1548  break;
1549  }
1550  return i;
1551 }
1552 
1553 // Merge the given array into us.
1554 // If direction is -1, then it assumes us and 'other' are both already
1555 // sorted in descending order. Similarly, +1 means ascending.
1556 // If allow_dups is false, then it further assumes that both arrays have no
1557 // duplicates and will produce a result that also has no duplicates.
1558 // More work will be needed if you want allow_dups to mean remove duplicates
1559 template <typename T>
1560 template <typename ComparatorBool>
1561 inline void
1563  const UT_Array<T> &other, int direction, bool allow_dups,
1564  ComparatorBool is_less)
1565 {
1567  exint our_idx;
1568  exint other_idx;
1569 
1570  // handle trivial cases to avoid extra work
1571  if (other.size() == 0)
1572  return;
1573  if (size() == 0)
1574  {
1575  concat(other);
1576  return;
1577  }
1578 
1579  UT_ASSERT( direction == -1 || direction == +1 );
1580  direction = (direction > 0) ? +1 : -1;
1581 
1582  our_idx = 0;
1583  other_idx = 0;
1584  while( our_idx < size() && other_idx < other.size() )
1585  {
1586  const T &our_item = (*this)(our_idx);
1587  const T &other_item = other(other_idx);
1588  exint item_dir;
1589 
1590  if (our_item == other_item)
1591  item_dir = 0;
1592  else if (is_less(our_item, other_item))
1593  item_dir = -1;
1594  else
1595  item_dir = +1;
1596 
1597  if( item_dir != 0 )
1598  {
1599  // we need to do an comparison in the next line to take care of the
1600  // fact that -INT_MIN is still less than 0.
1601  item_dir = ( (item_dir > 0) ? +1 : -1 ) * direction;
1602  }
1603 
1604  if( item_dir < 0 )
1605  {
1606  result.append( our_item );
1607  our_idx++;
1608  }
1609  else if( item_dir > 0 )
1610  {
1611  result.append( other_item );
1612  other_idx++;
1613  }
1614  else
1615  {
1616  result.append( our_item );
1617  our_idx++;
1618  if( allow_dups )
1619  result.append( other_item );
1620  other_idx++;
1621  }
1622  }
1623 
1624  UT_ASSERT( our_idx == size() || other_idx == other.size() );
1625  for( ; our_idx < size(); our_idx++ )
1626  result.append( (*this)(our_idx) );
1627  for( ; other_idx < other.size(); other_idx++ )
1628  result.append( other(other_idx) );
1629 
1630  // finally swap the result into us
1631  swap( result );
1632 }
1633 
1634 template <typename T>
1635 inline bool
1637  const UT_Array<T> &other,
1638  Comparator compare) const
1639 {
1640  return hasSortedSubset(other, UTcompareLess(compare));
1641 }
1642 
1643 template <typename T>
1644 template <typename ComparatorBool, typename>
1645 inline bool
1647  const UT_Array<T> &other,
1648  ComparatorBool compare) const
1649 {
1650  return std::includes(
1651  myData, myData + mySize,
1652  other.myData, other.myData + other.mySize,
1653  compare);
1654 }
1655 
1656 template <typename T>
1657 inline void
1659 {
1660  sortedUnion(other, UTcompareLess(compare));
1661 }
1662 
1663 template <typename T>
1664 inline void
1666  const UT_Array<T> &other,
1668  Comparator compare) const
1669 {
1670  sortedUnion(other, result, UTcompareLess(compare));
1671 }
1672 
1673 template <typename T>
1674 inline void
1676 {
1677  sortedIntersection(other, UTcompareLess(compare));
1678 }
1679 
1680 template <typename T>
1681 inline void
1683  const UT_Array<T> &other,
1685  Comparator compare) const
1686 {
1687  sortedIntersection(other, result, UTcompareLess(compare));
1688 }
1689 
1690 template <typename T>
1691 inline void
1693 {
1694  sortedSetDifference(other, UTcompareLess(compare));
1695 }
1696 
1697 template <typename T>
1698 inline void
1700  const UT_Array<T> &other,
1702  Comparator compare) const
1703 {
1704  sortedSetDifference(other, result, UTcompareLess(compare));
1705 }
1706 
1707 template <typename T>
1708 template <typename ComparatorBool, typename>
1709 inline void
1710 UT_Array<T>::sortedUnion(const UT_Array<T> &other, ComparatorBool is_less)
1711 {
1712  UT_Array<T> temp;
1713  sortedUnion( other, temp, is_less );
1714  swap( temp );
1715 }
1716 
1717 template <typename T>
1718 template <typename ComparatorBool, typename>
1719 inline void
1721  const UT_Array<T> &other,
1723  ComparatorBool is_less) const
1724 {
1725  // Can't store to either input.
1726  UT_ASSERT(&result != this && &result != &other);
1727  UT_ASSERT(result.size() == 0);
1728 
1729  std::set_union(
1730  begin(), end(), other.begin(), other.end(), AppendIterator(result),
1731  is_less);
1732 }
1733 
1734 template <typename T>
1735 template <typename ComparatorBool, typename>
1736 inline void
1738  const UT_Array<T> &other,
1739  ComparatorBool is_less)
1740 {
1741  UT_Array<T> temp;
1742  sortedIntersection( other, temp, is_less );
1743  swap( temp );
1744 }
1745 
1746 template <typename T>
1747 template <typename ComparatorBool, typename>
1748 inline void
1750  const UT_Array<T> &other,
1752  ComparatorBool is_less) const
1753 {
1754  // Can't store to either input.
1755  UT_ASSERT(&result != this && &result != &other);
1756  UT_ASSERT(result.size() == 0);
1757 
1758  std::set_intersection(
1759  begin(), end(), other.begin(), other.end(), AppendIterator(result),
1760  is_less);
1761 }
1762 
1763 template <typename T>
1764 template <typename ComparatorBool, typename>
1765 inline void
1767  const UT_Array<T> &other,
1768  ComparatorBool is_less)
1769 {
1770  UT_Array<T> temp;
1771  sortedSetDifference(other, temp, is_less);
1772  swap( temp );
1773 }
1774 
1775 template <typename T>
1776 template <typename ComparatorBool, typename>
1777 inline void
1779  const UT_Array<T> &other,
1781  ComparatorBool is_less) const
1782 {
1783  // Can't store to either input.
1784  UT_ASSERT(&result != this && &result != &other);
1785  UT_ASSERT(result.size() == 0);
1786 
1787  std::set_difference(
1788  begin(), end(), other.begin(), other.end(), AppendIterator(result),
1789  is_less);
1790 }
1791 
1792 template <typename T>
1793 template <typename CompareEqual>
1794 inline exint
1795 UT_Array<T>::sortedRemoveDuplicatesIf(CompareEqual compare_equal)
1796 {
1797  exint n = size();
1798 
1799  // Trivial, no duplicates!
1800  if (n < 2)
1801  return 0;
1802 
1803  exint dst = 1;
1804  for (exint i = 1; i < n; i++)
1805  {
1806  if (!compare_equal((*this)(i), (*this)(i-1)))
1807  {
1808  if (i != dst)
1809  (*this)(dst) = (*this)(i);
1810  dst++;
1811  }
1812  }
1813 
1814  // Store the number of remaining elements.
1815  setSize(dst);
1816  return n - dst; // Return the number of elements removed
1817 }
1818 
1819 namespace {
1820  template<typename T>
1821  struct srdCompareEqual
1822  {
1823  bool operator()(const T& x, const T& y) const { return (x == y); }
1824  };
1825 }
1826 
1827 template <typename T>
1828 inline exint
1830 {
1831  srdCompareEqual<T> cmp;
1832  return sortedRemoveDuplicatesIf(cmp);
1833 }
1834 
1835 template <typename T>
1836 template <typename BinaryOp>
1837 inline T
1838 UT_Array<T>::accumulate(const T &init_value, BinaryOp add) const
1839 {
1840  T sum(init_value);
1841  for (exint i = 0; i < mySize; i++)
1842  sum = add(sum, myData[i]);
1843  return sum;
1844 }
1845 
1846 #endif // __UT_ARRAYIMPL_H_INCLUDED__
void swap(ArAssetInfo &lhs, ArAssetInfo &rhs)
Definition: assetInfo.h:74
int isEqual(const UT_Array< T > &a, Comparator compare) const
int(* ut_ptr_compare_func_t)(const void *, const void *)
Definition: UT_ArrayHelp.h:23
void merge(const UT_Array< T > &other, int direction, bool allow_dups, ComparatorBool is_less={})
bool isHeapBuffer() const
Returns true if the data used by the array was allocated on the heap.
Definition: UT_Array.h:1079
void UTnth_element(IT start, IT nth, IT end, COMPARE isAbeforeB)
Definition: UT_Permute.h:75
bool operator!=(const UT_Array< T > &a) const
#define SYS_PRAGMA_PUSH_WARN()
Definition: SYS_Pragma.h:34
void UTswap(T &a, T &b)
Definition: UT_Swap.h:35
exint insertImpl(S &&s, exint index)
Similar to appendImpl() but for insertion.
void
Definition: png.h:1083
GLboolean * data
Definition: glcorearb.h:131
exint findAndRemove(const S &s)
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
GLsizei const GLfloat * value
Definition: glcorearb.h:824
void extractRange(exint begin_i, exint end_i, UT_Array< T > &dest)
void zero()
Zeros the array if a POD type, else trivial constructs if a class type.
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)
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
#define SYSabs(a)
Definition: SYS_Math.h:1540
T * array()
Definition: UT_Array.h:819
static constexpr struct UT_ArrayCT::GeneralizedMove GENERALIZED_MOVE
#define UT_API
Definition: UT_API.h:14
void setCapacity(exint new_capacity)
GLint y
Definition: glcorearb.h:103
exint concat(const UT_Array< T > &a)
Takes another T array and concatenate it onto my end.
Definition: UT_ArrayImpl.h:982
**But if you need a result
Definition: thread.h:613
constexpr UT_LabeledCapacityRep LABELED_CAPACITY_MASK_VALUE
GLfloat GLfloat GLfloat v2
Definition: glcorearb.h:818
exint uniqueSortedInsert(const T &t, Comparator compare)
Definition: UT_Array.h:233
exint find(const S &s, exint start=0) const
float fpreal32
Definition: SYS_Types.h:200
exint size() const
Definition: UT_Array.h:646
void sortedUnion(const UT_Array< T > &other, ComparatorBool is_less={})
constexpr UT_LabeledCapacityRep LABELED_CAPACITY_FLAG_EXTERNAL
IMATH_HOSTDEVICE constexpr int cmp(T a, T b) IMATH_NOEXCEPT
Definition: ImathFun.h:84
CompareResults OIIO_API compare(const ImageBuf &A, const ImageBuf &B, float failthresh, float warnthresh, ROI roi={}, int nthreads=0)
GLdouble n
Definition: glcorearb.h:2008
exint apply(int(*apply_func)(T &t, void *d), void *d)
exint emplace_back(S &&...s)
Definition: UT_ArrayImpl.h:769
constexpr UT_LabeledCapacity ownedLabeledCapacity(const exint capacity) noexcept
constexpr UT_LabeledCapacity externalLabeledCapacity(const exint capacity) noexcept
exint uniqueSortedInsertImpl(S &&s, Comparator compare)
Definition: UT_ArrayImpl.h:853
void sort(ComparatorBool is_less={})
Sort using std::sort with bool comparator. Defaults to operator<().
Definition: UT_Array.h:456
#define UT_ASSERT_P(ZZ)
Definition: UT_Assert.h:155
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
UT_Vector3T< T > SYSclamp(const UT_Vector3T< T > &v, const UT_Vector3T< T > &min, const UT_Vector3T< T > &max)
Definition: UT_Vector3.h:1057
exint sortedInsert(const T &t, Comparator compare)
Definition: UT_ArrayImpl.h:819
#define SYS_PRAGMA_DISABLE_FREE_NONHEAP_OBJECT()
Definition: SYS_Pragma.h:117
exint appendImpl(S &&s)
Definition: UT_ArrayImpl.h:746
void appendMultiple(const T &t, exint count)
Definition: UT_ArrayImpl.h:795
iterator begin()
Definition: UT_Array.h:986
void setCapacityIfNeeded(exint min_capacity)
Definition: UT_Array.h:603
#define SYS_PRAGMA_POP_WARN()
Definition: SYS_Pragma.h:35
exint removeIf(IsEqual is_equal)
exint sortedRemoveDuplicates()
void sortedSetDifference(const UT_Array< T > &other, ComparatorBool is_less={})
GLboolean GLboolean GLboolean b
Definition: glcorearb.h:1222
constexpr exint capacityValue(const UT_LabeledCapacity &a) noexcept
constexpr bool UTareOverlapping(const T *const a, const T *const b, exint n) noexcept
Definition: UT_ArrayImpl.h:332
GLint GLenum GLint x
Definition: glcorearb.h:409
exint append()
Definition: UT_Array.h:142
GLdouble t
Definition: glad.h:2397
exint sortedRemoveDuplicatesIf(CompareEqual compare_equal)
T selectNthLargest(exint idx, ComparatorBool is_less={})
#define SYS_PRAGMA_DISABLE_ALLOC_SIZE_LARGER_THAN()
Definition: SYS_Pragma.h:173
GLsizeiptr size
Definition: glcorearb.h:664
GLfloat GLfloat GLfloat GLfloat h
Definition: glcorearb.h:2002
GLenum GLenum dst
Definition: glcorearb.h:1793
UT_Compare::Less< T > UTcompareLess(UT_Compare::Ternary< T > compare)
Definition: UT_Compare.h:64
VULKAN_HPP_CONSTEXPR_14 VULKAN_HPP_INLINE T exchange(T &obj, U &&newValue)
Definition: vulkan_raii.hpp:25
GLuint index
Definition: glcorearb.h:786
#define SYS_PRAGMA_DISABLE_MISMATCHED_NEW_DELETE()
Definition: SYS_Pragma.h:180
GLuint GLfloat * val
Definition: glcorearb.h:1608
void constant(const T &v)
Quickly set the array to a single value.
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:156
void sortedIntersection(const UT_Array< T > &other, ComparatorBool is_less={})
Definition: core.h:1131
ImageBuf OIIO_API add(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
#define const
Definition: zconf.h:214
UT_Array(const UT_Array< T > &a)
Definition: UT_ArrayImpl.h:519
#define SYSmin(a, b)
Definition: SYS_Math.h:1539
T heapPop(Comparator compare)
Definition: UT_ArrayImpl.h:945
exint heapPush(const T &t, Comparator compare)
Definition: UT_ArrayImpl.h:928
std::string OIIO_UTIL_API concat(string_view s, string_view t)
void sort(I begin, I end, const Pred &pred)
Definition: pugixml.cpp:7334
void reverse()
Reverses the array by swapping elements in mirrored locations.
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)
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:991
constexpr auto SYS_UseTrivialRelocation_v
Definition: UT_ArrayImpl.h:99
FMT_CONSTEXPR auto find(Ptr first, Ptr last, T value, Ptr &out) -> bool
Definition: core.h:2089
GLenum src
Definition: glcorearb.h:1793
bool operator==(const UT_Array< T > &a) const
exint sortedFind(const T &t, Comparator compare) const
PcpNodeRef_ChildrenIterator begin(const PcpNodeRef::child_const_range &r)
Support for range-based for loops for PcpNodeRef children ranges.
Definition: node.h:483