GEOSX
sortedArrayManipulationHelpers.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020, 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 >
40 struct DualIteratorAccessor
41 {
46  struct Temporary
47  {
51  inline Temporary() = delete;
52 
56  inline Temporary( Temporary const & ) = delete;
57 
63  LVARRAY_HOST_DEVICE inline Temporary( Temporary && src ):
64  m_a( std::move( src.m_a )),
65  m_b( std::move( src.m_b ))
66  {}
67 
73  LVARRAY_HOST_DEVICE inline Temporary( DualIteratorAccessor && src ):
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 
114  LVARRAY_HOST_DEVICE inline DualIteratorAccessor( A & a, B & b ):
115  m_a( a ),
116  m_b( b )
117  {}
118 
122  DualIteratorAccessor( DualIteratorAccessor const & ) = delete;
123 
128  inline DualIteratorAccessor( DualIteratorAccessor && ) = default;
129 
134  DualIteratorAccessor & operator=( DualIteratorAccessor const & ) = delete;
135 
142  LVARRAY_HOST_DEVICE inline DualIteratorAccessor & operator=( DualIteratorAccessor && src )
143  {
144  m_a = std::move( src.m_a );
145  m_b = std::move( src.m_b );
146  return *this;
147  }
148 
155  LVARRAY_HOST_DEVICE DualIteratorAccessor & operator=( Temporary && src )
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 >
178 struct DualIteratorComparator
179 {
185  LVARRAY_HOST_DEVICE inline DualIteratorComparator( Compare comp ):
186  m_compare( comp )
187  {}
188 
196  LVARRAY_HOST_DEVICE inline bool operator()( DualIteratorAccessor< A, B > const & lhs,
197  DualIteratorAccessor< A, B > const & rhs ) const
198  { return m_compare( lhs.m_a, rhs.m_a ); }
199 
207  LVARRAY_HOST_DEVICE inline bool operator()( typename DualIteratorAccessor< A, B >::Temporary const & lhs,
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 >
223 class DualIterator
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 
306  LVARRAY_HOST_DEVICE inline DualIterator & operator++()
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 
349  LVARRAY_HOST_DEVICE inline DualIterator & operator--()
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 
379  LVARRAY_HOST_DEVICE inline DualIteratorAccessor< A, B > operator*() const
380  { return DualIteratorAccessor< A, B >( *m_itA, *m_itB ); }
381 
389  template< class Compare >
390  LVARRAY_HOST_DEVICE inline DualIteratorComparator< A, B, Compare > createComparator( Compare && comp ) const
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 >
410 LVARRAY_HOST_DEVICE inline T && createTemporary( T & a )
411 {
412  return std::move( a );
413 }
414 
423 template< class A, class B >
424 inline LVARRAY_HOST_DEVICE typename DualIteratorAccessor< A, B >::Temporary createTemporary( DualIteratorAccessor< A, B > && it )
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
#define LVARRAY_ASSERT(EXP)
Assert EXP is true with no message.
Definition: Macros.hpp:142
bool operator!=(InputFlags const left, InputFlags const right)
Comparison operator for InputFlags enumeration.
Definition: InputFlags.hpp:154
bool operator<(InputFlags const left, InputFlags const right)
Comparison operator for InputFlags enumeration.
Definition: InputFlags.hpp:162
The top level namespace.
Definition: Array.hpp:24
Contains a bunch of macro definitions.
#define DISABLE_HD_WARNING
Disable host device warnings.
Definition: Macros.hpp:401
#define LVARRAY_ASSERT_EQ(lhs, rhs)
Assert that two values compare equal in debug builds.
Definition: Macros.hpp:325
#define LVARRAY_HOST_DEVICE
Mark a function for both host and device usage.
Definition: Macros.hpp:389