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 template <typename ComparatorBool, typename>
1528 inline bool
1529 UT_Array<T>::isEqual(const UT_Array<T> &a, ComparatorBool is_equal) const
1530 {
1531  if (this == &a) return true;
1532  if (mySize != a.size()) return false;
1533  for (exint i = 0; i < mySize; i++)
1534  {
1535  if (!is_equal(myData[i], a[i])) return false;
1536  }
1537  return true;
1538 }
1539 
1540 template <typename T>
1541 inline int
1542 UT_Array<T>::isEqual(const UT_Array<T> &a, Comparator compare) const
1543 {
1544  return isEqual(a, UTcompareEqual(compare));
1545 }
1546 
1547 template <typename T>
1548 inline exint
1549 UT_Array<T>::apply(int (*apply_func)(T &t, void *d), void *d)
1550 {
1551  exint i;
1552  for (i = 0; i < mySize; i++)
1553  {
1554  if (apply_func(myData[i], d))
1555  break;
1556  }
1557  return i;
1558 }
1559 
1560 // Merge the given array into us.
1561 // If direction is -1, then it assumes us and 'other' are both already
1562 // sorted in descending order. Similarly, +1 means ascending.
1563 // If allow_dups is false, then it further assumes that both arrays have no
1564 // duplicates and will produce a result that also has no duplicates.
1565 // More work will be needed if you want allow_dups to mean remove duplicates
1566 template <typename T>
1567 template <typename ComparatorBool>
1568 inline void
1570  const UT_Array<T> &other, int direction, bool allow_dups,
1571  ComparatorBool is_less)
1572 {
1574  exint our_idx;
1575  exint other_idx;
1576 
1577  // handle trivial cases to avoid extra work
1578  if (other.size() == 0)
1579  return;
1580  if (size() == 0)
1581  {
1582  concat(other);
1583  return;
1584  }
1585 
1586  UT_ASSERT( direction == -1 || direction == +1 );
1587  direction = (direction > 0) ? +1 : -1;
1588 
1589  our_idx = 0;
1590  other_idx = 0;
1591  while( our_idx < size() && other_idx < other.size() )
1592  {
1593  const T &our_item = (*this)(our_idx);
1594  const T &other_item = other(other_idx);
1595  exint item_dir;
1596 
1597  if (our_item == other_item)
1598  item_dir = 0;
1599  else if (is_less(our_item, other_item))
1600  item_dir = -1;
1601  else
1602  item_dir = +1;
1603 
1604  if( item_dir != 0 )
1605  {
1606  // we need to do an comparison in the next line to take care of the
1607  // fact that -INT_MIN is still less than 0.
1608  item_dir = ( (item_dir > 0) ? +1 : -1 ) * direction;
1609  }
1610 
1611  if( item_dir < 0 )
1612  {
1613  result.append( our_item );
1614  our_idx++;
1615  }
1616  else if( item_dir > 0 )
1617  {
1618  result.append( other_item );
1619  other_idx++;
1620  }
1621  else
1622  {
1623  result.append( our_item );
1624  our_idx++;
1625  if( allow_dups )
1626  result.append( other_item );
1627  other_idx++;
1628  }
1629  }
1630 
1631  UT_ASSERT( our_idx == size() || other_idx == other.size() );
1632  for( ; our_idx < size(); our_idx++ )
1633  result.append( (*this)(our_idx) );
1634  for( ; other_idx < other.size(); other_idx++ )
1635  result.append( other(other_idx) );
1636 
1637  // finally swap the result into us
1638  swap( result );
1639 }
1640 
1641 template <typename T>
1642 inline bool
1644  const UT_Array<T> &other,
1645  Comparator compare) const
1646 {
1647  return hasSortedSubset(other, UTcompareLess(compare));
1648 }
1649 
1650 template <typename T>
1651 template <typename ComparatorBool, typename>
1652 inline bool
1654  const UT_Array<T> &other,
1655  ComparatorBool compare) const
1656 {
1657  return std::includes(
1658  myData, myData + mySize,
1659  other.myData, other.myData + other.mySize,
1660  compare);
1661 }
1662 
1663 template <typename T>
1664 inline void
1666 {
1667  sortedUnion(other, UTcompareLess(compare));
1668 }
1669 
1670 template <typename T>
1671 inline void
1673  const UT_Array<T> &other,
1675  Comparator compare) const
1676 {
1677  sortedUnion(other, result, UTcompareLess(compare));
1678 }
1679 
1680 template <typename T>
1681 inline void
1683 {
1684  sortedIntersection(other, UTcompareLess(compare));
1685 }
1686 
1687 template <typename T>
1688 inline void
1690  const UT_Array<T> &other,
1692  Comparator compare) const
1693 {
1694  sortedIntersection(other, result, UTcompareLess(compare));
1695 }
1696 
1697 template <typename T>
1698 inline void
1700 {
1701  sortedSetDifference(other, UTcompareLess(compare));
1702 }
1703 
1704 template <typename T>
1705 inline void
1707  const UT_Array<T> &other,
1709  Comparator compare) const
1710 {
1711  sortedSetDifference(other, result, UTcompareLess(compare));
1712 }
1713 
1714 template <typename T>
1715 template <typename ComparatorBool, typename>
1716 inline void
1717 UT_Array<T>::sortedUnion(const UT_Array<T> &other, ComparatorBool is_less)
1718 {
1719  UT_Array<T> temp;
1720  sortedUnion( other, temp, is_less );
1721  swap( temp );
1722 }
1723 
1724 template <typename T>
1725 template <typename ComparatorBool, typename>
1726 inline void
1728  const UT_Array<T> &other,
1730  ComparatorBool is_less) const
1731 {
1732  // Can't store to either input.
1733  UT_ASSERT(&result != this && &result != &other);
1734  UT_ASSERT(result.size() == 0);
1735 
1736  std::set_union(
1737  begin(), end(), other.begin(), other.end(), AppendIterator(result),
1738  is_less);
1739 }
1740 
1741 template <typename T>
1742 template <typename ComparatorBool, typename>
1743 inline void
1745  const UT_Array<T> &other,
1746  ComparatorBool is_less)
1747 {
1748  UT_Array<T> temp;
1749  sortedIntersection( other, temp, is_less );
1750  swap( temp );
1751 }
1752 
1753 template <typename T>
1754 template <typename ComparatorBool, typename>
1755 inline void
1757  const UT_Array<T> &other,
1759  ComparatorBool is_less) const
1760 {
1761  // Can't store to either input.
1762  UT_ASSERT(&result != this && &result != &other);
1763  UT_ASSERT(result.size() == 0);
1764 
1765  std::set_intersection(
1766  begin(), end(), other.begin(), other.end(), AppendIterator(result),
1767  is_less);
1768 }
1769 
1770 template <typename T>
1771 template <typename ComparatorBool, typename>
1772 inline void
1774  const UT_Array<T> &other,
1775  ComparatorBool is_less)
1776 {
1777  UT_Array<T> temp;
1778  sortedSetDifference(other, temp, is_less);
1779  swap( temp );
1780 }
1781 
1782 template <typename T>
1783 template <typename ComparatorBool, typename>
1784 inline void
1786  const UT_Array<T> &other,
1788  ComparatorBool is_less) const
1789 {
1790  // Can't store to either input.
1791  UT_ASSERT(&result != this && &result != &other);
1792  UT_ASSERT(result.size() == 0);
1793 
1794  std::set_difference(
1795  begin(), end(), other.begin(), other.end(), AppendIterator(result),
1796  is_less);
1797 }
1798 
1799 template <typename T>
1800 template <typename CompareEqual>
1801 inline exint
1802 UT_Array<T>::sortedRemoveDuplicatesIf(CompareEqual compare_equal)
1803 {
1804  exint n = size();
1805 
1806  // Trivial, no duplicates!
1807  if (n < 2)
1808  return 0;
1809 
1810  exint dst = 1;
1811  for (exint i = 1; i < n; i++)
1812  {
1813  if (!compare_equal((*this)(i), (*this)(i-1)))
1814  {
1815  if (i != dst)
1816  (*this)(dst) = (*this)(i);
1817  dst++;
1818  }
1819  }
1820 
1821  // Store the number of remaining elements.
1822  setSize(dst);
1823  return n - dst; // Return the number of elements removed
1824 }
1825 
1826 namespace {
1827  template<typename T>
1828  struct srdCompareEqual
1829  {
1830  bool operator()(const T& x, const T& y) const { return (x == y); }
1831  };
1832 }
1833 
1834 template <typename T>
1835 inline exint
1837 {
1838  srdCompareEqual<T> cmp;
1839  return sortedRemoveDuplicatesIf(cmp);
1840 }
1841 
1842 template <typename T>
1843 template <typename BinaryOp>
1844 inline T
1845 UT_Array<T>::accumulate(const T &init_value, BinaryOp add) const
1846 {
1847  T sum(init_value);
1848  for (exint i = 0; i < mySize; i++)
1849  sum = add(sum, myData[i]);
1850  return sum;
1851 }
1852 
1853 #endif // __UT_ARRAYIMPL_H_INCLUDED__
void swap(ArAssetInfo &lhs, ArAssetInfo &rhs)
Definition: assetInfo.h:74
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:1099
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:1572
T * array()
Definition: UT_Array.h:839
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
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:1006
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:180
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
LeafData & operator=(const LeafData &)=delete
VULKAN_HPP_CONSTEXPR_14 VULKAN_HPP_INLINE T exchange(T &obj, U &&newValue)
Definition: vulkan_raii.hpp:25
GLuint index
Definition: glcorearb.h:786
UT_Compare::Equal< T > UTcompareEqual(UT_Compare::Ternary< T > compare)
Definition: UT_Compare.h:78
bool isEqual(const UT_Array< T > &a, ComparatorBool is_equal) const
#define SYS_PRAGMA_DISABLE_MISMATCHED_NEW_DELETE()
Definition: SYS_Pragma.h:187
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)
UT_Array(const UT_Array< T > &a)
Definition: UT_ArrayImpl.h:519
#define SYSmin(a, b)
Definition: SYS_Math.h:1571
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:1011
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:558