General Utility Library for C++14  2.12
SmallVector.h
Go to the documentation of this file.
1 
23 #ifndef GUL14_SMALLVECTOR_H_
24 #define GUL14_SMALLVECTOR_H_
25 
26 #include <algorithm>
27 #include <array>
28 #include <initializer_list>
29 #include <iterator>
30 #include <limits>
31 #include <memory>
32 #include <stdexcept>
33 #include <type_traits>
34 
35 #include "gul14/internal.h"
36 #include "gul14/cat.h"
37 
38 namespace gul14 {
39 
268 template <typename ElementT, size_t in_capacity>
270 {
271 public:
273  using ValueType = ElementT;
277  using SizeType = uint32_t;
281  using DifferenceType = std::ptrdiff_t;
289  using ConstReference = const ValueType&;
293  using Iterator = ValueType*;
297  using ConstIterator = const ValueType*;
301  using ReverseIterator = std::reverse_iterator<Iterator>;
305  using ConstReverseIterator = std::reverse_iterator<ConstIterator>;
308 
317  SmallVector() noexcept = default;
318 
325  explicit SmallVector(SizeType num_elements)
326  {
327  static_assert(std::is_default_constructible<ValueType>::value,
328  "SmallVector: Element type is not default-constructible");
329 
330  reserve(num_elements);
331  for (SizeType i = 0u; i != num_elements; ++i)
332  ::new(static_cast<void*>(data() + i)) ValueType{};
333  size_ = num_elements;
334  }
335 
343  SmallVector(SizeType num_elements, const ValueType& value)
344  {
345  fill_empty_vector_with_copied_value(num_elements, value);
346  }
347 
364  template<class InputIterator,
365  typename = std::enable_if_t<not std::is_integral<InputIterator>::value>>
366  SmallVector(InputIterator first, InputIterator last)
367  {
368  fill_empty_vector_with_copied_range(first, last);
369  }
370 
379  SmallVector(const SmallVector& other)
380  noexcept(std::is_nothrow_copy_constructible<ValueType>::value)
381  {
382  static_assert(std::is_copy_constructible<ValueType>::value == true,
383  "SmallVector: Element type is not copy-constructible");
384  fill_empty_vector_with_copied_range(other.cbegin(), other.cend());
385  }
386 
403  noexcept(std::is_nothrow_move_constructible<ValueType>::value)
404  {
405  move_or_copy_all_elements_from(std::move(other));
406  }
407 
415  SmallVector(std::initializer_list<ValueType> init)
416  {
417  fill_empty_vector_with_copied_range(init.begin(), init.end());
418  }
419 
422  {
423  clear();
424 
425  if (is_storage_allocated())
426  delete[] data_ptr_;
427  }
428 
436  void assign(SizeType num_elements, const ValueType& value)
437  {
438  clear();
439  fill_empty_vector_with_copied_value(num_elements, value);
440  }
441 
461  template<class InputIterator,
462  typename = std::enable_if_t<not std::is_integral<InputIterator>::value>>
463  void assign(InputIterator first, InputIterator last)
464  {
465  clear();
466  fill_empty_vector_with_copied_range(first, last);
467  }
468 
476  void assign(std::initializer_list<ValueType> init)
477  {
478  const auto num_elements = static_cast<SizeType>(init.size());
479 
480  clear();
481  reserve(num_elements);
482  std::uninitialized_copy(init.begin(), init.end(), data());
483  size_ = num_elements;
484  }
485 
490  constexpr Reference at(SizeType idx)
491  {
492  if (idx >= size_)
493  throw std::out_of_range(cat("Index out of range: ", idx, " >= ", size_));
494  return *(data() + idx);
495  }
496 
498  constexpr ConstReference at(SizeType idx) const
499  {
500  if (idx >= size_)
501  throw std::out_of_range(cat("Index out of range: ", idx, " >= ", size_));
502  return *(data() + idx);
503  }
504 
509  constexpr Reference back() noexcept
510  {
511  return *(data_end() - 1);
512  }
513 
518  constexpr ConstReference back() const noexcept
519  {
520  return *(data_end() - 1);
521  }
522 
527  constexpr Iterator begin() noexcept
528  {
529  return data();
530  }
531 
536  constexpr ConstIterator begin() const noexcept
537  {
538  return data();
539  }
540 
545  constexpr SizeType capacity() const noexcept { return capacity_; }
546 
551  constexpr ConstIterator cbegin() const noexcept
552  {
553  return begin();
554  }
555 
560  constexpr ConstIterator cend() const noexcept
561  {
562  return end();
563  }
564 
569  void clear() noexcept
570  {
571  destroy_range(data(), data_end());
572  size_ = 0;
573  }
574 
582  {
583  return std::make_reverse_iterator(end());
584  }
585 
593  {
594  return std::make_reverse_iterator(begin());
595  }
596 
601  constexpr ValueType* data() noexcept
602  {
603  return reinterpret_cast<ValueType*>(data_ptr_);
604  }
605 
610  constexpr const ValueType* data() const noexcept
611  {
612  return reinterpret_cast<const ValueType*>(data_ptr_);
613  }
614 
640  template <typename... ArgumentTypes>
641  Iterator emplace(ConstIterator pos, ArgumentTypes&&... arguments)
642  {
643  if (pos == cend())
644  {
645  emplace_back(std::forward<ArgumentTypes>(arguments)...);
646  return data_end() - 1;
647  }
648 
649  ValueType v(std::forward<ArgumentTypes>(arguments)...);
650 
651  return insert_single_value(pos, std::move(v));
652  }
653 
671  template <typename... ArgumentTypes>
672  Reference emplace_back(ArgumentTypes&&... arguments)
673  {
674  if (size_ == capacity_)
675  grow();
676 
677  ::new(static_cast<void*>(data_end()))
678  ValueType(std::forward<ArgumentTypes>(arguments)...);
679 
680  ++size_;
681 
682  return back();
683  }
684 
686  constexpr bool empty() const noexcept { return size_ == 0u; }
687 
692  constexpr Iterator end() noexcept
693  {
694  return data_end();
695  }
696 
701  constexpr ConstIterator end() const noexcept
702  {
703  return data_end();
704  }
705 
718  {
719  return erase(pos, pos + 1);
720  }
721 
736  {
737  auto range_begin = const_cast<Iterator>(first);
738  auto range_end = const_cast<Iterator>(last);
739  auto num_elements = range_end - range_begin;
740 
741  std::move(range_end, end(), range_begin);
742  destroy_range(end() - num_elements, end());
743 
744  size_ -= static_cast<SizeType>(num_elements);
745 
746  return range_begin;
747  }
748 
753  constexpr Reference front() noexcept
754  {
755  return *data();
756  }
757 
762  constexpr ConstReference front() const noexcept
763  {
764  return *data();
765  }
766 
771  constexpr SizeType inner_capacity() const noexcept { return in_capacity; }
772 
783  {
784  return insert_single_value(pos, value);
785  }
786 
797  {
798  return insert_single_value(pos, std::move(value));
799  }
800 
810  Iterator insert(ConstIterator pos, SizeType num_elements, const ValueType& value)
811  {
812  const auto idx = static_cast<SizeType>(pos - begin());
813  if (num_elements < 1)
814  return begin() + idx;
815 
816  const SizeType num_assignable = make_space_at_idx_for_n_elements(idx, num_elements);
817  Iterator insert_pos = begin() + idx;
818 
819  // Copy-assign to moved-from elements
820  std::fill_n(insert_pos, num_assignable, value);
821 
822  // Copy the remaining values into uninitialized cells
823  copy_value_into_uninitialized_cells(size_, num_elements - num_assignable, value);
824 
825  size_ += num_elements;
826 
827  return insert_pos;
828  }
829 
849  template<class InputIterator,
850  typename = std::enable_if_t<not std::is_integral<InputIterator>::value>>
851  Iterator insert(ConstIterator pos, InputIterator first, InputIterator last)
852  {
853  const auto idx = static_cast<SizeType>(pos - begin());
854  const auto num_elements = static_cast<SizeType>(std::distance(first, last));
855  if (num_elements < 1)
856  return begin() + idx;
857 
858  const SizeType num_assignable = make_space_at_idx_for_n_elements(idx, num_elements);
859  Iterator insert_pos = begin() + idx;
860 
861  // Copy-assign to moved-from elements
862  std::copy_n(first, num_assignable, insert_pos);
863 
864  // Copy the remaining values into uninitialized cells
865  copy_range_into_uninitialized_cells(size_, first + num_assignable, last);
866 
867  size_ += num_elements;
868 
869  return insert_pos;
870  }
871 
885  Iterator insert(ConstIterator pos, std::initializer_list<ValueType> init)
886  {
887  return insert(pos, init.begin(), init.end());
888  }
889 
896  constexpr SizeType max_size() const noexcept
897  {
898  return std::numeric_limits<SizeType>::max();
899  }
900 
909  noexcept(std::is_nothrow_copy_assignable<ValueType>::value)
910  {
911  if (&other != this)
912  {
913  clear();
914  reserve(other.size());
915  std::uninitialized_copy(other.cbegin(), other.cend(), data());
916  size_ = other.size();
917  }
918 
919  return *this;
920  }
921 
936  noexcept(std::is_nothrow_move_constructible<ValueType>::value)
937  {
938  if (&other != this)
939  {
940  clear();
941  if (is_storage_allocated())
942  delete[] data_ptr_;
943  move_or_copy_all_elements_from(std::move(other));
944  }
945 
946  return *this;
947  }
948 
953  SmallVector& operator=(std::initializer_list<ValueType> init)
954  {
955  assign(init);
956  return *this;
957  }
958 
966  friend bool operator==(const SmallVector& lhs, const SmallVector& rhs)
967  {
968  return std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend());
969  }
970 
978  friend bool operator!=(const SmallVector& lhs, const SmallVector& rhs)
979  {
980  return not (lhs == rhs);
981  }
982 
985  {
986  return *(data() + idx);
987  }
988 
990  constexpr ConstReference operator[](SizeType idx) const
991  {
992  return *(data() + idx);
993  }
994 
999  void pop_back()
1000  {
1001  --size_;
1002  auto p = data_end();
1003  p->~ValueType();
1004  }
1005 
1015  void push_back(const ValueType& value)
1016  {
1017  if (size_ == capacity_)
1018  grow();
1019 
1020  ::new(static_cast<void*>(data_end())) ValueType(value);
1021 
1022  ++size_;
1023  }
1024 
1033  void push_back(ValueType&& value)
1034  {
1035  if (size_ == capacity_)
1036  grow();
1037 
1038  ::new(static_cast<void*>(data_end())) ValueType(std::move(value));
1039 
1040  ++size_;
1041  }
1042 
1050  {
1051  return std::make_reverse_iterator(end());
1052  }
1053 
1060  {
1061  return std::make_reverse_iterator(begin());
1062  }
1063 
1072  void reserve(SizeType new_capacity)
1073  {
1074  if (new_capacity <= capacity_)
1075  return;
1076 
1077  auto new_data = std::make_unique<AlignedStorage[]>(new_capacity);
1078 
1079  const auto d_end = data_end();
1080 
1081  uninitialized_move_or_copy(data(), d_end, reinterpret_cast<ValueType*>(new_data.get()));
1082  destroy_range(data(), d_end);
1083 
1084  if (is_storage_allocated())
1085  delete[] data_ptr_;
1086 
1087  data_ptr_ = new_data.release();
1088  capacity_ = new_capacity;
1089  }
1090 
1106  void resize(SizeType num_elements)
1107  {
1108  static_assert(std::is_default_constructible<ValueType>::value,
1109  "SmallVector: For using resize(), element type must be default-constructible");
1110 
1111  if (num_elements < size_)
1112  {
1113  destroy_range(data() + num_elements, data_end());
1114  }
1115  else if (num_elements > size_)
1116  {
1117  reserve(num_elements);
1118  fill_uninitialized_cells_with_default_constructed_elements(size_,
1119  num_elements - size_);
1120  }
1121 
1122  size_ = num_elements;
1123  }
1124 
1136  void resize(SizeType num_elements, const ValueType& element)
1137  {
1138  if (num_elements < size_)
1139  {
1140  destroy_range(data() + num_elements, data_end());
1141  }
1142  else if (num_elements > size_)
1143  {
1144  reserve(num_elements);
1145  copy_value_into_uninitialized_cells(size_, num_elements - size_, element);
1146  }
1147 
1148  size_ = num_elements;
1149  }
1150 
1156  {
1157  const SizeType new_capacity = std::max(inner_capacity(), size_);
1158 
1159  // No shrinking required?
1160  if (new_capacity == capacity_)
1161  return;
1162 
1163  AlignedStorage* new_data;
1164  auto new_memory = std::unique_ptr<AlignedStorage[]>{};
1165 
1166  if (new_capacity == inner_capacity()) {
1167  new_data = internal_array_.data();
1168  } else {
1169  new_memory = std::make_unique<AlignedStorage[]>(new_capacity);
1170  new_data = new_memory.get();
1171  }
1172 
1173  const auto d_end = data_end();
1174 
1175  uninitialized_move_or_copy(data(), d_end, reinterpret_cast<ValueType*>(new_data));
1176  destroy_range(data(), d_end);
1177 
1178  if (is_storage_allocated())
1179  delete[] data_ptr_;
1180 
1181  data_ptr_ = new_memory ? new_memory.release() : new_data;
1182  capacity_ = new_capacity;
1183  }
1184 
1186  constexpr SizeType size() const noexcept { return size_; }
1187 
1195  void swap(SmallVector& other)
1196  {
1197  if (is_storage_allocated())
1198  {
1199  if (other.is_storage_allocated())
1200  swap_heap_with_heap(*this, other);
1201  else
1202  swap_heap_with_internal(*this, other);
1203  }
1204  else
1205  {
1206  if (other.is_storage_allocated())
1207  swap_heap_with_internal(other, *this);
1208  else
1209  swap_internal_with_internal(*this, other);
1210  }
1211  }
1212 
1213 private:
1214  using AlignedStorage =
1215  typename std::aligned_storage<sizeof(ValueType), alignof(ValueType)>::type;
1216 
1221  std::array<AlignedStorage, in_capacity> internal_array_;
1222 
1224  AlignedStorage* data_ptr_{ internal_array_.data() };
1225 
1228  SizeType capacity_{ in_capacity };
1230  SizeType size_{ 0u };
1231 
1244  template<class InputIterator>
1245  void copy_range_into_uninitialized_cells(SizeType pos, InputIterator first,
1246  InputIterator last)
1247  {
1248  auto data_ptr = data() + pos;
1249 
1250  try
1251  {
1252  for (auto it = first; it != last; ++it)
1253  {
1254  ::new(static_cast<void*>(data_ptr)) ValueType{ *it };
1255  ++data_ptr;
1256  }
1257  }
1258  catch (...)
1259  {
1260  for (auto p = data() + pos; p != data_ptr; ++p)
1261  p->~ValueType();
1262 
1263  throw;
1264  }
1265  }
1266 
1273  void copy_value_into_uninitialized_cells(SizeType pos, SizeType num_elements,
1274  const ValueType& value)
1275  {
1276  const auto start_ptr = data() + pos;
1277  const auto end_ptr = start_ptr + num_elements;
1278  for (auto p = start_ptr; p != end_ptr; ++p)
1279  ::new(static_cast<void*>(p)) ValueType(value);
1280  }
1281 
1283  constexpr ValueType* data_end() noexcept
1284  {
1285  return reinterpret_cast<ValueType*>(data_ptr_) + size_;
1286  }
1287 
1289  constexpr const ValueType* data_end() const noexcept
1290  {
1291  return reinterpret_cast<const ValueType*>(data_ptr_) + size_;
1292  }
1293 
1302  static void destroy_range(Iterator it_start, Iterator it_end) noexcept
1303  {
1304  for (auto it = it_start; it != it_end; ++it)
1305  it->~ValueType();
1306  }
1307 
1322  template<typename InputIterator>
1323  void fill_empty_vector_with_copied_range(InputIterator first, InputIterator last)
1324  {
1325  const auto num_elements = static_cast<SizeType>(std::distance(first, last));
1326 
1327  reserve(num_elements);
1328  copy_range_into_uninitialized_cells(0u, first, last);
1329  size_ = num_elements;
1330  }
1331 
1340  void fill_empty_vector_with_copied_value(SizeType num_elements, const ValueType& value)
1341  {
1342  reserve(num_elements);
1343  copy_value_into_uninitialized_cells(0u, num_elements, value);
1344  size_ = num_elements;
1345  }
1346 
1355  void fill_uninitialized_cells_with_default_constructed_elements(SizeType pos,
1356  SizeType num_elements)
1357  {
1358  const auto start_ptr = data() + pos;
1359  const auto end_ptr = start_ptr + num_elements;
1360  auto ptr = start_ptr;
1361 
1362  try
1363  {
1364  for (; ptr != end_ptr; ++ptr)
1365  ::new(static_cast<void*>(ptr)) ValueType{};
1366  }
1367  catch (...)
1368  {
1369  destroy_range(start_ptr, ptr);
1370  throw;
1371  }
1372  }
1373 
1383  void grow()
1384  {
1385  const auto remaining_space = std::numeric_limits<SizeType>::max() - capacity_;
1386 
1387  if (remaining_space == 0u)
1388  throw std::length_error("Max. capacity reached");
1389 
1390  SizeType increase = capacity_ / 2u;
1391  if (increase > remaining_space)
1392  increase = remaining_space;
1393  else if (increase == 0u)
1394  increase = 1u;
1395 
1396  reserve(capacity_ + increase);
1397  }
1398 
1400  template <typename T>
1401  Iterator insert_single_value(ConstIterator pos, T&& value)
1402  {
1403  if (pos == end())
1404  {
1405  push_back(std::forward<T>(value));
1406  return begin() + size_ - 1;
1407  }
1408 
1409  const auto idx = static_cast<SizeType>(pos - begin());
1410 
1411  if (size_ == capacity_)
1412  grow();
1413 
1414  Iterator insert_pos = begin() + idx;
1415 
1416  auto data_ptr = data();
1417 
1418  // Construct new back() element by moving from the old back()
1419  ::new(static_cast<void*>(data_ptr + size_)) ValueType(std::move(*(data_ptr + size_ - 1)));
1420 
1421  std::move_backward(insert_pos, data_ptr + size_ - 1, data_ptr + size_);
1422  ++size_;
1423 
1424  *insert_pos = std::forward<T>(value);
1425 
1426  return insert_pos;
1427  }
1428 
1430  bool is_storage_allocated() const noexcept
1431  {
1432  return data_ptr_ != internal_array_.data();
1433  }
1434 
1445  SizeType make_space_at_idx_for_n_elements(SizeType idx, SizeType num_elements)
1446  {
1447  const auto new_size = size_ + num_elements;
1448 
1449  if (new_size > capacity_)
1450  reserve(new_size);
1451 
1452  auto data_ptr = data();
1453 
1454  // We have a total number of elements that need to be shifted backwards,
1455  // of which some need to be move-initialized at the end of the vector
1456  // and some simply need to be moved from one element to another.
1457  const SizeType num_shifted = size_ - idx;
1458  const SizeType num_move_initialized = std::min(num_shifted, num_elements);
1459  const SizeType num_moved = num_shifted - num_move_initialized;
1460 
1461  // Move-initialize elements in uninitialized space at the back of the container
1462  const auto from_ptr = data_ptr + size_ - num_move_initialized;
1463  const auto to_ptr = from_ptr + num_elements;
1464  for (SizeType i = 0; i != num_move_initialized; ++i)
1465  ::new(static_cast<void*>(to_ptr + i)) ValueType(std::move(*(from_ptr + i)));
1466 
1467  // Move elements backwards within old vector size
1468  std::move_backward(data_ptr + idx, data_ptr + idx + num_moved, to_ptr);
1469 
1470  return num_move_initialized;
1471  }
1472 
1491  void move_or_copy_all_elements_from(SmallVector&& other)
1492  noexcept(std::is_nothrow_move_constructible<ValueType>::value)
1493  {
1494  // Can we simply steal the complete allocated storage?
1495  if (other.is_storage_allocated())
1496  {
1497  data_ptr_ = other.data_ptr_; other.data_ptr_ = other.internal_array_.data();
1498  capacity_ = other.capacity_; other.capacity_ = other.inner_capacity();
1499  size_ = other.size_; other.size_ = 0u;
1500  }
1501  else // otherwise fall back to moving (or at least copying) all elements
1502  {
1503  data_ptr_ = internal_array_.data();
1504  capacity_ = in_capacity;
1505  uninitialized_move_or_copy(other.begin(), other.end(), data());
1506  size_ = other.size();
1507  other.clear();
1508  }
1509  }
1510 
1516  static void swap_heap_with_heap(SmallVector &a, SmallVector &b) noexcept
1517  {
1518  std::swap(a.data_ptr_, b.data_ptr_);
1519  std::swap(a.capacity_, b.capacity_);
1520  std::swap(a.size_, b.size_);
1521  }
1522 
1529  static void swap_heap_with_internal(SmallVector &a, SmallVector &b)
1530  {
1531  uninitialized_move_or_copy(b.begin(), b.end(),
1532  reinterpret_cast<ValueType*>(a.internal_array_.data()));
1533  destroy_range(b.begin(), b.end());
1534 
1535  b.data_ptr_ = a.data_ptr_;
1536  a.data_ptr_ = a.internal_array_.data();
1537 
1538  std::swap(a.capacity_, b.capacity_);
1539  std::swap(a.size_, b.size_);
1540  }
1541 
1547  static void swap_internal_with_internal(SmallVector &a, SmallVector &b)
1548  {
1549  if (a.size_ <= b.size_)
1550  {
1551  for (SmallVector::SizeType i = 0; i != a.size_; ++i)
1552  std::swap(a.data()[i], b.data()[i]);
1553 
1554  uninitialized_move_or_copy(b.begin() + a.size_, b.end(), a.begin() + a.size_);
1555  destroy_range(b.begin() + a.size_, b.end());
1556  }
1557  else
1558  {
1559  for (SizeType i = 0; i != b.size_; ++i)
1560  std::swap(a.data()[i], b.data()[i]);
1561 
1562  uninitialized_move_or_copy(a.begin() + b.size_, a.end(), b.begin() + b.size_);
1563  destroy_range(a.begin() + b.size_, a.end());
1564  }
1565 
1566  std::swap(a.size_, b.size_);
1567  }
1568 
1573  template <typename T>
1574  static typename std::enable_if_t<not std::is_nothrow_move_constructible<T>::value>
1575  uninitialized_move(T* src_begin, T* src_end, T* dest_begin)
1576  {
1577  auto src = src_begin;
1578  auto dest = dest_begin;
1579 
1580  try
1581  {
1582  while (src != src_end)
1583  {
1584  ::new (static_cast<void*>(dest)) ValueType(std::move(*src));
1585  ++src;
1586  ++dest;
1587  }
1588  }
1589  catch (...)
1590  {
1591  for (auto p = dest_begin; p != dest; ++p)
1592  p->~ValueType();
1593 
1594  throw;
1595  }
1596  }
1597 
1602  template <typename T>
1603  static typename std::enable_if_t<std::is_nothrow_move_constructible<T>::value>
1604  uninitialized_move(T* src_begin, T* src_end, T* dest_begin) noexcept
1605  {
1606  auto src = src_begin;
1607  auto dest = dest_begin;
1608 
1609  while (src != src_end)
1610  {
1611  ::new (static_cast<void*>(dest)) ValueType(std::move(*src));
1612  ++src;
1613  ++dest;
1614  }
1615  }
1616 
1619  template <typename T>
1620  static typename std::enable_if_t<std::is_nothrow_move_constructible<T>::value>
1621  uninitialized_move_or_copy(T* src_begin, T* src_end, T* dest_begin) noexcept
1622  {
1623  uninitialized_move(src_begin, src_end, dest_begin);
1624  }
1625 
1628  template <typename T>
1629  static typename std::enable_if_t<not std::is_nothrow_move_constructible<T>::value and
1630  std::is_copy_constructible<T>::value>
1631  uninitialized_move_or_copy(T* src_begin, T* src_end, T* dest_begin)
1632  {
1633  std::uninitialized_copy(src_begin, src_end, dest_begin);
1634  }
1635 
1638  template <typename T>
1639  static typename std::enable_if_t<not std::is_nothrow_move_constructible<T>::value
1640  and not std::is_copy_constructible<T>::value>
1641  uninitialized_move_or_copy(T* src_begin, T* src_end, T* dest_begin)
1642  {
1643  uninitialized_move(src_begin, src_end, dest_begin);
1644  }
1645 };
1646 
1647 
1655 template<typename ElementT, size_t in_capacity>
1657 {
1658  a.swap(b);
1659 }
1660 
1662 
1663 } // namespace gul14
1664 
1665 #endif
1666 
1667 // vi:ts=4:sw=4:sts=4:et
Declaration of the overload set for cat() and of the associated class ConvertingStringView.
A resizable container with contiguous storage that can hold a specified number of elements without al...
Definition: SmallVector.h:270
constexpr SizeType capacity() const noexcept
Return the number of elements that can currently be stored in this vector without having to allocate ...
Definition: SmallVector.h:545
constexpr ConstReference back() const noexcept
Return a const reference to the last element in the vector.
Definition: SmallVector.h:518
Iterator iterator
Iterator to an element.
Definition: SmallVector.h:295
SmallVector & operator=(SmallVector &&other) noexcept(std::is_nothrow_move_constructible< ValueType >::value)
Move assignment operator: Assign all of the elements from another vector to this one using move seman...
Definition: SmallVector.h:935
Iterator erase(ConstIterator pos)
Erase a single element from the vector, moving elements behind it forward.
Definition: SmallVector.h:717
SmallVector & operator=(const SmallVector &other) noexcept(std::is_nothrow_copy_assignable< ValueType >::value)
Copy assignment operator: Copy all elements from another SmallVector after clearing all previous cont...
Definition: SmallVector.h:908
constexpr ConstReference front() const noexcept
Return a const reference to the first element in the vector.
Definition: SmallVector.h:762
ReverseIterator rbegin() noexcept
Return a reverse iterator to the first element of the reversed vector (which is the last element of t...
Definition: SmallVector.h:1049
friend bool operator!=(const SmallVector &lhs, const SmallVector &rhs)
Inequality operator: Return true if both vectors have a different size() or at least one different el...
Definition: SmallVector.h:978
void resize(SizeType num_elements)
Change the number of elements in the container.
Definition: SmallVector.h:1106
constexpr Iterator begin() noexcept
Return an iterator to the first element of the vector.
Definition: SmallVector.h:527
Reference emplace_back(ArgumentTypes &&... arguments)
Construct an additional element at the end of the buffer.
Definition: SmallVector.h:672
Iterator insert(ConstIterator pos, SizeType num_elements, const ValueType &value)
Insert a number of copies of the given value before the indicated position.
Definition: SmallVector.h:810
ReverseIterator reverse_iterator
Iterator to an element in reversed container.
Definition: SmallVector.h:303
void pop_back()
Remove the last element from the vector.
Definition: SmallVector.h:999
SmallVector & operator=(std::initializer_list< ValueType > init)
Assign the elements of an initializer list to this vector after clearing all previous contents.
Definition: SmallVector.h:953
uint32_t SizeType
Unsigned integer type for indexing, number of elements, capacity.
Definition: SmallVector.h:277
constexpr const ValueType * data() const noexcept
Return a pointer to the contiguous data storage of the vector.
Definition: SmallVector.h:610
constexpr Reference at(SizeType idx)
Return a reference to the element at the specified index with bounds-checking.
Definition: SmallVector.h:490
const ValueType & ConstReference
Reference to a const element.
Definition: SmallVector.h:289
Iterator insert(ConstIterator pos, InputIterator first, InputIterator last)
Insert a range of values before the indicated position.
Definition: SmallVector.h:851
void assign(SizeType num_elements, const ValueType &value)
Fill the vector with a certain number of copies of the given value after clearing all previous conten...
Definition: SmallVector.h:436
constexpr Reference back() noexcept
Return a reference to the last element in the vector.
Definition: SmallVector.h:509
friend bool operator==(const SmallVector &lhs, const SmallVector &rhs)
Equality operator: Return true if both vectors have the same size() and the same elements.
Definition: SmallVector.h:966
constexpr SizeType max_size() const noexcept
Return the maximum number of elements that this vector can theoretically hold.
Definition: SmallVector.h:896
Iterator insert(ConstIterator pos, std::initializer_list< ValueType > init)
Insert elements from an initializer list before the indicated position.
Definition: SmallVector.h:885
void reserve(SizeType new_capacity)
Increase the capacity of the vector to the specified size.
Definition: SmallVector.h:1072
~SmallVector()
Destructor: Destroys all stored elements and frees all allocated memory.
Definition: SmallVector.h:421
ValueType * Iterator
Iterator to an element.
Definition: SmallVector.h:293
void swap(SmallVector &other)
Exchange the contents of this SmallVector with those of another one.
Definition: SmallVector.h:1195
ReverseIterator rend() noexcept
Return a reverse iterator pointing past the last element of the reversed vector.
Definition: SmallVector.h:1059
Iterator erase(ConstIterator first, ConstIterator last)
Erase a range of elements from the vector, moving elements behind the range forward.
Definition: SmallVector.h:735
Iterator emplace(ConstIterator pos, ArgumentTypes &&... arguments)
Construct an additional element at an arbitrary position in the vector.
Definition: SmallVector.h:641
DifferenceType difference_type
Signed integer type for the difference of two iterators.
Definition: SmallVector.h:283
ConstIterator const_iterator
Iterator to a const element.
Definition: SmallVector.h:299
void assign(std::initializer_list< ValueType > init)
Assign the elements of an initializer list to this vector after clearing all previous contents.
Definition: SmallVector.h:476
constexpr ValueType * data() noexcept
Return a pointer to the contiguous data storage of the vector.
Definition: SmallVector.h:601
ElementT ValueType
Type of the elements in the underlying container.
Definition: SmallVector.h:273
constexpr ConstReference at(SizeType idx) const
Return a const reference to the element at the specified index.
Definition: SmallVector.h:498
constexpr Iterator end() noexcept
Return an iterator pointing past the last element of the vector.
Definition: SmallVector.h:692
SizeType size_type
Unsigned integer type for indexing, number of elements, capacity.
Definition: SmallVector.h:279
constexpr bool empty() const noexcept
Determine if the vector is empty.
Definition: SmallVector.h:686
constexpr ConstIterator cend() const noexcept
Return a const iterator pointing past the last element of the vector.
Definition: SmallVector.h:560
ValueType value_type
Type of the elements in the underlying container.
Definition: SmallVector.h:275
Iterator insert(ConstIterator pos, const ValueType &value)
Insert a single element before the indicated position.
Definition: SmallVector.h:782
ConstReference const_reference
Reference to a const element.
Definition: SmallVector.h:291
std::reverse_iterator< ConstIterator > ConstReverseIterator
Iterator to a const element in reversed container.
Definition: SmallVector.h:305
const ValueType * ConstIterator
Iterator to a const element.
Definition: SmallVector.h:297
SmallVector() noexcept=default
Construct an empty SmallVector.
SmallVector(SizeType num_elements, const ValueType &value)
Construct a SmallVector that is filled with a certain number of copies of the given value.
Definition: SmallVector.h:343
SmallVector(InputIterator first, InputIterator last)
Construct a SmallVector that is filled with copies of elements from the given range.
Definition: SmallVector.h:366
void resize(SizeType num_elements, const ValueType &element)
Change the number of elements in the container.
Definition: SmallVector.h:1136
ValueType & Reference
Reference to an element.
Definition: SmallVector.h:285
constexpr SizeType inner_capacity() const noexcept
Return the number of elements this SmallVector can hold internally without having to allocate storage...
Definition: SmallVector.h:771
Reference reference
Reference to an element.
Definition: SmallVector.h:287
SmallVector(std::initializer_list< ValueType > init)
Construct a SmallVector that is filled with copies of the elements from a given initializer list.
Definition: SmallVector.h:415
void shrink_to_fit()
Reduce the capacity as far as possible while retaining all stored elements.
Definition: SmallVector.h:1155
constexpr ConstIterator end() const noexcept
Return a const iterator pointing past the last element of the vector.
Definition: SmallVector.h:701
constexpr ConstIterator begin() const noexcept
Return a const iterator to the first element of the vector.
Definition: SmallVector.h:536
void push_back(ValueType &&value)
Move one element to the end of the buffer.
Definition: SmallVector.h:1033
constexpr ConstIterator cbegin() const noexcept
Return a const iterator to the first element of the vector.
Definition: SmallVector.h:551
ConstReverseIterator crbegin() noexcept
Return a const reverse iterator to the first element of the reversed vector (which is the last elemen...
Definition: SmallVector.h:581
Iterator insert(ConstIterator pos, ValueType &&value)
Insert a single element before the indicated position.
Definition: SmallVector.h:796
std::reverse_iterator< Iterator > ReverseIterator
Iterator to an element in reversed container.
Definition: SmallVector.h:301
void assign(InputIterator first, InputIterator last)
Fill the vector with copies of elements from the given range.
Definition: SmallVector.h:463
constexpr Reference operator[](SizeType idx)
Return a reference to the element at the specified index.
Definition: SmallVector.h:984
void clear() noexcept
Erase all elements from the container without changing its capacity.
Definition: SmallVector.h:569
constexpr Reference front() noexcept
Return a reference to the first element in the vector.
Definition: SmallVector.h:753
constexpr ConstReference operator[](SizeType idx) const
Return a const reference to the element at the specified index.
Definition: SmallVector.h:990
std::ptrdiff_t DifferenceType
Signed integer type for the difference of two iterators.
Definition: SmallVector.h:281
ConstReverseIterator const_reverse_iterator
Iterator to a const element in reversed container.
Definition: SmallVector.h:307
SmallVector(SmallVector &&other) noexcept(std::is_nothrow_move_constructible< ValueType >::value)
Move constructor: Create a SmallVector from the contents of another one with the same inner capacity ...
Definition: SmallVector.h:402
ConstReverseIterator crend() noexcept
Return a const reverse iterator pointing past the last element of the reversed vector.
Definition: SmallVector.h:592
void push_back(const ValueType &value)
Copy one element to the end of the buffer.
Definition: SmallVector.h:1015
constexpr SizeType size() const noexcept
Return the number of elements that are currently stored.
Definition: SmallVector.h:1186
SmallVector(const SmallVector &other) noexcept(std::is_nothrow_copy_constructible< ValueType >::value)
Create a copy of another SmallVector with the same inner capacity.
Definition: SmallVector.h:379
void swap(SmallVector< ElementT, in_capacity > &a, SmallVector< ElementT, in_capacity > &b)
Exchange the contents of one SmallVector with those of another one.
Definition: SmallVector.h:1656
std::string cat()
Efficiently concatenate an arbitrary number of strings and numbers.
Definition: cat.h:97
Definition of macros used internally by GUL.
Namespace gul14 contains all functions and classes of the General Utility Library.
Definition: doxygen.h:26