Block-Structured AMR Software Framework
Loading...
Searching...
No Matches
AMReX_PODVector.H
Go to the documentation of this file.
1#ifndef AMREX_PODVECTOR_H_
2#define AMREX_PODVECTOR_H_
3#include <AMReX_Config.H>
4
5#include <AMReX.H>
6#include <AMReX_Arena.H>
7#include <AMReX_Enum.H>
8#include <AMReX_GpuLaunch.H>
10#include <AMReX_GpuDevice.H>
11#include <AMReX_MemPool.H>
12#include <AMReX_TypeTraits.H>
13
14#include <cmath>
15#include <iterator>
16#include <type_traits>
17#include <utility>
18#include <memory>
19#include <cstring>
20
21namespace amrex
22{
24 namespace detail
25 {
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)
29 {
30 if constexpr (IsArenaAllocator<Allocator<T>>::value) {
31 return allocator.allocate_in_place(p, nmin, nmax);
32 } else {
33 T* pnew = allocator.allocate(nmax);
34 return {pnew, nmax};
35 }
36 }
37
38 template <typename T, typename Size, template<class> class Allocator>
39 T* shrink_in_place ([[maybe_unused]] T* p, Size n, Allocator<T>& allocator)
40 {
41 if constexpr (IsArenaAllocator<Allocator<T>>::value) {
42 return allocator.shrink_in_place(p, n);
43 } else {
44 return allocator.allocate(n);
45 }
46 }
47
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)
51 {
52#ifdef AMREX_USE_GPU
53#ifdef _WIN32
54 if (RunOnGpu<Allocator<T>>::value)
55#else
56 if constexpr (RunOnGpu<Allocator<T>>::value)
57#endif
58 {
59 amrex::ParallelFor(count, [=] AMREX_GPU_DEVICE (Size i) noexcept {
60 data[i] = value;
61 });
63 return;
64 }
65#ifdef _WIN32
66 else if (IsPolymorphicArenaAllocator<Allocator<T>>::value)
67#else
68 else if constexpr (IsPolymorphicArenaAllocator<Allocator<T>>::value)
69#endif
70 {
71 if (allocator.arena()->isManaged() ||
72 allocator.arena()->isDevice())
73 {
74 amrex::ParallelFor(count, [=] AMREX_GPU_DEVICE (Size i) noexcept
75 {
76 data[i] = value;
77 });
79 return;
80 }
81 }
82#endif
83 std::uninitialized_fill_n(data, count, value);
84 }
85
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)
89 {
90 auto count = list.size() * sizeof(T);
91#ifdef AMREX_USE_GPU
92 if constexpr (RunOnGpu<Allocator<T>>::value)
93 {
94 Gpu::htod_memcpy_async(data, std::data(list), count);
96 return;
97 }
98 else if constexpr (IsPolymorphicArenaAllocator<Allocator<T>>::value)
99 {
100 if (allocator.arena()->isManaged() ||
101 allocator.arena()->isDevice())
102 {
103 Gpu::htod_memcpy_async(data, std::data(list), count);
105 return;
106 }
107 }
108#endif
109 std::memcpy(data, std::data(list), count);
110 }
111
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)
115 {
116#ifdef AMREX_USE_GPU
117#ifdef _WIN32
118 if (RunOnGpu<Allocator<T>>::value)
119#else
120 if constexpr (RunOnGpu<Allocator<T>>::value)
121#endif
122 {
123 amrex::ParallelFor(count, [=] AMREX_GPU_DEVICE (Size i) noexcept {
124 dst[i] = src[i];
125 });
127 return;
128 }
129#ifdef _WIN32
130 else if (IsPolymorphicArenaAllocator<Allocator<T>>::value)
131#else
132 else if constexpr (IsPolymorphicArenaAllocator<Allocator<T>>::value)
133#endif
134 {
135 if (allocator.arena()->isManaged() ||
136 allocator.arena()->isDevice())
137 {
138 amrex::ParallelFor(count, [=] AMREX_GPU_DEVICE (Size i) noexcept
139 {
140 dst[i] = src[i];
141 });
143 return;
144 }
145 }
146#else
147 static_assert(RunOnGpu<Allocator<T>>::value == false);
148#endif
149 if constexpr (! RunOnGpu<Allocator<T>>::value) {
150 for (Size i = 0; i < count; ++i) { dst[i] = src[i]; }
151 }
152 }
153
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)
159 {
160#ifdef AMREX_USE_GPU
161 if constexpr (RunOnGpu<Allocator>::value)
162 {
163 Gpu::dtod_memcpy_async(dst, src, count);
164 if (sync) { Gpu::streamSynchronize(); }
165 return;
166 }
167 else if constexpr (IsPolymorphicArenaAllocator<Allocator>::value)
168 {
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)
174 {
175 if (dst_on_device && src_on_device) {
176 Gpu::dtod_memcpy_async(dst, src, count);
177 } else if (dst_on_device) {
178 Gpu::htod_memcpy_async(dst, src, count);
179 } else {
180 Gpu::dtoh_memcpy_async(dst, src, count);
181 }
182 if (sync) { Gpu::streamSynchronize(); }
183 return;
184 }
185 }
186#endif
187 std::memcpy(dst, src, count);
188 }
189
190 template <typename Allocator>
191 void memMoveImpl (void* dst, const void* src, std::size_t count,
192 [[maybe_unused]] Allocator const& allocator)
193 {
194#ifdef AMREX_USE_GPU
195 if constexpr (RunOnGpu<Allocator>::value)
196 {
197 auto* tmp = The_Arena()->alloc(count);
198 Gpu::dtod_memcpy_async(tmp, src, count);
199 Gpu::dtod_memcpy_async(dst, tmp, count);
201 The_Arena()->free(tmp);
202 return;
203 }
204 else if constexpr (IsPolymorphicArenaAllocator<Allocator>::value)
205 {
206 if (allocator.arena()->isManaged() ||
207 allocator.arena()->isDevice())
208 {
209 auto* tmp = The_Arena()->alloc(count);
210 Gpu::dtod_memcpy_async(tmp, src, count);
211 Gpu::dtod_memcpy_async(dst, tmp, count);
213 The_Arena()->free(tmp);
214 return;
215 }
216 }
217#endif
218 std::memmove(dst, src, count);
219 }
220
221 template <typename T, typename Size, template<class> class Allocator>
222 void maybe_init_snan (T* data, Size count, Allocator<T> const& allocator)
223 {
224 amrex::ignore_unused(data, count, 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>>) {
227 if (amrex::InitSNaN()) {
228#ifdef AMREX_USE_GPU
229 if constexpr (RunOnGpu<Allocator<T>>::value) {
230 amrex::fill_snan<RunOn::Device>(data, count);
232 return;
233 } else if constexpr (IsPolymorphicArenaAllocator<Allocator<T>>::value) {
234 if (allocator.arena()->isManaged() ||
235 allocator.arena()->isDevice())
236 {
237 amrex::fill_snan<RunOn::Device>(data, count);
239 return;
240 }
241 }
242#endif
243 amrex::fill_snan<RunOn::Host>(data, count);
244 }
245 }
246 }
247 }
249
251
252 namespace VectorGrowthStrategy
253 {
255 inline Real GetGrowthFactor () { return growth_factor; }
256 void SetGrowthFactor (Real a_factor);
257
259 namespace detail
260 {
261 void ValidateUserInput ();
262 }
264
265 void Initialize ();
266 }
267
268 inline std::size_t grow_podvector_capacity (GrowthStrategy strategy, std::size_t new_size,
269 std::size_t old_capacity, std::size_t sizeof_T)
270 {
271 switch (strategy) {
273 if (new_size <= 900) {
274 // 3*sqrt(900) = 900/10. Note that we don't need to be precise
275 // here. Even if later we change the else block to
276 // 4*std::sqrt(s), it's not really an issue to still use 900
277 // here.
278 return new_size + new_size/10;
279 } else {
280 return new_size + std::size_t(3*std::sqrt(new_size));
281 }
283 return new_size;
285 if (old_capacity == 0) {
286 return std::max(64/sizeof_T, new_size);
287 } else {
289 if (amrex::almostEqual(gf, Real(1.5))) {
290 return std::max((old_capacity*3+1)/2, new_size);
291 } else {
292 return std::max(std::size_t(gf*Real(old_capacity+1)), new_size);
293 }
294 }
295 }
296 return 0; // unreachable
297 }
298
306 template <class T, class Allocator = std::allocator<T> >
307 class PODVector : public Allocator
308 {
309 // static_assert(std::is_standard_layout<T>(), "PODVector can only hold standard layout types");
310 static_assert(std::is_trivially_copyable<T>(), "PODVector can only hold trivially copyable types");
311 // static_assert(std::is_trivially_default_constructible<T>(), "PODVector can only hold trivial dc types");
312
313 using Allocator::allocate;
314 using Allocator::deallocate;
315
316 public:
317 using value_type = T;
318 using allocator_type = Allocator;
319 using size_type = std::size_t;
320 using difference_type = std::ptrdiff_t;
321
322 using reference = T&;
323 using pointer = T*;
324 using iterator = T*;
325 using reverse_iterator = std::reverse_iterator<iterator>;
326
327 using const_reference = const T&;
328 using const_pointer = const T*;
329 using const_iterator = const T*;
330 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
331
332 private:
333 pointer m_data = nullptr;
334 size_type m_size{0}, m_capacity{0};
335
336 public:
337 constexpr PODVector () noexcept = default;
338
339 constexpr explicit PODVector (const allocator_type& a_allocator) noexcept
340 : Allocator(a_allocator)
341 {}
342
343 explicit PODVector (size_type a_size)
344 : m_size(a_size),
345 m_capacity(grow_podvector_capacity(GrowthStrategy::Poisson, a_size, 0, sizeof(T)))
346 {
347 if (m_capacity != 0) {
348 m_data = allocate(m_capacity);
349 if (a_size != 0) {
350 detail::maybe_init_snan(m_data, m_size, (Allocator const&)(*this));
351 }
352 }
353 }
354
355 PODVector (size_type a_size, const value_type& a_value,
356 const allocator_type& a_allocator = Allocator())
357 : Allocator(a_allocator), m_size(a_size),
358 m_capacity(grow_podvector_capacity(GrowthStrategy::Poisson, a_size, 0, sizeof(T)))
359 {
360 if (m_capacity != 0) {
361 m_data = allocate(m_capacity);
362 if (a_size != 0) {
363 detail::uninitializedFillNImpl(m_data, a_size, a_value,
364 (Allocator const&)(*this));
365 }
366 }
367 }
368
369 PODVector (std::initializer_list<T> a_initializer_list,
370 const allocator_type& a_allocator = Allocator())
371 : Allocator(a_allocator),
372 m_size (a_initializer_list.size()),
373 m_capacity(grow_podvector_capacity(
374 GrowthStrategy::Poisson, a_initializer_list.size(), 0, sizeof(T)))
375 {
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));
381 }
382 }
383 }
384
386 : Allocator(a_vector),
387 m_size (a_vector.size()),
388 m_capacity(a_vector.capacity())
389 {
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);
396 }
397 }
398 }
399
400 PODVector (PODVector<T, Allocator>&& a_vector) noexcept
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)
405 {
406 a_vector.m_data = nullptr;
407 a_vector.m_size = 0;
408 a_vector.m_capacity = 0;
409 }
410
412 {
413 // let's not worry about other allocators
414 static_assert(std::is_same_v<Allocator,std::allocator<T>> ||
416 if (m_data != nullptr) {
417 deallocate(m_data, capacity());
418 }
419 }
420
422 {
423 if (this == &a_vector) { return *this; }
424
425 if ((Allocator const&)(*this) != (Allocator const&)a_vector) {
426 if (m_data != nullptr) {
427 deallocate(m_data, m_capacity);
428 m_data = nullptr;
429 m_size = 0;
430 m_capacity = 0;
431 }
432 (Allocator&)(*this) = (Allocator const&)a_vector;
433 }
434
435 const auto other_size = a_vector.size();
436 if ( other_size > m_capacity ) {
437 clear();
438 reserve_doit(other_size);
439 }
440
441 m_size = other_size;
442 if (m_size > 0) {
443 detail::memCopyImpl(m_data, a_vector.m_data, nBytes(),
444 (Allocator const&)(*this),
445 (Allocator const&)a_vector);
446 }
447 return *this;
448 }
449
451 {
452 if (this == &a_vector) { return *this; }
453
454 if (static_cast<Allocator const&>(a_vector) ==
455 static_cast<Allocator const&>(*this))
456 {
457 if (m_data != nullptr) {
458 deallocate(m_data, m_capacity);
459 }
460
461 m_data = a_vector.m_data;
462 m_size = a_vector.m_size;
463 m_capacity = a_vector.m_capacity;
464
465 a_vector.m_data = nullptr;
466 a_vector.m_size = 0;
467 a_vector.m_capacity = 0;
468 }
469 else
470 {
471 // if the allocators are not the same we give up and copy
472 *this = a_vector; // must copy instead of move
473 }
474
475 return *this;
476 }
477
479 {
480 auto* pos = const_cast<iterator>(a_pos);
481 --m_size;
482 detail::memMoveImpl(pos, a_pos+1, (end() - pos)*sizeof(T),
483 (Allocator const&)(*this));
484 return pos;
485 }
486
488 {
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));
495 }
496 return first;
497 }
498
499 iterator insert (const_iterator a_pos, const T& a_item)
500 {
501 return insert(a_pos, 1, a_item);
502 }
503
504 iterator insert (const_iterator a_pos, size_type a_count, const T& a_value)
505 {
506 auto* pos = const_cast<iterator>(a_pos);
507 if (a_count > 0) {
508 // Copy first because a_value could be a reference to an element of this vector.
509 T const value = a_value;
510 if (m_capacity < m_size + a_count)
511 {
512 std::size_t insert_index = std::distance(m_data, pos);
513 AllocateBufferForInsert(insert_index, a_count);
514 pos = m_data + insert_index;
515 }
516 else
517 {
518 detail::memMoveImpl(pos+a_count, a_pos, (end() - pos) * sizeof(T),
519 (Allocator const&)(*this));
520 m_size += a_count;
521 }
522 detail::uninitializedFillNImpl(pos, a_count, value,
523 (Allocator const&)(*this));
524 }
525 return pos;
526 }
527
528 iterator insert (const_iterator a_pos, T&& a_item)
529 {
530 // This is *POD* vector after all
531 return insert(a_pos, 1, std::move(a_item));
532 }
533
535 std::initializer_list<T> a_initializer_list)
536 {
537 auto* pos = const_cast<iterator>(a_pos);
538 size_type count = a_initializer_list.size();
539 if (count > 0) {
540 if (m_capacity < m_size + count)
541 {
542 std::size_t insert_index = std::distance(m_data, pos);
543 AllocateBufferForInsert(insert_index, count);
544 pos = m_data + insert_index;
545 }
546 else
547 {
548 detail::memMoveImpl(pos+count, a_pos, (end() - pos) * sizeof(T),
549 (Allocator const&)(*this));
550 m_size += count;
551 }
552 detail::initFromListImpl(pos, a_initializer_list,
553 (Allocator const&)(*this));
554 }
555 return pos;
556 }
557
558 template <class InputIt, class bar = typename std::iterator_traits<InputIt>::difference_type>
559 iterator insert (const_iterator a_pos, InputIt a_first, InputIt a_last)
560 {
561 auto* pos = const_cast<iterator>(a_pos);
562 size_type count = std::distance(a_first, a_last);
563 if (count > 0) {
564 if (m_capacity < m_size + count)
565 {
566 std::size_t insert_index = std::distance(m_data, pos);
567 AllocateBufferForInsert(insert_index, count);
568 pos = m_data + insert_index;
569 }
570 else
571 {
572 detail::memMoveImpl(pos+count, a_pos, (end() - pos) * sizeof(T),
573 (Allocator const&)(*this));
574 m_size += count;
575 }
576 // Unfortunately we don't know whether InputIt points
577 // GPU or CPU memory. We will assume it's the same as
578 // the vector.
579 detail::fillValuesImpl(pos, a_first, count,
580 (Allocator const&)(*this));
581 }
582 return pos;
583 }
584
585 void assign (size_type a_count, const T& a_value)
586 {
587 // Copy first because a_value could be a reference to an element of this vector.
588 T const value = a_value;
589 if ( a_count > m_capacity ) {
590 clear();
591 reserve(a_count);
592 }
593 m_size = a_count;
594 detail::uninitializedFillNImpl(m_data, a_count, value,
595 (Allocator const&)(*this));
596 }
597
598 void assign (std::initializer_list<T> a_initializer_list)
599 {
600 if (a_initializer_list.size() > m_capacity) {
601 clear();
602 reserve(a_initializer_list.size());
603 }
604 m_size = a_initializer_list.size();
605 detail::initFromListImpl(m_data, a_initializer_list,
606 (Allocator const&)(*this));
607 }
608
609 template <class InputIt, class bar = typename std::iterator_traits<InputIt>::difference_type>
610 void assign (InputIt a_first, InputIt a_last)
611 {
612 std::size_t count = std::distance(a_first, a_last);
613 if (count > m_capacity) {
614 clear();
615 reserve(count);
616 }
617 m_size = count;
618 detail::fillValuesImpl(m_data, a_first, count,
619 (Allocator const&)(*this));
620 }
621
626 void assign (const T& a_value)
627 {
628 assign(m_size, a_value);
629 }
630
631 [[nodiscard]] allocator_type get_allocator () const noexcept { return *this; }
632
633 void push_back (const T& a_value)
634 {
635 // Copy first because a_value could be a reference to an element of this vector.
636 T const value = a_value;
637 if (m_size == m_capacity) {
638 auto new_capacity = GetNewCapacityForPush();
639 AllocateBufferForPush(new_capacity);
640 }
641 detail::uninitializedFillNImpl(m_data+m_size, 1, value,
642 (Allocator const&)(*this));
643 ++m_size;
644 }
645
646 // Because T is trivial, there is no need for push_back(T&&)
647
648 // Don't have the emplace methods, but not sure how often we use those.
649
650 void pop_back () noexcept { --m_size; }
651
652 void clear () noexcept { m_size = 0; }
653
654 [[nodiscard]] size_type size () const noexcept { return m_size; }
655
656 [[nodiscard]] size_type capacity () const noexcept { return m_capacity; }
657
658 [[nodiscard]] bool empty () const noexcept { return m_size == 0 || m_data == nullptr; } // test m_data to avoid compiler warning
659
660 [[nodiscard]] T& operator[] (size_type a_index) noexcept { return m_data[a_index]; }
661
662 [[nodiscard]] const T& operator[] (size_type a_index) const noexcept { return m_data[a_index]; }
663
664 [[nodiscard]] T& front () noexcept { return *m_data; }
665
666 [[nodiscard]] const T& front () const noexcept { return *m_data; }
667
668 [[nodiscard]] T& back () noexcept { return *(m_data + m_size - 1); }
669
670 [[nodiscard]] const T& back () const noexcept { return *(m_data + m_size - 1); }
671
672 [[nodiscard]] T* data () noexcept { return m_data; }
673
674 [[nodiscard]] const T* data () const noexcept { return m_data; }
675
676 [[nodiscard]] T* dataPtr () noexcept { return m_data; }
677
678 [[nodiscard]] const T* dataPtr () const noexcept { return m_data; }
679
680 [[nodiscard]] iterator begin () noexcept { return m_data; }
681
682 [[nodiscard]] const_iterator begin () const noexcept { return m_data; }
683
684 [[nodiscard]] iterator end () noexcept { return m_data + m_size; }
685
686 [[nodiscard]] const_iterator end () const noexcept { return m_data + m_size; }
687
688 [[nodiscard]] reverse_iterator rbegin () noexcept { return reverse_iterator(end()); }
689
690 [[nodiscard]] const_reverse_iterator rbegin () const noexcept { return const_reverse_iterator(end()); }
691
692 [[nodiscard]] reverse_iterator rend () noexcept { return reverse_iterator(begin()); }
693
694 [[nodiscard]] const_reverse_iterator rend () const noexcept { return const_reverse_iterator(begin()); }
695
696 [[nodiscard]] const_iterator cbegin () const noexcept { return m_data; }
697
698 [[nodiscard]] const_iterator cend () const noexcept { return m_data + m_size; }
699
700 [[nodiscard]] const_reverse_iterator crbegin () const noexcept { return const_reverse_iterator(end()); }
701
702 [[nodiscard]] const_reverse_iterator crend () const noexcept { return const_reverse_iterator(begin()); }
703
734 void resize (size_type a_new_size,
736 {
737 auto old_size = m_size;
738 resize_without_init_snan(a_new_size, strategy);
739 if (old_size < a_new_size) {
740 detail::maybe_init_snan(m_data + old_size,
741 m_size - old_size, (Allocator const&)(*this));
742 }
743 }
744
775 void resize (size_type a_new_size, const T& a_val,
777 {
778 // Copy first because a_val could be a reference to an element of this vector.
779 T const value = a_val;
780 size_type old_size = m_size;
781 resize_without_init_snan(a_new_size, strategy);
782 if (old_size < a_new_size)
783 {
784 detail::uninitializedFillNImpl(m_data + old_size,
785 m_size - old_size, value,
786 (Allocator const&)(*this));
787 }
788 }
789
820 {
821 if (m_capacity < a_capacity) {
822 reserve_doit(grow_podvector_capacity(strategy, a_capacity, m_capacity, sizeof(T)));
823 }
824 }
825
827 {
828 if (m_data != nullptr) {
829 if (m_size == 0) {
830 deallocate(m_data, m_capacity);
831 m_data = nullptr;
832 m_capacity = 0;
833 } else if (m_size < m_capacity) {
834 auto* new_data = detail::shrink_in_place(m_data, m_size,
835 (Allocator&)(*this));
836 if (new_data != m_data) {
837 detail::memCopyImpl(new_data, m_data, nBytes(),
838 (Allocator const&)(*this),
839 (Allocator const&)(*this));
840 deallocate(m_data, m_capacity);
841 }
842 m_data = new_data;
843 m_capacity = m_size;
844 }
845 }
846 }
847
848 void swap (PODVector<T, Allocator>& a_vector) noexcept
849 {
850 std::swap(m_data, a_vector.m_data);
851 std::swap(m_size, a_vector.m_size);
852 std::swap(m_capacity, a_vector.m_capacity);
853 std::swap(static_cast<Allocator&>(a_vector), static_cast<Allocator&>(*this));
854 }
855
861 void free_async () noexcept
862 {
863 if (m_data != nullptr) {
865 Gpu::freeAsync(Allocator::arena(), m_data);
866 } else {
867 deallocate(m_data, capacity());
868 }
869 m_data = nullptr;
870 m_size = 0;
871 m_capacity = 0;
872 }
873 }
874
875 private:
876
877 void reserve_doit (size_type a_capacity) {
878 if (m_capacity < a_capacity) {
879 auto fp = detail::allocate_in_place(m_data, a_capacity, a_capacity,
880 (Allocator&)(*this));
881 UpdateDataPtr(fp);
882 }
883 }
884
885 [[nodiscard]] size_type nBytes () const noexcept
886 {
887 return m_size*sizeof(T);
888 }
889
890 // this is where we would change the growth strategy for push_back
891 [[nodiscard]] size_type GetNewCapacityForPush () const noexcept
892 {
894 m_capacity, sizeof(T));
895 }
896
897 void UpdateDataPtr (FatPtr<T> const& fp)
898 {
899 auto* new_data = fp.ptr();
900 auto new_capacity = fp.size();
901 if (m_data != nullptr && m_data != new_data) {
902 if (m_size > 0) {
903 detail::memCopyImpl(new_data, m_data, nBytes(),
904 (Allocator const&)(*this),
905 (Allocator const&)(*this));
906 }
907 deallocate(m_data, capacity());
908 }
909 m_data = new_data;
910 m_capacity = new_capacity;
911 }
912
913 // This is where we play games with the allocator. This function
914 // updates m_data and m_capacity, but not m_size.
915 void AllocateBufferForPush (size_type target_capacity)
916 {
917 auto fp = detail::allocate_in_place(m_data, m_size+1, target_capacity,
918 (Allocator&)(*this));
919 UpdateDataPtr(fp);
920 }
921
922 // This is where we play games with the allocator and the growth
923 // strategy for insert. This function updates m_data, m_size and
924 // m_capacity.
925 void AllocateBufferForInsert (size_type a_index, size_type a_count)
926 {
927 size_type new_size = m_size + a_count;
928 size_type new_capacity = std::max(new_size, GetNewCapacityForPush());
929 auto fp = detail::allocate_in_place(m_data, new_size, new_capacity,
930 (Allocator&)(*this));
931 auto* new_data = fp.ptr();
932 new_capacity = fp.size();
933
934 if (m_data != nullptr) {
935 if (m_data == new_data) {
936 if (m_size > a_index) {
937 detail::memMoveImpl(m_data+a_index+a_count, m_data+a_index,
938 (m_size-a_index)*sizeof(T),
939 (Allocator const&)(*this));
940 }
941 } else {
942 if (m_size > 0) {
943 if (a_index > 0) {
944 detail::memCopyImpl(new_data, m_data, a_index*sizeof(T),
945 (Allocator const&)(*this),
946 (Allocator const&)(*this), false);
947 }
948 if (m_size > a_index) {
949 detail::memCopyImpl(new_data+a_index+a_count, m_data+a_index,
950 (m_size-a_index)*sizeof(T),
951 (Allocator const&)(*this),
952 (Allocator const&)(*this), false);
953 }
955 }
956 deallocate(m_data, m_capacity);
957 }
958 }
959 m_data = new_data;
960 m_size = new_size;
961 m_capacity = new_capacity;
962 }
963
964 void resize_without_init_snan (size_type a_new_size, GrowthStrategy strategy)
965 {
966 if (m_capacity < a_new_size) {
967 reserve(a_new_size, strategy);
968 }
969 m_size = a_new_size;
970 }
971 };
972}
973
974#endif
Runtime initialization/finalization helpers and global diagnostics.
Memory arena base class and global arena accessors.
Enum reflection utilities and the AMREX_ENUM macro.
#define AMREX_EXPORT
Definition AMReX_Extension.H:223
#define AMREX_GPU_DEVICE
Definition AMReX_GpuQualifiers.H:18
virtual void free(void *pt)=0
Free a previously allocated block pointed to by pt.
virtual void * alloc(std::size_t sz)=0
Allocate sz bytes from this arena.
static void streamSynchronize() noexcept
Definition AMReX_GpuDevice.cpp:861
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:528
void reserve(size_type a_capacity, GrowthStrategy strategy=GrowthStrategy::Poisson)
Definition AMReX_PODVector.H:819
const_iterator begin() const noexcept
Definition AMReX_PODVector.H:682
const_iterator cbegin() const noexcept
Definition AMReX_PODVector.H:696
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:654
const T * const_pointer
Definition AMReX_PODVector.H:328
void swap(PODVector< T, Allocator > &a_vector) noexcept
Definition AMReX_PODVector.H:848
const_reverse_iterator crbegin() const noexcept
Definition AMReX_PODVector.H:700
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:826
void assign(const T &a_value)
Definition AMReX_PODVector.H:626
void pop_back() noexcept
Definition AMReX_PODVector.H:650
iterator insert(const_iterator a_pos, std::initializer_list< T > a_initializer_list)
Definition AMReX_PODVector.H:534
iterator insert(const_iterator a_pos, InputIt a_first, InputIt a_last)
Definition AMReX_PODVector.H:559
T * iterator
Definition AMReX_PODVector.H:324
reverse_iterator rend() noexcept
Definition AMReX_PODVector.H:692
PODVector(size_type a_size)
Definition AMReX_PODVector.H:343
allocator_type get_allocator() const noexcept
Definition AMReX_PODVector.H:631
iterator begin() noexcept
Definition AMReX_PODVector.H:680
void resize(size_type a_new_size, GrowthStrategy strategy=GrowthStrategy::Poisson)
Definition AMReX_PODVector.H:734
void free_async() noexcept
Definition AMReX_PODVector.H:861
void assign(std::initializer_list< T > a_initializer_list)
Definition AMReX_PODVector.H:598
iterator end() noexcept
Definition AMReX_PODVector.H:684
T value_type
Definition AMReX_PODVector.H:317
const T * dataPtr() const noexcept
Definition AMReX_PODVector.H:678
constexpr PODVector() noexcept=default
void assign(size_type a_count, const T &a_value)
Definition AMReX_PODVector.H:585
const_reverse_iterator rbegin() const noexcept
Definition AMReX_PODVector.H:690
std::size_t size_type
Definition AMReX_PODVector.H:319
const_reverse_iterator rend() const noexcept
Definition AMReX_PODVector.H:694
void assign(InputIt a_first, InputIt a_last)
Definition AMReX_PODVector.H:610
T & front() noexcept
Definition AMReX_PODVector.H:664
const_reverse_iterator crend() const noexcept
Definition AMReX_PODVector.H:702
reverse_iterator rbegin() noexcept
Definition AMReX_PODVector.H:688
iterator erase(const_iterator a_first, const_iterator a_last)
Definition AMReX_PODVector.H:487
void clear() noexcept
Definition AMReX_PODVector.H:652
size_type capacity() const noexcept
Definition AMReX_PODVector.H:656
const_iterator cend() const noexcept
Definition AMReX_PODVector.H:698
T * dataPtr() noexcept
Definition AMReX_PODVector.H:676
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:674
const T * const_iterator
Definition AMReX_PODVector.H:329
~PODVector()
Definition AMReX_PODVector.H:411
const_iterator end() const noexcept
Definition AMReX_PODVector.H:686
void resize(size_type a_new_size, const T &a_val, GrowthStrategy strategy=GrowthStrategy::Poisson)
Definition AMReX_PODVector.H:775
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:668
std::ptrdiff_t difference_type
Definition AMReX_PODVector.H:320
const T & back() const noexcept
Definition AMReX_PODVector.H:670
T & operator[](size_type a_index) noexcept
Definition AMReX_PODVector.H:660
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:672
const T & front() const noexcept
Definition AMReX_PODVector.H:666
bool empty() const noexcept
Definition AMReX_PODVector.H:658
void push_back(const T &a_value)
Definition AMReX_PODVector.H:633
Allocator allocator_type
Definition AMReX_PODVector.H:318
amrex_real Real
Floating Point Type for Fields.
Definition AMReX_REAL.H:80
Arena * The_Arena()
Definition AMReX_Arena.cpp:815
#define AMREX_ENUM(CLASS,...)
Declare a scoped enum with reflection support.
Definition AMReX_Enum.H:270
__host__ __device__ bool almostEqual(T x, T y, int ulp=2)
Definition AMReX_Algorithm.H:139
void dtod_memcpy_async(void *p_d_dst, const void *p_d_src, const std::size_t sz) noexcept
Definition AMReX_GpuDevice.H:449
void freeAsync(Arena *arena, void *mem) noexcept
Definition AMReX_GpuDevice.H:345
void streamSynchronize() noexcept
Definition AMReX_GpuDevice.H:310
void dtoh_memcpy_async(void *p_h, const void *p_d, const std::size_t sz) noexcept
Definition AMReX_GpuDevice.H:435
void htod_memcpy_async(void *p_d, const void *p_h, const std::size_t sz) noexcept
Definition AMReX_GpuDevice.H:421
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:50
__host__ __device__ void ignore_unused(const Ts &...)
No-op helper that marks variables as intentionally unused.
Definition AMReX.H:259
bool InitSNaN() noexcept
Whether new allocations are filled with signaling NaNs when enabled.
Definition AMReX.cpp:186
void ParallelFor(TypeList< CTOs... > ctos, std::array< int, sizeof...(CTOs)> const &runtime_options, T N, F &&f)
Definition AMReX_CTOParallelForImpl.H:202
GrowthStrategy
Definition AMReX_PODVector.H:250
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:173