KTL
Loading...
Searching...
No Matches
trivial_array.h
Go to the documentation of this file.
1#pragma once
2
3#include "../utility/assert.h"
4#include "../utility/empty_base.h"
5#include "trivial_array_fwd.h"
6
7#include <cstring>
8#include <iterator>
9#include <memory>
10#include <utility>
11
12namespace ktl
13{
19 template<typename T, typename Alloc>
21 {
22 private:
23 static_assert(std::is_default_constructible<T>::value, "Template class needs to be default constructible");
24 static_assert(std::is_trivially_copyable<T>::value, "Template class needs to be trivially copyable");
25
26 typedef std::allocator_traits<Alloc> Traits;
27
28 public:
29 typedef T* iterator;
30 typedef const T* const_iterator;
31
32 typedef std::reverse_iterator<T*> reverse_iterator;
33 typedef std::reverse_iterator<const T*> const_reverse_iterator;
34
35 public:
39 trivial_array() noexcept :
40 m_Alloc(),
41 m_Begin(nullptr),
42 m_End(nullptr) {}
43
48 trivial_array(const Alloc& allocator) noexcept :
49 m_Alloc(allocator),
50 m_Begin(nullptr),
51 m_End(nullptr) {}
52
58 explicit trivial_array(size_t n, const Alloc& allocator = Alloc()) :
59 m_Alloc(allocator),
60 m_Begin(Traits::allocate(m_Alloc, n)),
61 m_End(m_Begin + n) {}
62
69 explicit trivial_array(size_t n, const T& value, const Alloc& allocator = Alloc()) :
70 m_Alloc(allocator),
71 m_Begin(Traits::allocate(m_Alloc, n)),
72 m_End(m_Begin + n)
73 {
74 std::uninitialized_fill_n<T*, size_t>(m_Begin, n, value);
75 }
76
82 trivial_array(std::initializer_list<T> initializer, const Alloc& allocator = Alloc()) :
83 m_Alloc(allocator),
84 m_Begin(Traits::allocate(m_Alloc, initializer.size())),
85 m_End(m_Begin + initializer.size())
86 {
87 T* dst = m_Begin;
88 for (auto value : initializer)
89 {
90 *dst = value;
91 dst++;
92 }
93 }
94
101 explicit trivial_array(const T* first, const T* last, const Alloc& allocator = Alloc()) :
102 m_Alloc(allocator),
103 m_Begin(Traits::allocate(m_Alloc, size_t(last - first))),
104 m_End(m_Begin + size_t(last - first))
105 {
106 size_t n = last - first;
107 std::memcpy(m_Begin, first, n * sizeof(T));
108 }
109
110 trivial_array(const trivial_array& other) noexcept :
111 m_Alloc(Traits::select_on_container_copy_construction(other.m_Alloc)),
112 m_Begin(Traits::allocate(m_Alloc, other.size())),
113 m_End(m_Begin + other.size())
114 {
115 if (other.m_Begin != nullptr)
116 std::memcpy(m_Begin, other.m_Begin, other.size() * sizeof(T));
117 }
118
119 trivial_array(trivial_array&& other) noexcept :
120 m_Alloc(std::move(other.m_Alloc)),
121 m_Begin(other.m_Begin),
122 m_End(other.m_End)
123 {
124 other.m_Begin = nullptr;
125 other.m_End = nullptr;
126 }
127
128 trivial_array(const trivial_array& other, const Alloc& allocator) noexcept :
129 m_Alloc(allocator),
130 m_Begin(Traits::allocate(m_Alloc, other.size())),
131 m_End(m_Begin + other.size())
132 {
133 if (other.m_Begin != nullptr)
134 std::memcpy(m_Begin, other.m_Begin, other.size() * sizeof(T));
135 }
136
137 trivial_array(trivial_array&& other, const Alloc& allocator) noexcept :
138 m_Alloc(allocator),
139 m_Begin(Traits::allocate(m_Alloc, other.size())),
140 m_End(m_Begin + other.size())
141 {
142 // Moving using a different allocator means we can't just move, we have to reallocate
143 if (other.m_Begin != nullptr)
144 {
145 std::memcpy(m_Begin, other.m_Begin, other.size() * sizeof(T));
146
147 Traits::deallocate(other.m_Alloc, other.m_Begin, other.size() * sizeof(T));
148 }
149
150 other.m_Begin = nullptr;
151 other.m_End = nullptr;
152 }
153
154 ~trivial_array() noexcept
155 {
156 if (m_Begin != nullptr)
157 Traits::deallocate(m_Alloc, m_Begin, size());
158 }
159
160 trivial_array& operator=(const trivial_array& other) noexcept
161 {
162 if (m_Begin != nullptr)
163 Traits::deallocate(m_Alloc, m_Begin, size());
164
165 m_Alloc = other.m_Alloc;
166
167 size_t n = other.size();
168
169 T* alBlock = Traits::allocate(m_Alloc, n);
170
171 m_Begin = alBlock;
172 m_End = m_Begin + n;
173
174 std::memcpy(m_Begin, other.m_Begin, n * sizeof(T));
175 return *this;
176 }
177
179 {
180 if (m_Begin != nullptr)
181 Traits::deallocate(m_Alloc, m_Begin, size());
182
183 m_Alloc = std::move(other.m_Alloc);
184 m_Begin = other.m_Begin;
185 m_End = other.m_End;
186
187 other.m_Begin = nullptr;
188 other.m_End = nullptr;
189 return *this;
190 }
191
198 T& operator[](size_t index) noexcept { KTL_ASSERT(index < size()); return m_Begin[index]; }
199
206 const T& operator[](size_t index) const noexcept { KTL_ASSERT(index < size()); return m_Begin[index]; }
207
208
209 iterator begin() noexcept { return m_Begin; }
210
211 const_iterator begin() const noexcept { return m_Begin; }
212
213 iterator end() noexcept { return m_End; }
214
215 const_iterator end() const noexcept { return m_End; }
216
217 std::reverse_iterator<T*> rbegin() noexcept { return std::reverse_iterator(m_End); }
218
219 std::reverse_iterator<const T*> rbegin() const noexcept { return std::reverse_iterator(m_End); }
220
221 std::reverse_iterator<T*> rend() noexcept { return std::reverse_iterator(m_Begin); }
222
223 std::reverse_iterator<const T*> rend() const noexcept { return std::reverse_iterator(m_Begin); }
224
225
230 size_t size() const noexcept { return m_End - m_Begin; }
231
236 bool empty() const noexcept { return m_Begin == m_End; }
237
238
243 iterator data() noexcept { return m_Begin; }
244
249 const_iterator data() const noexcept { return m_Begin; }
250
257 T& at(size_t index) const noexcept { KTL_ASSERT(index < size()); return m_Begin[index]; }
258
259
264 void resize(size_t n)
265 {
266 if (size() != n)
267 {
268 size_t curSize = size();
269 T* alBlock = Traits::allocate(m_Alloc, n);
270
271 if (m_Begin != nullptr)
272 {
273 std::memcpy(alBlock, m_Begin, (std::min)(curSize, n) * sizeof(T));
274 Traits::deallocate(m_Alloc, m_Begin, curSize);
275 }
276
277 m_Begin = alBlock;
278 m_End = m_Begin + n;
279 }
280 }
281
287 void assign(const T* first, const T* last)
288 {
289 const size_t n = last - first;
290
291 if (n != size())
292 {
293 T* alBlock = Traits::allocate(m_Alloc, n);
294
295 if (m_Begin != nullptr)
296 Traits::deallocate(m_Alloc, m_Begin, size());
297
298 m_Begin = alBlock;
299 m_End = m_Begin + n;
300 }
301
302 std::memcpy(m_Begin, first, n * sizeof(T));
303 }
304
305 private:
306 KTL_EMPTY_BASE Alloc m_Alloc;
307 T* m_Begin;
308 T* m_End;
309 };
310}
#define KTL_ASSERT(x)
Definition assert.h:17
A dynamically alloacted array of trivial types.
Definition trivial_array.h:21
bool empty() const noexcept
Returns true if the array has been initialized with no size.
Definition trivial_array.h:236
const_iterator data() const noexcept
Returns a const iterator to the start of the array.
Definition trivial_array.h:249
void assign(const T *first, const T *last)
Assigns the given values from first to last. It also resizes if the size doesn't match the number of ...
Definition trivial_array.h:287
size_t size() const noexcept
Returns the current size of the array.
Definition trivial_array.h:230
const T & operator[](size_t index) const noexcept
Returns a reference to the element at index.
Definition trivial_array.h:206
std::reverse_iterator< const T * > rend() const noexcept
Definition trivial_array.h:223
std::reverse_iterator< T * > rbegin() noexcept
Definition trivial_array.h:217
std::reverse_iterator< T * > reverse_iterator
Definition trivial_array.h:32
trivial_array(const T *first, const T *last, const Alloc &allocator=Alloc())
Construct the array with the allocator and range of values.
Definition trivial_array.h:101
trivial_array(size_t n, const Alloc &allocator=Alloc())
Construct the array with the given allocator and size.
Definition trivial_array.h:58
trivial_array(trivial_array &&other, const Alloc &allocator) noexcept
Definition trivial_array.h:137
std::reverse_iterator< T * > rend() noexcept
Definition trivial_array.h:221
std::reverse_iterator< const T * > const_reverse_iterator
Definition trivial_array.h:33
trivial_array(std::initializer_list< T > initializer, const Alloc &allocator=Alloc())
Construct the array with the allocator and range of values.
Definition trivial_array.h:82
std::reverse_iterator< const T * > rbegin() const noexcept
Definition trivial_array.h:219
void resize(size_t n)
Resizes the array to the given size.
Definition trivial_array.h:264
iterator data() noexcept
Returns an iterator to the start of the array.
Definition trivial_array.h:243
trivial_array(const trivial_array &other, const Alloc &allocator) noexcept
Definition trivial_array.h:128
const_iterator end() const noexcept
Definition trivial_array.h:215
T & at(size_t index) const noexcept
Returns a reference to the element at index.
Definition trivial_array.h:257
T & operator[](size_t index) noexcept
Returns a reference to the element at index.
Definition trivial_array.h:198
trivial_array(size_t n, const T &value, const Alloc &allocator=Alloc())
Construct the array with the given allocator, size and default value.
Definition trivial_array.h:69
trivial_array(trivial_array &&other) noexcept
Definition trivial_array.h:119
T * iterator
Definition trivial_array.h:29
trivial_array(const trivial_array &other) noexcept
Definition trivial_array.h:110
trivial_array & operator=(const trivial_array &other) noexcept
Definition trivial_array.h:160
trivial_array(const Alloc &allocator) noexcept
Construct the array with the given allocator.
Definition trivial_array.h:48
iterator end() noexcept
Definition trivial_array.h:213
const T * const_iterator
Definition trivial_array.h:30
iterator begin() noexcept
Definition trivial_array.h:209
trivial_array() noexcept
Construct the array with a default constructed allocator.
Definition trivial_array.h:39
~trivial_array() noexcept
Definition trivial_array.h:154
const_iterator begin() const noexcept
Definition trivial_array.h:211
trivial_array & operator=(trivial_array &&other) noexcept
Definition trivial_array.h:178
#define KTL_EMPTY_BASE
Definition empty_base.h:6
Definition cascading.h:16