HIBF 1.0.0-rc.1
Loading...
Searching...
No Matches
bit_vector.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2006-2026, Knut Reinert & Freie Universität Berlin
2// SPDX-FileCopyrightText: 2016-2026, 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, copy, fill
25#include <bit> // for countr_zero
26#include <cassert> // for assert
27#include <climits> // for CHAR_BIT
28#include <compare> // for strong_ordering, operator==
29#include <concepts> // for assignable_from
30#include <cstddef> // for size_t, ptrdiff_t
31#include <cstdint> // for uint64_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, allocator_traits, assume_aligned, __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, basic_string
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_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 *this = bool(other);
123 return *this;
124 }
125 bit_reference & operator=(bit_reference && other) noexcept
126 {
127 *this = bool(other);
128 return *this;
129 }
130
135 constexpr bit_reference & operator=(bool const bit) noexcept
136 {
137 bit ? set() : clear();
138 return *this;
139 }
140
142 // Needed to model std::output_iterator<bit_iterator, bool>, which requires the assignment to an const && version
143 // of the proxy.
144 // NOLINTNEXTLINE(misc-unconventional-assign-operator)
145 constexpr bit_reference const & operator=(bool const bit) const noexcept
146 requires (!is_const)
147 {
148 bit ? set() : clear();
149 return *this;
150 }
152
154 constexpr operator bool() const noexcept
155 {
156 return *_chunk & _chunk_mask;
157 }
158
160 constexpr bit_reference & flip() noexcept
161 {
162 (*this) ? clear() : set();
163 return *this;
164 }
165
166 private:
168 constexpr void set() noexcept
169 {
170 *_chunk |= _chunk_mask;
171 }
172
174 constexpr void clear() noexcept
175 {
176 *_chunk &= ~_chunk_mask;
177 }
178 };
179
183 template <bool is_const>
184 class bit_iterator
185 {
186 private:
188 template <bool>
189 friend class bit_iterator;
190
193
194 maybe_const_chunk_type * _chunk{};
195 size_type _chunk_position{};
196
197 public:
201 using value_type = bool;
202 using reference = bit_reference<is_const>;
203 using pointer = void;
205 using iterator_category = std::random_access_iterator_tag;
206 using iterator_concept = std::random_access_iterator_tag;
208
212 bit_iterator() = default;
213
218 explicit constexpr bit_iterator(maybe_const_chunk_type * chunk) noexcept : _chunk{chunk}, _chunk_position{0}
219 {}
220
225 constexpr bit_iterator(bit_iterator<!is_const> const & other) noexcept
226 requires (is_const)
227 : _chunk{other._chunk}, _chunk_position{other._chunk_position}
228 {}
230
235 constexpr reference operator*() const noexcept
236 {
237 return reference{_chunk, _chunk_position};
238 }
239
241 constexpr reference operator[](difference_type const count) const noexcept
242 {
243 return *((*this) + count);
244 }
246
251 constexpr bit_iterator & operator++() noexcept
252 {
253 _chunk += !static_cast<bool>(to_local_chunk_position(++_chunk_position));
254 return *this;
255 }
256
258 constexpr bit_iterator operator++(int) noexcept
259 {
260 bit_iterator tmp{*this};
261 ++(*this);
262 return tmp;
263 }
264
266 constexpr bit_iterator & operator+=(difference_type const count) noexcept
267 {
268 // chunk:| 0 | 1 | 2 | 3 | 4 | 5 |
269 // |--------|--------|--------|--------|-x------|--------|
270 // chunk_position:|01234567|01234567|01234567|01234567|01234567|01234567|
271 // global position:|01234567|89012345|67890123|45678901|23456789|01234567|
272 // |0 | 1 | 2 | 3 | |4 |
273 if (count < 0)
274 {
275 size_type updated_count = modulo_mask - to_local_chunk_position(_chunk_position) - count;
276 _chunk_position = modulo_mask - to_local_chunk_position(updated_count);
277 _chunk -= to_chunk_position(updated_count);
278 //(to_chunk_position(-count) + (old_chunk_position < _chunk_position));
279 }
280 else
281 {
282 _chunk += to_chunk_position(to_local_chunk_position(_chunk_position) + count);
283 _chunk_position = to_local_chunk_position(_chunk_position + count);
284 }
285
286 return *this;
287 }
288
290 constexpr bit_iterator operator+(difference_type const count) const noexcept
291 {
292 bit_iterator tmp{*this};
293 return tmp += count;
294 }
295
297 friend constexpr bit_iterator operator+(difference_type const count, bit_iterator rhs) noexcept
298 {
299 return rhs + count;
300 }
301
303 constexpr bit_iterator & operator--() noexcept
304 {
305 _chunk -= !static_cast<bool>(to_local_chunk_position(--_chunk_position));
306 return *this;
307 }
308
310 constexpr bit_iterator operator--(int) noexcept
311 {
312 bit_iterator tmp{*this};
313 --(*this);
314 return tmp;
315 }
316
318 constexpr bit_iterator & operator-=(difference_type const count) noexcept
319 {
320 return *this += -count;
321 }
322
324 constexpr bit_iterator operator-(difference_type const count) const noexcept
325 {
326 bit_iterator tmp{*this};
327 return tmp -= count;
328 }
329
331 template <bool is_const_other>
332 constexpr difference_type operator-(bit_iterator<is_const_other> rhs) const noexcept
333 {
334 return ((_chunk - rhs._chunk) << division_mask) - // number of bits between chunks.
335 to_local_chunk_position(rhs._chunk_position) + // minus the first bits in rhs.
336 to_local_chunk_position(_chunk_position); // plus the first bits of the lhs
337 }
339
344 template <bool is_const_other>
345 bool operator==(bit_iterator<is_const_other> const & rhs) const
346 {
347 return _chunk == rhs._chunk
348 && (to_local_chunk_position(_chunk_position) == to_local_chunk_position(rhs._chunk_position));
349 }
350
352 template <bool is_const_other>
353 std::strong_ordering operator<=>(bit_iterator<is_const_other> const & rhs) const
354 {
355 if (std::strong_ordering order = _chunk <=> rhs._chunk; order == std::strong_ordering::equivalent)
356 return to_local_chunk_position(_chunk_position) <=> to_local_chunk_position(rhs._chunk_position);
357 else
358 return order;
359 }
361 };
362
363public:
368 using iterator = bit_iterator<false>;
370 using const_iterator = bit_iterator<true>;
378 using size_type = size_t;
382 using allocator_type = allocator_t;
384
385private:
387 static constexpr size_type chunk_size = sizeof(chunk_type) * CHAR_BIT;
389 static constexpr size_type modulo_mask = chunk_size - 1u;
391 static constexpr size_type division_mask = std::countr_zero(chunk_size);
392
394 size_type _size{};
395
396public:
401 constexpr bit_vector(allocator_type const & alloc = allocator_type{}) : base_t{alloc}
402 {}
403 constexpr bit_vector(bit_vector const &) = default;
404 constexpr bit_vector(bit_vector &&) = default;
405 constexpr bit_vector & operator=(bit_vector const &) = default;
406 constexpr bit_vector & operator=(bit_vector &&) = default;
407 constexpr ~bit_vector() = default;
408
415 constexpr bit_vector(size_type const count, bool const bit, allocator_type const & alloc = allocator_type{}) :
416 base_t{alloc}
417 {
418 assign(count, bit);
419 }
420
427 base_t{alloc}
428 {
429 assign(list);
430 }
431
437 constexpr bit_vector(size_type const count, allocator_type const & alloc = allocator_type{}) :
438 bit_vector{count, bool{}, alloc}
439 {}
441
470 template <std::input_iterator iterator_t, std::sentinel_for<iterator_t> sentinel_t>
472 constexpr void assign(iterator_t first, sentinel_t last)
473 {
474 bit_vector tmp{}; // To ensure strong exception guarantee.
476 tmp.reserve(std::ranges::distance(first, last));
477
478 std::ranges::copy(first, last, std::back_inserter(tmp));
479
480 // ----- no exception after this.
481 swap(tmp);
482 set_new_size(std::ranges::distance(begin(), end()));
483 }
484
504 constexpr void assign(std::initializer_list<bool> const & ilist)
505 {
506 assign(std::ranges::begin(ilist), std::ranges::end(ilist));
507 }
508
529 constexpr void assign(size_type const count, bool const bit)
530 {
531 resize(count, bit);
532 std::ranges::for_each(*as_base(),
533 [value = fill_chunk(bit)](chunk_type & chunk)
534 {
535 chunk = value;
536 });
537 }
539
544 constexpr reference operator[](size_type const position) noexcept
545 {
546 assert(position < size());
547
548 return *std::ranges::next(begin(), position);
549 }
550
552 constexpr const_reference operator[](size_type const position) const noexcept
553 {
554 assert(position < size());
555
556 return *std::ranges::next(begin(), position);
557 }
558
575 constexpr reference back() noexcept
576 {
577 assert(!empty()); // Calling on empty container is undefined behaviour.
578
579 return (*this)[size() - 1u];
580 }
581
583 constexpr const_reference back() const noexcept
584 {
585 assert(!empty()); // Calling on empty container is undefined behaviour.
586
587 return (*this)[size() - 1u];
588 }
589
591 constexpr bool all() const noexcept
592 {
593 if (empty())
594 return true;
595
596 constexpr chunk_type mask = ~chunk_type{};
597 chunk_type const * const ptr = data();
598 size_type const last_chunk = host_size_impl(size()) - 1u;
599
600 for (size_t i = 0; i < last_chunk; ++i)
601 if (ptr[i] != mask)
602 return false;
603
604 // The last chunk may contain unset bits beyond `size()`. Those must not be considered.
605 return (ptr[last_chunk] | ~last_chunk_mask()) == mask;
606 }
607
609 constexpr bool any() const noexcept
610 {
611 if (empty())
612 return false;
613
614 chunk_type const * const ptr = data();
615 size_type const last_chunk = host_size_impl(size()) - 1u;
616
617 for (size_t i = 0; i < last_chunk; ++i)
618 if (ptr[i])
619 return true;
620
621 // The last chunk may contain set bits beyond `size()`. Those must not be considered.
622 return (ptr[last_chunk] & last_chunk_mask()) != chunk_type{};
623 }
624
626 constexpr bool none() const noexcept
627 {
628 return !any();
629 }
630
632 constexpr size_t count() const noexcept
633 {
634 if (empty())
635 return 0u;
636
637 chunk_type const * const ptr = data();
638 size_type const size = host_size_impl(this->size());
639 size_t result{};
640
641 for (size_t i = 0; i < size; ++i)
642 result += std::popcount(ptr[i]);
643
644 // The last chunk may contain bits beyond `size()`, e.g., after `flip()`. Those must not be counted.
645 return result - std::popcount(ptr[size - 1] & ~last_chunk_mask());
646 }
648
653 constexpr size_type size() const noexcept
654 {
655 return _size;
656 }
657
659 constexpr bool empty() const noexcept
660 {
661 return _size == 0u;
662 }
663
665 constexpr size_type capacity() const noexcept
666 {
667 return base_t::capacity() * chunk_size;
668 }
669
687 constexpr void reserve(size_type const new_capacity)
688 {
689 base_t::reserve(host_size_impl(new_capacity));
690 }
692
717 constexpr void push_back(bool bit)
718 {
719 size_t const new_size = size() + 1u;
720 resize(new_size);
721 // ---- no exception after this point.
722 set_new_size(new_size);
723 back() = bit; // set the bit.
724 }
725
727 constexpr void resize(size_type const count, bool const bit = {})
728 {
729 base_t::resize(host_size_impl(count));
730
731 size_t const old_size = size();
732 set_new_size(count);
733
734 // If bit is true and we increase the size.
735 if (bit && size() > old_size)
736 std::ranges::fill(begin() + old_size, end(), bit);
737 }
738
740 constexpr void clear() noexcept
741 {
743 _size = 0u;
744 }
745
747 constexpr bit_vector & operator&=(bit_vector const & rhs) noexcept
748 {
749 assert(rhs.size() == size());
750
751 return binary_transform_impl(rhs,
752 [](auto const & left_chunk, auto const & right_chunk)
753 {
754 return left_chunk & right_chunk;
755 });
756 }
757
759 constexpr bit_vector & operator|=(bit_vector const & rhs) noexcept
760 {
761 assert(rhs.size() == size());
762
763 return binary_transform_impl(rhs,
764 [](auto const & left_chunk, auto const & right_chunk)
765 {
766 return left_chunk | right_chunk;
767 });
768 }
769
771 constexpr bit_vector & operator^=(bit_vector const & rhs) noexcept
772 {
773 assert(rhs.size() == size());
774
775 return binary_transform_impl(rhs,
776 [](auto const & left_chunk, auto const & right_chunk)
777 {
778 return left_chunk ^ right_chunk;
779 });
780 }
781
783 constexpr bit_vector operator~() const noexcept
784 {
785 bit_vector tmp(size());
786
787 tmp.binary_transform_impl(*this,
788 [](auto const &, auto const & right_chunk)
789 {
790 return ~right_chunk;
791 });
792
793 return tmp;
794 }
795
797 constexpr friend bit_vector operator&(bit_vector lhs, bit_vector const & rhs) noexcept
798 {
799 return lhs &= rhs;
800 }
801
803 constexpr friend bit_vector operator|(bit_vector lhs, bit_vector const & rhs) noexcept
804 {
805 return lhs |= rhs;
806 }
807
809 constexpr friend bit_vector operator^(bit_vector lhs, bit_vector const & rhs) noexcept
810 {
811 return lhs ^= rhs;
812 }
813
815 constexpr bit_vector & and_not(bit_vector const & rhs) noexcept
816 {
817 assert(rhs.size() == size());
818
819 return binary_transform_impl(rhs,
820 [](auto const & left_chunk, auto const & right_chunk)
821 {
822 return left_chunk & ~right_chunk;
823 });
824 }
825
827 constexpr bit_vector & flip() noexcept
828 {
829 std::ranges::for_each(*as_base(),
830 [](chunk_type & chunk)
831 {
832 chunk = ~chunk;
833 });
834 return *this;
835 }
836
838 constexpr bit_vector & flip(size_type position)
839 {
840 using namespace std::literals;
841
842 if (position >= size())
843 throw std::out_of_range{"The given posisiton "s + std::to_string(position) + " is out of the range [0, "s
844 + std::to_string(size()) + ")!"s};
845
846 (*this)[position].flip();
847 return *this;
848 }
849
851 constexpr void swap(bit_vector & other) noexcept
852 {
853 base_t::swap(*other.as_base());
854 std::swap(_size, other._size);
855 }
857
862 constexpr iterator begin() noexcept
863 {
864 return iterator{base_t::data()};
865 }
866
868 constexpr const_iterator begin() const noexcept
869 {
871 }
872
874 constexpr const_iterator cbegin() const noexcept
875 {
876 return begin();
877 }
878
880 constexpr iterator end() noexcept
881 {
882 return begin() + size();
883 }
884
886 constexpr const_iterator end() const noexcept
887 {
888 return begin() + size();
889 }
890
892 constexpr const_iterator cend() const noexcept
893 {
894 return end();
895 }
897
898 [[gnu::always_inline]] inline constexpr chunk_type * data() noexcept
899 {
901 }
902
903 [[gnu::always_inline]] inline constexpr chunk_type const * data() const noexcept
904 {
906 }
907
915 template <cereal_archive archive_t>
916 void CEREAL_LOAD_FUNCTION_NAME(archive_t & archive)
917 {
918 // Not using `cereal::make_size_tag(_size)`, because the size tag is inferred for text (XML/JSON) archives.
919 // For text archives, `cereal::make_size_tag(_size)` would be the number of elements serialised in the for-loop.
920 // E.g., `_size == 100` would store `2` (`== host_size_impl(_size)`).
921 archive(_size);
922 size_t const vector_size = host_size_impl(_size);
923
924 resize_for_overwrite(vector_size);
925
926 if constexpr (cereal_text_archive<archive_t>)
927 {
928 for (auto && v : *as_base())
929 archive(v);
930 }
931 else
932 {
933 archive(cereal::binary_data(data(), vector_size * sizeof(chunk_type)));
934 }
935 }
936
938 template <cereal_archive archive_t>
939 void CEREAL_SAVE_FUNCTION_NAME(archive_t & archive) const
940 {
941 // Not using `cereal::make_size_tag(_size)`, because the size tag is inferred for text (XML/JSON) archives.
942 // For text archives, `cereal::make_size_tag(_size)` would be the number of elements serialised in the for-loop.
943 // E.g., `_size == 100` would store `2` (`== host_size_impl(_size)`).
944 archive(_size);
945
946 if constexpr (cereal_text_archive<archive_t>)
947 {
948 for (auto && v : *as_base())
949 archive(v);
950 }
951 else
952 {
953 archive(cereal::binary_data(data(), base_t::size() * sizeof(chunk_type)));
954 }
955 }
957
958private:
959// If nothing else works: Just use `resize`.
960#ifndef HIBF_UNINITIALISED_RESIZE
961 inline constexpr void resize_for_overwrite(size_t const size)
962 {
964 }
965#else
966// libc++: reinterpret_cast to a struct that has the same layout as std::vector.
967// All internal members are private.
968# if defined(_LIBCPP_VERSION)
969 inline void resize_for_overwrite(size_t const size)
970 {
971 struct fake_vector
972 {
973 using allocator_t = typename base_t::allocator_type;
974 using pointer = typename std::allocator_traits<allocator_t>::pointer;
975
976 pointer begin;
977 pointer end;
978# pragma GCC diagnostic push
979# pragma GCC diagnostic ignored "-Wgnu-anonymous-struct" // Warning since clang-21
980 _LIBCPP_COMPRESSED_PAIR(pointer, end_cap = nullptr, allocator_type, allocator);
981# pragma GCC diagnostic pop
982 };
983
984 static_assert(sizeof(fake_vector) == sizeof(base_t));
985 static_assert(alignof(fake_vector) == alignof(base_t));
986
987 if (size > base_t::capacity())
989// Annotate the new memory as contiguous container for llvm's address sanitizer.
990# if __has_feature(address_sanitizer)
994 base_t::data() + size);
995# endif
996 fake_vector & vec = reinterpret_cast<fake_vector &>(*this);
997 vec.end = vec.begin + size;
998 }
999// libstdc++: The internal members are protected, so we can access them.
1000# else
1001 inline constexpr void resize_for_overwrite(size_t const size)
1002 {
1003 if (size > base_t::capacity())
1005
1006 this->_M_impl._M_finish = this->_M_impl._M_start + size;
1007 }
1008# endif
1009#endif
1010
1012 template <typename binary_operator_t>
1013 constexpr bit_vector & binary_transform_impl(bit_vector const & rhs, binary_operator_t && op) noexcept
1014 {
1015 chunk_type * const lhs_data = data();
1016 chunk_type const * const rhs_data = rhs.data();
1017 size_type const size = host_size_impl(this->size());
1018
1019 for (size_t i = 0; i < size; ++i)
1020 lhs_data[i] = op(lhs_data[i], rhs_data[i]);
1021
1022 return *this;
1023 }
1024
1027 constexpr size_type host_size_impl(size_type const count) const noexcept
1028 {
1029 return chunks_needed(count);
1030 }
1031
1033 constexpr void set_new_size(size_type const new_size) noexcept
1034 {
1035 _size = new_size;
1036 }
1037
1039 constexpr base_t const * as_base() const noexcept
1040 {
1041 return static_cast<base_t const *>(this);
1042 }
1043
1045 constexpr base_t * as_base() noexcept
1046 {
1047 return static_cast<base_t *>(this);
1048 }
1049
1051 constexpr size_type chunks_needed(size_type const count) const noexcept
1052 {
1053 return (count + 63u) >> 6; // ceil(count/64)
1054 }
1055
1063 constexpr chunk_type last_chunk_mask() const noexcept
1064 {
1065 assert(!empty());
1066
1067 size_type const bits_in_last_chunk = to_local_chunk_position(size());
1068 return bits_in_last_chunk ? (chunk_type{1u} << bits_in_last_chunk) - 1u : ~chunk_type{};
1069 }
1070
1072 constexpr chunk_type fill_chunk(bool const bit) const noexcept
1073 {
1074 return (bit) ? ~chunk_type{} : chunk_type{};
1075 }
1076
1078 static constexpr size_type to_local_chunk_position(size_type const position) noexcept
1079 {
1080 return position & modulo_mask; // e.g. position % 64
1081 }
1082
1084 static constexpr size_type to_chunk_position(size_type const position) noexcept
1085 {
1086 return position >> division_mask; // e.g. position / 64
1087 }
1088};
1089
1090} // namespace seqan::hibf
1091
1093// See https://uscilab.github.io/cereal/serialization_functions.html#inheritance
1094// seqan::hibf::bit_vector's base class is std::vector
1095// If we include <cereal/types/vector.hpp> for std::vector serialisation (e.g., HIBF),
1096// cereal provides these as non-member load/save functions.
1097// Since both load/save non-member functions (std::vector) and load/save member functions (bit_vector) are available,
1098// cereal needs to be told which one to use.
1099namespace cereal
1100{
1101
1102template <typename archive_t>
1103struct specialize<archive_t, seqan::hibf::bit_vector, cereal::specialization::member_load_save>
1104{};
1105
1106} // namespace cereal
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:727
constexpr reference back() noexcept
Access the last element.
Definition bit_vector.hpp:575
constexpr void swap(bit_vector &other) noexcept
Exchanges the contents of the container with those of others.
Definition bit_vector.hpp:851
allocator_t allocator_type
The allocator type to use.
Definition bit_vector.hpp:382
constexpr bit_vector operator~() const noexcept
Performs binary NOT.
Definition bit_vector.hpp:783
constexpr bit_vector & flip(size_type position)
Flips the bit at the given position.
Definition bit_vector.hpp:838
constexpr reference operator[](size_type const position) noexcept
Access specified element.
Definition bit_vector.hpp:544
constexpr bit_vector(allocator_type const &alloc=allocator_type{})
The default constructor which optionally sets the allocator.
Definition bit_vector.hpp:401
constexpr friend bit_vector operator|(bit_vector lhs, bit_vector const &rhs) noexcept
Performs binary OR.
Definition bit_vector.hpp:803
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:415
constexpr bit_vector & and_not(bit_vector const &rhs) noexcept
Computes the bitwise a &= ~b operator without an additional copy.
Definition bit_vector.hpp:815
constexpr size_type size() const noexcept
Returns the number of elements.
Definition bit_vector.hpp:653
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:426
constexpr size_t count() const noexcept
Returns the number of bits that are set to true.
Definition bit_vector.hpp:632
bit_iterator< false > iterator
The iterator over the bits.
Definition bit_vector.hpp:368
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:583
constexpr iterator end() noexcept
Returns an iterator to the end.
Definition bit_vector.hpp:880
constexpr friend bit_vector operator^(bit_vector lhs, bit_vector const &rhs) noexcept
Performs binary XOR.
Definition bit_vector.hpp:809
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:892
constexpr iterator begin() noexcept
Returns an iterator to the beginning.
Definition bit_vector.hpp:862
constexpr bit_vector & flip() noexcept
Flips all bits in-place.
Definition bit_vector.hpp:827
constexpr bool any() const noexcept
Checks if any bit is set to true.
Definition bit_vector.hpp:609
constexpr bool none() const noexcept
Checks if none of the bits is set to true.
Definition bit_vector.hpp:626
constexpr friend bit_vector operator&(bit_vector lhs, bit_vector const &rhs) noexcept
Performs binary AND.
Definition bit_vector.hpp:797
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:437
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:886
constexpr bit_vector & operator=(bit_vector &&)=default
Default.
bit_iterator< true > const_iterator
The const iterator over the bits.
Definition bit_vector.hpp:370
constexpr void assign(size_type const count, bool const bit)
Assigns values to the container.
Definition bit_vector.hpp:529
constexpr void assign(std::initializer_list< bool > const &ilist)
Assigns values to the container.
Definition bit_vector.hpp:504
constexpr bool all() const noexcept
Checks if all bits are set to true.
Definition bit_vector.hpp:591
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:868
constexpr void push_back(bool bit)
Adds an element to the end.
Definition bit_vector.hpp:717
size_t size_type
The size_type.
Definition bit_vector.hpp:378
constexpr bit_vector & operator|=(bit_vector const &rhs) noexcept
Performs binary OR between this and rhs.
Definition bit_vector.hpp:759
constexpr bool empty() const noexcept
Checks wether the container is empty.
Definition bit_vector.hpp:659
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:472
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:874
constexpr bit_vector & operator^=(bit_vector const &rhs) noexcept
Performs binary XOR between this and rhs.
Definition bit_vector.hpp:771
constexpr void reserve(size_type const new_capacity)
Reserves storage.
Definition bit_vector.hpp:687
constexpr bit_vector & operator&=(bit_vector const &rhs) noexcept
Performs binary AND between this and rhs.
Definition bit_vector.hpp:747
constexpr void clear() noexcept
Erases all elements. After this call, size() returns zero. capacity() remains unchanged.
Definition bit_vector.hpp:740
constexpr size_type capacity() const noexcept
Returns the capacity.
Definition bit_vector.hpp:665
constexpr const_reference operator[](size_type const position) const noexcept
Access specified element.
Definition bit_vector.hpp:552
T clear(T... args)
Definition concepts.hpp:27
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.
T popcount(T... args)
T reserve(T... args)
T resize(T... args)
T size(T... args)
T swap(T... args)
T to_string(T... args)