BioC++ core-0.7.0
The Modern C++ libraries for Bioinformatics.
 
Loading...
Searching...
No Matches
small_vector.hpp
Go to the documentation of this file.
1// -----------------------------------------------------------------------------------------------------
2// Copyright (c) 2022 deCODE Genetics
3// Copyright (c) 2006-2020, Knut Reinert & Freie Universität Berlin
4// Copyright (c) 2016-2020, Knut Reinert & MPI für molekulare Genetik
5// This file may be used, modified and/or redistributed under the terms of the 3-clause BSD-License
6// shipped with this file and also available at: https://github.com/biocpp/biocpp-core/blob/main/LICENSE.md
7// -----------------------------------------------------------------------------------------------------
8
14#pragma once
15
16#include <array>
17#include <type_traits>
18
19#if __has_include(<cereal/types/array.hpp>)
20# include <cereal/types/array.hpp>
21#endif
22
26
27namespace bio::ranges
28{
29
43template <typename value_type_, size_t capacity_>
45{
46private:
48 static constexpr bool is_noexcept = std::is_nothrow_copy_constructible_v<value_type_>;
49
50public:
54 using value_type = value_type_;
56 using const_reference = value_type const &;
57 using iterator = value_type *;
58 using const_iterator = value_type const *;
59 using difference_type = ptrdiff_t;
61
63
65 // this signals to range-v3 that something is a container :|
66 using allocator_type = void;
68
72 constexpr small_vector() noexcept = default;
73 constexpr small_vector(small_vector const &) noexcept = default;
74 constexpr small_vector(small_vector &&) noexcept = default;
75 constexpr small_vector & operator=(small_vector const &) noexcept = default;
76 constexpr small_vector & operator=(small_vector &&) noexcept = default;
77 ~small_vector() noexcept = default;
78
90 explicit constexpr small_vector(std::array<value_type, capacity_> const & array) noexcept(is_noexcept) :
91 data_{array}, sz{capacity_}
92 {}
93
95 template <size_t capacity2>
96 explicit constexpr small_vector(std::array<value_type, capacity2> const & array) noexcept(is_noexcept) :
97 sz{capacity2}
98 {
99 static_assert(capacity2 <= capacity_, "You can only initialize from array that has smaller or equal capacity.");
100 std::ranges::copy(array, data_.begin());
101 }
103
115 template <size_t capacity2>
116 explicit constexpr small_vector(value_type const (&array)[capacity2]) noexcept(is_noexcept) : sz{capacity2}
117 {
118 static_assert(capacity2 <= capacity_, "You can only initialize from array that has smaller or equal capacity.");
119 std::ranges::copy(array, data_.begin());
120 }
121
133 template <typename... other_value_type>
134 requires(std::same_as<value_type, other_value_type> && ...)
135 constexpr small_vector(other_value_type... args) noexcept(is_noexcept) :
136 data_{args...}, sz{sizeof...(other_value_type)}
137 {
138 static_assert(sizeof...(other_value_type) <= capacity_, "Value list must not exceed the capacity.");
139 }
140
156 template <std::forward_iterator begin_it_type, typename end_it_type>
157 requires(std::sentinel_for<end_it_type, begin_it_type> &&
158 std::constructible_from<value_type, std::iter_reference_t<begin_it_type>>)
159 constexpr small_vector(begin_it_type begin_it, end_it_type end_it) noexcept(is_noexcept) : small_vector{}
160 {
161 assign(begin_it, end_it);
162 }
163
177 template <meta::different_from<small_vector> other_range_t>
178 requires(std::ranges::input_range<other_range_t>)
179 explicit constexpr small_vector(other_range_t && range) noexcept(is_noexcept) :
180 small_vector{std::ranges::begin(range), std::ranges::end(range)}
181 {}
182
195 constexpr small_vector(size_type n, value_type value) noexcept(is_noexcept) : small_vector{} { assign(n, value); }
196
208 constexpr small_vector & operator=(std::initializer_list<value_type> ilist) noexcept(is_noexcept)
209 {
210 assign(std::ranges::begin(ilist), std::ranges::end(ilist));
211 return *this;
212 }
213
225 constexpr void assign(std::initializer_list<value_type> ilist) noexcept(is_noexcept)
226 {
227 assign(std::ranges::begin(ilist), std::ranges::end(ilist));
228 }
229
242 constexpr void assign(size_type const count, value_type const value) noexcept(is_noexcept)
243 {
244 clear();
245 auto tmp = views::repeat_n(value, count);
246 assign(std::ranges::begin(tmp), std::ranges::end(tmp));
247 }
248
262 template <std::ranges::input_range other_range_t>
263 requires std::constructible_from<value_type, std::ranges::range_reference_t<other_range_t>>
264 constexpr void assign(other_range_t && range) noexcept(is_noexcept)
265 {
266 assign(std::ranges::begin(range), std::ranges::end(range));
267 }
268
284 template <std::forward_iterator begin_it_type, typename end_it_type>
285 requires(std::sentinel_for<end_it_type, begin_it_type> &&
286 std::constructible_from<value_type, std::iter_reference_t<begin_it_type>>)
287 constexpr void assign(begin_it_type begin_it, end_it_type end_it) noexcept(is_noexcept)
288 {
289 clear();
290 insert(cbegin(), begin_it, end_it);
291 }
293
298 constexpr iterator begin() noexcept { return &data_[0]; }
299
301 constexpr const_iterator begin() const noexcept { return &data_[0]; }
302
304 constexpr const_iterator cbegin() const noexcept { return &data_[0]; }
305
307 constexpr iterator end() noexcept { return &data_[sz]; }
308
310 constexpr const_iterator end() const noexcept { return &data_[sz]; }
311
313 constexpr const_iterator cend() const noexcept { return &data_[sz]; }
315
335 {
336 if (i >= size()) // [[unlikely]]
337 {
338 throw std::out_of_range{"Trying to access element behind the last in small_vector."};
339 }
340 return (*this)[i];
341 }
342
345 {
346 if (i >= size()) // [[unlikely]]
347 {
348 throw std::out_of_range{"Trying to access element behind the last in small_vector."};
349 }
350 return (*this)[i];
351 }
352
368 constexpr reference operator[](size_type const i) noexcept
369 {
370 assert(i < size());
371 return data_[i];
372 }
373
375 constexpr const_reference operator[](size_type const i) const noexcept
376 {
377 assert(i < size());
378 return data_[i];
379 }
380
394 constexpr reference front() noexcept
395 {
396 assert(size() > 0);
397 return (*this)[0];
398 }
399
401 constexpr const_reference front() const noexcept
402 {
403 assert(size() > 0);
404 return (*this)[0];
405 }
406
420 constexpr reference back() noexcept
421 {
422 assert(size() > 0);
423 return (*this)[size() - 1];
424 }
425
427 constexpr const_reference back() const noexcept
428 {
429 assert(size() > 0);
430 return (*this)[size() - 1];
431 }
432
434 constexpr value_type * data() noexcept { return data_.data(); }
435
437 constexpr value_type const * data() const noexcept { return data_.data(); }
439
454 constexpr bool empty() const noexcept { return size() == 0; }
455
467 constexpr size_type size() const noexcept { return sz; }
468
483 constexpr size_type max_size() const noexcept { return capacity_; }
484
496 constexpr size_type capacity() const noexcept { return capacity_; }
497
499 constexpr void reserve(size_type) const noexcept
500 {
501 // no-op
502 }
503
505 constexpr void shrink_to_fit() const noexcept
506 {
507 // no-op
508 }
510
524 constexpr void clear() noexcept { sz = 0; }
525
541 constexpr iterator insert(const_iterator pos, value_type const value) noexcept(is_noexcept)
542 {
543 return insert(pos, 1, value);
544 }
545
562 constexpr iterator insert(const_iterator pos, size_type const count, value_type const value) noexcept(is_noexcept)
563 {
564 auto tmp = views::repeat_n(value, count);
565 return insert(pos, std::ranges::begin(tmp), std::ranges::end(tmp));
566 }
567
588 template <std::forward_iterator begin_it_type, typename end_it_type>
589 requires(std::sentinel_for<end_it_type, begin_it_type> &&
590 std::constructible_from<value_type, std::iter_reference_t<begin_it_type>>)
591 constexpr iterator insert(const_iterator pos, begin_it_type begin_it, end_it_type end_it) noexcept(is_noexcept)
592 {
593 auto const pos_as_num = std::ranges::distance(cbegin(), pos);
594 auto const length = std::ranges::distance(begin_it, end_it);
595
596 assert(pos_as_num + length <= capacity());
597
598 if (length == 0)
599 return begin(); // nothing to insert
600
601 for (size_type i = sz + length - 1; i > pos_as_num + length - 1; --i)
602 data_[i] = data_[i - length];
603
604 std::ranges::copy(begin_it, end_it, &data_[pos_as_num]);
605 sz += length;
606 return begin() + pos_as_num;
607 }
608
624 constexpr iterator insert(const_iterator pos, std::initializer_list<value_type> const & ilist) noexcept(is_noexcept)
625 {
626 return insert(pos, ilist.begin(), ilist.end());
627 }
628
647 constexpr iterator erase(const_iterator begin_it, const_iterator end_it) noexcept
648 {
649 if (begin_it >= end_it) // [[unlikely]]
650 return begin() + std::ranges::distance(cbegin(), end_it);
651
652 size_type const length = std::ranges::distance(begin_it, end_it);
653 auto out_it = begin() + std::ranges::distance(cbegin(), begin_it);
654
655 while (end_it != cend())
656 *(out_it++) = *(end_it++);
657
658 sz -= length;
659 return begin() + std::ranges::distance(cbegin(), begin_it);
660 }
661
680 constexpr iterator erase(const_iterator pos) noexcept { return erase(pos, pos + 1); }
681
695 constexpr void push_back(value_type const value) noexcept
696 {
697 assert(sz < capacity_);
698 data_[sz] = value;
699 ++sz;
700 }
701
716 constexpr void pop_back() noexcept
717 {
718 assert(sz > 0);
719 --sz;
720 }
721
735 constexpr void resize(size_type const count) noexcept
736 {
737 assert(count <= capacity_);
738 sz = count;
739 }
740
745 constexpr void resize(size_type const count, value_type const value) noexcept
746 {
747 assert(count <= capacity_);
748 for (size_t i = sz; i < count; ++i)
749 data_[i] = value;
750 sz = count;
751 }
752
764 constexpr void swap(small_vector & rhs) noexcept(is_noexcept)
765 {
766 auto tmp = *this;
767
768 data_ = rhs.data_;
769 sz = rhs.sz;
770
771 rhs.data_ = tmp.data_;
772 rhs.sz = tmp.sz;
773 }
774
776 constexpr void swap(small_vector && rhs) noexcept(is_noexcept)
777 {
778 data_ = rhs.data_;
779 sz = rhs.sz;
780 }
782
795 friend constexpr void swap(small_vector & lhs, small_vector & rhs) noexcept(is_noexcept) { lhs.swap(rhs); }
796
798 friend constexpr void swap(small_vector && lhs, small_vector && rhs) noexcept(is_noexcept) { lhs.swap(rhs); }
799
802
804 template <size_t cap2>
805 friend constexpr bool operator==(small_vector const & lhs, small_vector<value_type, cap2> const & rhs) noexcept
806 {
807 return std::ranges::equal(lhs, rhs);
808 }
809
811 template <size_t cap2>
812 friend constexpr bool operator<(small_vector const & lhs, small_vector<value_type, cap2> const & rhs) noexcept
813 {
814 for (size_t i = 0; i < std::min(lhs.size(), rhs.size()); ++i)
815 if (lhs[i] > rhs[i])
816 return false;
817 else if (lhs[i] < rhs[i])
818 return true;
819 return lhs.size() < rhs.size();
820 }
821
823 template <size_t cap2>
824 friend constexpr bool operator>(small_vector const & lhs, small_vector<value_type, cap2> const & rhs) noexcept
825 {
826 for (size_t i = 0; i < std::min(lhs.size(), rhs.size()); ++i)
827 if (lhs[i] < rhs[i])
828 return false;
829 else if (lhs[i] > rhs[i])
830 return true;
831 return lhs.size() > rhs.size();
832 }
833
835 template <size_t cap2>
836 friend constexpr bool operator<=(small_vector const & lhs, small_vector<value_type, cap2> const & rhs) noexcept
837 {
838 return !(lhs > rhs);
839 }
840
842 template <size_t cap2>
843 friend constexpr bool operator>=(small_vector const & lhs, small_vector<value_type, cap2> const & rhs) noexcept
844 {
845 return !(lhs < rhs);
846 }
848
849public:
851
855 size_type sz{0};
856
857public:
859
865 template <typename archive_t>
866 void serialize(archive_t & archive)
867 {
868 archive(data_);
869 archive(sz);
870 }
872};
873
879template <size_t capacity2, typename value_type>
880small_vector(const value_type (&array)[capacity2]) -> small_vector<value_type, capacity2>;
882
883} // namespace bio::ranges
T begin(T... args)
A constexpr vector implementation with dynamic size at compile time.
Definition: small_vector.hpp:45
constexpr value_type const * data() const noexcept
Direct access to the underlying array.
Definition: small_vector.hpp:437
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:591
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:776
reference at(size_type const i)
Return the i-th element.
Definition: small_vector.hpp:334
constexpr void reserve(size_type) const noexcept
Since the capacity is fixed on compile time, this is a no-op.
Definition: small_vector.hpp:499
friend constexpr void swap(small_vector &lhs, small_vector &rhs) noexcept(is_noexcept)
Swap contents with another instance.
Definition: small_vector.hpp:795
constexpr const_iterator cend() const noexcept
Returns iterator past the end of the vector.
Definition: small_vector.hpp:313
constexpr iterator erase(const_iterator pos) noexcept
Removes specified elements from the container.
Definition: small_vector.hpp:680
value_type & reference
The reference type.
Definition: small_vector.hpp:55
constexpr reference back() noexcept
Return the last element.
Definition: small_vector.hpp:420
constexpr iterator end() noexcept
Returns iterator past the end of the vector.
Definition: small_vector.hpp:307
value_type_ value_type
The value_type type.
Definition: small_vector.hpp:54
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:562
constexpr const_reference back() const noexcept
Return the last element.
Definition: small_vector.hpp:427
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:287
constexpr const_iterator end() const noexcept
Returns iterator past the end of the vector.
Definition: small_vector.hpp:310
constexpr void assign(std::initializer_list< value_type > ilist) noexcept(is_noexcept)
Assign from std::initializer_list.
Definition: small_vector.hpp:225
constexpr small_vector(other_range_t &&range) noexcept(is_noexcept)
Construct from a different range.
Definition: small_vector.hpp:179
friend constexpr 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:798
friend constexpr bool operator>(small_vector const &lhs, small_vector< value_type, cap2 > const &rhs) noexcept
Performs element-wise comparison.
Definition: small_vector.hpp:824
constexpr value_type * data() noexcept
Direct access to the underlying array.
Definition: small_vector.hpp:434
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:624
constexpr iterator insert(const_iterator pos, value_type const value) noexcept(is_noexcept)
Inserts value before position in the container.
Definition: small_vector.hpp:541
meta::detail::min_viable_uint_t< capacity_ > size_type
The size_type type.
Definition: small_vector.hpp:60
constexpr small_vector & operator=(std::initializer_list< value_type > ilist) noexcept(is_noexcept)
Assign from std::initializer_list.
Definition: small_vector.hpp:208
constexpr void resize(size_type const count, value_type const value) noexcept
Resizes the container to contain count elements.
Definition: small_vector.hpp:745
ptrdiff_t difference_type
The difference_type type.
Definition: small_vector.hpp:59
constexpr void resize(size_type const count) noexcept
Resizes the container to contain count elements.
Definition: small_vector.hpp:735
constexpr const_iterator cbegin() const noexcept
Returns the begin iterator of the vector.
Definition: small_vector.hpp:304
constexpr void pop_back() noexcept
Removes the last element of the container.
Definition: small_vector.hpp:716
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:116
constexpr reference operator[](size_type const i) noexcept
Return the i-th element.
Definition: small_vector.hpp:368
value_type const * const_iterator
The const_iterator type.
Definition: small_vector.hpp:58
constexpr small_vector(size_type n, value_type value) noexcept(is_noexcept)
Construct with n times value.
Definition: small_vector.hpp:195
friend constexpr bool operator==(small_vector const &lhs, small_vector< value_type, cap2 > const &rhs) noexcept
Performs element-wise comparison.
Definition: small_vector.hpp:805
constexpr const_reference front() const noexcept
Return the first element. Calling front on an empty container is undefined.
Definition: small_vector.hpp:401
constexpr const_iterator begin() const noexcept
Returns the begin iterator of the vector.
Definition: small_vector.hpp:301
constexpr void push_back(value_type const value) noexcept
Appends the given element value to the end of the container.
Definition: small_vector.hpp:695
value_type const & const_reference
The const_reference type.
Definition: small_vector.hpp:56
constexpr void shrink_to_fit() const noexcept
Since the capacity is fixed on compile time, this is a no-op.
Definition: small_vector.hpp:505
constexpr size_type size() const noexcept
Returns the number of elements in the container, i.e. std::distance(begin(), end()).
Definition: small_vector.hpp:467
constexpr void assign(size_type const count, value_type const value) noexcept(is_noexcept)
Assign with count times value.
Definition: small_vector.hpp:242
constexpr const_reference operator[](size_type const i) const noexcept
Return the i-th element.
Definition: small_vector.hpp:375
constexpr void swap(small_vector &rhs) noexcept(is_noexcept)
Swap contents with another instance.
Definition: small_vector.hpp:764
constexpr void clear() noexcept
Removes all elements from the container.
Definition: small_vector.hpp:524
constexpr iterator erase(const_iterator begin_it, const_iterator end_it) noexcept
Removes specified elements from the container.
Definition: small_vector.hpp:647
constexpr bool empty() const noexcept
Checks whether the container is empty.
Definition: small_vector.hpp:454
friend constexpr bool operator<(small_vector const &lhs, small_vector< value_type, cap2 > const &rhs) noexcept
Performs element-wise comparison.
Definition: small_vector.hpp:812
friend constexpr bool operator<=(small_vector const &lhs, small_vector< value_type, cap2 > const &rhs) noexcept
Performs element-wise comparison.
Definition: small_vector.hpp:836
friend constexpr bool operator>=(small_vector const &lhs, small_vector< value_type, cap2 > const &rhs) noexcept
Performs element-wise comparison.
Definition: small_vector.hpp:843
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:496
constexpr void assign(other_range_t &&range) noexcept(is_noexcept)
Assign from a different range.
Definition: small_vector.hpp:264
const_reference at(size_type const i) const
Return the i-th element.
Definition: small_vector.hpp:344
constexpr iterator begin() noexcept
Returns the begin iterator of the vector.
Definition: small_vector.hpp:298
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:483
value_type * iterator
The iterator type.
Definition: small_vector.hpp:57
constexpr small_vector() noexcept=default
Defaulted.
constexpr small_vector(begin_it_type begin_it, end_it_type end_it) noexcept(is_noexcept)
Construct from two iterators.
Definition: small_vector.hpp:159
constexpr reference front() noexcept
Return the first element. Calling front on an empty container is undefined.
Definition: small_vector.hpp:394
T copy(T... args)
T data(T... args)
T equal(T... args)
constexpr auto repeat_n
A view factory that repeats a given value n times.
Definition: repeat_n.hpp:98
Provides metaprogramming utilities for integer types.
T min(T... args)
The ranges module's namespace.
Provides bio::views::repeat_n.
Provides various traits to inspect templates.