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 if (empty()) {
337 throw Exceptions::IndexError("Buffer front cannot be accessed when the buffer is empty.");
338 }
339
340 return data_[0];
341 }
342
351 {
352 if (empty()) {
353 throw Exceptions::IndexError("Buffer front cannot be accessed when the buffer is empty.");
354 }
355
356 return data_[0];
357 }
358
367 {
368 if (empty()) {
369 throw Exceptions::IndexError("Buffer back cannot be accessed when the buffer is empty.");
370 }
371
372 return data_[size_ - 1];
373 }
374
383 {
384 if (empty()) {
385 throw Exceptions::IndexError("Buffer back cannot be accessed when the buffer is empty.");
386 }
387
388 return data_[size_ - 1];
389 }
390
402 [[nodiscard]] pointer data() noexcept {return data_;}
403
415 [[nodiscard]] const_pointer data() const noexcept {return data_;}
416
422 iterator begin() noexcept {return data_;}
428 const_iterator begin() const noexcept {return data_;}
434 const_iterator cbegin() const noexcept {return data_;}
440 iterator end() noexcept {return empty() ? data_ : data_ + size_;}
446 const_iterator end() const noexcept {return empty() ? data_ : data_ + size_;}
452 const_iterator cend() const noexcept {return empty() ? data_ : data_ + size_;}
489
499 [[nodiscard]] size_type size() const noexcept {return size_;}
500
507 [[nodiscard]] bool empty() const noexcept {return size_ == 0;}
508
521 {
522 std::fill_n(data_, size_, value);
523 }
524
536 void swap(Buffer& other) noexcept
537 {
538 std::swap(data_, other.data_);
539 std::swap(size_, other.size_);
540 }
541
542private:
543 pointer data_;
544 size_type size_;
545
556 static pointer allocate(size_type space)
557 {
558 if (space == 0) {
559 return nullptr;
560 }
561
562 if (space > max_size()) {
563 throw std::bad_array_new_length();
564 }
565
566 return static_cast<pointer>(
567 ::operator new(
568 sizeof(value_type) * space,
569 std::align_val_t{Alignment}
570 )
571 );
572 }
573
580 static void deallocate(pointer ptr) noexcept
581 {
582 if (ptr == nullptr) {
583 return;
584 }
585
586 ::operator delete(
587 ptr,
588 std::align_val_t{Alignment}
589 );
590 }
591
603 void construct_fill(const_reference value)
604 {
605 try {
606 std::uninitialized_fill_n(data_, size_, value);
607 } catch (...) {
608 deallocate(data_);
609 throw;
610 }
611 }
612
613};
614
615}
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:415
reverse_iterator rend() noexcept
Returns the past-the-end iterator for mutable reverse traversal.
Definition Buffer.hpp:476
void swap(Buffer &other) noexcept
Swaps storage and size with another buffer.
Definition Buffer.hpp:536
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
Definition Buffer.hpp:499
~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:464
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:488
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:452
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:507
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:470
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:458
void fill(const_reference value)
Assigns a value to every element in the buffer.
Definition Buffer.hpp:520
pointer data() noexcept
Returns a pointer to the underlying contiguous storage.
Definition Buffer.hpp:402
const_reference front() const
Returns a const reference to the first element.
Definition Buffer.hpp:350
iterator begin() noexcept
Returns a mutable iterator to the first element.
Definition Buffer.hpp:422
const_iterator cbegin() const noexcept
Returns a const iterator to the first element.
Definition Buffer.hpp:434
const_iterator end() const noexcept
Returns a const iterator one past the final element.
Definition Buffer.hpp:446
const_reference back() const
Returns a const reference to the last element.
Definition Buffer.hpp:382
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:366
const_iterator begin() const noexcept
Returns a const iterator to the first element.
Definition Buffer.hpp:428
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:440
const_reverse_iterator rend() const noexcept
Returns the past-the-end iterator for const reverse traversal.
Definition Buffer.hpp:482
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