1#ifndef AMREX_PODVECTOR_H_
2#define AMREX_PODVECTOR_H_
3#include <AMReX_Config.H>
26 template <
typename T,
typename Size,
template<
class>
class Allocator>
27 FatPtr<T> allocate_in_place ([[maybe_unused]] T* p, [[maybe_unused]] Size nmin, Size nmax,
28 Allocator<T>& allocator)
30 if constexpr (IsArenaAllocator<Allocator<T>>::value) {
31 return allocator.allocate_in_place(p, nmin, nmax);
33 T* pnew = allocator.allocate(nmax);
38 template <
typename T,
typename Size,
template<
class>
class Allocator>
39 T* shrink_in_place ([[maybe_unused]] T* p, Size n, Allocator<T>& allocator)
41 if constexpr (IsArenaAllocator<Allocator<T>>::value) {
42 return allocator.shrink_in_place(p, n);
44 return allocator.allocate(n);
48 template <
typename T,
typename Size,
template<
class>
class Allocator>
49 void uninitializedFillNImpl (T* data, Size count,
const T& value,
50 [[maybe_unused]] Allocator<T>
const& allocator)
54 if (RunOnGpu<Allocator<T>>::value)
56 if constexpr (RunOnGpu<Allocator<T>>::value)
66 else if (IsPolymorphicArenaAllocator<Allocator<T>>::value)
68 else if constexpr (IsPolymorphicArenaAllocator<Allocator<T>>::value)
71 if (allocator.arena()->isManaged() ||
72 allocator.arena()->isDevice())
83 std::uninitialized_fill_n(data, count, value);
86 template <
typename T,
template<
class>
class Allocator>
87 void initFromListImpl (T* data, std::initializer_list<T>
const& list,
88 [[maybe_unused]] Allocator<T>
const & allocator)
90 auto count = list.size() *
sizeof(T);
92 if constexpr (RunOnGpu<Allocator<T>>::value)
98 else if constexpr (IsPolymorphicArenaAllocator<Allocator<T>>::value)
100 if (allocator.arena()->isManaged() ||
101 allocator.arena()->isDevice())
109 std::memcpy(data, std::data(list), count);
112 template <
typename T,
typename Size,
template<
class>
class Allocator>
113 void fillValuesImpl (T* dst, T
const* src, Size count,
114 [[maybe_unused]] Allocator<T>
const& allocator)
118 if (RunOnGpu<Allocator<T>>::value)
120 if constexpr (RunOnGpu<Allocator<T>>::value)
130 else if (IsPolymorphicArenaAllocator<Allocator<T>>::value)
132 else if constexpr (IsPolymorphicArenaAllocator<Allocator<T>>::value)
135 if (allocator.arena()->isManaged() ||
136 allocator.arena()->isDevice())
147 static_assert(RunOnGpu<Allocator<T>>::value ==
false);
149 if constexpr (! RunOnGpu<Allocator<T>>::value) {
150 for (Size i = 0; i < count; ++i) { dst[i] = src[i]; }
154 template <
typename Allocator>
155 void memCopyImpl (
void* dst,
const void* src, std::size_t count,
156 [[maybe_unused]] Allocator
const& dst_allocator,
157 [[maybe_unused]] Allocator
const& src_allocator,
158 [[maybe_unused]]
bool sync =
true)
161 if constexpr (RunOnGpu<Allocator>::value)
167 else if constexpr (IsPolymorphicArenaAllocator<Allocator>::value)
169 bool dst_on_device = dst_allocator.arena()->isManaged() ||
170 dst_allocator.arena()->isDevice();
171 bool src_on_device = src_allocator.arena()->isManaged() ||
172 src_allocator.arena()->isDevice();
173 if (dst_on_device || src_on_device)
175 if (dst_on_device && src_on_device) {
177 }
else if (dst_on_device) {
187 std::memcpy(dst, src, count);
190 template <
typename Allocator>
191 void memMoveImpl (
void* dst,
const void* src, std::size_t count,
192 [[maybe_unused]] Allocator
const& allocator)
195 if constexpr (RunOnGpu<Allocator>::value)
204 else if constexpr (IsPolymorphicArenaAllocator<Allocator>::value)
206 if (allocator.arena()->isManaged() ||
207 allocator.arena()->isDevice())
218 std::memmove(dst, src, count);
221 template <
typename T,
typename Size,
template<
class>
class Allocator>
222 void maybe_init_snan (T* data, Size count, Allocator<T>
const& allocator)
225 if constexpr (std::is_same_v<float, std::remove_cv_t<T>> ||
226 std::is_same_v<double, std::remove_cv_t<T>>) {
229 if constexpr (RunOnGpu<Allocator<T>>::value) {
230 amrex::fill_snan<RunOn::Device>(data, count);
233 }
else if constexpr (IsPolymorphicArenaAllocator<Allocator<T>>::value) {
234 if (allocator.arena()->isManaged() ||
235 allocator.arena()->isDevice())
237 amrex::fill_snan<RunOn::Device>(data, count);
243 amrex::fill_snan<RunOn::Host>(data, count);
252 namespace VectorGrowthStrategy
261 void ValidateUserInput ();
269 std::size_t old_capacity, std::size_t sizeof_T)
273 if (new_size <= 900) {
278 return new_size + new_size/10;
280 return new_size + std::size_t(3*std::sqrt(new_size));
285 if (old_capacity == 0) {
286 return std::max(64/sizeof_T, new_size);
290 return std::max((old_capacity*3+1)/2, new_size);
292 return std::max(std::size_t(gf*
Real(old_capacity+1)), new_size);
306 template <
class T,
class Allocator = std::allocator<T> >
310 static_assert(std::is_trivially_copyable<T>(),
"PODVector can only hold trivially copyable types");
313 using Allocator::allocate;
314 using Allocator::deallocate;
340 : Allocator(a_allocator)
347 if (m_capacity != 0) {
348 m_data = allocate(m_capacity);
350 detail::maybe_init_snan(m_data, m_size, (Allocator
const&)(*
this));
357 : Allocator(a_allocator), m_size(a_size),
360 if (m_capacity != 0) {
361 m_data = allocate(m_capacity);
363 detail::uninitializedFillNImpl(m_data, a_size, a_value,
364 (Allocator
const&)(*
this));
371 : Allocator(a_allocator),
372 m_size (a_initializer_list.
size()),
376 if (m_capacity != 0) {
377 m_data = allocate(m_capacity);
378 if (a_initializer_list.size() != 0) {
379 detail::initFromListImpl(m_data, a_initializer_list,
380 (Allocator
const&)(*
this));
386 : Allocator(a_vector),
387 m_size (a_vector.
size()),
390 if (m_capacity != 0) {
391 m_data = allocate(m_capacity);
392 if (a_vector.
size() != 0) {
393 detail::memCopyImpl(m_data, a_vector.m_data, a_vector.nBytes(),
394 (Allocator
const&)(*
this),
395 (Allocator
const&)a_vector);
401 : Allocator(
static_cast<Allocator&&
>(a_vector)),
402 m_data(a_vector.m_data),
403 m_size(a_vector.m_size),
404 m_capacity(a_vector.m_capacity)
406 a_vector.m_data =
nullptr;
408 a_vector.m_capacity = 0;
414 static_assert(std::is_same<Allocator,std::allocator<T>>::value ||
416 if (m_data !=
nullptr) {
423 if (
this == &a_vector) {
return *
this; }
425 if ((Allocator
const&)(*
this) != (Allocator
const&)a_vector) {
426 if (m_data !=
nullptr) {
427 deallocate(m_data, m_capacity);
432 (Allocator&)(*
this) = (Allocator
const&)a_vector;
435 const auto other_size = a_vector.
size();
436 if ( other_size > m_capacity ) {
438 reserve_doit(other_size);
443 detail::memCopyImpl(m_data, a_vector.m_data, nBytes(),
444 (Allocator
const&)(*
this),
445 (Allocator
const&)a_vector);
452 if (
this == &a_vector) {
return *
this; }
454 if (
static_cast<Allocator const&
>(a_vector) ==
455 static_cast<Allocator const&
>(*
this))
457 if (m_data !=
nullptr) {
458 deallocate(m_data, m_capacity);
461 m_data = a_vector.m_data;
462 m_size = a_vector.m_size;
463 m_capacity = a_vector.m_capacity;
465 a_vector.m_data =
nullptr;
467 a_vector.m_capacity = 0;
480 auto* pos =
const_cast<iterator>(a_pos);
482 detail::memMoveImpl(pos, a_pos+1, (
end() - pos)*
sizeof(T),
483 (Allocator
const&)(*
this));
489 size_type num_to_erase = a_last - a_first;
490 auto* first =
const_cast<iterator>(a_first);
491 if (num_to_erase > 0) {
492 m_size -= num_to_erase;
493 detail::memMoveImpl(first, a_last, (
end() - first)*
sizeof(T),
494 (Allocator
const&)(*
this));
501 return insert(a_pos, 1, a_item);
506 auto* pos =
const_cast<iterator>(a_pos);
508 if (m_capacity < m_size + a_count)
510 std::size_t insert_index = std::distance(m_data, pos);
511 AllocateBufferForInsert(insert_index, a_count);
512 pos = m_data + insert_index;
516 detail::memMoveImpl(pos+a_count, a_pos, (
end() - pos) *
sizeof(T),
517 (Allocator
const&)(*
this));
520 detail::uninitializedFillNImpl(pos, a_count, a_value,
521 (Allocator
const&)(*
this));
529 return insert(a_pos, 1, std::move(a_item));
533 std::initializer_list<T> a_initializer_list)
535 auto* pos =
const_cast<iterator>(a_pos);
536 size_type count = a_initializer_list.size();
538 if (m_capacity < m_size + count)
540 std::size_t insert_index = std::distance(m_data, pos);
541 AllocateBufferForInsert(insert_index, count);
542 pos = m_data + insert_index;
546 detail::memMoveImpl(pos+count, a_pos, (
end() - pos) *
sizeof(T),
547 (Allocator
const&)(*
this));
550 detail::initFromListImpl(pos, a_initializer_list,
551 (Allocator
const&)(*
this));
556 template <class InputIt, class bar = typename std::iterator_traits<InputIt>::difference_type>
559 auto* pos =
const_cast<iterator>(a_pos);
560 size_type count = std::distance(a_first, a_last);
562 if (m_capacity < m_size + count)
564 std::size_t insert_index = std::distance(m_data, pos);
565 AllocateBufferForInsert(insert_index, count);
566 pos = m_data + insert_index;
570 detail::memMoveImpl(pos+count, a_pos, (
end() - pos) *
sizeof(T),
571 (Allocator
const&)(*
this));
577 detail::fillValuesImpl(pos, a_first, count,
578 (Allocator
const&)(*
this));
585 if ( a_count > m_capacity ) {
590 detail::uninitializedFillNImpl(m_data, a_count, a_value,
591 (Allocator
const&)(*
this));
594 void assign (std::initializer_list<T> a_initializer_list)
596 if (a_initializer_list.size() > m_capacity) {
598 reserve(a_initializer_list.size());
600 m_size = a_initializer_list.size();
601 detail::initFromListImpl(m_data, a_initializer_list,
602 (Allocator
const&)(*
this));
605 template <class InputIt, class bar = typename std::iterator_traits<InputIt>::difference_type>
606 void assign (InputIt a_first, InputIt a_last)
608 std::size_t count = std::distance(a_first, a_last);
609 if (count > m_capacity) {
614 detail::fillValuesImpl(m_data, a_first, count,
615 (Allocator
const&)(*
this));
631 if (m_size == m_capacity) {
632 auto new_capacity = GetNewCapacityForPush();
633 AllocateBufferForPush(new_capacity);
635 detail::uninitializedFillNImpl(m_data+m_size, 1, a_value,
636 (Allocator
const&)(*
this));
646 void clear () noexcept { m_size = 0; }
652 [[nodiscard]]
bool empty () const noexcept {
return m_size == 0 || m_data ==
nullptr; }
658 [[nodiscard]] T&
front () noexcept {
return *m_data; }
660 [[nodiscard]]
const T&
front () const noexcept {
return *m_data; }
662 [[nodiscard]] T&
back () noexcept {
return *(m_data + m_size - 1); }
664 [[nodiscard]]
const T&
back () const noexcept {
return *(m_data + m_size - 1); }
666 [[nodiscard]] T*
data () noexcept {
return m_data; }
668 [[nodiscard]]
const T*
data () const noexcept {
return m_data; }
670 [[nodiscard]] T*
dataPtr () noexcept {
return m_data; }
672 [[nodiscard]]
const T*
dataPtr () const noexcept {
return m_data; }
678 [[nodiscard]]
iterator end () noexcept {
return m_data + m_size; }
731 auto old_size = m_size;
732 resize_without_init_snan(a_new_size, strategy);
733 if (old_size < a_new_size) {
734 detail::maybe_init_snan(m_data + old_size,
735 m_size - old_size, (Allocator
const&)(*
this));
773 resize_without_init_snan(a_new_size, strategy);
774 if (old_size < a_new_size)
776 detail::uninitializedFillNImpl(m_data + old_size,
777 m_size - old_size, a_val,
778 (Allocator
const&)(*
this));
813 if (m_capacity < a_capacity) {
820 if (m_data !=
nullptr) {
822 deallocate(m_data, m_capacity);
825 }
else if (m_size < m_capacity) {
826 auto* new_data = detail::shrink_in_place(m_data, m_size,
827 (Allocator&)(*
this));
828 if (new_data != m_data) {
829 detail::memCopyImpl(new_data, m_data, nBytes(),
830 (Allocator
const&)(*
this),
831 (Allocator
const&)(*
this));
832 deallocate(m_data, m_capacity);
842 std::swap(m_data, a_vector.m_data);
843 std::swap(m_size, a_vector.m_size);
844 std::swap(m_capacity, a_vector.m_capacity);
845 std::swap(
static_cast<Allocator&
>(a_vector),
static_cast<Allocator&
>(*
this));
855 if (m_data !=
nullptr) {
869 void reserve_doit (
size_type a_capacity) {
870 if (m_capacity < a_capacity) {
871 auto fp = detail::allocate_in_place(m_data, a_capacity, a_capacity,
872 (Allocator&)(*
this));
877 [[nodiscard]]
size_type nBytes () const noexcept
879 return m_size*
sizeof(T);
883 [[nodiscard]]
size_type GetNewCapacityForPush () const noexcept
886 m_capacity,
sizeof(T));
889 void UpdateDataPtr (FatPtr<T>
const& fp)
891 auto* new_data = fp.ptr();
892 auto new_capacity = fp.size();
893 if (m_data !=
nullptr && m_data != new_data) {
895 detail::memCopyImpl(new_data, m_data, nBytes(),
896 (Allocator
const&)(*
this),
897 (Allocator
const&)(*
this));
902 m_capacity = new_capacity;
907 void AllocateBufferForPush (
size_type target_capacity)
909 auto fp = detail::allocate_in_place(m_data, m_size+1, target_capacity,
910 (Allocator&)(*
this));
920 size_type new_capacity = std::max(new_size, GetNewCapacityForPush());
921 auto fp = detail::allocate_in_place(m_data, new_size, new_capacity,
922 (Allocator&)(*
this));
923 auto* new_data = fp.ptr();
924 new_capacity = fp.size();
926 if (m_data !=
nullptr) {
927 if (m_data == new_data) {
928 if (m_size > a_index) {
929 detail::memMoveImpl(m_data+a_index+a_count, m_data+a_index,
930 (m_size-a_index)*
sizeof(T),
931 (Allocator
const&)(*
this));
936 detail::memCopyImpl(new_data, m_data, a_index*
sizeof(T),
937 (Allocator
const&)(*
this),
938 (Allocator
const&)(*
this),
false);
940 if (m_size > a_index) {
941 detail::memCopyImpl(new_data+a_index+a_count, m_data+a_index,
942 (m_size-a_index)*
sizeof(T),
943 (Allocator
const&)(*
this),
944 (Allocator
const&)(*
this),
false);
948 deallocate(m_data, m_capacity);
953 m_capacity = new_capacity;
958 if (m_capacity < a_new_size) {
#define AMREX_ENUM(CLASS,...)
Definition AMReX_Enum.H:208
#define AMREX_EXPORT
Definition AMReX_Extension.H:191
#define AMREX_GPU_DEVICE
Definition AMReX_GpuQualifiers.H:18
virtual void free(void *pt)=0
A pure virtual function for deleting the arena pointed to by pt.
virtual void * alloc(std::size_t sz)=0
static void streamSynchronize() noexcept
Definition AMReX_GpuDevice.cpp:757
Dynamically allocated vector for trivially copyable data.
Definition AMReX_PODVector.H:308
PODVector(std::initializer_list< T > a_initializer_list, const allocator_type &a_allocator=Allocator())
Definition AMReX_PODVector.H:369
iterator insert(const_iterator a_pos, T &&a_item)
Definition AMReX_PODVector.H:526
void reserve(size_type a_capacity, GrowthStrategy strategy=GrowthStrategy::Poisson)
Definition AMReX_PODVector.H:811
const_iterator begin() const noexcept
Definition AMReX_PODVector.H:676
const_iterator cbegin() const noexcept
Definition AMReX_PODVector.H:690
iterator insert(const_iterator a_pos, const T &a_item)
Definition AMReX_PODVector.H:499
PODVector & operator=(const PODVector< T, Allocator > &a_vector)
Definition AMReX_PODVector.H:421
iterator erase(const_iterator a_pos)
Definition AMReX_PODVector.H:478
iterator insert(const_iterator a_pos, size_type a_count, const T &a_value)
Definition AMReX_PODVector.H:504
size_type size() const noexcept
Definition AMReX_PODVector.H:648
const T * const_pointer
Definition AMReX_PODVector.H:328
void swap(PODVector< T, Allocator > &a_vector) noexcept
Definition AMReX_PODVector.H:840
const_reverse_iterator crbegin() const noexcept
Definition AMReX_PODVector.H:694
PODVector(const PODVector< T, Allocator > &a_vector)
Definition AMReX_PODVector.H:385
std::reverse_iterator< iterator > reverse_iterator
Definition AMReX_PODVector.H:325
T * pointer
Definition AMReX_PODVector.H:323
void shrink_to_fit()
Definition AMReX_PODVector.H:818
void assign(const T &a_value)
Definition AMReX_PODVector.H:622
void pop_back() noexcept
Definition AMReX_PODVector.H:644
iterator insert(const_iterator a_pos, std::initializer_list< T > a_initializer_list)
Definition AMReX_PODVector.H:532
iterator insert(const_iterator a_pos, InputIt a_first, InputIt a_last)
Definition AMReX_PODVector.H:557
T * iterator
Definition AMReX_PODVector.H:324
reverse_iterator rend() noexcept
Definition AMReX_PODVector.H:686
PODVector(size_type a_size)
Definition AMReX_PODVector.H:343
allocator_type get_allocator() const noexcept
Definition AMReX_PODVector.H:627
iterator begin() noexcept
Definition AMReX_PODVector.H:674
void resize(size_type a_new_size, GrowthStrategy strategy=GrowthStrategy::Poisson)
Definition AMReX_PODVector.H:728
void free_async() noexcept
Definition AMReX_PODVector.H:853
void assign(std::initializer_list< T > a_initializer_list)
Definition AMReX_PODVector.H:594
iterator end() noexcept
Definition AMReX_PODVector.H:678
T value_type
Definition AMReX_PODVector.H:317
const T * dataPtr() const noexcept
Definition AMReX_PODVector.H:672
constexpr PODVector() noexcept=default
void assign(size_type a_count, const T &a_value)
Definition AMReX_PODVector.H:583
const_reverse_iterator rbegin() const noexcept
Definition AMReX_PODVector.H:684
std::size_t size_type
Definition AMReX_PODVector.H:319
const_reverse_iterator rend() const noexcept
Definition AMReX_PODVector.H:688
void assign(InputIt a_first, InputIt a_last)
Definition AMReX_PODVector.H:606
T & front() noexcept
Definition AMReX_PODVector.H:658
const_reverse_iterator crend() const noexcept
Definition AMReX_PODVector.H:696
reverse_iterator rbegin() noexcept
Definition AMReX_PODVector.H:682
iterator erase(const_iterator a_first, const_iterator a_last)
Definition AMReX_PODVector.H:487
void clear() noexcept
Definition AMReX_PODVector.H:646
size_type capacity() const noexcept
Definition AMReX_PODVector.H:650
const_iterator cend() const noexcept
Definition AMReX_PODVector.H:692
T * dataPtr() noexcept
Definition AMReX_PODVector.H:670
PODVector(PODVector< T, Allocator > &&a_vector) noexcept
Definition AMReX_PODVector.H:400
T & reference
Definition AMReX_PODVector.H:322
const T * data() const noexcept
Definition AMReX_PODVector.H:668
const T * const_iterator
Definition AMReX_PODVector.H:329
~PODVector()
Definition AMReX_PODVector.H:411
const_iterator end() const noexcept
Definition AMReX_PODVector.H:680
void resize(size_type a_new_size, const T &a_val, GrowthStrategy strategy=GrowthStrategy::Poisson)
Definition AMReX_PODVector.H:769
const T & const_reference
Definition AMReX_PODVector.H:327
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition AMReX_PODVector.H:330
T & back() noexcept
Definition AMReX_PODVector.H:662
std::ptrdiff_t difference_type
Definition AMReX_PODVector.H:320
const T & back() const noexcept
Definition AMReX_PODVector.H:664
T & operator[](size_type a_index) noexcept
Definition AMReX_PODVector.H:654
PODVector(size_type a_size, const value_type &a_value, const allocator_type &a_allocator=Allocator())
Definition AMReX_PODVector.H:355
T * data() noexcept
Definition AMReX_PODVector.H:666
const T & front() const noexcept
Definition AMReX_PODVector.H:660
bool empty() const noexcept
Definition AMReX_PODVector.H:652
void push_back(const T &a_value)
Definition AMReX_PODVector.H:629
Allocator allocator_type
Definition AMReX_PODVector.H:318
amrex_real Real
Floating Point Type for Fields.
Definition AMReX_REAL.H:79
Arena * The_Arena()
Definition AMReX_Arena.cpp:783
void dtod_memcpy_async(void *p_d_dst, const void *p_d_src, const std::size_t sz) noexcept
Definition AMReX_GpuDevice.H:329
void freeAsync(Arena *arena, void *mem) noexcept
Definition AMReX_GpuDevice.H:284
void streamSynchronize() noexcept
Definition AMReX_GpuDevice.H:263
void dtoh_memcpy_async(void *p_h, const void *p_d, const std::size_t sz) noexcept
Definition AMReX_GpuDevice.H:315
void htod_memcpy_async(void *p_d, const void *p_h, const std::size_t sz) noexcept
Definition AMReX_GpuDevice.H:301
void Initialize()
Definition AMReX_PODVector.cpp:36
Real growth_factor
Definition AMReX_PODVector.cpp:7
Real GetGrowthFactor()
Definition AMReX_PODVector.H:255
void SetGrowthFactor(Real a_factor)
Definition AMReX_PODVector.cpp:43
Definition AMReX_Amr.cpp:49
__host__ __device__ void ignore_unused(const Ts &...)
This shuts up the compiler about unused variables.
Definition AMReX.H:138
std::enable_if_t< std::is_integral_v< T > > ParallelFor(TypeList< CTOs... > ctos, std::array< int, sizeof...(CTOs)> const &runtime_options, T N, F &&f)
Definition AMReX_CTOParallelForImpl.H:193
bool InitSNaN() noexcept
Definition AMReX.cpp:173
GrowthStrategy
Definition AMReX_PODVector.H:250
__host__ __device__ std::enable_if_t< std::is_floating_point_v< T >, bool > almostEqual(T x, T y, int ulp=2)
Definition AMReX_Algorithm.H:116
std::size_t grow_podvector_capacity(GrowthStrategy strategy, std::size_t new_size, std::size_t old_capacity, std::size_t sizeof_T)
Definition AMReX_PODVector.H:268
Definition AMReX_GpuAllocators.H:167