Atoms Crowd  7.0.0
Array.impl.h
1 #pragma once
2 #include <type_traits>
3 #include <string.h>
4 #ifndef _WIN32
5 #include <new>
6 #else
7 #include <new>
8 #endif
9 
10 namespace ToolchefsSTL
11 {
12 
13  template<typename T>
14  Array<T>::Array(Allocator* allocator) noexcept:
15  m_data(nullptr),
16  m_allocator(allocator),
17  m_length(0),
18  m_capacity(0)
19  {
20 
21  }
22 
23  template<typename T>
24  Array<T>::Array(size_t num_elements, Allocator* allocator) noexcept:
25  m_data(nullptr),
26  m_allocator(allocator),
27  m_length(num_elements),
28  m_capacity(num_elements)
29  {
30  m_data = static_cast<Array::ptr_type>(m_allocator->malloc(sizeof(T) * m_capacity));
31  for (size_t i = 0; i < m_capacity; ++i)
32  {
33  new (m_data + i) T;
34  }
35  }
36 
37  template<typename T>
38  Array<T>::Array(size_t num_elements, const T& init_value, Allocator* allocator) noexcept:
39  m_data(nullptr),
40  m_allocator(allocator),
41  m_length(num_elements),
42  m_capacity(num_elements)
43  {
44  m_data = static_cast<Array::ptr_type>(m_allocator->malloc(sizeof(T) * m_capacity));
45  for (size_t i = 0; i < m_capacity; ++i)
46  {
47  new (m_data + i) T(init_value);
48  }
49  }
50 
51  template<typename T>
52  Array<T>::~Array() noexcept
53  {
54  clear();
55  }
56 
57  template<typename T>
58  Array<T>::Array(const Array& rhs) noexcept:
59  m_data(nullptr),
60  m_allocator(rhs.m_allocator),
61  m_length(rhs.m_length),
62  m_capacity(rhs.m_length)
63  {
64  if (m_length == 0) return;
65  m_data = static_cast<Array::ptr_type>(m_allocator->malloc(sizeof(T) * m_capacity));
66 #if __cplusplus >= 201703L
67  if(std::is_trivially_copyable_v<T>)
68  {
69  memcpy(m_data, rhs.m_data, sizeof(T) * m_length);
70  }
71  else
72 #endif
73  {
74  for (size_t i = 0; i < m_length; ++i)
75  {
76  new (m_data + i) T(rhs.m_data[i]);
77  }
78  }
79  }
80 
81  template<typename T>
82  Array<T>& Array<T>::operator=(const Array<T>& rhs) noexcept
83  {
84  if (this == &rhs) return *this;
85  if (rhs.m_length == 0)
86  {
87  clear();
88  return *this;
89  }
90 
91  resize(rhs.m_length);
92 #if __cplusplus >= 201703L
93  if (std::is_trivially_copyable_v<T>)
94  {
95  memcpy(m_data, rhs.m_data, sizeof(T) * m_length);
96  }
97  else
98 #endif
99  {
100  for (size_t i = 0; i < m_length; ++i)
101  {;
102  m_data[i] = rhs.m_data[i];
103  }
104  }
105  return *this;
106  }
107 
108  template<typename T>
109  Array<T>::Array(Array<T>&& rhs) noexcept:
110  m_data(rhs.m_data),
111  m_allocator(rhs.m_allocator),
112  m_length(rhs.m_length),
113  m_capacity(rhs.m_capacity)
114  {
115  rhs.m_length = 0;
116  rhs.m_capacity = 0;
117  rhs.m_data = nullptr;
118  }
119 
120  template<typename T>
121  Array<T>& Array<T>::operator=(Array<T>&& rhs) noexcept
122  {
123  if (m_data) clear();
124  m_data = rhs.m_data;
125  m_allocator = rhs.m_allocator;
126  m_length = rhs.m_length;
127  m_capacity = rhs.m_capacity;
128 
129  rhs.m_data = nullptr;
130  rhs.m_length = 0;
131  rhs.m_capacity = 0;
132  return *this;
133  }
134 
135  template<typename T>
136  bool Array<T>::operator==(const Array& rhs) const noexcept
137  {
138  if (rhs.m_length != m_length) return false;
139  for (size_t i=0; i < m_length; ++i)
140  {
141  if (m_data[i] != m_data[i]) return false;
142  }
143  return true;
144  }
145 
146  template<typename T>
147  void Array<T>::push_back(const T& element) noexcept
148  {
149  if (m_capacity == m_length) grow();
150  new (m_data + m_length++) T(element);
151  }
152 
153 
154 
155 #if __cplusplus >= 201703L
156  template<typename T>
157  constexpr T& Array<T>::operator[](const size_t index) noexcept
158  {
159  assert(index >= 0 && index < m_length);
160  return m_data[index];
161  }
162 
163  template<typename T>
164  constexpr const T& Array<T>::operator[](const size_t index) const noexcept
165  {
166  assert(index >= 0 && index < m_length);
167  return m_data[index];
168  }
169 #endif
170 
171  template<typename T>
172  typename Array<T>::iterator Array<T>::begin() noexcept
173  {
174  return m_data;
175  }
176 
177  template<typename T>
178  typename Array<T>::iterator Array<T>::end() noexcept
179  {
180  return &m_data[m_length];
181  }
182 
183  template<typename T>
184  typename Array<T>::const_iterator Array<T>::cbegin() const noexcept
185  {
186  return m_data;
187  }
188 
189  template<typename T>
190  typename Array<T>::const_iterator Array<T>::cend() const noexcept
191  {
192  return &m_data[m_length];
193  }
194 
195  template<typename T>
196  typename Array<T>::reverse_iterator Array<T>::rbegin() noexcept
197  {
198  return reverse_iterator(&back());
199  }
200 
201  template<typename T>
202  typename Array<T>::reverse_iterator Array<T>::rend() noexcept
203  {
204  T* front_ptr = &front();
205  return reverse_iterator(--front_ptr);
206  }
207 
208  template<typename T>
209  typename Array<T>::const_reverse_iterator Array<T>::crbegin() const noexcept
210  {
211  return const_reverse_iterator(&back());
212  }
213 
214  template<typename T>
215  typename Array<T>::const_reverse_iterator Array<T>::crend() const noexcept
216  {
217  T* front_ptr = const_cast<T*>(&front());
218  return const_reverse_iterator(--front_ptr);
219  }
220 
221  template<typename T>
222  T& Array<T>::back() noexcept
223  {
224  return m_data[m_length - 1];
225  }
226 
227  template<typename T>
228  const T& Array<T>::back() const noexcept
229  {
230  return m_data[m_length - 1];
231  }
232 
233  template<typename T>
234  T& Array<T>::front() noexcept
235  {
236  return m_data[0];
237  }
238 
239  template<typename T>
240  const T& Array<T>::front() const noexcept
241  {
242  return m_data[0];
243  }
244 
245  template<typename T>
246  const T* Array<T>::data() const noexcept
247  {
248  return m_data;
249  }
250 
251  template<typename T>
252  void Array<T>::resize(size_t new_length) noexcept
253  {
254  if (new_length == m_length) return;
255  if (new_length == 0)
256  {
257  clear();
258  return;
259  }
260  if (new_length > m_length)
261  {
262  reserve(new_length);
263  for (size_t i = m_length; i < new_length; ++i)
264  {
265  new (m_data + i) T();
266  }
267  m_length = new_length;
268  }
269  else
270  {
271  m_capacity = new_length;
272  ptr_type new_buffer = static_cast<ptr_type>(m_allocator->malloc(sizeof(T) * new_length));
273 #if __cplusplus >= 201703L
274  if (std::is_trivially_copyable_v<T>)
275  {
276  memcpy(new_buffer, m_data, sizeof(T) * new_length);
277  }
278  else
279 #endif
280  {
281  for (size_t i = 0; i < m_length; ++i)
282  {
283  T& item = m_data[i];
284  if (i < new_length)
285  new (new_buffer + i) T(std::move(item));
286  item.~T();
287  }
288  }
289  m_allocator->free(m_data);
290  m_data = new_buffer;
291  m_length = new_length;
292  }
293  }
294 
295  template<typename T>
296  void Array<T>::clear() noexcept
297  {
298  if (!std::is_trivially_destructible<T>::value)
299  {
300  for (size_t i = 0; i < m_length; ++i)
301  {
302  m_data[i].~T();
303  }
304  }
305 
306  if (m_data)
307  {
308  m_allocator->free(m_data);
309  m_data = nullptr;
310  }
311 
312  m_length = 0;
313  m_capacity = 0;
314  }
315 
316  template<typename T>
317  void Array<T>::reserve(size_t new_capacity) noexcept
318  {
319  if (new_capacity <= m_capacity) return;
320  m_capacity = new_capacity;
321  ptr_type new_buffer = static_cast<ptr_type>(m_allocator->malloc(sizeof(T) * m_capacity));
322 #if __cplusplus >= 201703L
323  if (std::is_trivially_copyable_v<T>)
324  {
325  memcpy(new_buffer, m_data, sizeof(T) * m_length);
326  }
327  else
328 #endif
329  {
330  for (size_t i = 0; i < m_length; ++i)
331  {
332  T& item = m_data[i];
333  new (new_buffer + i) T(std::move(item));
334  item.~T();
335  }
336  }
337 
338  m_allocator->free(m_data);
339  m_data = new_buffer;
340  }
341 
342  template<typename T>
343  size_t Array<T>::size() const noexcept
344  {
345  return m_length;
346  }
347 
348  template<typename T>
349  size_t Array<T>::length() const noexcept
350  {
351  return m_length;
352  }
353 
354  template<typename T>
355  size_t Array<T>::capacity() const noexcept
356  {
357  return m_capacity;
358  }
359 
360  template<typename T>
361  void Array<T>::grow() noexcept
362  {
363  m_capacity = m_capacity == 0 ? 1 : m_capacity << 1;
364  ptr_type new_buffer = static_cast<ptr_type>(m_allocator->malloc(sizeof(T) * m_capacity));
365 #if __cplusplus >= 201703L
366  if (std::is_trivially_copyable_v<T>)
367  {
368  memcpy(new_buffer, m_data, sizeof(T) * m_length);
369  }
370  else
371 #endif
372  {
373  for (size_t i=0; i < m_length; ++i)
374  {
375  T& item = m_data[i];
376  new (new_buffer + i) T(std::move(item));
377  item.~T();
378  }
379  }
380 
381  m_allocator->free(m_data);
382  m_data = new_buffer;
383 
384  }
385 
386  template<typename T>
387  void Array<T>::pop_back() noexcept
388  {
389  if (m_length == 0) return;
390  m_data[--m_length].~T();
391  if (m_length == 0) clear();
392  }
393 
394  template<typename T>
395  void Array<T>::insert(size_t index, const T& value) noexcept
396  {
397  if (index >= m_length) return;
398  resize(m_length + 1);
399  for (size_t i = (m_length-1); i > index; --i)
400  m_data[i] = std::move(m_data[i-1]);
401  m_data[index] = value;
402  }
403 
404  template<typename T>
405  void Array<T>::insert(iterator it, const T& value) noexcept
406  {
407  insert(it - m_data, value);
408  }
409 
410  template<typename T>
411  void Array<T>::erase(size_t index) noexcept
412  {
413  if (index >= m_length) return;
414  for (size_t i = (index + 1); i < m_length; ++i)
415  m_data[i-1] = std::move(m_data[i]);
416  m_length--;
417  m_data[m_length].~T();
418  }
419 
420  template<typename T>
421  typename Array<T>::iterator Array<T>::erase(iterator it) noexcept
422  {
423  size_t index = it - m_data;
424  erase(index);
425  return begin() + index;
426  }
427 
428  template<typename T>
429  void Array<T>::shrink_to_fit() noexcept
430  {
431  m_capacity = m_length;
432  ptr_type new_buffer = static_cast<ptr_type>(m_allocator->malloc(sizeof(T) * m_capacity));
433 #if __cplusplus >= 201703L
434  if (std::is_trivially_copyable_v<T>)
435  {
436  memcpy(new_buffer, m_data, sizeof(T) * m_length);
437  }
438  else
439 #endif
440  {
441  for (size_t i = 0; i < m_capacity; ++i)
442  {
443  T& item = m_data[i];
444  new (new_buffer + i) T(std::move(item));
445  item.~T();
446  }
447  }
448 
449  m_allocator->free(m_data);
450  m_data = new_buffer;
451  }
452 
453  template<typename T>
454  typename Array<T>::iterator Array<T>::find(const T& element) noexcept
455  {
456  auto end_it = end();
457  for (auto it=begin(); it != end_it; ++it)
458  {
459  if (*it == element) return it;
460  }
461  return end();
462  }
463 
464  template<typename T>
465  typename Array<T>::const_iterator Array<T>::find(const T& element) const noexcept
466  {
467  auto end_it = cend();
468  for (auto it = cbegin(); it != end_it; ++it)
469  {
470  if (*it == element) return it;
471  }
472  return cend();
473  }
474 
475  template<typename T>
476  bool Array<T>::empty() const noexcept
477  {
478  return m_length == 0;
479  }
480 }
Definition: Array.h:10
iterator begin() noexcept
Iterators.
Definition: Array.impl.h:172
T & back() noexcept
Direct access.
Definition: Array.impl.h:222