LCOV - code coverage report
Current view: top level - ext/amrex/2d-coverage-g++-24.08/include - AMReX_PODVector.H (source / functions) Hit Total Coverage
Test: coverage_merged.info Lines: 0 5 0.0 %
Date: 2024-11-18 05:28:54 Functions: 0 2 0.0 %

          Line data    Source code
       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_GpuLaunch.H>
       8             : #include <AMReX_GpuAllocators.H>
       9             : #include <AMReX_GpuDevice.H>
      10             : #include <AMReX_MemPool.H>
      11             : #include <AMReX_TypeTraits.H>
      12             : 
      13             : #include <iterator>
      14             : #include <type_traits>
      15             : #include <utility>
      16             : #include <memory>
      17             : #include <cstring>
      18             : 
      19             : namespace amrex
      20             : {
      21             :     namespace detail
      22             :     {
      23             :         template <typename T, typename Size, template<class> class Allocator>
      24             :         FatPtr<T> allocate_in_place ([[maybe_unused]] T* p, [[maybe_unused]] Size nmin, Size nmax,
      25             :                                      Allocator<T>& allocator)
      26             :         {
      27             :             if constexpr (IsArenaAllocator<Allocator<T>>::value) {
      28             :                 return allocator.allocate_in_place(p, nmin, nmax);
      29             :             } else {
      30             :                 T* pnew = allocator.allocate(nmax);
      31             :                 return {pnew, nmax};
      32             :             }
      33             :         }
      34             : 
      35             :         template <typename T, typename Size, template<class> class Allocator>
      36             :         T* shrink_in_place ([[maybe_unused]] T* p, Size n, Allocator<T>& allocator)
      37             :         {
      38             :             if constexpr (IsArenaAllocator<Allocator<T>>::value) {
      39             :                 return allocator.shrink_in_place(p, n);
      40             :             } else {
      41             :                 return allocator.allocate(n);
      42             :             }
      43             :         }
      44             : 
      45             :         template <typename T, typename Size, template<class> class Allocator>
      46             :         void uninitializedFillNImpl (T* data, Size count, const T& value,
      47             :                                      [[maybe_unused]] Allocator<T> const& allocator)
      48             :         {
      49             : #ifdef AMREX_USE_GPU
      50             :             if constexpr (RunOnGpu<Allocator<T>>::value)
      51             :             {
      52             :                 amrex::ParallelFor(count, [=] AMREX_GPU_DEVICE (Size i) noexcept {
      53             :                     data[i] = value;
      54             :                 });
      55             :                 Gpu::streamSynchronize();
      56             :                 return;
      57             :             }
      58             :             else if constexpr (IsPolymorphicArenaAllocator<Allocator<T>>::value)
      59             :             {
      60             :                 if (allocator.arena()->isManaged() ||
      61             :                     allocator.arena()->isDevice())
      62             :                 {
      63             :                     amrex::ParallelFor(count, [=] AMREX_GPU_DEVICE (Size i) noexcept
      64             :                     {
      65             :                         data[i] = value;
      66             :                     });
      67             :                     Gpu::streamSynchronize();
      68             :                     return;
      69             :                 }
      70             :             }
      71             : #endif
      72             :             std::uninitialized_fill_n(data, count, value);
      73             :         }
      74             : 
      75             :         template <typename T, template<class> class Allocator>
      76             :         void initFromListImpl (T* data, std::initializer_list<T> const& list,
      77             :                                [[maybe_unused]] Allocator<T> const & allocator)
      78             :         {
      79             :             auto count = list.size() * sizeof(T);
      80             : #ifdef AMREX_USE_GPU
      81             :             if constexpr (RunOnGpu<Allocator<T>>::value)
      82             :             {
      83             :                 Gpu::htod_memcpy_async(data, std::data(list), count);
      84             :                 Gpu::streamSynchronize();
      85             :                 return;
      86             :             }
      87             :             else if constexpr (IsPolymorphicArenaAllocator<Allocator<T>>::value)
      88             :             {
      89             :                 if (allocator.arena()->isManaged() ||
      90             :                     allocator.arena()->isDevice())
      91             :                 {
      92             :                     Gpu::htod_memcpy_async(data, std::data(list), count);
      93             :                     Gpu::streamSynchronize();
      94             :                     return;
      95             :                 }
      96             :             }
      97             : #endif
      98             :             std::memcpy(data, std::data(list), count);
      99             :         }
     100             : 
     101             :         template <typename T, typename Size, template<class> class Allocator>
     102             :         void fillValuesImpl (T* dst, T const* src, Size count,
     103             :                              [[maybe_unused]] Allocator<T> const& allocator)
     104             :         {
     105             : #ifdef AMREX_USE_GPU
     106             :             if constexpr (RunOnGpu<Allocator<T>>::value)
     107             :             {
     108             :                 amrex::ParallelFor(count, [=] AMREX_GPU_DEVICE (Size i) noexcept {
     109             :                     dst[i] = src[i];
     110             :                 });
     111             :                 Gpu::Device::streamSynchronize();
     112             :                 return;
     113             :             }
     114             :             else if constexpr (IsPolymorphicArenaAllocator<Allocator<T>>::value)
     115             :             {
     116             :                 if (allocator.arena()->isManaged() ||
     117             :                     allocator.arena()->isDevice())
     118             :                 {
     119             :                     amrex::ParallelFor(count, [=] AMREX_GPU_DEVICE (Size i) noexcept
     120             :                     {
     121             :                         dst[i] = src[i];
     122             :                     });
     123             :                     Gpu::streamSynchronize();
     124             :                     return;
     125             :                 }
     126             :             }
     127             : #else
     128             :             static_assert(RunOnGpu<Allocator<T>>::value == false);
     129             : #endif
     130             :             if constexpr (! RunOnGpu<Allocator<T>>::value) {
     131             :                 for (Size i = 0; i < count; ++i) { dst[i] = src[i]; }
     132             :             }
     133             :         }
     134             : 
     135             :         template <typename Allocator>
     136             :         void memCopyImpl (void* dst, const void* src, std::size_t count,
     137             :                           [[maybe_unused]] Allocator const& dst_allocator,
     138             :                           [[maybe_unused]] Allocator const& src_allocator,
     139             :                           [[maybe_unused]] bool sync = true)
     140             :         {
     141             : #ifdef AMREX_USE_GPU
     142             :             if constexpr (RunOnGpu<Allocator>::value)
     143             :             {
     144             :                 Gpu::dtod_memcpy_async(dst, src, count);
     145             :                 if (sync) { Gpu::streamSynchronize(); }
     146             :                 return;
     147             :             }
     148             :             else if constexpr (IsPolymorphicArenaAllocator<Allocator>::value)
     149             :             {
     150             :                 bool dst_on_device = dst_allocator.arena()->isManaged() ||
     151             :                                      dst_allocator.arena()->isDevice();
     152             :                 bool src_on_device = src_allocator.arena()->isManaged() ||
     153             :                                      src_allocator.arena()->isDevice();
     154             :                 if (dst_on_device || src_on_device)
     155             :                 {
     156             :                     if (dst_on_device && src_on_device) {
     157             :                         Gpu::dtod_memcpy_async(dst, src, count);
     158             :                     } else if (dst_on_device) {
     159             :                         Gpu::htod_memcpy_async(dst, src, count);
     160             :                     } else {
     161             :                         Gpu::dtoh_memcpy_async(dst, src, count);
     162             :                     }
     163             :                     if (sync) { Gpu::streamSynchronize(); }
     164             :                     return;
     165             :                 }
     166             :             }
     167             : #endif
     168             :             std::memcpy(dst, src, count);
     169             :         }
     170             : 
     171             :         template <typename Allocator>
     172             :         void memMoveImpl (void* dst, const void* src, std::size_t count,
     173             :                           [[maybe_unused]] Allocator const& allocator)
     174             :         {
     175             : #ifdef AMREX_USE_GPU
     176             :             if constexpr (RunOnGpu<Allocator>::value)
     177             :             {
     178             :                 auto* tmp = The_Arena()->alloc(count);
     179             :                 Gpu::dtod_memcpy_async(tmp, src, count);
     180             :                 Gpu::dtod_memcpy_async(dst, tmp, count);
     181             :                 Gpu::streamSynchronize();
     182             :                 The_Arena()->free(tmp);
     183             :                 return;
     184             :             }
     185             :             else if constexpr (IsPolymorphicArenaAllocator<Allocator>::value)
     186             :             {
     187             :                 if (allocator.arena()->isManaged() ||
     188             :                     allocator.arena()->isDevice())
     189             :                 {
     190             :                     auto* tmp = The_Arena()->alloc(count);
     191             :                     Gpu::dtod_memcpy_async(tmp, src, count);
     192             :                     Gpu::dtod_memcpy_async(dst, tmp, count);
     193             :                     Gpu::streamSynchronize();
     194             :                     The_Arena()->free(tmp);
     195             :                     return;
     196             :                 }
     197             :             }
     198             : #endif
     199             :             std::memmove(dst, src, count);
     200             :         }
     201             : 
     202             :         template <typename T, typename Size, template<class> class Allocator>
     203             :         void maybe_init_snan (T* data, Size count, Allocator<T> const& allocator)
     204             :         {
     205             :             amrex::ignore_unused(data, count, allocator);
     206             :             if constexpr (std::is_same_v<float,  std::remove_cv_t<T>> ||
     207             :                           std::is_same_v<double, std::remove_cv_t<T>>) {
     208             :                 if (amrex::InitSNaN()) {
     209             : #ifdef AMREX_USE_GPU
     210             :                    if constexpr (RunOnGpu<Allocator<T>>::value) {
     211             :                        amrex::fill_snan<RunOn::Device>(data, count);
     212             :                        Gpu::streamSynchronize();
     213             :                        return;
     214             :                    } else if constexpr (IsPolymorphicArenaAllocator<Allocator<T>>::value) {
     215             :                        if (allocator.arena()->isManaged() ||
     216             :                            allocator.arena()->isDevice())
     217             :                        {
     218             :                            amrex::fill_snan<RunOn::Device>(data, count);
     219             :                            Gpu::streamSynchronize();
     220             :                            return;
     221             :                        }
     222             :                    }
     223             : #endif
     224             :                    amrex::fill_snan<RunOn::Host>(data, count);
     225             :                 }
     226             :             }
     227             :         }
     228             :     }
     229             : 
     230             :     namespace VectorGrowthStrategy
     231             :     {
     232             :         extern AMREX_EXPORT Real growth_factor;
     233             :         inline Real GetGrowthFactor () { return growth_factor; }
     234             :         inline void SetGrowthFactor (Real a_factor);
     235             : 
     236             :         namespace detail
     237             :         {
     238             :             void ValidateUserInput ();
     239             :         }
     240             : 
     241             :         void Initialize ();
     242             :     }
     243             : 
     244             :     template <class T, class Allocator = std::allocator<T> >
     245             :     class PODVector : public Allocator
     246             :     {
     247             :         //        static_assert(std::is_standard_layout<T>(), "PODVector can only hold standard layout types");
     248             :         static_assert(std::is_trivially_copyable<T>(), "PODVector can only hold trivially copyable types");
     249             :         //        static_assert(std::is_trivially_default_constructible<T>(), "PODVector can only hold trivial dc types");
     250             : 
     251             :         using Allocator::allocate;
     252             :         using Allocator::deallocate;
     253             : 
     254             :     public:
     255             :         using value_type      = T;
     256             :         using allocator_type  = Allocator;
     257             :         using size_type       = std::size_t;
     258             :         using difference_type = std::ptrdiff_t;
     259             : 
     260             :         using reference        = T&;
     261             :         using pointer          = T*;
     262             :         using iterator         = T*;
     263             :         using reverse_iterator = std::reverse_iterator<iterator>;
     264             : 
     265             :         using const_reference        = const T&;
     266             :         using const_pointer          = const T*;
     267             :         using const_iterator         = const T*;
     268             :         using const_reverse_iterator = std::reverse_iterator<const_iterator>;
     269             : 
     270             :     private:
     271             :         pointer m_data = nullptr;
     272             :         size_type m_size{0}, m_capacity{0};
     273             : 
     274             :     public:
     275             :         constexpr PODVector () noexcept = default;
     276             : 
     277             :         constexpr explicit PODVector (const allocator_type& a_allocator) noexcept
     278             :             : Allocator(a_allocator)
     279             :         {}
     280             : 
     281             :         explicit PODVector (size_type a_size)
     282             :             : m_size(a_size), m_capacity(a_size)
     283             :         {
     284             :             if (a_size != 0) {
     285             :                 m_data = allocate(m_size);
     286             :                 detail::maybe_init_snan(m_data, m_size, (Allocator const&)(*this));
     287             :             }
     288             :         }
     289             : 
     290             :         PODVector (size_type a_size, const value_type& a_value,
     291             :                    const allocator_type& a_allocator = Allocator())
     292             :             : Allocator(a_allocator), m_size(a_size), m_capacity(a_size)
     293             :         {
     294             :             if (a_size != 0) {
     295             :                 m_data = allocate(m_size);
     296             :                 detail::uninitializedFillNImpl(m_data, a_size, a_value,
     297             :                                                (Allocator const&)(*this));
     298             :             }
     299             :         }
     300             : 
     301             :         PODVector (std::initializer_list<T> a_initializer_list,
     302             :                    const allocator_type& a_allocator = Allocator())
     303             :             : Allocator(a_allocator),
     304             :               m_size    (a_initializer_list.size()),
     305             :               m_capacity(a_initializer_list.size())
     306             :         {
     307             :             if (a_initializer_list.size() != 0) {
     308             :                 m_data = allocate(m_size);
     309             :                 detail::initFromListImpl(m_data, a_initializer_list,
     310             :                                          (Allocator const&)(*this));
     311             :             }
     312             :         }
     313             : 
     314             :         PODVector (const PODVector<T, Allocator>& a_vector)
     315             :             : Allocator(a_vector),
     316             :               m_size    (a_vector.size()),
     317             :               m_capacity(a_vector.size())
     318             :         {
     319             :             if (a_vector.size() != 0) {
     320             :                 m_data = allocate(m_size);
     321             :                 detail::memCopyImpl(m_data, a_vector.m_data, a_vector.nBytes(),
     322             :                                     (Allocator const&)(*this),
     323             :                                     (Allocator const&)a_vector);
     324             :             }
     325             :         }
     326             : 
     327             :         PODVector (PODVector<T, Allocator>&& a_vector) noexcept
     328             :             : Allocator(static_cast<Allocator&&>(a_vector)),
     329             :               m_data(a_vector.m_data),
     330             :               m_size(a_vector.m_size),
     331             :               m_capacity(a_vector.m_capacity)
     332             :         {
     333             :             a_vector.m_data = nullptr;
     334             :             a_vector.m_size = 0;
     335             :             a_vector.m_capacity = 0;
     336             :         }
     337             : 
     338           0 :         ~PODVector ()
     339             :         {
     340             :             // let's not worry about other allocators
     341             :             static_assert(std::is_same<Allocator,std::allocator<T>>::value ||
     342             :                           IsArenaAllocator<Allocator>::value);
     343           0 :             if (m_data != nullptr) {
     344           0 :                 deallocate(m_data, capacity());
     345             :             }
     346           0 :         }
     347             : 
     348             :         PODVector& operator= (const PODVector<T, Allocator>& a_vector)
     349             :         {
     350             :             if (this == &a_vector) { return *this; }
     351             : 
     352             :             if ((Allocator const&)(*this) != (Allocator const&)a_vector) {
     353             :                 if (m_data != nullptr) {
     354             :                     deallocate(m_data, m_capacity);
     355             :                     m_data = nullptr;
     356             :                     m_size = 0;
     357             :                     m_capacity = 0;
     358             :                 }
     359             :                 (Allocator&)(*this) = (Allocator const&)a_vector;
     360             :             }
     361             : 
     362             :             const auto other_size = a_vector.size();
     363             :             if ( other_size > m_capacity ) {
     364             :                 clear();
     365             :                 reserve(other_size);
     366             :             }
     367             : 
     368             :             m_size = other_size;
     369             :             if (m_size > 0) {
     370             :                 detail::memCopyImpl(m_data, a_vector.m_data, nBytes(),
     371             :                                     (Allocator const&)(*this),
     372             :                                     (Allocator const&)a_vector);
     373             :             }
     374             :             return *this;
     375             :         }
     376             : 
     377             :         PODVector& operator= (PODVector<T, Allocator>&& a_vector) noexcept
     378             :         {
     379             :             if (this == &a_vector) { return *this; }
     380             : 
     381             :             if (static_cast<Allocator const&>(a_vector) ==
     382             :                 static_cast<Allocator const&>(*this))
     383             :             {
     384             :                 if (m_data != nullptr) {
     385             :                     deallocate(m_data, m_capacity);
     386             :                 }
     387             : 
     388             :                 m_data = a_vector.m_data;
     389             :                 m_size = a_vector.m_size;
     390             :                 m_capacity = a_vector.m_capacity;
     391             : 
     392             :                 a_vector.m_data = nullptr;
     393             :                 a_vector.m_size = 0;
     394             :                 a_vector.m_capacity = 0;
     395             :             }
     396             :             else
     397             :             {
     398             :                 // if the allocators are not the same we give up and copy
     399             :                 *this = a_vector; // must copy instead of move
     400             :             }
     401             : 
     402             :             return *this;
     403             :         }
     404             : 
     405             :         iterator erase (const_iterator a_pos)
     406             :         {
     407             :             auto* pos = const_cast<iterator>(a_pos);
     408             :             --m_size;
     409             :             detail::memMoveImpl(pos, a_pos+1, (end() - pos)*sizeof(T),
     410             :                                 (Allocator const&)(*this));
     411             :             return pos;
     412             :         }
     413             : 
     414             :         iterator erase (const_iterator a_first, const_iterator a_last)
     415             :         {
     416             :             size_type num_to_erase = a_last - a_first;
     417             :             auto* first = const_cast<iterator>(a_first);
     418             :             if (num_to_erase > 0) {
     419             :                 m_size -= num_to_erase;
     420             :                 detail::memMoveImpl(first, a_last, (end() - first)*sizeof(T),
     421             :                                     (Allocator const&)(*this));
     422             :             }
     423             :             return first;
     424             :         }
     425             : 
     426             :         iterator insert (const_iterator a_pos, const T& a_item)
     427             :         {
     428             :             return insert(a_pos, 1, a_item);
     429             :         }
     430             : 
     431             :         iterator insert (const_iterator a_pos, size_type a_count, const T& a_value)
     432             :         {
     433             :             auto* pos = const_cast<iterator>(a_pos);
     434             :             if (a_count > 0) {
     435             :                 if (m_capacity < m_size + a_count)
     436             :                 {
     437             :                     std::size_t insert_index = std::distance(m_data, pos);
     438             :                     AllocateBufferForInsert(insert_index, a_count);
     439             :                     pos = m_data + insert_index;
     440             :                 }
     441             :                 else
     442             :                 {
     443             :                     detail::memMoveImpl(pos+a_count, a_pos, (end() - pos) * sizeof(T),
     444             :                                         (Allocator const&)(*this));
     445             :                     m_size += a_count;
     446             :                 }
     447             :                 detail::uninitializedFillNImpl(pos, a_count, a_value,
     448             :                                                (Allocator const&)(*this));
     449             :             }
     450             :             return pos;
     451             :         }
     452             : 
     453             :         iterator insert (const_iterator a_pos, T&& a_item)
     454             :         {
     455             :             // This is *POD* vector after all
     456             :             return insert(a_pos, 1, std::move(a_item));
     457             :         }
     458             : 
     459             :         iterator insert (const_iterator a_pos,
     460             :                          std::initializer_list<T> a_initializer_list)
     461             :         {
     462             :             auto* pos = const_cast<iterator>(a_pos);
     463             :             size_type count = a_initializer_list.size();
     464             :             if (count > 0) {
     465             :                 if (m_capacity < m_size + count)
     466             :                 {
     467             :                     std::size_t insert_index = std::distance(m_data, pos);
     468             :                     AllocateBufferForInsert(insert_index, count);
     469             :                     pos = m_data + insert_index;
     470             :                 }
     471             :                 else
     472             :                 {
     473             :                     detail::memMoveImpl(pos+count, a_pos, (end() - pos) * sizeof(T),
     474             :                                         (Allocator const&)(*this));
     475             :                     m_size += count;
     476             :                 }
     477             :                 detail::initFromListImpl(pos, a_initializer_list,
     478             :                                          (Allocator const&)(*this));
     479             :             }
     480             :             return pos;
     481             :         }
     482             : 
     483             :         template <class InputIt, class bar = typename std::iterator_traits<InputIt>::difference_type>
     484             :         iterator insert (const_iterator a_pos, InputIt a_first, InputIt a_last)
     485             :         {
     486             :             auto* pos = const_cast<iterator>(a_pos);
     487             :             size_type count = std::distance(a_first, a_last);
     488             :             if (count > 0) {
     489             :                 if (m_capacity < m_size + count)
     490             :                 {
     491             :                     std::size_t insert_index = std::distance(m_data, pos);
     492             :                     AllocateBufferForInsert(insert_index, count);
     493             :                     pos = m_data + insert_index;
     494             :                 }
     495             :                 else
     496             :                 {
     497             :                     detail::memMoveImpl(pos+count, a_pos, (end() - pos) * sizeof(T),
     498             :                                         (Allocator const&)(*this));
     499             :                     m_size += count;
     500             :                 }
     501             :                 // Unfortunately we don't know whether InputIt points
     502             :                 // GPU or CPU memory. We will assume it's the same as
     503             :                 // the vector.
     504             :                 detail::fillValuesImpl(pos, a_first, count,
     505             :                                        (Allocator const&)(*this));
     506             :             }
     507             :             return pos;
     508             :         }
     509             : 
     510             :         void assign (size_type a_count, const T& a_value)
     511             :         {
     512             :             if ( a_count > m_capacity ) {
     513             :                 clear();
     514             :                 reserve(a_count);
     515             :             }
     516             :             m_size = a_count;
     517             :             detail::uninitializedFillNImpl(m_data, a_count, a_value,
     518             :                                            (Allocator const&)(*this));
     519             :         }
     520             : 
     521             :         void assign (std::initializer_list<T> a_initializer_list)
     522             :         {
     523             :             if (a_initializer_list.size() > m_capacity) {
     524             :                 clear();
     525             :                 reserve(a_initializer_list.size());
     526             :             }
     527             :             m_size = a_initializer_list.size();
     528             :             detail::initFromListImpl(m_data, a_initializer_list,
     529             :                                      (Allocator const&)(*this));
     530             :         }
     531             : 
     532             :         template <class InputIt, class bar = typename std::iterator_traits<InputIt>::difference_type>
     533             :         void assign (InputIt a_first, InputIt a_last)
     534             :         {
     535             :             std::size_t count = std::distance(a_first, a_last);
     536             :             if (count > m_capacity) {
     537             :                 clear();
     538             :                 reserve(count);
     539             :             }
     540             :             m_size = count;
     541             :             detail::fillValuesImpl(m_data, a_first, count,
     542             :                                    (Allocator const&)(*this));
     543             :         }
     544             : 
     545             :         /** Set the same value to every element of the vector
     546             :          *
     547             :          * @param a_value the value to assign
     548             :          */
     549             :         void assign (const T& a_value)
     550             :         {
     551             :             assign(m_size, a_value);
     552             :         }
     553             : 
     554             :         [[nodiscard]] allocator_type get_allocator () const noexcept { return *this; }
     555             : 
     556             :         void push_back (const T& a_value)
     557             :         {
     558             :             if (m_size == m_capacity) {
     559             :                 auto new_capacity = GetNewCapacityForPush();
     560             :                 AllocateBufferForPush(new_capacity);
     561             :             }
     562             :             detail::uninitializedFillNImpl(m_data+m_size, 1, a_value,
     563             :                                            (Allocator const&)(*this));
     564             :             ++m_size;
     565             :         }
     566             : 
     567             :         // Because T is trivial, there is no need for push_back(T&&)
     568             : 
     569             :         // Don't have the emplace methods, but not sure how often we use those.
     570             : 
     571             :         void pop_back () noexcept { --m_size; }
     572             : 
     573             :         void clear () noexcept { m_size = 0; }
     574             : 
     575             :         [[nodiscard]] size_type size () const noexcept { return m_size; }
     576             : 
     577           0 :         [[nodiscard]] size_type capacity () const noexcept { return m_capacity; }
     578             : 
     579             :         [[nodiscard]] bool empty () const noexcept { return m_size == 0; }
     580             : 
     581             :         [[nodiscard]] T& operator[] (size_type a_index) noexcept { return m_data[a_index]; }
     582             : 
     583             :         [[nodiscard]] const T& operator[] (size_type a_index) const noexcept { return m_data[a_index]; }
     584             : 
     585             :         [[nodiscard]] T& front () noexcept { return *m_data; }
     586             : 
     587             :         [[nodiscard]] const T& front () const noexcept { return *m_data; }
     588             : 
     589             :         [[nodiscard]] T& back () noexcept { return *(m_data + m_size - 1); }
     590             : 
     591             :         [[nodiscard]] const T& back () const noexcept { return *(m_data + m_size - 1); }
     592             : 
     593             :         [[nodiscard]] T* data () noexcept { return m_data; }
     594             : 
     595             :         [[nodiscard]] const T* data () const noexcept { return m_data; }
     596             : 
     597             :         [[nodiscard]] T* dataPtr () noexcept { return m_data; }
     598             : 
     599             :         [[nodiscard]] const T* dataPtr () const noexcept { return m_data; }
     600             : 
     601             :         [[nodiscard]] iterator begin () noexcept { return m_data; }
     602             : 
     603             :         [[nodiscard]] const_iterator begin () const noexcept { return m_data; }
     604             : 
     605             :         [[nodiscard]] iterator end () noexcept { return m_data + m_size; }
     606             : 
     607             :         [[nodiscard]] const_iterator end () const noexcept { return m_data + m_size; }
     608             : 
     609             :         [[nodiscard]] reverse_iterator rbegin () noexcept { return reverse_iterator(end()); }
     610             : 
     611             :         [[nodiscard]] const_reverse_iterator rbegin () const noexcept { return const_reverse_iterator(end()); }
     612             : 
     613             :         [[nodiscard]] reverse_iterator rend () noexcept { return reverse_iterator(begin()); }
     614             : 
     615             :         [[nodiscard]] const_reverse_iterator rend () const noexcept { return const_reverse_iterator(begin()); }
     616             : 
     617             :         [[nodiscard]] const_iterator cbegin () const noexcept { return m_data; }
     618             : 
     619             :         [[nodiscard]] const_iterator cend () const noexcept { return m_data + m_size; }
     620             : 
     621             :         [[nodiscard]] const_reverse_iterator crbegin () const noexcept { return const_reverse_iterator(end()); }
     622             : 
     623             :         [[nodiscard]] const_reverse_iterator crend () const noexcept { return const_reverse_iterator(begin()); }
     624             : 
     625             :         void resize (size_type a_new_size)
     626             :         {
     627             :             auto old_size = m_size;
     628             :             resize_without_init_snan(a_new_size);
     629             :             if (old_size < a_new_size) {
     630             :                 detail::maybe_init_snan(m_data + old_size,
     631             :                                         m_size - old_size, (Allocator const&)(*this));
     632             :             }
     633             :         }
     634             : 
     635             :         void resize (size_type a_new_size, const T& a_val)
     636             :         {
     637             :             size_type old_size = m_size;
     638             :             resize_without_init_snan(a_new_size);
     639             :             if (old_size < a_new_size)
     640             :             {
     641             :                 detail::uninitializedFillNImpl(m_data + old_size,
     642             :                                                m_size - old_size, a_val,
     643             :                                                (Allocator const&)(*this));
     644             :             }
     645             :         }
     646             : 
     647             :         void reserve (size_type a_capacity)
     648             :         {
     649             :             if (m_capacity < a_capacity) {
     650             :                 auto fp = detail::allocate_in_place(m_data, a_capacity, a_capacity,
     651             :                                                     (Allocator&)(*this));
     652             :                 UpdateDataPtr(fp);
     653             :             }
     654             :         }
     655             : 
     656             :         void shrink_to_fit ()
     657             :         {
     658             :             if (m_data != nullptr) {
     659             :                 if (m_size == 0) {
     660             :                     deallocate(m_data, m_capacity);
     661             :                     m_data = nullptr;
     662             :                     m_capacity = 0;
     663             :                 } else if (m_size < m_capacity) {
     664             :                     auto* new_data = detail::shrink_in_place(m_data, m_size,
     665             :                                                              (Allocator&)(*this));
     666             :                     if (new_data != m_data) {
     667             :                         detail::memCopyImpl(new_data, m_data, nBytes(),
     668             :                                             (Allocator const&)(*this),
     669             :                                             (Allocator const&)(*this));
     670             :                         deallocate(m_data, m_capacity);
     671             :                     }
     672             :                     m_capacity = m_size;
     673             :                 }
     674             :             }
     675             :         }
     676             : 
     677             :         void swap (PODVector<T, Allocator>& a_vector) noexcept
     678             :         {
     679             :             std::swap(m_data, a_vector.m_data);
     680             :             std::swap(m_size, a_vector.m_size);
     681             :             std::swap(m_capacity, a_vector.m_capacity);
     682             :             std::swap(static_cast<Allocator&>(a_vector), static_cast<Allocator&>(*this));
     683             :         }
     684             : 
     685             :     private:
     686             : 
     687             :         [[nodiscard]] size_type nBytes () const noexcept
     688             :         {
     689             :             return m_size*sizeof(T);
     690             :         }
     691             : 
     692             :         // this is where we would change the growth strategy for push_back
     693             :         [[nodiscard]] size_type GetNewCapacityForPush () const noexcept
     694             :         {
     695             :             if (m_capacity == 0) {
     696             :                 return std::max(64/sizeof(T), size_type(1));
     697             :             } else {
     698             :                 Real const gf = VectorGrowthStrategy::GetGrowthFactor();
     699             :                 if (amrex::almostEqual(gf, Real(1.5))) {
     700             :                     return (m_capacity*3+1)/2;
     701             :                 } else {
     702             :                     return size_type(gf*Real(m_capacity+1));
     703             :                 }
     704             :             }
     705             :         }
     706             : 
     707             :         void UpdateDataPtr (FatPtr<T> const& fp)
     708             :         {
     709             :             auto* new_data = fp.ptr();
     710             :             auto new_capacity = fp.size();
     711             :             if (m_data != nullptr && m_data != new_data) {
     712             :                 if (m_size > 0) {
     713             :                     detail::memCopyImpl(new_data, m_data, nBytes(),
     714             :                                         (Allocator const&)(*this),
     715             :                                         (Allocator const&)(*this));
     716             :                 }
     717             :                 deallocate(m_data, capacity());
     718             :             }
     719             :             m_data = new_data;
     720             :             m_capacity = new_capacity;
     721             :         }
     722             : 
     723             :         // This is where we play games with the allocator. This function
     724             :         // updates m_data and m_capacity, but not m_size.
     725             :         void AllocateBufferForPush (size_type target_capacity)
     726             :         {
     727             :             auto fp = detail::allocate_in_place(m_data, m_size+1, target_capacity,
     728             :                                                 (Allocator&)(*this));
     729             :             UpdateDataPtr(fp);
     730             :         }
     731             : 
     732             :         // This is where we play games with the allocator and the growth
     733             :         // strategy for insert. This function updates m_data, m_size and
     734             :         // m_capacity.
     735             :         void AllocateBufferForInsert (size_type a_index, size_type a_count)
     736             :         {
     737             :             size_type new_size = m_size + a_count;
     738             :             size_type new_capacity = std::max(new_size, GetNewCapacityForPush());
     739             :             auto fp = detail::allocate_in_place(m_data, new_size, new_capacity,
     740             :                                                 (Allocator&)(*this));
     741             :             auto* new_data = fp.ptr();
     742             :             new_capacity = fp.size();
     743             : 
     744             :             if (m_data != nullptr) {
     745             :                 if (m_data == new_data) {
     746             :                     if (m_size > a_index) {
     747             :                         detail::memMoveImpl(m_data+a_index+a_count, m_data+a_index,
     748             :                                             (m_size-a_index)*sizeof(T),
     749             :                                             (Allocator const&)(*this));
     750             :                     }
     751             :                 } else {
     752             :                     if (m_size > 0) {
     753             :                         if (a_index > 0) {
     754             :                             detail::memCopyImpl(new_data, m_data, a_index*sizeof(T),
     755             :                                                 (Allocator const&)(*this),
     756             :                                                 (Allocator const&)(*this), false);
     757             :                         }
     758             :                         if (m_size > a_index) {
     759             :                             detail::memCopyImpl(new_data+a_index+a_count, m_data+a_index,
     760             :                                                 (m_size-a_index)*sizeof(T),
     761             :                                                 (Allocator const&)(*this),
     762             :                                                 (Allocator const&)(*this), false);
     763             :                         }
     764             :                         Gpu::streamSynchronize();
     765             :                     }
     766             :                     deallocate(m_data, m_capacity);
     767             :                 }
     768             :             }
     769             :             m_data = new_data;
     770             :             m_size = new_size;
     771             :             m_capacity = new_capacity;
     772             :         }
     773             : 
     774             :         void resize_without_init_snan (size_type a_new_size)
     775             :         {
     776             :             if (m_capacity < a_new_size) {
     777             :                 reserve(a_new_size);
     778             :             }
     779             :             m_size = a_new_size;
     780             :         }
     781             :     };
     782             : }
     783             : 
     784             : #endif

Generated by: LCOV version 1.14