Stratax 0.3.1
Loading...
Searching...
No Matches
Buffer.hpp
1#pragma once
2
3#include "Config.hpp"
4#include <algorithm>
5#include <cstddef>
6#include <initializer_list>
7#include <iterator>
8#include <limits>
9#include <memory>
10#include <new>
11#include <utility>
12
13#include <stratax/exceptions/Exceptions.hpp>
14
15namespace stratax::core {
16
49template<typename T, std::size_t Alignment = config::default_alignment>
50class Buffer
51{
52
53 static_assert(Alignment >= alignof(T));
54 static_assert((Alignment & (Alignment - 1)) == 0);
55
56public:
58 using value_type = T;
60 using size_type = std::size_t;
62 using difference_type = std::ptrdiff_t;
64 using reference = T&;
66 using const_reference = const T&;
68 using pointer = T*;
70 using const_pointer = const T*;
76 using reverse_iterator = std::reverse_iterator<iterator>;
78 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
79
88 [[nodiscard]] static constexpr size_type alignment() noexcept
89 {
90 return Alignment;
91 }
92
102 [[nodiscard]] static constexpr size_type max_size() noexcept
103 {
104 return std::numeric_limits<size_type>::max() / sizeof(value_type);
105 }
106
114 Buffer() noexcept: data_(nullptr), size_(0) {}
115
130 : data_(allocate(size)), size_(size)
131 {
132 construct_fill(value_type{});
133 }
134
149 : data_(allocate(size)), size_(size)
150 {
151 construct_fill(value);
152 }
153
167 Buffer(std::initializer_list<value_type> list)
168 : data_(allocate(list.size())), size_(list.size())
169 {
170 size_type i = 0;
171
172 try {
173 for (const_reference value : list) {
174 std::construct_at(data_ + i, value);
175 ++i;
176 }
177 } catch (...) {
178 std::destroy_n(data_, i);
179 deallocate(data_);
180 throw;
181 }
182 }
183
196 Buffer(const Buffer& other)
197 : data_(allocate(other.size_)),
198 size_(other.size_)
199 {
200 try {
201 std::uninitialized_copy_n(
202 other.data_,
203 size_,
204 data_
205 );
206 }
207 catch (...) {
208 deallocate(data_);
209 throw;
210 }
211 }
212
224 Buffer(Buffer&& other) noexcept
225 : data_(other.data_), size_(other.size_)
226 {
227 other.data_ = nullptr;
228 other.size_ = 0;
229 }
230
245 Buffer& operator=(const Buffer& other)
246 {
247 if (this == &other) {
248 return *this;
249 }
250
251 Buffer temp(other);
252 swap(temp);
253 return *this;
254 }
255
270 Buffer& operator=(Buffer&& other) noexcept
271 {
272 if (this == &other) {
273 return *this;
274 }
275
276 if (size_ != 0) {
277 std::destroy_n(data_, size_);
278 }
279
280 deallocate(data_);
281
282 data_ = other.data_;
283 size_ = other.size_;
284
285 other.data_ = nullptr;
286 other.size_ = 0;
287
288 return *this;
289 }
290
299 {
300 if (size_ != 0) {
301 std::destroy_n(data_, size_);
302 }
303
304 deallocate(data_);
305 }
306
315 reference operator[](size_type index) noexcept {return data_[index];}
316
325 const_reference operator[](size_type index) const noexcept {return data_[index];}
326
335 {
336 return data_[0];
337 }
338
347 {
348 return data_[0];
349 }
350
359 {
360 return data_[size_ - 1];
361 }
362
371 {
372 return data_[size_ - 1];
373 }
374
386 [[nodiscard]] pointer data() noexcept {return data_;}
387
399 [[nodiscard]] const_pointer data() const noexcept
400 {
401 return data_;
402 }
403
409 iterator begin() noexcept {return data_;}
415 const_iterator begin() const noexcept {return data_;}
421 const_iterator cbegin() const noexcept {return data_;}
427 iterator end() noexcept {return empty() ? data_ : data_ + size_;}
433 const_iterator end() const noexcept {return empty() ? data_ : data_ + size_;}
439 const_iterator cend() const noexcept {return empty() ? data_ : data_ + size_;}
476
486 [[nodiscard]] size_type size() const noexcept {return size_;}
487
494 [[nodiscard]] bool empty() const noexcept {return size_ == 0;}
495
508 {
509 std::fill_n(data_, size_, value);
510 }
511
523 void swap(Buffer& other) noexcept
524 {
525 std::swap(data_, other.data_);
526 std::swap(size_, other.size_);
527 }
528
529private:
530 pointer data_;
531 size_type size_;
532
543 static pointer allocate(size_type space)
544 {
545 if (space == 0) {
546 return nullptr;
547 }
548
549 if (space > max_size()) {
550 throw std::bad_array_new_length();
551 }
552
553 return static_cast<pointer>(
554 ::operator new(
555 sizeof(value_type) * space,
556 std::align_val_t{Alignment}
557 )
558 );
559 }
560
567 static void deallocate(pointer ptr) noexcept
568 {
569 if (ptr == nullptr) {
570 return;
571 }
572
573 ::operator delete(
574 ptr,
575 std::align_val_t{Alignment}
576 );
577 }
578
590 void construct_fill(const_reference value)
591 {
592 try {
593 std::uninitialized_fill_n(data_, size_, value);
594 } catch (...) {
595 deallocate(data_);
596 throw;
597 }
598 }
599
600};
601
602}
Fixed-size owner of aligned, contiguous element storage.
Definition Buffer.hpp:51
const_pointer const_iterator
Read-only contiguous random-access iterator type.
Definition Buffer.hpp:74
std::reverse_iterator< iterator > reverse_iterator
Mutable iterator that traverses elements in reverse order.
Definition Buffer.hpp:76
Buffer(size_type size, const_reference value)
Constructs a buffer with all elements initialized to value.
Definition Buffer.hpp:148
Buffer & operator=(Buffer &&other) noexcept
Move-assigns from another buffer.
Definition Buffer.hpp:270
const_pointer data() const noexcept
Returns a const pointer to the underlying contiguous storage.
Definition Buffer.hpp:399
reverse_iterator rend() noexcept
Returns the past-the-end iterator for mutable reverse traversal.
Definition Buffer.hpp:463
void swap(Buffer &other) noexcept
Swaps storage and size with another buffer.
Definition Buffer.hpp:523
Buffer(const Buffer &other)
Copy-constructs a buffer with independent storage.
Definition Buffer.hpp:196
Buffer(size_type size)
Constructs a buffer with value-initialized elements.
Definition Buffer.hpp:129
T & reference
Mutable element reference type.
Definition Buffer.hpp:64
size_type size() const noexcept
Returns the number of stored elements.
Definition Buffer.hpp:486
~Buffer()
Destroys the buffer and releases owned storage.
Definition Buffer.hpp:298
static constexpr size_type alignment() noexcept
Returns the alignment, in bytes, used for buffer allocations.
Definition Buffer.hpp:88
const_reverse_iterator rbegin() const noexcept
Returns a const reverse iterator to the final element.
Definition Buffer.hpp:451
T * pointer
Mutable pointer to an element.
Definition Buffer.hpp:68
static constexpr size_type max_size() noexcept
Returns the largest element count that cannot overflow in bytes.
Definition Buffer.hpp:102
const_reverse_iterator crend() const noexcept
Returns the past-the-end iterator for const reverse traversal.
Definition Buffer.hpp:475
std::ptrdiff_t difference_type
Signed type used for distances between iterators.
Definition Buffer.hpp:62
reference front()
Returns a reference to the first element.
Definition Buffer.hpp:334
const_iterator cend() const noexcept
Returns a const iterator one past the final element.
Definition Buffer.hpp:439
pointer iterator
Mutable contiguous random-access iterator type.
Definition Buffer.hpp:72
bool empty() const noexcept
Returns whether the buffer has no elements.
Definition Buffer.hpp:494
reference operator[](size_type index) noexcept
Returns an unchecked reference to an element.
Definition Buffer.hpp:315
Buffer(std::initializer_list< value_type > list)
Constructs a buffer from an initializer list.
Definition Buffer.hpp:167
const_reverse_iterator crbegin() const noexcept
Returns a const reverse iterator to the final element.
Definition Buffer.hpp:457
std::size_t size_type
Unsigned type used for element counts and indices.
Definition Buffer.hpp:60
reverse_iterator rbegin() noexcept
Returns a mutable reverse iterator to the final element.
Definition Buffer.hpp:445
void fill(const_reference value)
Assigns a value to every element in the buffer.
Definition Buffer.hpp:507
pointer data() noexcept
Returns a pointer to the underlying contiguous storage.
Definition Buffer.hpp:386
const_reference front() const
Returns a const reference to the first element.
Definition Buffer.hpp:346
iterator begin() noexcept
Returns a mutable iterator to the first element.
Definition Buffer.hpp:409
const_iterator cbegin() const noexcept
Returns a const iterator to the first element.
Definition Buffer.hpp:421
const_iterator end() const noexcept
Returns a const iterator one past the final element.
Definition Buffer.hpp:433
const_reference back() const
Returns a const reference to the last element.
Definition Buffer.hpp:370
Buffer(Buffer &&other) noexcept
Move-constructs a buffer by transferring ownership.
Definition Buffer.hpp:224
const T * const_pointer
Read-only pointer to an element.
Definition Buffer.hpp:70
reference back()
Returns a reference to the last element.
Definition Buffer.hpp:358
const_iterator begin() const noexcept
Returns a const iterator to the first element.
Definition Buffer.hpp:415
Buffer() noexcept
Constructs an empty buffer that owns no allocation.
Definition Buffer.hpp:114
std::reverse_iterator< const_iterator > const_reverse_iterator
Read-only iterator that traverses elements in reverse order.
Definition Buffer.hpp:78
Buffer & operator=(const Buffer &other)
Copy-assigns from another buffer.
Definition Buffer.hpp:245
const T & const_reference
Read-only element reference type.
Definition Buffer.hpp:66
iterator end() noexcept
Returns a mutable iterator one past the final element.
Definition Buffer.hpp:427
const_reverse_iterator rend() const noexcept
Returns the past-the-end iterator for const reverse traversal.
Definition Buffer.hpp:469
const_reference operator[](size_type index) const noexcept
Returns an unchecked const reference to an element.
Definition Buffer.hpp:325
T value_type
Type of each stored element.
Definition Buffer.hpp:58