General Utility Library for C++14  2.13
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 <cstdint>
29 #include <initializer_list>
30 #include <iterator>
31 #include <limits>
32 #include <memory>
33 #include <stdexcept>
34 #include <type_traits>
35 
36 #include "gul14/internal.h"
37 #include "gul14/cat.h"
38 
39 namespace gul14 {
40 
269 template <typename ElementT, size_t in_capacity>
271 {
272 public:
274  using ValueType = ElementT;
278  using SizeType = uint32_t;
282  using DifferenceType = std::ptrdiff_t;
290  using ConstReference = const ValueType&;
294  using Iterator = ValueType*;
298  using ConstIterator = const ValueType*;
302  using ReverseIterator = std::reverse_iterator<Iterator>;
306  using ConstReverseIterator = std::reverse_iterator<ConstIterator>;
309 
318  SmallVector() noexcept = default;
319 
326  explicit SmallVector(SizeType num_elements)
327  {
328  static_assert(std::is_default_constructible<ValueType>::value,
329  "SmallVector: Element type is not default-constructible");
330 
331  reserve(num_elements);
332  for (SizeType i = 0u; i != num_elements; ++i)
333  ::new(static_cast<void*>(data() + i)) ValueType{};
334  size_ = num_elements;
335  }
336 
344  SmallVector(SizeType num_elements, const ValueType& value)
345  {
346  fill_empty_vector_with_copied_value(num_elements, value);
347  }
348 
365  template<class InputIterator,
366  typename = std::enable_if_t<not std::is_integral<InputIterator>::value>>
367  SmallVector(InputIterator first, InputIterator last)
368  {
369  fill_empty_vector_with_copied_range(first, last);
370  }
371 
380  SmallVector(const SmallVector& other)
381  noexcept(std::is_nothrow_copy_constructible<ValueType>::value)
382  {
383  static_assert(std::is_copy_constructible<ValueType>::value == true,
384  "SmallVector: Element type is not copy-constructible");
385  fill_empty_vector_with_copied_range(other.cbegin(), other.cend());
386  }
387 
404  noexcept(std::is_nothrow_move_constructible<ValueType>::value)
405  {
406  move_or_copy_all_elements_from(std::move(other));
407  }
408 
416  SmallVector(std::initializer_list<ValueType> init)
417  {
418  fill_empty_vector_with_copied_range(init.begin(), init.end());
419  }
420 
423  {
424  clear();
425 
426  if (is_storage_allocated())
427  delete[] data_ptr_;
428  }
429 
437  void assign(SizeType num_elements, const ValueType& value)
438  {
439  clear();
440  fill_empty_vector_with_copied_value(num_elements, value);
441  }
442 
462  template<class InputIterator,
463  typename = std::enable_if_t<not std::is_integral<InputIterator>::value>>
464  void assign(InputIterator first, InputIterator last)
465  {
466  clear();
467  fill_empty_vector_with_copied_range(first, last);
468  }
469 
477  void assign(std::initializer_list<ValueType> init)
478  {
479  const auto num_elements = static_cast<SizeType>(init.size());
480 
481  clear();
482  reserve(num_elements);
483  std::uninitialized_copy(init.begin(), init.end(), data());
484  size_ = num_elements;
485  }
486 
491  constexpr Reference at(SizeType idx)
492  {
493  if (idx >= size_)
494  throw std::out_of_range(cat("Index out of range: ", idx, " >= ", size_));
495  return *(data() + idx);
496  }
497 
499  constexpr ConstReference at(SizeType idx) const
500  {
501  if (idx >= size_)
502  throw std::out_of_range(cat("Index out of range: ", idx, " >= ", size_));
503  return *(data() + idx);
504  }
505 
510  constexpr Reference back() noexcept
511  {
512  return *(data_end() - 1);
513  }
514 
519  constexpr ConstReference back() const noexcept
520  {
521  return *(data_end() - 1);
522  }
523 
528  constexpr Iterator begin() noexcept
529  {
530  return data();
531  }
532 
537  constexpr ConstIterator begin() const noexcept
538  {
539  return data();
540  }
541 
546  constexpr SizeType capacity() const noexcept { return capacity_; }
547 
552  constexpr ConstIterator cbegin() const noexcept
553  {
554  return begin();
555  }
556 
561  constexpr ConstIterator cend() const noexcept
562  {
563  return end();
564  }
565 
570  void clear() noexcept
571  {
572  destroy_range(data(), data_end());
573  size_ = 0;
574  }
575 
583  {
584  return std::make_reverse_iterator(end());
585  }
586 
594  {
595  return std::make_reverse_iterator(begin());
596  }
597 
602  constexpr ValueType* data() noexcept
603  {
604  return reinterpret_cast<ValueType*>(data_ptr_);
605  }
606 
611  constexpr const ValueType* data() const noexcept
612  {
613  return reinterpret_cast<const ValueType*>(data_ptr_);
614  }
615 
641  template <typename... ArgumentTypes>
642  Iterator emplace(ConstIterator pos, ArgumentTypes&&... arguments)
643  {
644  if (pos == cend())
645  {
646  emplace_back(std::forward<ArgumentTypes>(arguments)...);
647  return data_end() - 1;
648  }
649 
650  ValueType v(std::forward<ArgumentTypes>(arguments)...);
651 
652  return insert_single_value(pos, std::move(v));
653  }
654 
672  template <typename... ArgumentTypes>
673  Reference emplace_back(ArgumentTypes&&... arguments)
674  {
675  if (size_ == capacity_)
676  grow();
677 
678  ::new(static_cast<void*>(data_end()))
679  ValueType(std::forward<ArgumentTypes>(arguments)...);
680 
681  ++size_;
682 
683  return back();
684  }
685 
687  constexpr bool empty() const noexcept { return size_ == 0u; }
688 
693  constexpr Iterator end() noexcept
694  {
695  return data_end();
696  }
697 
702  constexpr ConstIterator end() const noexcept
703  {
704  return data_end();
705  }
706 
719  {
720  return erase(pos, pos + 1);
721  }
722 
737  {
738  auto range_begin = const_cast<Iterator>(first);
739  auto range_end = const_cast<Iterator>(last);
740  auto num_elements = range_end - range_begin;
741 
742  std::move(range_end, end(), range_begin);
743  destroy_range(end() - num_elements, end());
744 
745  size_ -= static_cast<SizeType>(num_elements);
746 
747  return range_begin;
748  }
749 
754  constexpr Reference front() noexcept
755  {
756  return *data();
757  }
758 
763  constexpr ConstReference front() const noexcept
764  {
765  return *data();
766  }
767 
772  constexpr SizeType inner_capacity() const noexcept { return in_capacity; }
773 
784  {
785  return insert_single_value(pos, value);
786  }
787 
798  {
799  return insert_single_value(pos, std::move(value));
800  }
801 
811  Iterator insert(ConstIterator pos, SizeType num_elements, const ValueType& value)
812  {
813  const auto idx = static_cast<SizeType>(pos - begin());
814  if (num_elements < 1)
815  return begin() + idx;
816 
817  const SizeType num_assignable = make_space_at_idx_for_n_elements(idx, num_elements);
818  Iterator insert_pos = begin() + idx;
819 
820  // Copy-assign to moved-from elements
821  std::fill_n(insert_pos, num_assignable, value);
822 
823  // Copy the remaining values into uninitialized cells
824  copy_value_into_uninitialized_cells(size_, num_elements - num_assignable, value);
825 
826  size_ += num_elements;
827 
828  return insert_pos;
829  }
830 
850  template<class InputIterator,
851  typename = std::enable_if_t<not std::is_integral<InputIterator>::value>>
852  Iterator insert(ConstIterator pos, InputIterator first, InputIterator last)
853  {
854  const auto idx = static_cast<SizeType>(pos - begin());
855  const auto num_elements = static_cast<SizeType>(std::distance(first, last));
856  if (num_elements < 1)
857  return begin() + idx;
858 
859  const SizeType num_assignable = make_space_at_idx_for_n_elements(idx, num_elements);
860  Iterator insert_pos = begin() + idx;
861 
862  // Copy-assign to moved-from elements
863  std::copy_n(first, num_assignable, insert_pos);
864 
865  // Copy the remaining values into uninitialized cells
866  copy_range_into_uninitialized_cells(size_, first + num_assignable, last);
867 
868  size_ += num_elements;
869 
870  return insert_pos;
871  }
872 
886  Iterator insert(ConstIterator pos, std::initializer_list<ValueType> init)
887  {
888  return insert(pos, init.begin(), init.end());
889  }
890 
897  constexpr SizeType max_size() const noexcept
898  {
899  return std::numeric_limits<SizeType>::max();
900  }
901 
910  noexcept(std::is_nothrow_copy_assignable<ValueType>::value)
911  {
912  if (&other != this)
913  {
914  clear();
915  reserve(other.size());
916  std::uninitialized_copy(other.cbegin(), other.cend(), data());
917  size_ = other.size();
918  }
919 
920  return *this;
921  }
922 
937  noexcept(std::is_nothrow_move_constructible<ValueType>::value)
938  {
939  if (&other != this)
940  {
941  clear();
942  if (is_storage_allocated())
943  delete[] data_ptr_;
944  move_or_copy_all_elements_from(std::move(other));
945  }
946 
947  return *this;
948  }
949 
954  SmallVector& operator=(std::initializer_list<ValueType> init)
955  {
956  assign(init);
957  return *this;
958  }
959 
967  friend bool operator==(const SmallVector& lhs, const SmallVector& rhs)
968  {
969  return std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend());
970  }
971 
979  friend bool operator!=(const SmallVector& lhs, const SmallVector& rhs)
980  {
981  return not (lhs == rhs);
982  }
983 
986  {
987  return *(data() + idx);
988  }
989 
991  constexpr ConstReference operator[](SizeType idx) const
992  {
993  return *(data() + idx);
994  }
995 
1000  void pop_back()
1001  {
1002  --size_;
1003  auto p = data_end();
1004  p->~ValueType();
1005  }
1006 
1016  void push_back(const ValueType& value)
1017  {
1018  if (size_ == capacity_)
1019  grow();
1020 
1021  ::new(static_cast<void*>(data_end())) ValueType(value);
1022 
1023  ++size_;
1024  }
1025 
1034  void push_back(ValueType&& value)
1035  {
1036  if (size_ == capacity_)
1037  grow();
1038 
1039  ::new(static_cast<void*>(data_end())) ValueType(std::move(value));
1040 
1041  ++size_;
1042  }
1043 
1051  {
1052  return std::make_reverse_iterator(end());
1053  }
1054 
1061  {
1062  return std::make_reverse_iterator(begin());
1063  }
1064 
1073  void reserve(SizeType new_capacity)
1074  {
1075  if (new_capacity <= capacity_)
1076  return;
1077 
1078  auto new_data = std::make_unique<AlignedStorage[]>(new_capacity);
1079 
1080  const auto d_end = data_end();
1081 
1082  uninitialized_move_or_copy(data(), d_end, reinterpret_cast<ValueType*>(new_data.get()));
1083  destroy_range(data(), d_end);
1084 
1085  if (is_storage_allocated())
1086  delete[] data_ptr_;
1087 
1088  data_ptr_ = new_data.release();
1089  capacity_ = new_capacity;
1090  }
1091 
1107  void resize(SizeType num_elements)
1108  {
1109  static_assert(std::is_default_constructible<ValueType>::value,
1110  "SmallVector: For using resize(), element type must be default-constructible");
1111 
1112  if (num_elements < size_)
1113  {
1114  destroy_range(data() + num_elements, data_end());
1115  }
1116  else if (num_elements > size_)
1117  {
1118  reserve(num_elements);
1119  fill_uninitialized_cells_with_default_constructed_elements(size_,
1120  num_elements - size_);
1121  }
1122 
1123  size_ = num_elements;
1124  }
1125 
1137  void resize(SizeType num_elements, const ValueType& element)
1138  {
1139  if (num_elements < size_)
1140  {
1141  destroy_range(data() + num_elements, data_end());
1142  }
1143  else if (num_elements > size_)
1144  {
1145  reserve(num_elements);
1146  copy_value_into_uninitialized_cells(size_, num_elements - size_, element);
1147  }
1148 
1149  size_ = num_elements;
1150  }
1151 
1157  {
1158  const SizeType new_capacity = std::max(inner_capacity(), size_);
1159 
1160  // No shrinking required?
1161  if (new_capacity == capacity_)
1162  return;
1163 
1164  AlignedStorage* new_data;
1165  auto new_memory = std::unique_ptr<AlignedStorage[]>{};
1166 
1167  if (new_capacity == inner_capacity()) {
1168  new_data = internal_array_.data();
1169  } else {
1170  new_memory = std::make_unique<AlignedStorage[]>(new_capacity);
1171  new_data = new_memory.get();
1172  }
1173 
1174  const auto d_end = data_end();
1175 
1176  uninitialized_move_or_copy(data(), d_end, reinterpret_cast<ValueType*>(new_data));
1177  destroy_range(data(), d_end);
1178 
1179  if (is_storage_allocated())
1180  delete[] data_ptr_;
1181 
1182  data_ptr_ = new_memory ? new_memory.release() : new_data;
1183  capacity_ = new_capacity;
1184  }
1185 
1187  constexpr SizeType size() const noexcept { return size_; }
1188 
1196  void swap(SmallVector& other)
1197  {
1198  if (is_storage_allocated())
1199  {
1200  if (other.is_storage_allocated())
1201  swap_heap_with_heap(*this, other);
1202  else
1203  swap_heap_with_internal(*this, other);
1204  }
1205  else
1206  {
1207  if (other.is_storage_allocated())
1208  swap_heap_with_internal(other, *this);
1209  else
1210  swap_internal_with_internal(*this, other);
1211  }
1212  }
1213 
1214 private:
1215  using AlignedStorage =
1216  typename std::aligned_storage<sizeof(ValueType), alignof(ValueType)>::type;
1217 
1222  std::array<AlignedStorage, in_capacity> internal_array_;
1223 
1225  AlignedStorage* data_ptr_{ internal_array_.data() };
1226 
1229  SizeType capacity_{ in_capacity };
1231  SizeType size_{ 0u };
1232 
1245  template<class InputIterator>
1246  void copy_range_into_uninitialized_cells(SizeType pos, InputIterator first,
1247  InputIterator last)
1248  {
1249  auto data_ptr = data() + pos;
1250 
1251  try
1252  {
1253  for (auto it = first; it != last; ++it)
1254  {
1255  ::new(static_cast<void*>(data_ptr)) ValueType{ *it };
1256  ++data_ptr;
1257  }
1258  }
1259  catch (...)
1260  {
1261  for (auto p = data() + pos; p != data_ptr; ++p)
1262  p->~ValueType();
1263 
1264  throw;
1265  }
1266  }
1267 
1274  void copy_value_into_uninitialized_cells(SizeType pos, SizeType num_elements,
1275  const ValueType& value)
1276  {
1277  const auto start_ptr = data() + pos;
1278  const auto end_ptr = start_ptr + num_elements;
1279  for (auto p = start_ptr; p != end_ptr; ++p)
1280  ::new(static_cast<void*>(p)) ValueType(value);
1281  }
1282 
1284  constexpr ValueType* data_end() noexcept
1285  {
1286  return reinterpret_cast<ValueType*>(data_ptr_) + size_;
1287  }
1288 
1290  constexpr const ValueType* data_end() const noexcept
1291  {
1292  return reinterpret_cast<const ValueType*>(data_ptr_) + size_;
1293  }
1294 
1303  static void destroy_range(Iterator it_start, Iterator it_end) noexcept
1304  {
1305  for (auto it = it_start; it != it_end; ++it)
1306  it->~ValueType();
1307  }
1308 
1323  template<typename InputIterator>
1324  void fill_empty_vector_with_copied_range(InputIterator first, InputIterator last)
1325  {
1326  const auto num_elements = static_cast<SizeType>(std::distance(first, last));
1327 
1328  reserve(num_elements);
1329  copy_range_into_uninitialized_cells(0u, first, last);
1330  size_ = num_elements;
1331  }
1332 
1341  void fill_empty_vector_with_copied_value(SizeType num_elements, const ValueType& value)
1342  {
1343  reserve(num_elements);
1344  copy_value_into_uninitialized_cells(0u, num_elements, value);
1345  size_ = num_elements;
1346  }
1347 
1356  void fill_uninitialized_cells_with_default_constructed_elements(SizeType pos,
1357  SizeType num_elements)
1358  {
1359  const auto start_ptr = data() + pos;
1360  const auto end_ptr = start_ptr + num_elements;
1361  auto ptr = start_ptr;
1362 
1363  try
1364  {
1365  for (; ptr != end_ptr; ++ptr)
1366  ::new(static_cast<void*>(ptr)) ValueType{};
1367  }
1368  catch (...)
1369  {
1370  destroy_range(start_ptr, ptr);
1371  throw;
1372  }
1373  }
1374 
1384  void grow()
1385  {
1386  const auto remaining_space = std::numeric_limits<SizeType>::max() - capacity_;
1387 
1388  if (remaining_space == 0u)
1389  throw std::length_error("Max. capacity reached");
1390 
1391  SizeType increase = capacity_ / 2u;
1392  if (increase > remaining_space)
1393  increase = remaining_space;
1394  else if (increase == 0u)
1395  increase = 1u;
1396 
1397  reserve(capacity_ + increase);
1398  }
1399 
1401  template <typename T>
1402  Iterator insert_single_value(ConstIterator pos, T&& value)
1403  {
1404  if (pos == end())
1405  {
1406  push_back(std::forward<T>(value));
1407  return begin() + size_ - 1;
1408  }
1409 
1410  const auto idx = static_cast<SizeType>(pos - begin());
1411 
1412  if (size_ == capacity_)
1413  grow();
1414 
1415  Iterator insert_pos = begin() + idx;
1416 
1417  auto data_ptr = data();
1418 
1419  // Construct new back() element by moving from the old back()
1420  ::new(static_cast<void*>(data_ptr + size_)) ValueType(std::move(*(data_ptr + size_ - 1)));
1421 
1422  std::move_backward(insert_pos, data_ptr + size_ - 1, data_ptr + size_);
1423  ++size_;
1424 
1425  *insert_pos = std::forward<T>(value);
1426 
1427  return insert_pos;
1428  }
1429 
1431  bool is_storage_allocated() const noexcept
1432  {
1433  return data_ptr_ != internal_array_.data();
1434  }
1435 
1446  SizeType make_space_at_idx_for_n_elements(SizeType idx, SizeType num_elements)
1447  {
1448  const auto new_size = size_ + num_elements;
1449 
1450  if (new_size > capacity_)
1451  reserve(new_size);
1452 
1453  auto data_ptr = data();
1454 
1455  // We have a total number of elements that need to be shifted backwards,
1456  // of which some need to be move-initialized at the end of the vector
1457  // and some simply need to be moved from one element to another.
1458  const SizeType num_shifted = size_ - idx;
1459  const SizeType num_move_initialized = std::min(num_shifted, num_elements);
1460  const SizeType num_moved = num_shifted - num_move_initialized;
1461 
1462  // Move-initialize elements in uninitialized space at the back of the container
1463  const auto from_ptr = data_ptr + size_ - num_move_initialized;
1464  const auto to_ptr = from_ptr + num_elements;
1465  for (SizeType i = 0; i != num_move_initialized; ++i)
1466  ::new(static_cast<void*>(to_ptr + i)) ValueType(std::move(*(from_ptr + i)));
1467 
1468  // Move elements backwards within old vector size
1469  std::move_backward(data_ptr + idx, data_ptr + idx + num_moved, to_ptr);
1470 
1471  return num_move_initialized;
1472  }
1473 
1492  void move_or_copy_all_elements_from(SmallVector&& other)
1493  noexcept(std::is_nothrow_move_constructible<ValueType>::value)
1494  {
1495  // Can we simply steal the complete allocated storage?
1496  if (other.is_storage_allocated())
1497  {
1498  data_ptr_ = other.data_ptr_; other.data_ptr_ = other.internal_array_.data();
1499  capacity_ = other.capacity_; other.capacity_ = other.inner_capacity();
1500  size_ = other.size_; other.size_ = 0u;
1501  }
1502  else // otherwise fall back to moving (or at least copying) all elements
1503  {
1504  data_ptr_ = internal_array_.data();
1505  capacity_ = in_capacity;
1506  uninitialized_move_or_copy(other.begin(), other.end(), data());
1507  size_ = other.size();
1508  other.clear();
1509  }
1510  }
1511 
1517  static void swap_heap_with_heap(SmallVector &a, SmallVector &b) noexcept
1518  {
1519  std::swap(a.data_ptr_, b.data_ptr_);
1520  std::swap(a.capacity_, b.capacity_);
1521  std::swap(a.size_, b.size_);
1522  }
1523 
1530  static void swap_heap_with_internal(SmallVector &a, SmallVector &b)
1531  {
1532  uninitialized_move_or_copy(b.begin(), b.end(),
1533  reinterpret_cast<ValueType*>(a.internal_array_.data()));
1534  destroy_range(b.begin(), b.end());
1535 
1536  b.data_ptr_ = a.data_ptr_;
1537  a.data_ptr_ = a.internal_array_.data();
1538 
1539  std::swap(a.capacity_, b.capacity_);
1540  std::swap(a.size_, b.size_);
1541  }
1542 
1548  static void swap_internal_with_internal(SmallVector &a, SmallVector &b)
1549  {
1550  if (a.size_ <= b.size_)
1551  {
1552  for (SmallVector::SizeType i = 0; i != a.size_; ++i)
1553  std::swap(a.data()[i], b.data()[i]);
1554 
1555  uninitialized_move_or_copy(b.begin() + a.size_, b.end(), a.begin() + a.size_);
1556  destroy_range(b.begin() + a.size_, b.end());
1557  }
1558  else
1559  {
1560  for (SizeType i = 0; i != b.size_; ++i)
1561  std::swap(a.data()[i], b.data()[i]);
1562 
1563  uninitialized_move_or_copy(a.begin() + b.size_, a.end(), b.begin() + b.size_);
1564  destroy_range(a.begin() + b.size_, a.end());
1565  }
1566 
1567  std::swap(a.size_, b.size_);
1568  }
1569 
1574  template <typename T>
1575  static typename std::enable_if_t<not std::is_nothrow_move_constructible<T>::value>
1576  uninitialized_move(T* src_begin, T* src_end, T* dest_begin)
1577  {
1578  auto src = src_begin;
1579  auto dest = dest_begin;
1580 
1581  try
1582  {
1583  while (src != src_end)
1584  {
1585  ::new (static_cast<void*>(dest)) ValueType(std::move(*src));
1586  ++src;
1587  ++dest;
1588  }
1589  }
1590  catch (...)
1591  {
1592  for (auto p = dest_begin; p != dest; ++p)
1593  p->~ValueType();
1594 
1595  throw;
1596  }
1597  }
1598 
1603  template <typename T>
1604  static typename std::enable_if_t<std::is_nothrow_move_constructible<T>::value>
1605  uninitialized_move(T* src_begin, T* src_end, T* dest_begin) noexcept
1606  {
1607  auto src = src_begin;
1608  auto dest = dest_begin;
1609 
1610  while (src != src_end)
1611  {
1612  ::new (static_cast<void*>(dest)) ValueType(std::move(*src));
1613  ++src;
1614  ++dest;
1615  }
1616  }
1617 
1620  template <typename T>
1621  static typename std::enable_if_t<std::is_nothrow_move_constructible<T>::value>
1622  uninitialized_move_or_copy(T* src_begin, T* src_end, T* dest_begin) noexcept
1623  {
1624  uninitialized_move(src_begin, src_end, dest_begin);
1625  }
1626 
1629  template <typename T>
1630  static typename std::enable_if_t<not std::is_nothrow_move_constructible<T>::value and
1631  std::is_copy_constructible<T>::value>
1632  uninitialized_move_or_copy(T* src_begin, T* src_end, T* dest_begin)
1633  {
1634  std::uninitialized_copy(src_begin, src_end, dest_begin);
1635  }
1636 
1639  template <typename T>
1640  static typename std::enable_if_t<not std::is_nothrow_move_constructible<T>::value
1641  and not std::is_copy_constructible<T>::value>
1642  uninitialized_move_or_copy(T* src_begin, T* src_end, T* dest_begin)
1643  {
1644  uninitialized_move(src_begin, src_end, dest_begin);
1645  }
1646 };
1647 
1648 
1656 template<typename ElementT, size_t in_capacity>
1658 {
1659  a.swap(b);
1660 }
1661 
1663 
1664 } // namespace gul14
1665 
1666 #endif
1667 
1668 // 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:271
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:546
constexpr ConstReference back() const noexcept
Return a const reference to the last element in the vector.
Definition: SmallVector.h:519
Iterator iterator
Iterator to an element.
Definition: SmallVector.h:296
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:936
Iterator erase(ConstIterator pos)
Erase a single element from the vector, moving elements behind it forward.
Definition: SmallVector.h:718
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:909
constexpr ConstReference front() const noexcept
Return a const reference to the first element in the vector.
Definition: SmallVector.h:763
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:1050
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:979
void resize(SizeType num_elements)
Change the number of elements in the container.
Definition: SmallVector.h:1107
constexpr Iterator begin() noexcept
Return an iterator to the first element of the vector.
Definition: SmallVector.h:528
Reference emplace_back(ArgumentTypes &&... arguments)
Construct an additional element at the end of the buffer.
Definition: SmallVector.h:673
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:811
ReverseIterator reverse_iterator
Iterator to an element in reversed container.
Definition: SmallVector.h:304
void pop_back()
Remove the last element from the vector.
Definition: SmallVector.h:1000
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:954
uint32_t SizeType
Unsigned integer type for indexing, number of elements, capacity.
Definition: SmallVector.h:278
constexpr const ValueType * data() const noexcept
Return a pointer to the contiguous data storage of the vector.
Definition: SmallVector.h:611
constexpr Reference at(SizeType idx)
Return a reference to the element at the specified index with bounds-checking.
Definition: SmallVector.h:491
const ValueType & ConstReference
Reference to a const element.
Definition: SmallVector.h:290
Iterator insert(ConstIterator pos, InputIterator first, InputIterator last)
Insert a range of values before the indicated position.
Definition: SmallVector.h:852
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:437
constexpr Reference back() noexcept
Return a reference to the last element in the vector.
Definition: SmallVector.h:510
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:967
constexpr SizeType max_size() const noexcept
Return the maximum number of elements that this vector can theoretically hold.
Definition: SmallVector.h:897
Iterator insert(ConstIterator pos, std::initializer_list< ValueType > init)
Insert elements from an initializer list before the indicated position.
Definition: SmallVector.h:886
void reserve(SizeType new_capacity)
Increase the capacity of the vector to the specified size.
Definition: SmallVector.h:1073
~SmallVector()
Destructor: Destroys all stored elements and frees all allocated memory.
Definition: SmallVector.h:422
ValueType * Iterator
Iterator to an element.
Definition: SmallVector.h:294
void swap(SmallVector &other)
Exchange the contents of this SmallVector with those of another one.
Definition: SmallVector.h:1196
ReverseIterator rend() noexcept
Return a reverse iterator pointing past the last element of the reversed vector.
Definition: SmallVector.h:1060
Iterator erase(ConstIterator first, ConstIterator last)
Erase a range of elements from the vector, moving elements behind the range forward.
Definition: SmallVector.h:736
Iterator emplace(ConstIterator pos, ArgumentTypes &&... arguments)
Construct an additional element at an arbitrary position in the vector.
Definition: SmallVector.h:642
DifferenceType difference_type
Signed integer type for the difference of two iterators.
Definition: SmallVector.h:284
ConstIterator const_iterator
Iterator to a const element.
Definition: SmallVector.h:300
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:477
constexpr ValueType * data() noexcept
Return a pointer to the contiguous data storage of the vector.
Definition: SmallVector.h:602
ElementT ValueType
Type of the elements in the underlying container.
Definition: SmallVector.h:274
constexpr ConstReference at(SizeType idx) const
Return a const reference to the element at the specified index.
Definition: SmallVector.h:499
constexpr Iterator end() noexcept
Return an iterator pointing past the last element of the vector.
Definition: SmallVector.h:693
SizeType size_type
Unsigned integer type for indexing, number of elements, capacity.
Definition: SmallVector.h:280
constexpr bool empty() const noexcept
Determine if the vector is empty.
Definition: SmallVector.h:687
constexpr ConstIterator cend() const noexcept
Return a const iterator pointing past the last element of the vector.
Definition: SmallVector.h:561
ValueType value_type
Type of the elements in the underlying container.
Definition: SmallVector.h:276
Iterator insert(ConstIterator pos, const ValueType &value)
Insert a single element before the indicated position.
Definition: SmallVector.h:783
ConstReference const_reference
Reference to a const element.
Definition: SmallVector.h:292
std::reverse_iterator< ConstIterator > ConstReverseIterator
Iterator to a const element in reversed container.
Definition: SmallVector.h:306
const ValueType * ConstIterator
Iterator to a const element.
Definition: SmallVector.h:298
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:344
SmallVector(InputIterator first, InputIterator last)
Construct a SmallVector that is filled with copies of elements from the given range.
Definition: SmallVector.h:367
void resize(SizeType num_elements, const ValueType &element)
Change the number of elements in the container.
Definition: SmallVector.h:1137
ValueType & Reference
Reference to an element.
Definition: SmallVector.h:286
constexpr SizeType inner_capacity() const noexcept
Return the number of elements this SmallVector can hold internally without having to allocate storage...
Definition: SmallVector.h:772
Reference reference
Reference to an element.
Definition: SmallVector.h:288
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:416
void shrink_to_fit()
Reduce the capacity as far as possible while retaining all stored elements.
Definition: SmallVector.h:1156
constexpr ConstIterator end() const noexcept
Return a const iterator pointing past the last element of the vector.
Definition: SmallVector.h:702
constexpr ConstIterator begin() const noexcept
Return a const iterator to the first element of the vector.
Definition: SmallVector.h:537
void push_back(ValueType &&value)
Move one element to the end of the buffer.
Definition: SmallVector.h:1034
constexpr ConstIterator cbegin() const noexcept
Return a const iterator to the first element of the vector.
Definition: SmallVector.h:552
ConstReverseIterator crbegin() noexcept
Return a const reverse iterator to the first element of the reversed vector (which is the last elemen...
Definition: SmallVector.h:582
Iterator insert(ConstIterator pos, ValueType &&value)
Insert a single element before the indicated position.
Definition: SmallVector.h:797
std::reverse_iterator< Iterator > ReverseIterator
Iterator to an element in reversed container.
Definition: SmallVector.h:302
void assign(InputIterator first, InputIterator last)
Fill the vector with copies of elements from the given range.
Definition: SmallVector.h:464
constexpr Reference operator[](SizeType idx)
Return a reference to the element at the specified index.
Definition: SmallVector.h:985
void clear() noexcept
Erase all elements from the container without changing its capacity.
Definition: SmallVector.h:570
constexpr Reference front() noexcept
Return a reference to the first element in the vector.
Definition: SmallVector.h:754
constexpr ConstReference operator[](SizeType idx) const
Return a const reference to the element at the specified index.
Definition: SmallVector.h:991
std::ptrdiff_t DifferenceType
Signed integer type for the difference of two iterators.
Definition: SmallVector.h:282
ConstReverseIterator const_reverse_iterator
Iterator to a const element in reversed container.
Definition: SmallVector.h:308
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:403
ConstReverseIterator crend() noexcept
Return a const reverse iterator pointing past the last element of the reversed vector.
Definition: SmallVector.h:593
void push_back(const ValueType &value)
Copy one element to the end of the buffer.
Definition: SmallVector.h:1016
constexpr SizeType size() const noexcept
Return the number of elements that are currently stored.
Definition: SmallVector.h:1187
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:380
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:1657
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