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 template <typename IsEqual>
1313 exint
1314 UT_Array<T>::findIf(IsEqual is_equal, exint start) const
1315 {
1316  const T *end = myData + mySize;
1317  for (const T *p = myData + start; p < end; ++p)
1318  if (is_equal(*p))
1319  return (p - myData);
1320  return -1;
1321 }
1322 
1323 template <typename T>
1324 exint
1325 UT_Array<T>::sortedFind(const T &t, Comparator compare) const
1326 {
1327  T *found;
1328 
1329  if( mySize == 0 ) return -1;
1330 
1331  // NOLINTNEXTLINE
1332  found = (T *)::bsearch(&t, myData, mySize, sizeof(T),
1333  (ut_ptr_compare_func_t)compare);
1334  return found ? (found - myData) : -1;
1335 }
1336 
1337 template <typename T>
1338 inline void
1340 {
1341  exint n = mySize / 2;
1342  for (exint i = 0; i < n; i++ )
1343  UTswap(myData[i], myData[mySize-1-i]);
1344 }
1345 
1346 template <typename T>
1347 inline void
1349 {
1350  std::sort(myData, myData + mySize, UTcompareLess(compare));
1351 }
1352 
1353 template <typename T>
1354 template <typename ComparatorBool>
1355 inline T
1356 UT_Array<T>::selectNthLargest(exint idx, ComparatorBool is_less)
1357 {
1358  // The idea of returning doesn't make sense if we have
1359  // an empty array.
1360  UT_ASSERT(size() > 0);
1361  if (size() == 0)
1362  return T();
1363 
1364  idx = SYSclamp(idx, (exint)0, (exint)(size())-1);
1365 
1366  UTnth_element(myData, &myData[idx], &myData[size()], is_less);
1367 
1368  return myData[idx];
1369 }
1370 
1371 template <typename T>
1372 inline void
1374 {
1375  // Do nothing when new capacity is the same as the current
1376  if (new_capacity == capacity())
1377  {
1378  return;
1379  }
1380 
1381  // Special case for non-heap buffers
1382  if (!isHeapBuffer())
1383  {
1384  if (new_capacity < mySize)
1385  {
1386  // Destroy the extra elements without changing capacity()
1387  destroyRange(myData + new_capacity, mySize - new_capacity);
1388  mySize = new_capacity;
1389  }
1390  else if (new_capacity > capacity())
1391  {
1392  convertToHeapBuffer(new_capacity);
1393  }
1394  else
1395  {
1396  // Keep capacity unchanged in this case
1397  UT_ASSERT_P(new_capacity >= mySize && new_capacity <= capacity());
1398  }
1399  return;
1400  }
1401 
1402  if (new_capacity == 0)
1403  {
1404  if (myData)
1405  {
1406  destroyRange(myData, mySize);
1407  deallocateArray(myData);
1408  }
1409  myData = nullptr;
1410  myCapacity = labelOwned(0);
1411  mySize = 0;
1412  return;
1413  }
1414 
1415  if (new_capacity < mySize)
1416  {
1417  destroyRange(myData + new_capacity, mySize - new_capacity);
1418  mySize = new_capacity;
1419  }
1420 
1421  if (myData)
1422  {
1423  if constexpr( SYS_UseTrivialRelocation_v< T > )
1424  {
1425  myData = reallocateArray(myData, new_capacity);
1426  }
1427  else // constexpr
1428  {
1429  T *prev = myData;
1430  myData = allocateArray(new_capacity);
1431  if (mySize > 0)
1432  {
1433  relocateNonoverlapping(myData, prev, mySize);
1434  }
1435 
1436  deallocateArray(prev);
1437  }
1438  }
1439  else
1440  {
1441  myData = allocateArray(new_capacity);
1442  }
1443 
1444  // Avoid degenerate case if we happen to be aliased the wrong way
1445  if (!isHeapBuffer())
1446  {
1447  // `myData` points to the end of us which erroneously causes
1448  // isHeapBuffer() to incorrectly identify us as a small buffer instead
1449  // of a heap buffer. Retry the allocation. Since `myData` is still
1450  // occupied, the new allocation's address cannot be at our end anymore.
1451  T *prev = myData;
1452  myData = allocateArray(new_capacity);
1453  if (mySize > 0)
1454  {
1455  relocateNonoverlapping(myData, prev, mySize);
1456  }
1457 
1458  deallocateArray(prev);
1459  }
1460 
1461  myCapacity = labelOwned(new_capacity);
1462  UT_ASSERT(myData);
1463 }
1464 
1465 template <typename T>
1466 inline UT_Array<T> &
1468 {
1469  if (this == &a)
1470  {
1471  return *this;
1472  }
1473 
1474  UT_Array t{ a };
1475  swap( t );
1476 
1477  return *this;
1478 }
1479 
1480 template <typename T>
1481 inline UT_Array<T> &
1482 UT_Array<T>::operator=(std::initializer_list<T> a)
1483 {
1484  const exint new_size = a.size();
1485 
1486  // Grow the raw array if necessary.
1487  setCapacityIfNeeded(new_size);
1488 
1489  // Make sure destructors and constructors are called on all elements
1490  // being removed/added.
1491  destroyRange(myData, mySize);
1492 
1493  copyNonoverlapping(myData, a.begin(), new_size);
1494 
1495  mySize = new_size;
1496 
1497  return *this;
1498 }
1499 
1500 template <typename T>
1501 inline UT_Array<T> &
1503 {
1504  // Satisfy requirement that if 'a' has a heap buffer,
1505  // then *this has to have a heap buffer as well.
1506  if((!isHeapBuffer()) && a.isHeapBuffer())
1507  {
1508  destroyRange(myData, mySize);
1509  mySize = 0;
1510  convertToHeapBuffer(0);
1511  }
1512 
1513  UT_Array t{ std::move( a ) };
1514  swap( t );
1515 
1516  return *this;
1517 }
1518 
1519 
1520 template <typename T>
1521 inline bool
1523 {
1524  if (this == &a) return true;
1525  if (mySize != a.size()) return false;
1526  for (exint i = 0; i < mySize; i++)
1527  if (!(myData[i] == a(i))) return false;
1528  return true;
1529 }
1530 
1531 template <typename T>
1532 inline bool
1534 {
1535  return (!operator==(a));
1536 }
1537 
1538 template <typename T>
1539 template <typename ComparatorBool, typename>
1540 inline bool
1541 UT_Array<T>::isEqual(const UT_Array<T> &a, ComparatorBool is_equal) const
1542 {
1543  if (this == &a) return true;
1544  if (mySize != a.size()) return false;
1545  for (exint i = 0; i < mySize; i++)
1546  {
1547  if (!is_equal(myData[i], a[i])) return false;
1548  }
1549  return true;
1550 }
1551 
1552 template <typename T>
1553 inline int
1554 UT_Array<T>::isEqual(const UT_Array<T> &a, Comparator compare) const
1555 {
1556  return isEqual(a, UTcompareEqual(compare));
1557 }
1558 
1559 template <typename T>
1560 inline exint
1561 UT_Array<T>::apply(int (*apply_func)(T &t, void *d), void *d)
1562 {
1563  exint i;
1564  for (i = 0; i < mySize; i++)
1565  {
1566  if (apply_func(myData[i], d))
1567  break;
1568  }
1569  return i;
1570 }
1571 
1572 // Merge the given array into us.
1573 // If direction is -1, then it assumes us and 'other' are both already
1574 // sorted in descending order. Similarly, +1 means ascending.
1575 // If allow_dups is false, then it further assumes that both arrays have no
1576 // duplicates and will produce a result that also has no duplicates.
1577 // More work will be needed if you want allow_dups to mean remove duplicates
1578 template <typename T>
1579 template <typename ComparatorBool>
1580 inline void
1582  const UT_Array<T> &other, int direction, bool allow_dups,
1583  ComparatorBool is_less)
1584 {
1586  exint our_idx;
1587  exint other_idx;
1588 
1589  // handle trivial cases to avoid extra work
1590  if (other.size() == 0)
1591  return;
1592  if (size() == 0)
1593  {
1594  concat(other);
1595  return;
1596  }
1597 
1598  UT_ASSERT( direction == -1 || direction == +1 );
1599  direction = (direction > 0) ? +1 : -1;
1600 
1601  our_idx = 0;
1602  other_idx = 0;
1603  while( our_idx < size() && other_idx < other.size() )
1604  {
1605  const T &our_item = (*this)(our_idx);
1606  const T &other_item = other(other_idx);
1607  exint item_dir;
1608 
1609  if (our_item == other_item)
1610  item_dir = 0;
1611  else if (is_less(our_item, other_item))
1612  item_dir = -1;
1613  else
1614  item_dir = +1;
1615 
1616  if( item_dir != 0 )
1617  {
1618  // we need to do an comparison in the next line to take care of the
1619  // fact that -INT_MIN is still less than 0.
1620  item_dir = ( (item_dir > 0) ? +1 : -1 ) * direction;
1621  }
1622 
1623  if( item_dir < 0 )
1624  {
1625  result.append( our_item );
1626  our_idx++;
1627  }
1628  else if( item_dir > 0 )
1629  {
1630  result.append( other_item );
1631  other_idx++;
1632  }
1633  else
1634  {
1635  result.append( our_item );
1636  our_idx++;
1637  if( allow_dups )
1638  result.append( other_item );
1639  other_idx++;
1640  }
1641  }
1642 
1643  UT_ASSERT( our_idx == size() || other_idx == other.size() );
1644  for( ; our_idx < size(); our_idx++ )
1645  result.append( (*this)(our_idx) );
1646  for( ; other_idx < other.size(); other_idx++ )
1647  result.append( other(other_idx) );
1648 
1649  // finally swap the result into us
1650  swap( result );
1651 }
1652 
1653 template <typename T>
1654 inline bool
1656  const UT_Array<T> &other,
1657  Comparator compare) const
1658 {
1659  return hasSortedSubset(other, UTcompareLess(compare));
1660 }
1661 
1662 template <typename T>
1663 template <typename ComparatorBool, typename>
1664 inline bool
1666  const UT_Array<T> &other,
1667  ComparatorBool compare) const
1668 {
1669  return std::includes(
1670  myData, myData + mySize,
1671  other.myData, other.myData + other.mySize,
1672  compare);
1673 }
1674 
1675 template <typename T>
1676 inline void
1678 {
1679  sortedUnion(other, UTcompareLess(compare));
1680 }
1681 
1682 template <typename T>
1683 inline void
1685  const UT_Array<T> &other,
1687  Comparator compare) const
1688 {
1689  sortedUnion(other, result, UTcompareLess(compare));
1690 }
1691 
1692 template <typename T>
1693 inline void
1695 {
1696  sortedIntersection(other, UTcompareLess(compare));
1697 }
1698 
1699 template <typename T>
1700 inline void
1702  const UT_Array<T> &other,
1704  Comparator compare) const
1705 {
1706  sortedIntersection(other, result, UTcompareLess(compare));
1707 }
1708 
1709 template <typename T>
1710 inline void
1712 {
1713  sortedSetDifference(other, UTcompareLess(compare));
1714 }
1715 
1716 template <typename T>
1717 inline void
1719  const UT_Array<T> &other,
1721  Comparator compare) const
1722 {
1723  sortedSetDifference(other, result, UTcompareLess(compare));
1724 }
1725 
1726 template <typename T>
1727 template <typename ComparatorBool, typename>
1728 inline void
1729 UT_Array<T>::sortedUnion(const UT_Array<T> &other, ComparatorBool is_less)
1730 {
1731  UT_Array<T> temp;
1732  sortedUnion( other, temp, is_less );
1733  swap( temp );
1734 }
1735 
1736 template <typename T>
1737 template <typename ComparatorBool, typename>
1738 inline void
1740  const UT_Array<T> &other,
1742  ComparatorBool is_less) const
1743 {
1744  // Can't store to either input.
1745  UT_ASSERT(&result != this && &result != &other);
1746  UT_ASSERT(result.size() == 0);
1747 
1748  std::set_union(
1749  begin(), end(), other.begin(), other.end(), AppendIterator(result),
1750  is_less);
1751 }
1752 
1753 template <typename T>
1754 template <typename ComparatorBool, typename>
1755 inline void
1757  const UT_Array<T> &other,
1758  ComparatorBool is_less)
1759 {
1760  UT_Array<T> temp;
1761  sortedIntersection( other, temp, is_less );
1762  swap( temp );
1763 }
1764 
1765 template <typename T>
1766 template <typename ComparatorBool, typename>
1767 inline void
1769  const UT_Array<T> &other,
1771  ComparatorBool is_less) const
1772 {
1773  // Can't store to either input.
1774  UT_ASSERT(&result != this && &result != &other);
1775  UT_ASSERT(result.size() == 0);
1776 
1777  std::set_intersection(
1778  begin(), end(), other.begin(), other.end(), AppendIterator(result),
1779  is_less);
1780 }
1781 
1782 template <typename T>
1783 template <typename ComparatorBool, typename>
1784 inline void
1786  const UT_Array<T> &other,
1787  ComparatorBool is_less)
1788 {
1789  UT_Array<T> temp;
1790  sortedSetDifference(other, temp, is_less);
1791  swap( temp );
1792 }
1793 
1794 template <typename T>
1795 template <typename ComparatorBool, typename>
1796 inline void
1798  const UT_Array<T> &other,
1800  ComparatorBool is_less) const
1801 {
1802  // Can't store to either input.
1803  UT_ASSERT(&result != this && &result != &other);
1804  UT_ASSERT(result.size() == 0);
1805 
1806  std::set_difference(
1807  begin(), end(), other.begin(), other.end(), AppendIterator(result),
1808  is_less);
1809 }
1810 
1811 template <typename T>
1812 template <typename CompareEqual>
1813 inline exint
1814 UT_Array<T>::sortedRemoveDuplicatesIf(CompareEqual compare_equal)
1815 {
1816  exint n = size();
1817 
1818  // Trivial, no duplicates!
1819  if (n < 2)
1820  return 0;
1821 
1822  exint dst = 1;
1823  for (exint i = 1; i < n; i++)
1824  {
1825  if (!compare_equal((*this)(i), (*this)(i-1)))
1826  {
1827  if (i != dst)
1828  (*this)(dst) = (*this)(i);
1829  dst++;
1830  }
1831  }
1832 
1833  // Store the number of remaining elements.
1834  setSize(dst);
1835  return n - dst; // Return the number of elements removed
1836 }
1837 
1838 namespace {
1839  template<typename T>
1840  struct srdCompareEqual
1841  {
1842  bool operator()(const T& x, const T& y) const { return (x == y); }
1843  };
1844 }
1845 
1846 template <typename T>
1847 inline exint
1849 {
1850  srdCompareEqual<T> cmp;
1851  return sortedRemoveDuplicatesIf(cmp);
1852 }
1853 
1854 template <typename T>
1855 template <typename BinaryOp>
1856 inline T
1857 UT_Array<T>::accumulate(const T &init_value, BinaryOp add) const
1858 {
1859  T sum(init_value);
1860  for (exint i = 0; i < mySize; i++)
1861  sum = add(sum, myData[i]);
1862  return sum;
1863 }
1864 
1865 #endif // __UT_ARRAYIMPL_H_INCLUDED__
void swap(ArAssetInfo &lhs, ArAssetInfo &rhs)
Definition: assetInfo.h:57
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:1106
void UTnth_element(IT start, IT nth, IT end, COMPARE isAbeforeB)
Definition: UT_Permute.h:77
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)
CompareResults OIIO_API compare(const ImageBuf &A, const ImageBuf &B, float failthresh, float warnthresh, float failrelative, float warnrelative, ROI roi={}, int nthreads=0)
void zero()
Zeros the array if a POD type, else trivial constructs if a class type.
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:1584
T * array()
Definition: UT_Array.h:846
static constexpr struct UT_ArrayCT::GeneralizedMove GENERALIZED_MOVE
#define UT_API
Definition: UT_API.h:14
void setCapacity(exint new_capacity)
PUGI__FN void sort(I begin, I end, const Pred &pred)
Definition: pugixml.cpp:7550
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:622
FMT_CONSTEXPR auto find(Ptr first, Ptr last, T value, Ptr &out) -> bool
Definition: core.h:2138
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:653
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
GLdouble n
Definition: glcorearb.h:2008
exint findIf(IsEqual is_equal, exint start=0) const
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:463
#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:123
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:1013
void setCapacityIfNeeded(exint min_capacity)
Definition: UT_Array.h:610
#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:186
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:193
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={})
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:1583
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 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:1821
iterator end()
End iterator.
Definition: UT_Array.h:1018
constexpr auto SYS_UseTrivialRelocation_v
Definition: UT_ArrayImpl.h:99
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:566