SeqAn3  3.0.3
The Modern C++ library for sequence analysis.
small_vector.hpp
Go to the documentation of this file.
1 // -----------------------------------------------------------------------------------------------------
2 // Copyright (c) 2006-2021, Knut Reinert & Freie Universität Berlin
3 // Copyright (c) 2016-2021, Knut Reinert & MPI für molekulare Genetik
4 // This file may be used, modified and/or redistributed under the terms of the 3-clause BSD-License
5 // shipped with this file and also available at: https://github.com/seqan/seqan3/blob/master/LICENSE.md
6 // -----------------------------------------------------------------------------------------------------
7 
13 #pragma once
14 
15 #include <array>
16 #include <type_traits>
17 
18 #if SEQAN3_WITH_CEREAL
19 #include <cereal/types/array.hpp>
20 #endif // SEQAN3_WITH_CEREAL
21 
26 
27 namespace seqan3
28 {
29 
45 template <typename value_type_, size_t capacity_>
47 {
48 private:
50  static constexpr bool is_noexcept = std::is_nothrow_copy_constructible_v<value_type_>;
51 
52 public:
60  using value_type = value_type_;
61 
66  using reference = value_type &;
67 
72  using const_reference = const value_type &;
73 
78  using iterator = value_type *;
79 
84  using const_iterator = value_type const *;
85 
90  using difference_type = ptrdiff_t;
91 
97 
99 
101  // this signals to range-v3 that something is a container :|
102  using allocator_type = void;
104 
108  constexpr small_vector() noexcept = default;
109  constexpr small_vector(small_vector const &) noexcept = default;
110  constexpr small_vector(small_vector &&) noexcept = default;
111  constexpr small_vector & operator=(small_vector const &) noexcept = default;
112  constexpr small_vector & operator=(small_vector &&) noexcept = default;
113  ~small_vector() noexcept = default;
114 
128  explicit constexpr small_vector(std::array<value_type, capacity_> const & array) noexcept(is_noexcept) :
129  data_{array}, sz{capacity_}
130  {}
131 
133  template <size_t capacity2>
134  explicit constexpr small_vector(std::array<value_type, capacity2> const & array) noexcept(is_noexcept) :
135  sz{capacity2}
136  {
137  static_assert(capacity2 <= capacity_, "You can only initialize from array that has smaller or equal capacity.");
138  std::ranges::copy(array, data_.begin());
139  }
141 
155  template <size_t capacity2>
156  explicit constexpr small_vector(value_type const (&array)[capacity2]) noexcept(is_noexcept) :
157  sz{capacity2}
158  {
159  static_assert(capacity2 <= capacity_, "You can only initialize from array that has smaller or equal capacity.");
160  std::ranges::copy(array, data_.begin());
161  }
162 
176  template <typename ...other_value_type>
178  requires (std::same_as<value_type, other_value_type> && ...)
180  constexpr small_vector(other_value_type... args) noexcept(is_noexcept) :
181  data_{args...}, sz{sizeof...(other_value_type)}
182  {
183  static_assert(sizeof...(other_value_type) <= capacity_, "Value list must not exceed the capacity.");
184  }
185 
203  template <std::forward_iterator begin_it_type, typename end_it_type>
205  requires std::sentinel_for<end_it_type, begin_it_type> &&
206  std::constructible_from<value_type, std::iter_reference_t<begin_it_type>>
208  constexpr small_vector(begin_it_type begin_it, end_it_type end_it) noexcept(is_noexcept) :
209  small_vector{}
210  {
211  assign(begin_it, end_it);
212  }
213 
229  template <std::ranges::input_range other_range_t>
232  /*ICE: && std::constructible_from<value_type, std::ranges::range_reference_t<other_range_t>>*/
234  explicit constexpr small_vector(other_range_t && range) noexcept(is_noexcept) :
235  small_vector{std::ranges::begin(range), std::ranges::end(range)}
236  {}
237 
252  constexpr small_vector(size_type n, value_type value) noexcept(is_noexcept) :
253  small_vector{}
254  {
255  assign(n, value);
256  }
257 
271  constexpr small_vector & operator=(std::initializer_list<value_type> ilist) noexcept(is_noexcept)
272  {
273  assign(std::ranges::begin(ilist), std::ranges::end(ilist));
274  return *this;
275  }
276 
290  constexpr void assign(std::initializer_list<value_type> ilist) noexcept(is_noexcept)
291  {
292  assign(std::ranges::begin(ilist), std::ranges::end(ilist));
293  }
294 
309  constexpr void assign(size_type const count, value_type const value) noexcept(is_noexcept)
310  {
311  clear();
312  auto tmp = views::repeat_n(value, count);
313  assign(std::ranges::begin(tmp), std::ranges::end(tmp));
314  }
315 
331  template <std::ranges::input_range other_range_t>
333  requires std::constructible_from<value_type, std::ranges::range_reference_t<other_range_t>>
335  constexpr void assign(other_range_t && range) noexcept(is_noexcept)
336  {
337  assign(std::ranges::begin(range), std::ranges::end(range));
338  }
339 
357  template <std::forward_iterator begin_it_type, typename end_it_type>
359  requires std::sentinel_for<end_it_type, begin_it_type> &&
360  std::constructible_from<value_type, std::iter_reference_t<begin_it_type>>
362  constexpr void assign(begin_it_type begin_it, end_it_type end_it) noexcept(is_noexcept)
363  {
364  clear();
365  insert(cbegin(), begin_it, end_it);
366  }
368 
376  constexpr iterator begin() noexcept
377  {
378  return data_.data();
379  }
380 
382  constexpr const_iterator begin() const noexcept
383  {
384  return data_.data();
385  }
386 
388  constexpr const_iterator cbegin() const noexcept
389  {
390  return data_.data();
391  }
392 
397  constexpr iterator end() noexcept
398  {
399  return data_.data() + sz;
400  }
401 
403  constexpr const_iterator end() const noexcept
404  {
405  return data_.data() + sz;
406  }
407 
409  constexpr const_iterator cend() const noexcept
410  {
411  return data_.data() + sz;
412  }
414 
436  {
437  if (i >= size()) // [[unlikely]]
438  {
439  throw std::out_of_range{"Trying to access element behind the last in small_vector."};
440  }
441  return (*this)[i];
442  }
443 
445  const_reference at(size_type const i) const
446  {
447  if (i >= size()) // [[unlikely]]
448  {
449  throw std::out_of_range{"Trying to access element behind the last in small_vector."};
450  }
451  return (*this)[i];
452  }
453 
471  constexpr reference operator[](size_type const i) noexcept
472  {
473  assert(i < size());
474  return data_[i];
475  }
476 
478  constexpr const_reference operator[](size_type const i) const noexcept
479  {
480  assert(i < size());
481  return data_[i];
482  }
483 
499  constexpr reference front() noexcept
500  {
501  assert(size() > 0);
502  return (*this)[0];
503  }
504 
506  constexpr const_reference front() const noexcept
507  {
508  assert(size() > 0);
509  return (*this)[0];
510  }
511 
527  constexpr reference back() noexcept
528  {
529  assert(size() > 0);
530  return (*this)[size()-1];
531  }
532 
534  constexpr const_reference back() const noexcept
535  {
536  assert(size() > 0);
537  return (*this)[size()-1];
538  }
539 
544  constexpr value_type * data() noexcept
545  {
546  return data_.data();
547  }
548 
550  constexpr value_type const * data() const noexcept
551  {
552  return data_.data();
553  }
555 
572  constexpr bool empty() const noexcept
573  {
574  return size() == 0;
575  }
576 
590  constexpr size_type size() const noexcept
591  {
592  return sz;
593  }
594 
611  constexpr size_type max_size() const noexcept
612  {
613  return capacity_;
614  }
615 
629  constexpr size_type capacity() const noexcept
630  {
631  return capacity_;
632  }
633 
638  constexpr void reserve(size_type) const noexcept
639  {
640  // no-op
641  }
642 
647  constexpr void shrink_to_fit() const noexcept
648  {
649  // no-op
650  }
652 
668  constexpr void clear() noexcept
669  {
670  sz = 0;
671  }
672 
690  constexpr iterator insert(const_iterator pos, value_type const value) noexcept(is_noexcept)
691  {
692  return insert(pos, 1, value);
693  }
694 
713  constexpr iterator insert(const_iterator pos, size_type const count, value_type const value) noexcept(is_noexcept)
714  {
715  auto tmp = views::repeat_n(value, count);
716  return insert(pos, std::ranges::begin(tmp), std::ranges::end(tmp));
717  }
718 
741  template <std::forward_iterator begin_it_type, typename end_it_type>
743  requires std::sentinel_for<end_it_type, begin_it_type> &&
744  std::constructible_from<value_type, std::iter_reference_t<begin_it_type>>
746  constexpr iterator insert(const_iterator pos, begin_it_type begin_it, end_it_type end_it) noexcept(is_noexcept)
747  {
748  auto const pos_as_num = std::ranges::distance(cbegin(), pos);
749  auto const length = std::ranges::distance(begin_it, end_it);
750 
751  assert(pos_as_num + length <= capacity());
752 
753  if (length == 0)
754  return begin(); // nothing to insert
755 
756  for (size_type i = sz + length - 1; i > pos_as_num + length - 1; --i)
757  data_[i] = data_[i - length];
758 
759  std::ranges::copy(begin_it, end_it, &data_[pos_as_num]);
760  sz += length;
761  return begin() + pos_as_num;
762  }
763 
781  constexpr iterator insert(const_iterator pos, std::initializer_list<value_type> const & ilist) noexcept(is_noexcept)
782  {
783  return insert(pos, ilist.begin(), ilist.end());
784  }
785 
806  constexpr iterator erase(const_iterator begin_it, const_iterator end_it) noexcept
807  {
808  if (begin_it >= end_it) // [[unlikely]]
809  return begin() + std::ranges::distance(cbegin(), end_it);
810 
811  size_type const length = std::ranges::distance(begin_it, end_it);
812  auto out_it = begin() + std::ranges::distance(cbegin(), begin_it);
813 
814  while (end_it != cend())
815  *(out_it++) = *(end_it++);
816 
817  sz -= length;
818  return begin() + std::ranges::distance(cbegin(), begin_it);
819  }
820 
841  constexpr iterator erase(const_iterator pos) noexcept
842  {
843  return erase(pos, pos + 1);
844  }
845 
861  constexpr void push_back(value_type const value) noexcept
862  {
863  assert(sz < capacity_);
864  data_[sz] = value;
865  ++sz;
866  }
867 
884  constexpr void pop_back() noexcept
885  {
886  assert(sz > 0);
887  --sz;
888  }
889 
905  constexpr void resize(size_type const count) noexcept
906  {
907  assert(count <= capacity_);
908  sz = count;
909  }
910 
915  constexpr void resize(size_type const count, value_type const value) noexcept
916  {
917  assert(count <= capacity_);
918  for (size_t i = sz; i < count; ++i)
919  data_[i] = value;
920  sz = count;
921  }
922 
936  constexpr void swap(small_vector & rhs) noexcept(is_noexcept)
937  {
938  auto tmp = *this;
939 
940  data_ = rhs.data_;
941  sz = rhs.sz;
942 
943  rhs.data_ = tmp.data_;
944  rhs.sz = tmp.sz;
945  }
946 
948  constexpr void swap(small_vector && rhs) noexcept(is_noexcept)
949  {
950  data_ = rhs.data_;
951  sz = rhs.sz;
952  }
954 
969  friend constexpr void swap(small_vector & lhs, small_vector & rhs) noexcept(is_noexcept)
970  {
971  lhs.swap(rhs);
972  }
973 
975  friend constexpr void swap(small_vector && lhs, small_vector && rhs) noexcept(is_noexcept)
976  {
977  lhs.swap(rhs);
978  }
979 
987  template <size_t cap2>
988  friend constexpr bool operator==(small_vector const & lhs, small_vector<value_type, cap2> const & rhs) noexcept
989  {
990  return std::ranges::equal(lhs, rhs);
991  }
992 
997  template <size_t cap2>
998  friend constexpr bool operator!=(small_vector const & lhs, small_vector<value_type, cap2> const & rhs) noexcept
999  {
1000  return !(lhs == rhs);
1001  }
1002 
1007  template <size_t cap2>
1008  friend constexpr bool operator<(small_vector const & lhs, small_vector<value_type, cap2> const & rhs) noexcept
1009  {
1010  for (size_t i = 0; i < std::min(lhs.size(), rhs.size()); ++i)
1011  if (lhs[i] > rhs[i])
1012  return false;
1013  else if (lhs[i] < rhs[i])
1014  return true;
1015  return lhs.size() < rhs.size();
1016  }
1017 
1022  template <size_t cap2>
1023  friend constexpr bool operator>(small_vector const & lhs, small_vector<value_type, cap2> const & rhs) noexcept
1024  {
1025  for (size_t i = 0; i < std::min(lhs.size(), rhs.size()); ++i)
1026  if (lhs[i] < rhs[i])
1027  return false;
1028  else if (lhs[i] > rhs[i])
1029  return true;
1030  return lhs.size() > rhs.size();
1031  }
1032 
1037  template <size_t cap2>
1038  friend constexpr bool operator<=(small_vector const & lhs, small_vector<value_type, cap2> const & rhs) noexcept
1039  {
1040  return !(lhs > rhs);
1041  }
1042 
1047  template <size_t cap2>
1048  friend constexpr bool operator>=(small_vector const & lhs, small_vector<value_type, cap2> const & rhs) noexcept
1049  {
1050  return !(lhs < rhs);
1051  }
1053 
1054 public:
1056 
1060  size_type sz{0};
1061 
1063 
1069  template <cereal_archive archive_t>
1070  void CEREAL_SERIALIZE_FUNCTION_NAME(archive_t & archive)
1071  {
1072  archive(data_);
1073  archive(sz);
1074  }
1076 };
1077 
1086 template <size_t capacity2, typename value_type>
1089 
1090 } // namespace seqan3
T begin(T... args)
Adaptions of concepts from the Cereal library.
A constexpr vector implementation with dynamic size at compile time.
Definition: small_vector.hpp:47
constexpr void swap(small_vector &rhs) noexcept(is_noexcept)
Swap contents with another instance.
Definition: small_vector.hpp:936
constexpr reference operator[](size_type const i) noexcept
Return the i-th element.
Definition: small_vector.hpp:471
constexpr bool empty() const noexcept
Checks whether the container is empty.
Definition: small_vector.hpp:572
constexpr friend bool operator>(small_vector const &lhs, small_vector< value_type, cap2 > const &rhs) noexcept
Performs element-wise comparison.
Definition: small_vector.hpp:1023
constexpr reference front() noexcept
Return the first element. Calling front on an empty container is undefined.
Definition: small_vector.hpp:499
constexpr friend bool operator==(small_vector const &lhs, small_vector< value_type, cap2 > const &rhs) noexcept
Performs element-wise comparison.
Definition: small_vector.hpp:988
constexpr friend bool operator<(small_vector const &lhs, small_vector< value_type, cap2 > const &rhs) noexcept
Performs element-wise comparison.
Definition: small_vector.hpp:1008
constexpr small_vector(begin_it_type begin_it, end_it_type end_it) noexcept(is_noexcept)
Construct from two iterators.
Definition: small_vector.hpp:208
constexpr void shrink_to_fit() const noexcept
Since the capacity is fixed on compile time, this is a no-op.
Definition: small_vector.hpp:647
constexpr const_iterator cbegin() const noexcept
Returns the begin to the string.
Definition: small_vector.hpp:388
constexpr iterator insert(const_iterator pos, size_type const count, value_type const value) noexcept(is_noexcept)
Inserts count copies of value before position in the container.
Definition: small_vector.hpp:713
constexpr void resize(size_type const count) noexcept
Resizes the container to contain count elements.
Definition: small_vector.hpp:905
constexpr size_type capacity() const noexcept
Returns the number of elements that the container is able to hold and resolves to capacity_.
Definition: small_vector.hpp:629
constexpr void assign(begin_it_type begin_it, end_it_type end_it) noexcept(is_noexcept)
Assign from pair of iterators.
Definition: small_vector.hpp:362
constexpr small_vector() noexcept=default
Defaulted.
const value_type & const_reference
The const_reference type.
Definition: small_vector.hpp:72
constexpr small_vector & operator=(std::initializer_list< value_type > ilist) noexcept(is_noexcept)
Assign from std::initializer_list.
Definition: small_vector.hpp:271
constexpr void assign(size_type const count, value_type const value) noexcept(is_noexcept)
Assign with count times value.
Definition: small_vector.hpp:309
constexpr void swap(small_vector &&rhs) noexcept(is_noexcept)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: small_vector.hpp:948
constexpr const_reference operator[](size_type const i) const noexcept
Return the i-th element.
Definition: small_vector.hpp:478
constexpr void push_back(value_type const value) noexcept
Appends the given element value to the end of the container.
Definition: small_vector.hpp:861
constexpr void pop_back() noexcept
Removes the last element of the container.
Definition: small_vector.hpp:884
constexpr void assign(std::initializer_list< value_type > ilist) noexcept(is_noexcept)
Assign from std::initializer_list.
Definition: small_vector.hpp:290
constexpr iterator insert(const_iterator pos, begin_it_type begin_it, end_it_type end_it) noexcept(is_noexcept)
Inserts elements from range [begin_it, end_it) before position in the container.
Definition: small_vector.hpp:746
value_type * iterator
The iterator type.
Definition: small_vector.hpp:78
constexpr small_vector(size_type n, value_type value) noexcept(is_noexcept)
Construct with n times value.
Definition: small_vector.hpp:252
constexpr iterator erase(const_iterator pos) noexcept
Removes specified elements from the container.
Definition: small_vector.hpp:841
constexpr friend void swap(small_vector &&lhs, small_vector &&rhs) noexcept(is_noexcept)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: small_vector.hpp:975
value_type const * const_iterator
The const_iterator type.
Definition: small_vector.hpp:84
constexpr iterator erase(const_iterator begin_it, const_iterator end_it) noexcept
Removes specified elements from the container.
Definition: small_vector.hpp:806
constexpr iterator insert(const_iterator pos, value_type const value) noexcept(is_noexcept)
Inserts value before position in the container.
Definition: small_vector.hpp:690
constexpr void resize(size_type const count, value_type const value) noexcept
Resizes the container to contain count elements.
Definition: small_vector.hpp:915
value_type_ value_type
The value_type type.
Definition: small_vector.hpp:60
constexpr const_iterator begin() const noexcept
Returns the begin to the string.
Definition: small_vector.hpp:382
detail::min_viable_uint_t< capacity_ > size_type
The size_type type.
Definition: small_vector.hpp:96
constexpr void assign(other_range_t &&range) noexcept(is_noexcept)
Assign from a different range.
Definition: small_vector.hpp:335
constexpr size_type size() const noexcept
Returns the number of elements in the container, i.e. std::distance(begin(), end()).
Definition: small_vector.hpp:590
constexpr const_iterator cend() const noexcept
Returns iterator past the end of the vector.
Definition: small_vector.hpp:409
constexpr reference back() noexcept
Return the last element.
Definition: small_vector.hpp:527
constexpr friend bool operator<=(small_vector const &lhs, small_vector< value_type, cap2 > const &rhs) noexcept
Performs element-wise comparison.
Definition: small_vector.hpp:1038
const_reference at(size_type const i) const
Return the i-th element.
Definition: small_vector.hpp:445
constexpr iterator begin() noexcept
Returns the begin to the string.
Definition: small_vector.hpp:376
constexpr small_vector(value_type const (&array)[capacity2]) noexcept(is_noexcept)
Construct from a (smaller or equally sized) built in array over the same value type.
Definition: small_vector.hpp:156
constexpr void clear() noexcept
Removes all elements from the container.
Definition: small_vector.hpp:668
ptrdiff_t difference_type
The difference_type type.
Definition: small_vector.hpp:90
constexpr iterator end() noexcept
Returns iterator past the end of the vector.
Definition: small_vector.hpp:397
value_type & reference
The reference type.
Definition: small_vector.hpp:66
constexpr friend void swap(small_vector &lhs, small_vector &rhs) noexcept(is_noexcept)
Swap contents with another instance.
Definition: small_vector.hpp:969
constexpr const_reference front() const noexcept
Return the first element. Calling front on an empty container is undefined.
Definition: small_vector.hpp:506
constexpr value_type const * data() const noexcept
Direct access to the underlying array.
Definition: small_vector.hpp:550
constexpr friend bool operator!=(small_vector const &lhs, small_vector< value_type, cap2 > const &rhs) noexcept
Performs element-wise comparison.
Definition: small_vector.hpp:998
reference at(size_type const i)
Return the i-th element.
Definition: small_vector.hpp:435
constexpr value_type * data() noexcept
Direct access to the underlying array.
Definition: small_vector.hpp:544
constexpr void reserve(size_type) const noexcept
Since the capacity is fixed on compile time, this is a no-op.
Definition: small_vector.hpp:638
constexpr const_reference back() const noexcept
Return the last element.
Definition: small_vector.hpp:534
constexpr size_type max_size() const noexcept
Returns the maximum number of elements the container is able to hold and resolves to capacity_.
Definition: small_vector.hpp:611
constexpr const_iterator end() const noexcept
Returns iterator past the end of the vector.
Definition: small_vector.hpp:403
constexpr iterator insert(const_iterator pos, std::initializer_list< value_type > const &ilist) noexcept(is_noexcept)
Inserts elements from initializer list before position in the container.
Definition: small_vector.hpp:781
constexpr friend bool operator>=(small_vector const &lhs, small_vector< value_type, cap2 > const &rhs) noexcept
Performs element-wise comparison.
Definition: small_vector.hpp:1048
T data(T... args)
Provides type traits for working with templates.
constexpr ptrdiff_t count
Count the occurrences of a type in a pack.
Definition: traits.hpp:169
constexpr auto repeat_n
A view factory that repeats a given value n times.
Definition: repeat_n.hpp:95
Provides metaprogramming utilities for integer types.
T is_same_v
T min(T... args)
The main SeqAn3 namespace.
Definition: aligned_sequence_concept.hpp:29
small_vector(value_type const (&array)[capacity2]) -> small_vector< value_type, capacity2 >
Deducts the size and value type from an built-in array on construction.
SeqAn specific customisations in the standard namespace.
Exposes the value_type of another type.
Definition: pre.hpp:58
Provides seqan3::views::repeat_n.