1 // license:GPL-2.0+ 2 // copyright-holders:Couriersud 3 4 #ifndef PARRAY_H_ 5 #define PARRAY_H_ 6 7 /// 8 /// \file parray.h 9 /// 10 11 #include "palloc.h" 12 #include "pconfig.h" 13 #include "pexception.h" 14 15 #include <array> 16 #include <memory> 17 #include <string> 18 #include <type_traits> 19 #include <utility> 20 #include <vector> 21 22 namespace plib { 23 24 template <typename FT, int SIZE, typename ARENA> 25 struct sizeabs 26 { ABSsizeabs27 static constexpr std::size_t ABS() noexcept { return (SIZE < 0) ? narrow_cast<std::size_t>(0 - SIZE) : narrow_cast<std::size_t>(SIZE); } 28 using container = typename std::array<FT, ABS()> ; 29 }; 30 31 template <typename FT, typename ARENA> 32 struct sizeabs<FT, 0, ARENA> 33 { 34 static constexpr std::size_t ABS() noexcept { return 0; } 35 using allocator_type = typename ARENA::template allocator_type<FT, PALIGN_VECTOROPT>; 36 //using container = typename std::vector<FT, arena_allocator<mempool, FT, 64>>; 37 using container = typename std::vector<FT, allocator_type>; 38 }; 39 40 /// \brief Array with preallocated or dynamic allocation. 41 /// 42 /// Passing SIZE > 0 has the same functionality as a std::array. 43 /// SIZE = 0 is pure dynamic allocation, the actual array size is passed to the 44 /// constructor. 45 /// SIZE < 0 reserves abs(SIZE) elements statically in place allocated. The 46 /// actual size is passed in by the constructor. 47 /// This array is purely intended for HPC application where depending on the 48 /// architecture a preference dynamic/static has to be made. 49 /// 50 /// This struct is not intended to be a full replacement to std::array. 51 /// It is a subset to enable switching between dynamic and static allocation. 52 /// I consider > 10% performance difference to be a use case. 53 /// 54 55 template <typename FT, int SIZE, typename ARENA = aligned_arena> 56 struct parray 57 { 58 public: 59 static constexpr std::size_t SIZEABS() noexcept { return sizeabs<FT, SIZE, ARENA>::ABS(); } 60 61 using base_type = typename sizeabs<FT, SIZE, ARENA>::container; 62 using size_type = typename base_type::size_type; 63 using value_type = FT; 64 using reference = FT &; 65 using const_reference = const FT &; 66 67 using pointer = FT *; 68 using const_pointer = const FT *; 69 70 template <int X = SIZE > 71 parray(size_type size, std::enable_if_t<(X==0), int> = 0) 72 : m_a(size), m_size(size) 73 { 74 } 75 76 template <int X = SIZE > 77 parray(size_type size, const FT &val, std::enable_if_t<(X==0), int> = 0) 78 : m_a(size, val), m_size(size) 79 { 80 } 81 82 template <int X = SIZE > 83 parray(size_type size, std::enable_if_t<(X != 0), int> = 0) noexcept(false) 84 : m_size(size) 85 { 86 if ((SIZE < 0 && size > SIZEABS()) 87 || (SIZE > 0 && size != SIZEABS())) 88 throw pexception(pfmt("parray: size error: {1} > {2}")(size, SIZE)); 89 } 90 91 template <int X = SIZE > 92 parray(size_type size, const FT &val, std::enable_if_t<(X != 0), int> = 0) noexcept(false) 93 : m_size(size) 94 { 95 if ((SIZE < 0 && size > SIZEABS()) 96 || (SIZE > 0 && size != SIZEABS())) 97 throw pexception(pfmt("parray: size error: {1} > {2}")(size, SIZE)); 98 m_a.fill(val); 99 } 100 101 102 // allow construction in fixed size arrays 103 parray() 104 : m_size(SIZEABS()) 105 { 106 } 107 108 parray(const parray &rhs) : m_a(rhs.m_a), m_size(rhs.m_size) {} 109 parray(parray &&rhs) noexcept : m_a(std::move(rhs.m_a)), m_size(std::move(rhs.m_size)) {} 110 111 parray &operator=(const parray &rhs) noexcept // NOLINT(bugprone-unhandled-self-assignment, cert-oop54-cpp) 112 { 113 if (this == &rhs) 114 return *this; 115 116 m_a = rhs.m_a; 117 m_size = rhs.m_size; 118 return *this; 119 } 120 121 parray &operator=(parray &&rhs) noexcept { std::swap(m_a,rhs.m_a); std::swap(m_size, rhs.m_size); return *this; } 122 123 ~parray() noexcept = default; 124 125 base_type &as_base() noexcept { return m_a; } 126 127 constexpr size_type size() const noexcept { return SIZE <= 0 ? m_size : SIZEABS(); } 128 129 constexpr size_type max_size() const noexcept { return base_type::max_size(); } 130 131 bool empty() const noexcept { return size() == 0; } 132 133 constexpr reference operator[](size_type i) noexcept 134 { 135 return m_a[i]; 136 } 137 constexpr const_reference operator[](size_type i) const noexcept 138 { 139 return m_a[i]; 140 } 141 142 pointer data() noexcept { return m_a.data(); } 143 const_pointer data() const noexcept { return m_a.data(); } 144 145 private: 146 PALIGNAS_VECTOROPT() 147 base_type m_a; 148 size_type m_size; 149 }; 150 151 template <typename FT, int SIZE1, int SIZE2> 152 struct parray2D : public parray<parray<FT, SIZE2>, SIZE1> 153 { 154 public: 155 156 using size_type = std::size_t; 157 using base_type = parray<parray<FT, SIZE2>, SIZE1>; 158 159 parray2D(size_type size1, size_type size2) 160 : parray<parray<FT, SIZE2>, SIZE1>(size1) 161 { 162 if (SIZE2 <= 0) 163 { 164 for (size_type i=0; i < this->size(); i++) 165 (*this)[i] = parray<FT, SIZE2>(size2); 166 } 167 } 168 169 parray2D(const parray2D &) = default; 170 parray2D &operator=(const parray2D &) = default; 171 parray2D(parray2D &&) noexcept(std::is_nothrow_move_constructible<base_type>::value) = default; 172 parray2D &operator=(parray2D &&) noexcept(std::is_nothrow_move_assignable<base_type>::value) = default; 173 174 ~parray2D() noexcept = default; 175 176 }; 177 178 } // namespace plib 179 180 181 182 #endif // PARRAY_H_ 183