list.hpp (7887B)
1 #pragma once 2 #include <cstddef> 3 #include <iostream> 4 #include <utility> 5 #include <memory> 6 7 namespace spank_olm 8 { 9 // Possibly should be replaced by implace_vector. For example https://godbolt.org/z/5P78aG5xE 10 11 /** 12 * \brief A fixed-size array implementation. 13 * 14 * \tparam T The type of elements stored in the array. 15 * \tparam max_size The maximum number of elements the array can hold. 16 */ 17 template <typename T, std::size_t max_size> 18 class FixedSizeArray 19 { 20 public: 21 /** 22 * \brief Constructs an empty FixedSizeArray. 23 */ 24 FixedSizeArray() : current_size(0) 25 { 26 data = std::make_unique<T*[]>(max_size + 1); 27 } 28 29 /** 30 * \brief Copy constructor. 31 * 32 * \param other The FixedSizeArray to copy from. 33 */ 34 FixedSizeArray(const FixedSizeArray& other) 35 : current_size(other.current_size) 36 { 37 data = std::make_unique<T*[]>(max_size + 1); 38 for (std::size_t i = 0; i < other.current_size; ++i) 39 { 40 data[i] = new T(*other.data[i]); 41 } 42 } 43 44 45 /** 46 * \brief Destroys the FixedSizeArray and frees allocated memory. 47 */ 48 ~FixedSizeArray() 49 { 50 clear(); 51 } 52 53 // Error codes 54 enum ErrorCode 55 { 56 SUCCESS = 0, ///< Operation was successful. 57 INDEX_OUT_OF_RANGE = 1 ///< Index was out of range. 58 }; 59 60 /** 61 * \brief Inserts a value at the beginning of the array. 62 * 63 * \param value The value to insert. 64 * \return ErrorCode indicating the result of the operation. 65 */ 66 constexpr ErrorCode insert(const T& value) 67 { 68 return insert_at(0, value); 69 } 70 71 /** 72 * \brief Inserts a value at a specified index in the array. 73 * 74 * \param index The index at which to insert the value. 75 * \param value The value to insert. 76 * \return ErrorCode indicating the result of the operation. 77 */ 78 constexpr ErrorCode insert_at(std::size_t index, const T& value) 79 { 80 if (index > current_size) 81 { 82 return INDEX_OUT_OF_RANGE; 83 } 84 if (current_size < max_size) 85 { 86 // Shift elements to the right 87 for (std::size_t i = current_size; i > index; --i) 88 { 89 data[i] = std::move(data[i - 1]); 90 } 91 data[index] = new T(value); 92 ++current_size; 93 } 94 else 95 { 96 // Drop the last element and shift others to the right 97 delete data[max_size - 1]; 98 for (std::size_t i = max_size - 1; i > index; --i) 99 { 100 data[i] = std::move(data[i - 1]); 101 } 102 data[index] = new T(value); 103 } 104 105 return SUCCESS; 106 } 107 108 /** 109 * \brief Erases the element at a specified index. 110 * 111 * \param index_given The index of the element to erase. 112 * \return ErrorCode indicating the result of the operation. 113 */ 114 constexpr ErrorCode erase_at(const std::size_t index_given) 115 { 116 // The list behaves reversed to the array, so we need to reverse the index 117 const std::size_t index = current_size - index_given - 1; 118 119 if (index >= current_size) 120 { 121 return INDEX_OUT_OF_RANGE; 122 } 123 delete data[index]; 124 for (std::size_t i = index; i < current_size - 1; ++i) 125 { 126 data[i] = std::move(data[i + 1]); 127 } 128 --current_size; 129 return SUCCESS; 130 } 131 132 /** 133 * \brief Erases the element at the specified pointer position. 134 * 135 * \param ptr The pointer to the element to erase. 136 * \return ErrorCode indicating the result of the operation. 137 */ 138 constexpr ErrorCode erase(T* const ptr) 139 { 140 for (std::size_t i = 0; i < current_size; ++i) 141 { 142 if (data[i] == ptr) 143 { 144 return erase_at(i); 145 } 146 } 147 return INDEX_OUT_OF_RANGE; 148 } 149 150 /** 151 * \brief Accesses the element at a specified index. 152 * 153 * \param index The index of the element to access. 154 * \return A reference to the element at the specified index. 155 */ 156 constexpr T& operator[](std::size_t index) 157 { 158 return *data[index]; 159 } 160 161 /** 162 * \brief Accesses the element at a specified index (const version). 163 * 164 * \param index The index of the element to access. 165 * \return A const reference to the element at the specified index. 166 */ 167 constexpr const T& operator[](std::size_t index) const 168 { 169 return *data[index]; 170 } 171 172 /** 173 * \brief Assigns the contents of another FixedSizeArray to this one. 174 * 175 * \param other The FixedSizeArray to copy from. 176 * \return A reference to this FixedSizeArray. 177 */ 178 constexpr FixedSizeArray& operator=(const FixedSizeArray& other) 179 { 180 if (this != &other) 181 { 182 clear(); 183 data = std::make_unique<T*[]>(max_size); 184 for (std::size_t i = 0; i < other.current_size; ++i) 185 { 186 data[i] = new T(*other.data[i]); 187 } 188 current_size = other.current_size; 189 } 190 return *this; 191 } 192 193 /** 194 * \brief Returns the number of elements in the array. 195 * 196 * \return The number of elements in the array. 197 */ 198 [[nodiscard]] constexpr std::size_t size() const 199 { 200 return current_size; 201 } 202 203 /** 204 * \brief Checks if the array is empty. 205 * 206 * \return True if the array is empty, false otherwise. 207 */ 208 [[nodiscard]] constexpr bool empty() const 209 { 210 return current_size == 0; 211 } 212 213 // Iterator support 214 using iterator = T**; 215 using const_iterator = const T**; 216 217 /** 218 * \brief Returns an iterator to the beginning of the array. 219 * 220 * \return An iterator to the beginning of the array. 221 */ 222 constexpr iterator begin() { return data.get(); } 223 224 /** 225 * \brief Returns a const iterator to the beginning of the array. 226 * 227 * \return A const iterator to the beginning of the array. 228 */ 229 constexpr const_iterator begin() const { return const_cast<const_iterator>(data.get()); } 230 231 /** 232 * \brief Returns an iterator to the end of the array. 233 * 234 * \return An iterator to the end of the array. 235 */ 236 constexpr iterator end() { return data.get() + current_size; } 237 238 /** 239 * \brief Returns a const iterator to the end of the array. 240 * 241 * \return A const iterator to the end of the array. 242 */ 243 constexpr const_iterator end() const { return const_cast<const_iterator>(data.get() + current_size); } 244 245 private: 246 /** 247 * \brief Clears the array and frees allocated memory. 248 */ 249 void clear() 250 { 251 for (std::size_t i = 0; i < current_size; ++i) 252 { 253 delete data[i]; 254 } 255 current_size = 0; 256 } 257 258 std::unique_ptr<T*[]> data; ///< Pointer to the array data. 259 std::size_t current_size; ///< The current number of elements in the array. 260 }; 261 }