KTL
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 
12 namespace 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
std::reverse_iterator< T * > rbegin() noexcept
Definition: trivial_array.h:217
bool empty() const noexcept
Returns true if the array has been initialized with no size.
Definition: trivial_array.h:236
trivial_array & operator=(const trivial_array &other) noexcept
Definition: trivial_array.h:160
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
std::reverse_iterator< T * > reverse_iterator
Definition: trivial_array.h:32
const T & operator[](size_t index) const noexcept
Returns a reference to the element at index.
Definition: trivial_array.h:206
trivial_array & operator=(trivial_array &&other) noexcept
Definition: trivial_array.h:178
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
std::reverse_iterator< T * > rend() noexcept
Definition: trivial_array.h:221
trivial_array(trivial_array &&other, const Alloc &allocator) noexcept
Definition: trivial_array.h:137
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
void resize(size_t n)
Resizes the array to the given size.
Definition: trivial_array.h:264
T & operator[](size_t index) noexcept
Returns a reference to the element at index.
Definition: trivial_array.h:198
iterator data() noexcept
Returns an iterator to the start of the array.
Definition: trivial_array.h:243
std::reverse_iterator< const T * > rend() const noexcept
Definition: trivial_array.h:223
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
std::reverse_iterator< const T * > rbegin() const noexcept
Definition: trivial_array.h:219
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(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
T & at(size_t index) const noexcept
Returns a reference to the element at index.
Definition: trivial_array.h:257
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
#define KTL_EMPTY_BASE
Definition: empty_base.h:6
Definition: cascading.h:15