LvArray
arrayManipulation.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 
13 #pragma once
14 
15 // Source includes
16 #include "limits.hpp"
17 #include "Macros.hpp"
18 #include "typeManipulation.hpp"
19 
20 // System includes
21 #include <cstring>
22 
23 #ifdef LVARRAY_BOUNDS_CHECK
24 
30 #define ARRAYMANIPULATION_CHECK_BOUNDS( index ) \
31  LVARRAY_ERROR_IF( !isPositive( index ) || index >= size, \
32  "Array Bounds Check Failed: index=" << index << " size()=" << size )
33 
39 #define ARRAYMANIPULATION_CHECK_INSERT_BOUNDS( index ) \
40  LVARRAY_ERROR_IF( !isPositive( index ) || index > size, \
41  "Array Bounds Insert Check Failed: index=" << index << " size()=" << size )
42 
43 #else // LVARRAY_BOUNDS_CHECK
44 
50 #define ARRAYMANIPULATION_CHECK_BOUNDS( index )
51 
57 #define ARRAYMANIPULATION_CHECK_INSERT_BOUNDS( index )
58 
59 #endif // LVARRAY_BOUNDS_CHECK
60 
61 namespace LvArray
62 {
63 
71 namespace arrayManipulation
72 {
73 
79 template< typename INDEX_TYPE >
80 LVARRAY_HOST_DEVICE inline constexpr
81 typename std::enable_if< std::is_signed< INDEX_TYPE >::value, bool >::type
82 isPositive( INDEX_TYPE const i )
83 { return i >= 0; }
84 
89 template< typename INDEX_TYPE >
90 LVARRAY_HOST_DEVICE inline constexpr
91 typename std::enable_if< !std::is_signed< INDEX_TYPE >::value, bool >::type
92 isPositive( INDEX_TYPE )
93 { return true; }
94 
102 template< typename ITER >
103 inline constexpr LVARRAY_HOST_DEVICE
104 typename std::iterator_traits< ITER >::difference_type
105 iterDistance( ITER first, ITER const last, std::input_iterator_tag )
106 {
107  typename std::iterator_traits< ITER >::difference_type n = 0;
108  while( first != last )
109  {
110  ++first;
111  ++n;
112  }
113 
114  return n;
115 }
116 
124 template< typename RandomAccessIterator >
125 inline constexpr LVARRAY_HOST_DEVICE
126 typename std::iterator_traits< RandomAccessIterator >::difference_type
127 iterDistance( RandomAccessIterator first, RandomAccessIterator last, std::random_access_iterator_tag )
128 { return last - first; }
129 
137 template< typename ITER >
138 inline constexpr LVARRAY_HOST_DEVICE
139 typename std::iterator_traits< ITER >::difference_type
140 iterDistance( ITER const first, ITER const last )
141 { return iterDistance( first, last, typename std::iterator_traits< ITER >::iterator_category() ); }
142 
150 template< typename T >
151 LVARRAY_HOST_DEVICE inline
152 void destroy( T * const LVARRAY_RESTRICT ptr,
153  std::ptrdiff_t const size )
154 {
155  LVARRAY_ASSERT( ptr != nullptr || size == 0 );
156 
157  if( !std::is_trivially_destructible< T >::value )
158  {
159  for( std::ptrdiff_t i = 0; i < size; ++i )
160  {
161  ptr[ i ].~T();
162  }
163  }
164 }
165 
175 template< typename ITER, typename T >
176 LVARRAY_HOST_DEVICE inline
177 void uninitializedCopy( ITER first,
178  ITER const & last,
179  T * LVARRAY_RESTRICT dst )
180 {
181  LVARRAY_ASSERT( dst != nullptr || first == last );
182 
183  while( first != last )
184  {
185  new ( dst ) T( *first );
186  ++dst;
187  ++first;
188  }
189 }
190 
199 template< typename T >
200 LVARRAY_HOST_DEVICE inline
201 void uninitializedMove( T * const LVARRAY_RESTRICT dst,
202  std::ptrdiff_t const size,
203  T * const LVARRAY_RESTRICT src )
204 {
205  LVARRAY_ASSERT( dst != nullptr || size == 0 );
206  LVARRAY_ASSERT( isPositive( size ) );
207  LVARRAY_ASSERT( src != nullptr || size == 0 );
208 
209  for( std::ptrdiff_t i = 0; i < size; ++i )
210  {
211  new (dst + i) T( std::move( src[ i ] ) );
212  }
213 }
214 
223 template< typename T >
224 LVARRAY_HOST_DEVICE inline
225 void uninitializedShiftDown( T * const LVARRAY_RESTRICT ptr,
226  std::ptrdiff_t const size,
227  std::ptrdiff_t const amount )
228 {
229  LVARRAY_ASSERT( ptr != nullptr || size == 0 );
230  LVARRAY_ASSERT( isPositive( size ) );
231  LVARRAY_ASSERT( isPositive( amount ) );
232 
233  if( amount == 0 )
234  return;
235 
236  for( std::ptrdiff_t j = 0; j < size; ++j )
237  {
238  new ( ptr + j - amount ) T( std::move( ptr[ j ] ) );
239  ptr[ j ].~T();
240  }
241 }
242 
251 template< typename T >
252 LVARRAY_HOST_DEVICE inline
253 void uninitializedShiftUp( T * const LVARRAY_RESTRICT ptr,
254  std::ptrdiff_t const size,
255  std::ptrdiff_t const amount )
256 {
257  LVARRAY_ASSERT( ptr != nullptr || size == 0 );
258  LVARRAY_ASSERT( isPositive( size ) );
259  LVARRAY_ASSERT( isPositive( amount ) );
260 
261  if( amount == 0 )
262  return;
263 
264  for( std::ptrdiff_t j = size - 1; j >= 0; --j )
265  {
266  new ( ptr + amount + j ) T( std::move( ptr[ j ] ) );
267  ptr[ j ].~T();
268  }
269 }
270 
281 template< typename T, typename ... ARGS >
282 LVARRAY_HOST_DEVICE inline
283 void resize( T * const LVARRAY_RESTRICT ptr,
284  std::ptrdiff_t const size,
285  std::ptrdiff_t const newSize,
286  ARGS && ... args )
287 {
288  LVARRAY_ASSERT( ptr != nullptr || (size == 0 && newSize == 0) );
289  LVARRAY_ASSERT( isPositive( size ) );
290  LVARRAY_ASSERT( isPositive( newSize ) );
291 
292  // Delete things between newSize and size.
293  destroy( ptr + newSize, size - newSize );
294 
295  // Initialize things between size and newSize.
296  if( sizeof ... ( ARGS ) == 0 && std::is_trivially_default_constructible< T >::value )
297  {
298  if( newSize - size > 0 )
299  {
300  std::size_t const sizeDiff = integerConversion< std::size_t >( newSize - size );
301  memset( reinterpret_cast< void * >( ptr + size ), 0, ( sizeDiff ) * sizeof( T ) );
302  }
303  }
304  else
305  {
306  // Use std::size_t so that when GCC optimizes this it doesn't produce sign warnings.
307  for( std::size_t i = size; i < std::size_t( newSize ); ++i )
308  {
309  new ( ptr + i ) T( std::forward< ARGS >( args )... );
310  }
311  }
312 }
313 
324 template< typename T >
325 LVARRAY_HOST_DEVICE inline
326 void shiftUp( T * const LVARRAY_RESTRICT ptr,
327  std::ptrdiff_t const size,
328  std::ptrdiff_t const index,
329  std::ptrdiff_t const n )
330 {
331  LVARRAY_ASSERT( ptr != nullptr || (size == 0 && n == 0) );
332  LVARRAY_ASSERT( isPositive( size ) );
333  LVARRAY_ASSERT( isPositive( n ) );
335 
336  if( n == 0 )
337  return;
338 
339  // Move the existing values up by n.
340  for( std::ptrdiff_t i = size; i > index; --i )
341  {
342  std::ptrdiff_t const curIndex = i - 1;
343  new ( ptr + curIndex + n ) T( std::move( ptr[ curIndex ] ) );
344  }
345 
346  // Delete the values moved out of.
347  std::ptrdiff_t const bounds = (index + n < size) ? index + n : size;
348  destroy( ptr + index, bounds - index );
349 }
350 
361 template< typename T >
362 LVARRAY_HOST_DEVICE inline
363 void shiftDown( T * const LVARRAY_RESTRICT ptr,
364  std::ptrdiff_t const size,
365  std::ptrdiff_t const index,
366  std::ptrdiff_t const n )
367 {
369  LVARRAY_ASSERT( ptr != nullptr || (size == 0 && n == 0) );
370  LVARRAY_ASSERT( isPositive( size ) );
371  LVARRAY_ASSERT( isPositive( n ) );
372  LVARRAY_ASSERT( index >= n );
373 
374  if( n == 0 )
375  return;
376 
377  // Move the existing down by n.
378  for( std::ptrdiff_t i = index; i < size; ++i )
379  {
380  ptr[i - n] = std::move( ptr[i] );
381  }
382 }
383 
394 template< typename T >
395 LVARRAY_HOST_DEVICE inline
396 void erase( T * const LVARRAY_RESTRICT ptr,
397  std::ptrdiff_t const size,
398  std::ptrdiff_t const index,
399  std::ptrdiff_t const n=1 )
400 {
401  LVARRAY_ASSERT( isPositive( n ) );
402  if( n == 0 )
403  return;
404 
406  ARRAYMANIPULATION_CHECK_BOUNDS( index + n - 1 );
407 
408  shiftDown( ptr, size, std::ptrdiff_t( index + n ), n );
409 
410  // Delete the values that were moved out of at the end of the array.
411  destroy( ptr + size - n, n );
412 }
413 
423 template< typename T, typename ... ARGS >
424 LVARRAY_HOST_DEVICE inline
425 void emplaceBack( T * const LVARRAY_RESTRICT ptr,
426  std::ptrdiff_t const size,
427  ARGS && ... args )
428 {
429  LVARRAY_ASSERT( ptr != nullptr );
430  LVARRAY_ASSERT( isPositive( size ) );
431  new ( ptr + size ) T( std::forward< ARGS >( args ) ... );
432 }
433 
445 template< typename T, typename ITER >
446 LVARRAY_HOST_DEVICE inline
447 std::ptrdiff_t append( T * const LVARRAY_RESTRICT ptr,
448  std::ptrdiff_t const size,
449  ITER first,
450  ITER const last )
451 {
452  LVARRAY_ASSERT( ptr != nullptr || (size == 0 && first == last) );
453  LVARRAY_ASSERT( isPositive( size ) );
454 
455  std::ptrdiff_t i = 0;
456  while( first != last )
457  {
458  new( ptr + size + i ) T( *first );
459  ++first;
460  ++i;
461  }
462 
463  return i;
464 }
465 
476 template< typename T, typename ... ARGS >
477 LVARRAY_HOST_DEVICE inline
478 void emplace( T * const LVARRAY_RESTRICT ptr,
479  std::ptrdiff_t const size,
480  std::ptrdiff_t const index,
481  ARGS && ... args )
482 {
483  LVARRAY_ASSERT( ptr != nullptr );
484  LVARRAY_ASSERT( isPositive( size ) );
486 
487  // Create space for the new value.
488  shiftUp( ptr, size, index, std::ptrdiff_t( 1 ) );
489  new ( ptr + index ) T( std::forward< ARGS >( args ) ... );
490 }
491 
503 template< typename T, typename ITERATOR >
504 LVARRAY_HOST_DEVICE inline
505 void insert( T * const LVARRAY_RESTRICT ptr,
506  std::ptrdiff_t const size,
507  std::ptrdiff_t const index,
508  ITERATOR first,
509  std::ptrdiff_t const n )
510 {
511  LVARRAY_ASSERT( ptr != nullptr );
512  LVARRAY_ASSERT( isPositive( size ) );
514 
515  shiftUp( ptr, size, index, n );
516 
517  for( std::ptrdiff_t i = 0; i < n; ++i )
518  {
519  new ( ptr + index + i ) T( *first );
520  ++first;
521  }
522 }
523 
531 template< typename T >
532 LVARRAY_HOST_DEVICE inline
533 void popBack( T * const LVARRAY_RESTRICT ptr,
534  std::ptrdiff_t const size )
535 {
536  LVARRAY_ASSERT( ptr != nullptr );
537  LVARRAY_ASSERT( size > 0 );
538  ptr[ size - 1 ].~T();
539 }
540 
541 } // namespace arrayManipulation
542 } // namespace LvArray
#define LVARRAY_ASSERT(EXP)
Assert EXP is true with no message.
Definition: Macros.hpp:223
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE std::ptrdiff_t append(T *const LVARRAY_RESTRICT ptr, std::ptrdiff_t const size, ITER first, ITER const last)
Append the given values to the array.
Definition: arrayManipulation.hpp:447
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE void uninitializedMove(T *const LVARRAY_RESTRICT dst, std::ptrdiff_t const size, T *const LVARRAY_RESTRICT src)
Move construct values from the source to the destination.
Definition: arrayManipulation.hpp:201
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE void emplaceBack(T *const LVARRAY_RESTRICT ptr, std::ptrdiff_t const size, ARGS &&... args)
Append the to the array constructing the new value in place.
Definition: arrayManipulation.hpp:425
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE void insert(T *const LVARRAY_RESTRICT ptr, std::ptrdiff_t const size, std::ptrdiff_t const index, ITERATOR first, std::ptrdiff_t const n)
Insert the given values into the array at the given position.
Definition: arrayManipulation.hpp:505
Contains templates useful for type manipulation.
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE void resize(T *const LVARRAY_RESTRICT ptr, std::ptrdiff_t const size, std::ptrdiff_t const newSize, ARGS &&... args)
Resize the give array.
Definition: arrayManipulation.hpp:283
Contains portable access to std::numeric_limits and functions for converting between integral types...
LVARRAY_HOST_DEVICE constexpr std::enable_if< std::is_signed< INDEX_TYPE >::value, bool >::type isPositive(INDEX_TYPE const i)
Definition: arrayManipulation.hpp:82
#define ARRAYMANIPULATION_CHECK_BOUNDS(index)
Check that index is a valid into into the array.
Definition: arrayManipulation.hpp:50
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE void erase(T *const LVARRAY_RESTRICT ptr, std::ptrdiff_t const size, std::ptrdiff_t const index, std::ptrdiff_t const n=1)
Shift the values in the array at or above the given position down by the given amount overwriting the...
Definition: arrayManipulation.hpp:396
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE void popBack(T *const LVARRAY_RESTRICT ptr, std::ptrdiff_t const size)
Destroy the value at the end of the array.
Definition: arrayManipulation.hpp:533
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE void uninitializedCopy(ITER first, ITER const &last, T *LVARRAY_RESTRICT dst)
Copy construct values from the source to the destination.
Definition: arrayManipulation.hpp:177
The top level namespace.
Definition: Array.hpp:24
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE void shiftDown(T *const LVARRAY_RESTRICT ptr, std::ptrdiff_t const size, std::ptrdiff_t const index, std::ptrdiff_t const n)
Shift the values in the array at or above the given position down by the given amount overwriting the...
Definition: arrayManipulation.hpp:363
Contains a bunch of macro definitions.
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE void destroy(T *const LVARRAY_RESTRICT ptr, std::ptrdiff_t const size)
Destory the values in the array.
Definition: arrayManipulation.hpp:152
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE void shiftUp(T *const LVARRAY_RESTRICT ptr, std::ptrdiff_t const size, std::ptrdiff_t const index, std::ptrdiff_t const n)
Shift the values in the array at or above the given position up by the given amount. New uninitialized values take their place.
Definition: arrayManipulation.hpp:326
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE void uninitializedShiftDown(T *const LVARRAY_RESTRICT ptr, std::ptrdiff_t const size, std::ptrdiff_t const amount)
Shift values down into uninitialized memory.
Definition: arrayManipulation.hpp:225
#define DISABLE_HD_WARNING
Disable host device warnings.
Definition: Macros.hpp:614
DISABLE_HD_WARNING constexpr LVARRAY_HOST_DEVICE std::iterator_traits< ITER >::difference_type iterDistance(ITER first, ITER const last, std::input_iterator_tag)
Definition: arrayManipulation.hpp:105
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE void uninitializedShiftUp(T *const LVARRAY_RESTRICT ptr, std::ptrdiff_t const size, std::ptrdiff_t const amount)
Shift values up into uninitialized memory.
Definition: arrayManipulation.hpp:253
#define ARRAYMANIPULATION_CHECK_INSERT_BOUNDS(index)
Check that index is a valid insertion position in the array.
Definition: arrayManipulation.hpp:57
DISABLE_HD_WARNING LVARRAY_HOST_DEVICE void emplace(T *const LVARRAY_RESTRICT ptr, std::ptrdiff_t const size, std::ptrdiff_t const index, ARGS &&... args)
Insert into the array constructing the new value in place.
Definition: arrayManipulation.hpp:478
#define LVARRAY_HOST_DEVICE
Mark a function for both host and device usage.
Definition: Macros.hpp:600