LvArray
sortedArrayManipulationHelpers.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2021, Lawrence Livermore National Security, LLC and LvArray contributors.
3  * All rights reserved.
4  * See the LICENSE file for details.
5  * SPDX-License-Identifier: (BSD-3-Clause)
6  */
7 
15 #pragma once
16 
17 #include "LvArrayConfig.hpp"
18 #include "Macros.hpp"
19 
20 #include <utility>
21 
22 namespace LvArray
23 {
24 namespace sortedArrayManipulation
25 {
26 namespace internal
27 {
28 
30 constexpr int INTROSORT_THRESHOLD = 64;
31 
39 template< class A, class B >
41 {
46  struct Temporary
47  {
51  inline Temporary() = delete;
52 
56  inline Temporary( Temporary const & ) = delete;
57 
64  m_a( std::move( src.m_a )),
65  m_b( std::move( src.m_b ))
66  {}
67 
74  m_a( std::move( src.m_a )),
75  m_b( std::move( src.m_b ))
76  {}
77 
82  inline ~Temporary() = default;
83 
88  inline Temporary & operator=( Temporary const & ) = delete;
89 
94  inline Temporary & operator=( Temporary && ) = delete;
95 
97  A m_a;
98 
100  B m_b;
101  };
102 
106  DualIteratorAccessor() = delete;
107 
115  m_a( a ),
116  m_b( b )
117  {}
118 
122  DualIteratorAccessor( DualIteratorAccessor const & ) = delete;
123 
128  inline DualIteratorAccessor( DualIteratorAccessor && ) = default;
129 
135 
143  {
144  m_a = std::move( src.m_a );
145  m_b = std::move( src.m_b );
146  return *this;
147  }
148 
156  {
157  m_a = std::move( src.m_a );
158  m_b = std::move( src.m_b );
159  return *this;
160  }
161 
163  A & m_a;
164 
166  B & m_b;
167 };
168 
177 template< typename A, typename B, typename Compare >
179 {
186  m_compare( comp )
187  {}
188 
197  DualIteratorAccessor< A, B > const & rhs ) const
198  { return m_compare( lhs.m_a, rhs.m_a ); }
199 
208  DualIteratorAccessor< A, B > const & rhs ) const
209  { return m_compare( lhs.m_a, rhs.m_a ); }
210 
211 private:
213  Compare m_compare;
214 };
215 
222 template< class RandomAccessIteratorA, class RandomAccessIteratorB >
224 {
225 public:
227  using A = typename std::remove_reference< decltype( *std::declval< RandomAccessIteratorA >() ) >::type;
228 
230  using B = typename std::remove_reference< decltype( *std::declval< RandomAccessIteratorB >() ) >::type;
231 
236  inline DualIterator() = default;
237 
244  LVARRAY_HOST_DEVICE inline DualIterator( RandomAccessIteratorA const itA, RandomAccessIteratorB const itB ):
245  m_itA( itA ),
246  m_itB( itB )
247  {}
248 
254  inline DualIterator( DualIterator const & src ) = default;
255 
261  inline DualIterator( DualIterator && src ) = default;
262 
269  inline DualIterator & operator=( DualIterator const & src ) = default;
270 
277  inline DualIterator & operator=( DualIterator && src ) = default;
278 
285  LVARRAY_HOST_DEVICE inline DualIterator operator+( std::ptrdiff_t const offset ) const
286  { return DualIterator( m_itA + offset, m_itB + offset ); }
287 
294  LVARRAY_HOST_DEVICE inline DualIterator & operator+=( std::ptrdiff_t const offset )
295  {
296  m_itA += offset;
297  m_itB += offset;
298  return *this;
299  }
300 
307  {
308  m_itA++;
309  m_itB++;
310  return *this;
311  }
312 
319  LVARRAY_HOST_DEVICE inline std::ptrdiff_t operator-( DualIterator const & rhs ) const
320  {
321  std::ptrdiff_t const distance = m_itA - rhs.m_itA;
322  LVARRAY_ASSERT_EQ( distance, m_itB - rhs.m_itB );
323  return distance;
324  }
325 
332  LVARRAY_HOST_DEVICE inline DualIterator operator-( std::ptrdiff_t const offset ) const
333  { return *this + (-offset); }
334 
341  LVARRAY_HOST_DEVICE inline DualIterator & operator-=( std::ptrdiff_t const offset )
342  { return *this += (-offset); }
343 
350  {
351  m_itA--;
352  m_itB--;
353  return *this;
354  }
355 
362  LVARRAY_HOST_DEVICE inline bool operator!=( DualIterator const & rhs ) const
363  { return m_itA != rhs.m_itA; }
364 
371  LVARRAY_HOST_DEVICE inline bool operator<( DualIterator const & rhs ) const
372  { return m_itA < rhs.m_itA; }
373 
380  { return DualIteratorAccessor< A, B >( *m_itA, *m_itB ); }
381 
389  template< class Compare >
391  { return DualIteratorComparator< A, B, Compare >( std::forward< Compare >( comp ) ); }
392 
393 private:
395  RandomAccessIteratorA m_itA;
396 
398  RandomAccessIteratorB m_itB;
399 
400 };
401 
409 template< class T >
411 {
412  return std::move( a );
413 }
414 
423 template< class A, class B >
425 { return typename DualIteratorAccessor< A, B >::Temporary( std::move( it )); }
426 
434 template< class Iterator >
435 LVARRAY_HOST_DEVICE inline void exchange( Iterator a, Iterator b )
436 {
437  auto temp = createTemporary( *a );
438  *a = std::move( *b );
439  *b = std::move( temp );
440 }
441 
454 template< class BidirIt1, class BidirIt2 >
455 LVARRAY_HOST_DEVICE inline void moveBackward( BidirIt1 first, BidirIt1 last, BidirIt2 d_last )
456 {
457  while( first != last )
458  {
459  *(--d_last) = std::move( *(--last));
460  }
461 }
462 
477 template< typename Iterator, typename Compare >
478 LVARRAY_HOST_DEVICE inline void computeMedian( Iterator result, Iterator a, Iterator b, Iterator c, Compare && comp )
479 {
480  if( comp( *a, *b ))
481  {
482  if( comp( *b, *c ))
483  {
484  exchange( result, b );
485  }
486  else if( comp( *a, *c ))
487  {
488  exchange( result, c );
489  }
490  else
491  {
492  exchange( result, a );
493  }
494  }
495  else if( comp( *a, *c ))
496  {
497  exchange( result, a );
498  }
499  else if( comp( *b, *c ))
500  {
501  exchange( result, c );
502  }
503  else
504  {
505  exchange( result, b );
506  }
507 }
508 
522 template< typename RandomAccessIterator, typename Compare >
523 LVARRAY_HOST_DEVICE inline RandomAccessIterator unguardedPartition( RandomAccessIterator first, RandomAccessIterator last,
524  RandomAccessIterator pivot, Compare && comp )
525 {
526  while( true )
527  {
528  while( comp( *first, *pivot ))
529  {
530  ++first;
531  }
532 
533  --last;
534  while( comp( *pivot, *last ))
535  {
536  --last;
537  }
538 
539  if( !(first < last))
540  {
541  return first;
542  }
543 
544  exchange( first, last );
545  ++first;
546  }
547 }
548 
561 template< typename RandomAccessIterator, typename Compare >
562 LVARRAY_HOST_DEVICE inline RandomAccessIterator unguardedPartitionPivot( RandomAccessIterator first, RandomAccessIterator last, Compare && comp )
563 {
564  RandomAccessIterator mid = first + (last - first) / 2;
565  computeMedian( first, first + 1, mid, last - 1, comp );
566  return unguardedPartition( first + 1, last, first, comp );
567 }
568 
579 template< typename RandomAccessIterator, typename Compare >
580 LVARRAY_HOST_DEVICE inline void unguardedLinearInsert( RandomAccessIterator last, Compare comp )
581 {
582  auto val = createTemporary( *last );
583  RandomAccessIterator next = last - 1;
584  while( comp( val, *next ))
585  {
586  *last = std::move( *next );
587  last = next;
588  --next;
589  }
590  *last = std::move( val );
591 }
592 
605 template< class RandomAccessIterator, class Compare >
606 LVARRAY_HOST_DEVICE inline void insertionSort( RandomAccessIterator first, std::ptrdiff_t const n, Compare comp )
607 {
608  for( std::ptrdiff_t i = 1; i < n; ++i )
609  {
610  if( comp( *(first + i), *first ))
611  {
612  auto val = createTemporary( *(first + i));
613  moveBackward( first, first + i, first + i + 1 );
614  *first = std::move( val );
615  }
616  else
617  {
618  unguardedLinearInsert( first + i, comp );
619  }
620  }
621 }
622 
640 template< typename RandomAccessIterator, typename Compare >
641 LVARRAY_HOST_DEVICE inline void introsortLoop( RandomAccessIterator first, RandomAccessIterator last, Compare && comp )
642 {
643  constexpr int MAX_RANGES = 31;
644  RandomAccessIterator ranges[MAX_RANGES + 1];
645 
646  int nRanges = 1;
647  ranges[0] = first;
648  ranges[1] = last;
649  while( nRanges != 0 )
650  {
651  RandomAccessIterator const m_first = ranges[nRanges - 1];
652 
653  if( ranges[nRanges] - m_first > INTROSORT_THRESHOLD )
654  {
655  LVARRAY_ASSERT( nRanges < MAX_RANGES );
656  ranges[nRanges + 1] = ranges[nRanges];
657  ranges[nRanges] = unguardedPartitionPivot( m_first, ranges[nRanges], comp );
658  ++nRanges;
659  }
660  else
661  {
662  --nRanges;
663  }
664  }
665 }
666 
667 } // namespace internal
668 } // namespace sortedArrayManipulation
669 } // namespace LvArray
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE bool operator<(DualIterator const &rhs) const
Return true if this less than rhs.
Definition: sortedArrayManipulationHelpers.hpp:371
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE T && createTemporary(T &a)
Return a temporary object holding the value of a.
Definition: sortedArrayManipulationHelpers.hpp:410
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE DualIterator operator-(std::ptrdiff_t const offset) const
Return a new DualIterator where both of the underlying iterators have been decrement by offset...
Definition: sortedArrayManipulationHelpers.hpp:332
#define LVARRAY_ASSERT(EXP)
Assert EXP is true with no message.
Definition: Macros.hpp:223
This class is used to make a comparison method that takes in DualIteratorAccessor<A, B> from a comparison method that takes in objects of type A.
Definition: sortedArrayManipulationHelpers.hpp:178
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE bool operator!=(DualIterator const &rhs) const
Return true if rhs does not point to the same values.
Definition: sortedArrayManipulationHelpers.hpp:362
B & m_b
A reference to the second value.
Definition: sortedArrayManipulationHelpers.hpp:166
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE DualIterator & operator-=(std::ptrdiff_t const offset)
Decrement the underlying iterators by offset and return a reference to *this.
Definition: sortedArrayManipulationHelpers.hpp:341
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE DualIteratorComparator< A, B, Compare > createComparator(Compare &&comp) const
Return a new Comparator which will compare two DualIteratorAccessors using the given comparison...
Definition: sortedArrayManipulationHelpers.hpp:390
RandomAccessIteratorA m_itA
The first iterator.
Definition: sortedArrayManipulationHelpers.hpp:395
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE DualIteratorAccessor & operator=(Temporary &&src)
Move assignment operator that moves the values of src into the values of this.
Definition: sortedArrayManipulationHelpers.hpp:155
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE void unguardedLinearInsert(RandomAccessIterator last, Compare comp)
Definition: sortedArrayManipulationHelpers.hpp:580
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE bool operator()(DualIteratorAccessor< A, B > const &lhs, DualIteratorAccessor< A, B > const &rhs) const
Compare lhs with rhs using their first values.
Definition: sortedArrayManipulationHelpers.hpp:196
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE DualIterator operator+(std::ptrdiff_t const offset) const
Return a new DualIterator where both of the underlying iterators have been incremented by offset...
Definition: sortedArrayManipulationHelpers.hpp:285
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE std::ptrdiff_t operator-(DualIterator const &rhs) const
Return the distance between *this and rhs.
Definition: sortedArrayManipulationHelpers.hpp:319
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE Temporary(DualIteratorAccessor &&src)
Move the values pointed at by src into a temporary location.
Definition: sortedArrayManipulationHelpers.hpp:73
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE void insertionSort(RandomAccessIterator first, std::ptrdiff_t const n, Compare comp)
sort the range [first, first + n) under comp using insertions sort.
Definition: sortedArrayManipulationHelpers.hpp:606
B m_b
A copy of type B.
Definition: sortedArrayManipulationHelpers.hpp:100
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE DualIterator & operator--()
Decrement the underlying iterators by 1 and return a reference to *this.
Definition: sortedArrayManipulationHelpers.hpp:349
Temporary & operator=(Temporary const &)=delete
Deleted copy assignment operator.
Compare m_compare
The comparator that compares objects of type A.
Definition: sortedArrayManipulationHelpers.hpp:213
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE DualIteratorAccessor & operator=(DualIteratorAccessor &&src)
Move assignment operator that moves the values of src into the values of this.
Definition: sortedArrayManipulationHelpers.hpp:142
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE DualIteratorAccessor(A &a, B &b)
Constructor to wrap the two given values.
Definition: sortedArrayManipulationHelpers.hpp:114
constexpr int INTROSORT_THRESHOLD
The size above which we continue with the introsortLoop.
Definition: sortedArrayManipulationHelpers.hpp:30
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE DualIterator & operator++()
Increment the underlying iterators by 1 and return a reference to *this.
Definition: sortedArrayManipulationHelpers.hpp:306
The top level namespace.
Definition: Array.hpp:24
This class is the type returned by the DualIterator operator* and holds a reference to a value in bot...
Definition: sortedArrayManipulationHelpers.hpp:40
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE DualIteratorAccessor< A, B > operator*() const
Return a DualIteratorAccessor to the two values at which m_itA and m_itB point at.
Definition: sortedArrayManipulationHelpers.hpp:379
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE DualIterator(RandomAccessIteratorA const itA, RandomAccessIteratorB const itB)
Constructor taking the two iterators to wrap.
Definition: sortedArrayManipulationHelpers.hpp:244
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE void exchange(Iterator a, Iterator b)
Exchange the values pointed at by the two iterators.
Definition: sortedArrayManipulationHelpers.hpp:435
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE DualIterator & operator+=(std::ptrdiff_t const offset)
Increment the underlying iterators by offset and return a reference to *this.
Definition: sortedArrayManipulationHelpers.hpp:294
A & m_a
A reference to the first value.
Definition: sortedArrayManipulationHelpers.hpp:163
Contains a bunch of macro definitions.
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE Temporary(Temporary &&src)
Move constructor, moves the values from src..
Definition: sortedArrayManipulationHelpers.hpp:63
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE RandomAccessIterator unguardedPartition(RandomAccessIterator first, RandomAccessIterator last, RandomAccessIterator pivot, Compare &&comp)
Partition the range [first, last) with regards to *pivot.
Definition: sortedArrayManipulationHelpers.hpp:523
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE void introsortLoop(RandomAccessIterator first, RandomAccessIterator last, Compare &&comp)
Partially sort the range [first, last) under comp.
Definition: sortedArrayManipulationHelpers.hpp:641
DISABLE_HD_WARNING ~Temporary()=default
Default destructor, must be declared default so we can disable host-device warnings.
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE void moveBackward(BidirIt1 first, BidirIt1 last, BidirIt2 d_last)
Move the elements in [first, last) to another range ending in d_last. The elements are moved in rever...
Definition: sortedArrayManipulationHelpers.hpp:455
A helper class that holds a copy of the values.
Definition: sortedArrayManipulationHelpers.hpp:46
#define DISABLE_HD_WARNING
Disable host device warnings.
Definition: Macros.hpp:614
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE DualIteratorComparator(Compare comp)
Constructor that takes in a comparison method.
Definition: sortedArrayManipulationHelpers.hpp:185
This class acts as a single iterator while wrapping two iterators.
Definition: sortedArrayManipulationHelpers.hpp:223
typename std::remove_reference< decltype(*std::declval< RandomAccessIteratorB >()) >::type B
An alias for the type pointed to by RandomAccessIteratorB.
Definition: sortedArrayManipulationHelpers.hpp:230
DualIteratorAccessor()=delete
Delete the default constructor.
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE RandomAccessIterator unguardedPartitionPivot(RandomAccessIterator first, RandomAccessIterator last, Compare &&comp)
Partition the range [first, last).
Definition: sortedArrayManipulationHelpers.hpp:562
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE bool operator()(typename DualIteratorAccessor< A, B >::Temporary const &lhs, DualIteratorAccessor< A, B > const &rhs) const
Compare lhs with rhs using their first values.
Definition: sortedArrayManipulationHelpers.hpp:207
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE void computeMedian(Iterator result, Iterator a, Iterator b, Iterator c, Compare &&comp)
Compute the median of *a, *b and *c and place it in *result.
Definition: sortedArrayManipulationHelpers.hpp:478
typename std::remove_reference< decltype(*std::declval< RandomAccessIteratorA >()) >::type A
An alias for the type pointed to by RandomAccessIteratorA.
Definition: sortedArrayManipulationHelpers.hpp:227
RandomAccessIteratorB m_itB
The second iterator.
Definition: sortedArrayManipulationHelpers.hpp:398
#define LVARRAY_ASSERT_EQ(lhs, rhs)
Assert that two values compare equal in debug builds.
Definition: Macros.hpp:524
A m_a
A copy of type A.
Definition: sortedArrayManipulationHelpers.hpp:97
#define LVARRAY_HOST_DEVICE
Mark a function for both host and device usage.
Definition: Macros.hpp:600