HIBF 1.0.0-rc.1
Loading...
Searching...
No Matches
bit_vector.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2006-2024, Knut Reinert & Freie Universität Berlin
2// SPDX-FileCopyrightText: 2016-2024, Knut Reinert & MPI für molekulare Genetik
3// SPDX-License-Identifier: BSD-3-Clause
4
11// Modified by Enrico Seiler <enrico.seiler AT fu-berlin.de>:
12// * To be a single header and non-template (was CRTP)
13// * Changed default allocator to 64-byte aligned allocator
14// * Changed `bit_vector operator~()` to be auto-vectorizable
15// * Changed `binary_transform_impl` to be auto-vectorizable
16// * Replaced `seqan3::detail::bits_of<chunk_type>` with `sizeof(chunk_type) * CHAR_BIT`
17// * Changed `difference_type` to `size_type` in `operator[]`
18// * Changed `1` to `1ULL` in `(1ULL << to_local_chunk_position(size()))` of `resize()`
19// * Changed `bit_reference & operator=` to be in accordance with STL
20// * Changed `resize` to do nothing when reducing size besides setting new size.
21
22#pragma once
23
24#include <algorithm> // for __fn, for_each, all_of, any_of, copy, fill
25#include <bit> // for countr_zero
26#include <cassert> // for assert
27#include <cinttypes> // for uint64_t
28#include <climits> // for CHAR_BIT
29#include <compare> // for strong_ordering, operator==
30#include <concepts> // for assignable_from
31#include <cstddef> // for size_t, ptrdiff_t
32#include <initializer_list> // for initializer_list
33#include <iterator> // for iter_reference_t, __fn, back_inserter, distance, iter_differen...
34#include <memory> // for allocator, assume_aligned, allocator_traits, __compressed_pair
35#include <ranges> // for __fn, begin, end
36#include <stdexcept> // for out_of_range
37#include <string> // for char_traits, operator+, to_string, operator""s
38#include <type_traits> // for conditional_t
39#include <utility> // for swap
40#include <vector> // for vector
41
42#include <cereal/cereal.hpp> // for binary_data
43#include <cereal/macros.hpp> // for CEREAL_LOAD_FUNCTION_NAME, CEREAL_SAVE_FUNCTION_NAME
44#include <cereal/specialize.hpp> // for specialization, specialize
45
46#include <hibf/cereal/concepts.hpp> // for cereal_archive, cereal_text_archive
47#include <hibf/contrib/aligned_allocator.hpp> // for aligned_allocator
48#include <hibf/platform.hpp> // for HIBF_CONSTEXPR_VECTOR, _LIBCPP_HAS_NO_ASAN, _LIBCPP_VERSION
49
50namespace seqan::hibf
51{
52
65 public std::vector<uint64_t,
66 typename std::allocator_traits<
67 seqan::hibf::contrib::aligned_allocator<bool, 64u>>::template rebind_alloc<uint64_t>>
68{
69private:
71 using allocator_t = seqan::hibf::contrib::aligned_allocator<bool, 64u>;
72
75
77 using chunk_type = uint64_t;
78
90 template <bool is_const>
91 class bit_reference
92 {
93 private:
95 friend class bit_vector;
96
99
100 maybe_const_chunk_type * _chunk{};
101 chunk_type _chunk_mask{};
102
108 constexpr bit_reference(maybe_const_chunk_type * chunk, size_type const local_chunk_position) noexcept :
109 _chunk{chunk},
110 _chunk_mask{static_cast<chunk_type>(1) << to_local_chunk_position(local_chunk_position)}
111 {}
112
113 public:
117 bit_reference() = delete;
118 bit_reference(bit_reference const & other) = default;
119 bit_reference(bit_reference && other) = default;
120 bit_reference & operator=(bit_reference const & other)
121 {
122 return *this = bool(other);
123 }
124 bit_reference & operator=(bit_reference && other) noexcept
125 {
126 return *this = bool(other);
127 }
128
133 constexpr bit_reference & operator=(bool const bit) noexcept
134 {
135 bit ? set() : clear();
136 return *this;
137 }
138
140 // Needed to model std::output_iterator<bit_iterator, bool>, which requires the assignment to an const && version
141 // of the proxy.
142 constexpr bit_reference const & operator=(bool const bit) const noexcept
143 requires (!is_const)
144 {
145 bit ? set() : clear();
146 return *this;
147 }
149
151 constexpr operator bool() const noexcept
152 {
153 return *_chunk & _chunk_mask;
154 }
155
157 constexpr bit_reference & flip() noexcept
158 {
159 (*this) ? clear() : set();
160 return *this;
161 }
162
163 private:
165 constexpr void set() noexcept
166 {
167 *_chunk |= _chunk_mask;
168 }
169
171 constexpr void clear() noexcept
172 {
173 *_chunk &= ~_chunk_mask;
174 }
175 };
176
180 template <bool is_const>
181 class bit_iterator
182 {
183 private:
185 template <bool>
186 friend class bit_iterator;
187
190
191 maybe_const_chunk_type * _chunk{};
192 size_type _chunk_position{};
193
194 public:
198 using value_type = bool;
199 using reference = bit_reference<is_const>;
200 using pointer = void;
202 using iterator_category = std::random_access_iterator_tag;
203 using iterator_concept = std::random_access_iterator_tag;
205
209 bit_iterator() = default;
210
215 explicit constexpr bit_iterator(maybe_const_chunk_type * chunk) noexcept : _chunk{chunk}, _chunk_position{0}
216 {}
217
222 constexpr bit_iterator(bit_iterator<!is_const> const & other) noexcept
223 requires (is_const)
224 : _chunk{other._chunk}, _chunk_position{other._chunk_position}
225 {}
227
232 constexpr reference operator*() const noexcept
233 {
234 return reference{_chunk, _chunk_position};
235 }
236
238 constexpr reference operator[](difference_type const count) const noexcept
239 {
240 return *((*this) + count);
241 }
243
248 constexpr bit_iterator & operator++() noexcept
249 {
250 _chunk += !static_cast<bool>(to_local_chunk_position(++_chunk_position));
251 return *this;
252 }
253
255 constexpr bit_iterator operator++(int) noexcept
256 {
257 bit_iterator tmp{*this};
258 ++(*this);
259 return tmp;
260 }
261
263 constexpr bit_iterator & operator+=(difference_type const count) noexcept
264 {
265 // chunk:| 0 | 1 | 2 | 3 | 4 | 5 |
266 // |--------|--------|--------|--------|-x------|--------|
267 // chunk_position:|01234567|01234567|01234567|01234567|01234567|01234567|
268 // global position:|01234567|89012345|67890123|45678901|23456789|01234567|
269 // |0 | 1 | 2 | 3 | |4 |
270 if (count < 0)
271 {
272 size_type updated_count = modulo_mask - to_local_chunk_position(_chunk_position) - count;
273 _chunk_position = modulo_mask - to_local_chunk_position(updated_count);
274 _chunk -= to_chunk_position(updated_count);
275 //(to_chunk_position(-count) + (old_chunk_position < _chunk_position));
276 }
277 else
278 {
279 _chunk += to_chunk_position(to_local_chunk_position(_chunk_position) + count);
280 _chunk_position = to_local_chunk_position(_chunk_position + count);
281 }
282
283 return *this;
284 }
285
287 constexpr bit_iterator operator+(difference_type const count) const noexcept
288 {
289 bit_iterator tmp{*this};
290 return tmp += count;
291 }
292
294 friend constexpr bit_iterator operator+(difference_type const count, bit_iterator rhs) noexcept
295 {
296 return rhs + count;
297 }
298
300 constexpr bit_iterator & operator--() noexcept
301 {
302 _chunk -= !static_cast<bool>(to_local_chunk_position(--_chunk_position));
303 return *this;
304 }
305
307 constexpr bit_iterator operator--(int) noexcept
308 {
309 bit_iterator tmp{*this};
310 --(*this);
311 return tmp;
312 }
313
315 constexpr bit_iterator & operator-=(difference_type const count) noexcept
316 {
317 return *this += -count;
318 }
319
321 constexpr bit_iterator operator-(difference_type const count) const noexcept
322 {
323 bit_iterator tmp{*this};
324 return tmp -= count;
325 }
326
328 template <bool is_const_other>
329 constexpr difference_type operator-(bit_iterator<is_const_other> rhs) const noexcept
330 {
331 return ((_chunk - rhs._chunk) << division_mask) - // number of bits between chunks.
332 to_local_chunk_position(rhs._chunk_position) + // minus the first bits in rhs.
333 to_local_chunk_position(_chunk_position); // plus the first bits of the lhs
334 }
336
341 template <bool is_const_other>
342 bool operator==(bit_iterator<is_const_other> const & rhs) const
343 {
344 return _chunk == rhs._chunk
345 && (to_local_chunk_position(_chunk_position) == to_local_chunk_position(rhs._chunk_position));
346 }
347
349 template <bool is_const_other>
350 std::strong_ordering operator<=>(bit_iterator<is_const_other> const & rhs) const
351 {
352 if (std::strong_ordering order = _chunk <=> rhs._chunk; order == std::strong_ordering::equivalent)
353 return to_local_chunk_position(_chunk_position) <=> to_local_chunk_position(rhs._chunk_position);
354 else
355 return order;
356 }
358 };
359
360public:
365 using iterator = bit_iterator<false>;
367 using const_iterator = bit_iterator<true>;
375 using size_type = size_t;
379 using allocator_type = allocator_t;
381
382private:
384 static constexpr size_type chunk_size = sizeof(chunk_type) * CHAR_BIT;
386 static constexpr size_type modulo_mask = chunk_size - 1u;
388 static constexpr size_type division_mask = std::countr_zero(chunk_size);
389
391 size_type _size{};
392
393public:
399 {}
405
413 bit_vector(size_type const count, bool const bit, allocator_type const & alloc = allocator_type{}) : base_t{alloc}
414 {
415 assign(count, bit);
416 }
417
424 allocator_type const & alloc = allocator_type{}) :
425 base_t{alloc}
426 {
427 assign(list);
428 }
429
436 bit_vector{count, bool{}, alloc}
437 {}
439
468 template <std::input_iterator iterator_t, std::sentinel_for<iterator_t> sentinel_t>
470 constexpr void assign(iterator_t first, sentinel_t last)
471 {
472 bit_vector tmp{}; // To ensure strong exception guarantee.
474 tmp.reserve(std::ranges::distance(first, last));
475
476 std::ranges::copy(first, last, std::back_inserter(tmp));
477
478 // ----- no exception after this.
479 swap(tmp);
480 set_new_size(std::ranges::distance(begin(), end()));
481 }
482
502 constexpr void assign(std::initializer_list<bool> const & ilist)
503 {
504 assign(std::ranges::begin(ilist), std::ranges::end(ilist));
505 }
506
527 HIBF_CONSTEXPR_VECTOR void assign(size_type const count, bool const bit)
528 {
529 resize(count, bit);
530 std::ranges::for_each(*as_base(),
531 [value = fill_chunk(bit)](chunk_type & chunk)
532 {
533 chunk = value;
534 });
535 }
537
543 {
544 assert(position < size());
545
546 return *std::ranges::next(begin(), position);
547 }
548
551 {
552 assert(position < size());
553
554 return *std::ranges::next(begin(), position);
555 }
556
574 {
575 assert(!empty()); // Calling on empty container is undefined behaviour.
576
577 return (*this)[size() - 1u];
578 }
579
582 {
583 assert(!empty()); // Calling on empty container is undefined behaviour.
584
585 return (*this)[size() - 1u];
586 }
587
589 constexpr bool all() const noexcept
590 {
591 constexpr chunk_type mask = ~static_cast<chunk_type>(0);
592 return std::ranges::all_of(*as_base(),
593 [](chunk_type const & chunk)
594 {
595 return chunk == mask;
596 });
597 }
598
600 constexpr bool any() const noexcept
601 {
602 constexpr chunk_type mask = static_cast<chunk_type>(0);
603 return std::ranges::any_of(*as_base(),
604 [](chunk_type const & chunk)
605 {
606 return chunk | mask;
607 });
608 }
609
611 constexpr bool none() const noexcept
612 {
613 return !any();
614 }
616
621 constexpr size_type size() const noexcept
622 {
623 return _size;
624 }
625
627 constexpr bool empty() const noexcept
628 {
629 return _size == 0u;
630 }
631
634 {
635 return base_t::capacity() * chunk_size;
636 }
637
655 HIBF_CONSTEXPR_VECTOR void reserve(size_type const new_capacity)
656 {
657 base_t::reserve(host_size_impl(new_capacity));
658 }
660
686 {
687 size_t const new_size = size() + 1u;
688 resize(new_size);
689 // ---- no exception after this point.
690 set_new_size(new_size);
691 back() = bit; // set the bit.
692 }
693
695 HIBF_CONSTEXPR_VECTOR void resize(size_type const count, bool const bit = {})
696 {
697 base_t::resize(host_size_impl(count));
698
699 size_t const old_size = size();
700 set_new_size(count);
701
702 // If bit is true and we increase the size.
703 if (bit && size() > old_size)
704 std::ranges::fill(begin() + old_size, end(), bit);
705 }
706
709 {
711 _size = 0u;
712 }
713
715 constexpr bit_vector & operator&=(bit_vector const & rhs) noexcept
716 {
717 assert(rhs.size() == size());
718
719 return binary_transform_impl(rhs,
720 [](auto const & left_chunk, auto const & right_chunk)
721 {
722 return left_chunk & right_chunk;
723 });
724 }
725
727 constexpr bit_vector & operator|=(bit_vector const & rhs) noexcept
728 {
729 assert(rhs.size() == size());
730
731 return binary_transform_impl(rhs,
732 [](auto const & left_chunk, auto const & right_chunk)
733 {
734 return left_chunk | right_chunk;
735 });
736 }
737
739 constexpr bit_vector & operator^=(bit_vector const & rhs) noexcept
740 {
741 assert(rhs.size() == size());
742
743 return binary_transform_impl(rhs,
744 [](auto const & left_chunk, auto const & right_chunk)
745 {
746 return left_chunk ^ right_chunk;
747 });
748 }
749
752 {
753 bit_vector tmp(size());
754
755 tmp.binary_transform_impl(*this,
756 [](auto const &, auto const & right_chunk)
757 {
758 return ~right_chunk;
759 });
760
761 return tmp;
762 }
763
766 {
767 return lhs &= rhs;
768 }
769
772 {
773 return lhs |= rhs;
774 }
775
778 {
779 return lhs ^= rhs;
780 }
781
783 constexpr bit_vector & and_not(bit_vector const & rhs) noexcept
784 {
785 assert(rhs.size() == size());
786
787 return binary_transform_impl(rhs,
788 [](auto const & left_chunk, auto const & right_chunk)
789 {
790 return left_chunk & ~right_chunk;
791 });
792 }
793
795 constexpr bit_vector & flip() noexcept
796 {
797 std::ranges::for_each(*as_base(),
798 [](chunk_type & chunk)
799 {
800 chunk = ~chunk;
801 });
802 return *this;
803 }
804
807 {
808 using namespace std::literals;
809
810 if (position >= size())
811 throw std::out_of_range{"The given posisiton "s + std::to_string(position) + " is out of the range [0, "s
812 + std::to_string(size()) + ")!"s};
813
814 (*this)[position].flip();
815 return *this;
816 }
817
819 HIBF_CONSTEXPR_VECTOR void swap(bit_vector & other) noexcept
820 {
821 base_t::swap(*other.as_base());
822 std::swap(_size, other._size);
823 }
825
831 {
832 return iterator{base_t::data()};
833 }
834
837 {
839 }
840
843 {
844 return begin();
845 }
846
849 {
850 return begin() + size();
851 }
852
855 {
856 return begin() + size();
857 }
858
861 {
862 return end();
863 }
865
866 [[gnu::always_inline]] inline HIBF_CONSTEXPR_VECTOR chunk_type * data() noexcept
867 {
869 }
870
871 [[gnu::always_inline]] inline HIBF_CONSTEXPR_VECTOR chunk_type const * data() const noexcept
872 {
874 }
875
883 template <cereal_archive archive_t>
884 void CEREAL_LOAD_FUNCTION_NAME(archive_t & archive)
885 {
886 // Not using `cereal::make_size_tag(_size)`, because the size tag is inferred for text (XML/JSON) archives.
887 // For text archives, `cereal::make_size_tag(_size)` would be the number of elements serialised in the for-loop.
888 // E.g., `_size == 100` would store `2` (`== host_size_impl(_size)`).
889 archive(_size);
890 size_t const vector_size = host_size_impl(_size);
891
892 resize_for_overwrite(vector_size);
893
894 if constexpr (cereal_text_archive<archive_t>)
895 {
896 for (auto && v : *as_base())
897 archive(v);
898 }
899 else
900 {
901 archive(cereal::binary_data(data(), vector_size * sizeof(chunk_type)));
902 }
903 }
904
906 template <cereal_archive archive_t>
907 void CEREAL_SAVE_FUNCTION_NAME(archive_t & archive) const
908 {
909 // Not using `cereal::make_size_tag(_size)`, because the size tag is inferred for text (XML/JSON) archives.
910 // For text archives, `cereal::make_size_tag(_size)` would be the number of elements serialised in the for-loop.
911 // E.g., `_size == 100` would store `2` (`== host_size_impl(_size)`).
912 archive(_size);
913
914 if constexpr (cereal_text_archive<archive_t>)
915 {
916 for (auto && v : *as_base())
917 archive(v);
918 }
919 else
920 {
921 archive(cereal::binary_data(data(), base_t::size() * sizeof(chunk_type)));
922 }
923 }
925
926private:
927// If nothing else works: Just use `resize`.
928#ifndef HIBF_UNINITIALISED_RESIZE
929 HIBF_CONSTEXPR_VECTOR inline void resize_for_overwrite(size_t const size)
930 {
932 }
933#else
934// libc++: reinterpret_cast to a struct that has the same layout as std::vector.
935// All internal members are private.
936# if defined(_LIBCPP_VERSION)
937 inline void resize_for_overwrite(size_t const size)
938 {
939 struct fake_vector
940 {
941 using allocator_t = typename base_t::allocator_type;
942 using pointer = typename std::allocator_traits<allocator_t>::pointer;
943
944 pointer begin;
945 pointer end;
947 };
948
949 static_assert(sizeof(fake_vector) == sizeof(base_t));
950 static_assert(alignof(fake_vector) == alignof(base_t));
951
952 if (size > base_t::capacity())
954
955// Annotate the new memory as contiguous container for llvm's address sanitizer.
956# ifndef _LIBCPP_HAS_NO_ASAN
957 __sanitizer_annotate_contiguous_container(base_t::data(),
960 base_t::data() + size);
961# endif
962
963 fake_vector & vec = reinterpret_cast<fake_vector &>(*this);
964 vec.end = vec.begin + size;
965 }
966// libstdc++: The internal members are protected, so we can access them.
967# else
968 HIBF_CONSTEXPR_VECTOR inline void resize_for_overwrite(size_t const size)
969 {
970 if (size > base_t::capacity())
972
973 this->_M_impl._M_finish = this->_M_impl._M_start + size;
974 }
975# endif
976#endif
977
979 template <typename binary_operator_t>
980 constexpr bit_vector & binary_transform_impl(bit_vector const & rhs, binary_operator_t && op) noexcept
981 {
982 chunk_type * const lhs_data = data();
983 chunk_type const * const rhs_data = rhs.data();
984 size_type const size = host_size_impl(this->size());
985
986 for (size_t i = 0; i < size; ++i)
987 lhs_data[i] = op(lhs_data[i], rhs_data[i]);
988
989 return *this;
990 }
991
994 constexpr size_type host_size_impl(size_type const count) const noexcept
995 {
996 return chunks_needed(count);
997 }
998
1000 constexpr void set_new_size(size_type const new_size) noexcept
1001 {
1002 _size = new_size;
1003 }
1004
1006 constexpr base_t const * as_base() const noexcept
1007 {
1008 return static_cast<base_t const *>(this);
1009 }
1010
1012 constexpr base_t * as_base() noexcept
1013 {
1014 return static_cast<base_t *>(this);
1015 }
1016
1018 constexpr size_type chunks_needed(size_type const count) const noexcept
1019 {
1020 return (count + 63u) >> 6; // ceil(count/64)
1021 }
1022
1024 constexpr chunk_type fill_chunk(bool const bit) const noexcept
1025 {
1026 return (bit) ? ~chunk_type{} : chunk_type{};
1027 }
1028
1030 static constexpr size_type to_local_chunk_position(size_type const position) noexcept
1031 {
1032 return position & modulo_mask; // e.g. position % 64
1033 }
1034
1036 static constexpr size_type to_chunk_position(size_type const position) noexcept
1037 {
1038 return position >> division_mask; // e.g. position / 64
1039 }
1040};
1041
1042} // namespace seqan::hibf
1043
1045// See https://uscilab.github.io/cereal/serialization_functions.html#inheritance
1046// seqan::hibf::bit_vector's base class is std::vector
1047// If we include <cereal/types/vector.hpp> for std::vector serialisation (e.g., HIBF),
1048// cereal provides these as non-member load/save functions.
1049// Since both load/save non-member functions (std::vector) and load/save member functions (bit_vector) are available,
1050// cereal needs to be told which one to use.
1051namespace cereal
1052{
1053
1054template <typename archive_t>
1055struct specialize<archive_t, seqan::hibf::bit_vector, cereal::specialization::member_load_save>
1056{};
1057
1058} // namespace cereal
T all_of(T... args)
T back_inserter(T... args)
T begin(T... args)
T capacity(T... args)
An bit vector.
Definition bit_vector.hpp:68
constexpr void resize(size_type const count, bool const bit={})
Changes the number of elements stored, where additional copies of bit are appended.
Definition bit_vector.hpp:695
constexpr reference back() noexcept
Access the last element.
Definition bit_vector.hpp:573
constexpr void swap(bit_vector &other) noexcept
Exchanges the contents of the container with those of others.
Definition bit_vector.hpp:819
allocator_t allocator_type
The allocator type to use.
Definition bit_vector.hpp:379
constexpr bit_vector operator~() const noexcept
Performs binary NOT.
Definition bit_vector.hpp:751
constexpr bit_vector & flip(size_type position)
Flips the bit at the given position.
Definition bit_vector.hpp:806
constexpr reference operator[](size_type const position) noexcept
Access specified element.
Definition bit_vector.hpp:542
constexpr bit_vector(allocator_type const &alloc=allocator_type{})
The default constructor which optionally sets the allocator.
Definition bit_vector.hpp:398
constexpr friend bit_vector operator|(bit_vector lhs, bit_vector const &rhs) noexcept
Performs binary OR.
Definition bit_vector.hpp:771
constexpr bit_vector(size_type const count, bool const bit, allocator_type const &alloc=allocator_type{})
Constructs the bit vector with count copies of elements with value bit.
Definition bit_vector.hpp:413
constexpr bit_vector & and_not(bit_vector const &rhs) noexcept
Computes the bitwise a &= ~b operator without an additional copy.
Definition bit_vector.hpp:783
constexpr size_type size() const noexcept
Returns the number of elements.
Definition bit_vector.hpp:621
constexpr bit_vector(std::initializer_list< bool > list, allocator_type const &alloc=allocator_type{})
Constructs the container initialised with the elements in list.
Definition bit_vector.hpp:423
bit_iterator< false > iterator
The iterator over the bits.
Definition bit_vector.hpp:365
constexpr bit_vector(bit_vector &&)=default
Default.
constexpr const_reference back() const noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition bit_vector.hpp:581
constexpr iterator end() noexcept
Returns an iterator to the end.
Definition bit_vector.hpp:848
constexpr friend bit_vector operator^(bit_vector lhs, bit_vector const &rhs) noexcept
Performs binary XOR.
Definition bit_vector.hpp:777
constexpr bit_vector(bit_vector const &)=default
Default.
constexpr ~bit_vector()=default
Default.
constexpr const_iterator cend() const noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition bit_vector.hpp:860
constexpr iterator begin() noexcept
Returns an iterator to the beginning.
Definition bit_vector.hpp:830
constexpr bit_vector & flip() noexcept
Flips all bits in-place.
Definition bit_vector.hpp:795
constexpr bool any() const noexcept
Checks if any bit is set to true.
Definition bit_vector.hpp:600
constexpr bool none() const noexcept
Checks if none of the bits is set to true.
Definition bit_vector.hpp:611
constexpr friend bit_vector operator&(bit_vector lhs, bit_vector const &rhs) noexcept
Performs binary AND.
Definition bit_vector.hpp:765
constexpr bit_vector(size_type const count, allocator_type const &alloc=allocator_type{})
Constructs the container with count default-inserted instances of bool. No copies are made.
Definition bit_vector.hpp:435
constexpr const_iterator end() const noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition bit_vector.hpp:854
constexpr bit_vector & operator=(bit_vector &&)=default
Default.
bit_iterator< true > const_iterator
The const iterator over the bits.
Definition bit_vector.hpp:367
constexpr void assign(size_type const count, bool const bit)
Assigns values to the container.
Definition bit_vector.hpp:527
constexpr void assign(std::initializer_list< bool > const &ilist)
Assigns values to the container.
Definition bit_vector.hpp:502
constexpr bool all() const noexcept
Checks if all bits are set to true.
Definition bit_vector.hpp:589
constexpr const_iterator begin() const noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition bit_vector.hpp:836
constexpr void push_back(bool bit)
Adds an element to the end.
Definition bit_vector.hpp:685
size_t size_type
The size_type.
Definition bit_vector.hpp:375
constexpr bit_vector & operator|=(bit_vector const &rhs) noexcept
Performs binary OR between this and rhs.
Definition bit_vector.hpp:727
constexpr bool empty() const noexcept
Checks wether the container is empty.
Definition bit_vector.hpp:627
constexpr bit_vector & operator=(bit_vector const &)=default
Default.
constexpr void assign(iterator_t first, sentinel_t last)
Assigns values to the container.
Definition bit_vector.hpp:470
constexpr const_iterator cbegin() const noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition bit_vector.hpp:842
constexpr bit_vector & operator^=(bit_vector const &rhs) noexcept
Performs binary XOR between this and rhs.
Definition bit_vector.hpp:739
constexpr void reserve(size_type const new_capacity)
Reserves storage.
Definition bit_vector.hpp:655
constexpr bit_vector & operator&=(bit_vector const &rhs) noexcept
Performs binary AND between this and rhs.
Definition bit_vector.hpp:715
constexpr void clear() noexcept
Erases all elements. After this call, size() returns zero. capacity() remains unchanged.
Definition bit_vector.hpp:708
constexpr size_type capacity() const noexcept
Returns the capacity.
Definition bit_vector.hpp:633
constexpr const_reference operator[](size_type const position) const noexcept
Access specified element.
Definition bit_vector.hpp:550
T clear(T... args)
Definition concepts.hpp:25
T copy(T... args)
T countr_zero(T... args)
T data(T... args)
T fill(T... args)
T for_each(T... args)
T is_base_of_v
Provides platform and dependency checks.
#define HIBF_CONSTEXPR_VECTOR
std::vector constexpr support.
Definition platform.hpp:156
T reserve(T... args)
T resize(T... args)
T size(T... args)
T swap(T... args)
T to_string(T... args)