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 initializer_list, __for_each, for_each, __fill, copy, fill
25#include <bit> // for popcount, countr_zero
26#include <cassert> // for assert
27#include <climits> // for CHAR_BIT
28#include <compare> // for strong_ordering, operator==
29#include <cstddef> // for size_t, ptrdiff_t
30#include <cstdint> // for uint64_t
31#include <iterator> // for iter_reference_t, __next, distance, iter_difference_t, iter_va...
32#include <memory> // for allocator, allocator_traits, assume_aligned, _LIBCPP_COMPRESSE...
33#include <ranges> // for __fn, begin, end
34#include <stdexcept> // for out_of_range
35#include <string> // for char_traits, operator+, operator""s, basic_string, to_string
36#include <type_traits> // for conditional_t
37#include <utility> // for swap
38#include <vector> // for vector
39
40#include <cereal/cereal.hpp> // for binary_data
41#include <cereal/macros.hpp> // for CEREAL_LOAD_FUNCTION_NAME, CEREAL_SAVE_FUNCTION_NAME
42#include <cereal/specialize.hpp> // for specialization, specialize
43
44#include <hibf/cereal/concepts.hpp> // for cereal_archive, cereal_text_archive
45#include <hibf/contrib/aligned_allocator.hpp> // for aligned_allocator
46#include <hibf/platform.hpp> // for _LIBCPP_VERSION
47
48namespace seqan::hibf
49{
50
63 public std::vector<uint64_t,
64 typename std::allocator_traits<
65 seqan::hibf::contrib::aligned_allocator<bool, 64u>>::template rebind_alloc<uint64_t>>
66{
67private:
69 using allocator_t = seqan::hibf::contrib::aligned_allocator<bool, 64u>;
70
73
75 using chunk_type = uint64_t;
76
88 template <bool is_const>
89 class bit_reference
90 {
91 private:
93 friend class bit_vector;
94
97
98 maybe_const_chunk_type * _chunk{};
99 chunk_type _chunk_mask{};
100
106 constexpr bit_reference(maybe_const_chunk_type * chunk, size_type const local_chunk_position) noexcept :
107 _chunk{chunk},
108 _chunk_mask{static_cast<chunk_type>(1) << to_local_chunk_position(local_chunk_position)}
109 {}
110
111 public:
115 bit_reference() = delete;
116 bit_reference(bit_reference const & other) = default;
117 bit_reference(bit_reference && other) = default;
118 bit_reference & operator=(bit_reference const & other)
119 {
120 *this = bool(other);
121 return *this;
122 }
123 bit_reference & operator=(bit_reference && other) noexcept
124 {
125 *this = bool(other);
126 return *this;
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 // NOLINTNEXTLINE(misc-unconventional-assign-operator)
143 constexpr bit_reference const & operator=(bool const bit) const noexcept
144 requires (!is_const)
145 {
146 bit ? set() : clear();
147 return *this;
148 }
150
152 constexpr operator bool() const noexcept
153 {
154 return *_chunk & _chunk_mask;
155 }
156
158 constexpr bit_reference & flip() noexcept
159 {
160 (*this) ? clear() : set();
161 return *this;
162 }
163
164 private:
166 constexpr void set() noexcept
167 {
168 *_chunk |= _chunk_mask;
169 }
170
172 constexpr void clear() noexcept
173 {
174 *_chunk &= ~_chunk_mask;
175 }
176 };
177
181 template <bool is_const>
182 class bit_iterator
183 {
184 private:
186 template <bool>
187 friend class bit_iterator;
188
191
192 maybe_const_chunk_type * _chunk{};
193 size_type _chunk_position{};
194
195 public:
199 using value_type = bool;
200 using reference = bit_reference<is_const>;
201 using pointer = void;
203 using iterator_category = std::random_access_iterator_tag;
204 using iterator_concept = std::random_access_iterator_tag;
206
210 bit_iterator() = default;
211
216 explicit constexpr bit_iterator(maybe_const_chunk_type * chunk) noexcept : _chunk{chunk}, _chunk_position{0}
217 {}
218
223 constexpr bit_iterator(bit_iterator<!is_const> const & other) noexcept
224 requires (is_const)
225 : _chunk{other._chunk}, _chunk_position{other._chunk_position}
226 {}
228
233 constexpr reference operator*() const noexcept
234 {
235 return reference{_chunk, _chunk_position};
236 }
237
239 constexpr reference operator[](difference_type const count) const noexcept
240 {
241 return *((*this) + count);
242 }
244
249 constexpr bit_iterator & operator++() noexcept
250 {
251 _chunk += !static_cast<bool>(to_local_chunk_position(++_chunk_position));
252 return *this;
253 }
254
256 constexpr bit_iterator operator++(int) noexcept
257 {
258 bit_iterator tmp{*this};
259 ++(*this);
260 return tmp;
261 }
262
264 constexpr bit_iterator & operator+=(difference_type const count) noexcept
265 {
266 // chunk:| 0 | 1 | 2 | 3 | 4 | 5 |
267 // |--------|--------|--------|--------|-x------|--------|
268 // chunk_position:|01234567|01234567|01234567|01234567|01234567|01234567|
269 // global position:|01234567|89012345|67890123|45678901|23456789|01234567|
270 // |0 | 1 | 2 | 3 | |4 |
271 if (count < 0)
272 {
273 size_type updated_count = modulo_mask - to_local_chunk_position(_chunk_position) - count;
274 _chunk_position = modulo_mask - to_local_chunk_position(updated_count);
275 _chunk -= to_chunk_position(updated_count);
276 //(to_chunk_position(-count) + (old_chunk_position < _chunk_position));
277 }
278 else
279 {
280 _chunk += to_chunk_position(to_local_chunk_position(_chunk_position) + count);
281 _chunk_position = to_local_chunk_position(_chunk_position + count);
282 }
283
284 return *this;
285 }
286
288 constexpr bit_iterator operator+(difference_type const count) const noexcept
289 {
290 bit_iterator tmp{*this};
291 return tmp += count;
292 }
293
295 friend constexpr bit_iterator operator+(difference_type const count, bit_iterator rhs) noexcept
296 {
297 return rhs + count;
298 }
299
301 constexpr bit_iterator & operator--() noexcept
302 {
303 _chunk -= !static_cast<bool>(to_local_chunk_position(--_chunk_position));
304 return *this;
305 }
306
308 constexpr bit_iterator operator--(int) noexcept
309 {
310 bit_iterator tmp{*this};
311 --(*this);
312 return tmp;
313 }
314
316 constexpr bit_iterator & operator-=(difference_type const count) noexcept
317 {
318 return *this += -count;
319 }
320
322 constexpr bit_iterator operator-(difference_type const count) const noexcept
323 {
324 bit_iterator tmp{*this};
325 return tmp -= count;
326 }
327
329 template <bool is_const_other>
330 constexpr difference_type operator-(bit_iterator<is_const_other> rhs) const noexcept
331 {
332 return ((_chunk - rhs._chunk) << division_mask) - // number of bits between chunks.
333 to_local_chunk_position(rhs._chunk_position) + // minus the first bits in rhs.
334 to_local_chunk_position(_chunk_position); // plus the first bits of the lhs
335 }
337
342 template <bool is_const_other>
343 bool operator==(bit_iterator<is_const_other> const & rhs) const
344 {
345 return _chunk == rhs._chunk
346 && (to_local_chunk_position(_chunk_position) == to_local_chunk_position(rhs._chunk_position));
347 }
348
350 template <bool is_const_other>
351 std::strong_ordering operator<=>(bit_iterator<is_const_other> const & rhs) const
352 {
353 if (std::strong_ordering order = _chunk <=> rhs._chunk; order == std::strong_ordering::equivalent)
354 return to_local_chunk_position(_chunk_position) <=> to_local_chunk_position(rhs._chunk_position);
355 else
356 return order;
357 }
359 };
360
361public:
366 using iterator = bit_iterator<false>;
368 using const_iterator = bit_iterator<true>;
376 using size_type = size_t;
380 using allocator_type = allocator_t;
382
383private:
385 static constexpr size_type chunk_size = sizeof(chunk_type) * CHAR_BIT;
387 static constexpr size_type modulo_mask = chunk_size - 1u;
389 static constexpr size_type division_mask = std::countr_zero(chunk_size);
390
392 size_type _size{};
393
394public:
399 constexpr bit_vector(allocator_type const & alloc = allocator_type{}) : base_t{alloc}
400 {}
401 constexpr bit_vector(bit_vector const &) = default;
402 constexpr bit_vector(bit_vector &&) = default;
403 constexpr bit_vector & operator=(bit_vector const &) = default;
404 constexpr bit_vector & operator=(bit_vector &&) = default;
405 constexpr ~bit_vector() = default;
406
413 constexpr bit_vector(size_type const count, bool const bit, allocator_type const & alloc = allocator_type{}) :
414 base_t{alloc}
415 {
416 assign(count, bit);
417 }
418
425 base_t{alloc}
426 {
427 assign(list);
428 }
429
435 constexpr bit_vector(size_type const count, allocator_type const & alloc = allocator_type{}) :
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 constexpr 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
542 constexpr reference operator[](size_type const position) noexcept
543 {
544 assert(position < size());
545
546 return *std::ranges::next(begin(), position);
547 }
548
550 constexpr const_reference operator[](size_type const position) const noexcept
551 {
552 assert(position < size());
553
554 return *std::ranges::next(begin(), position);
555 }
556
573 constexpr reference back() noexcept
574 {
575 assert(!empty()); // Calling on empty container is undefined behaviour.
576
577 return (*this)[size() - 1u];
578 }
579
581 constexpr const_reference back() const noexcept
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 if (empty())
592 return true;
593
594 constexpr chunk_type mask = ~chunk_type{};
595 chunk_type const * const ptr = data();
596 size_type const last_chunk = host_size_impl(size()) - 1u;
597
598 for (size_t i = 0; i < last_chunk; ++i)
599 if (ptr[i] != mask)
600 return false;
601
602 // The last chunk may contain unset bits beyond `size()`. Those must not be considered.
603 return (ptr[last_chunk] | ~last_chunk_mask()) == mask;
604 }
605
607 constexpr bool any() const noexcept
608 {
609 if (empty())
610 return false;
611
612 chunk_type const * const ptr = data();
613 size_type const last_chunk = host_size_impl(size()) - 1u;
614
615 for (size_t i = 0; i < last_chunk; ++i)
616 if (ptr[i])
617 return true;
618
619 // The last chunk may contain set bits beyond `size()`. Those must not be considered.
620 return (ptr[last_chunk] & last_chunk_mask()) != chunk_type{};
621 }
622
624 constexpr bool none() const noexcept
625 {
626 return !any();
627 }
628
630 constexpr size_t count() const noexcept
631 {
632 if (empty())
633 return 0u;
634
635 chunk_type const * const ptr = data();
636 size_type const size = host_size_impl(this->size());
637 size_t result{};
638
639 for (size_t i = 0; i < size; ++i)
640 result += std::popcount(ptr[i]);
641
642 // The last chunk may contain bits beyond `size()`, e.g., after `flip()`. Those must not be counted.
643 return result - std::popcount(ptr[size - 1] & ~last_chunk_mask());
644 }
646
651 constexpr size_type size() const noexcept
652 {
653 return _size;
654 }
655
657 constexpr bool empty() const noexcept
658 {
659 return _size == 0u;
660 }
661
663 constexpr size_type capacity() const noexcept
664 {
665 return base_t::capacity() * chunk_size;
666 }
667
685 constexpr void reserve(size_type const new_capacity)
686 {
687 base_t::reserve(host_size_impl(new_capacity));
688 }
690
715 constexpr void push_back(bool bit)
716 {
717 size_t const new_size = size() + 1u;
718 resize(new_size);
719 // ---- no exception after this point.
720 set_new_size(new_size);
721 back() = bit; // set the bit.
722 }
723
725 constexpr void resize(size_type const count, bool const bit = {})
726 {
727 base_t::resize(host_size_impl(count));
728
729 size_t const old_size = size();
730 set_new_size(count);
731
732 // If bit is true and we increase the size.
733 if (bit && size() > old_size)
734 std::ranges::fill(begin() + old_size, end(), bit);
735 }
736
738 constexpr void clear() noexcept
739 {
741 _size = 0u;
742 }
743
745 constexpr bit_vector & operator&=(bit_vector const & rhs) noexcept
746 {
747 assert(rhs.size() == size());
748
749 return binary_transform_impl(rhs,
750 [](auto const & left_chunk, auto const & right_chunk)
751 {
752 return left_chunk & right_chunk;
753 });
754 }
755
757 constexpr bit_vector & operator|=(bit_vector const & rhs) noexcept
758 {
759 assert(rhs.size() == size());
760
761 return binary_transform_impl(rhs,
762 [](auto const & left_chunk, auto const & right_chunk)
763 {
764 return left_chunk | right_chunk;
765 });
766 }
767
769 constexpr bit_vector & operator^=(bit_vector const & rhs) noexcept
770 {
771 assert(rhs.size() == size());
772
773 return binary_transform_impl(rhs,
774 [](auto const & left_chunk, auto const & right_chunk)
775 {
776 return left_chunk ^ right_chunk;
777 });
778 }
779
781 constexpr bit_vector operator~() const noexcept
782 {
783 bit_vector tmp(size());
784
785 tmp.binary_transform_impl(*this,
786 [](auto const &, auto const & right_chunk)
787 {
788 return ~right_chunk;
789 });
790
791 return tmp;
792 }
793
795 constexpr friend bit_vector operator&(bit_vector lhs, bit_vector const & rhs) noexcept
796 {
797 return lhs &= rhs;
798 }
799
801 constexpr friend bit_vector operator|(bit_vector lhs, bit_vector const & rhs) noexcept
802 {
803 return lhs |= rhs;
804 }
805
807 constexpr friend bit_vector operator^(bit_vector lhs, bit_vector const & rhs) noexcept
808 {
809 return lhs ^= rhs;
810 }
811
813 constexpr bit_vector & and_not(bit_vector const & rhs) noexcept
814 {
815 assert(rhs.size() == size());
816
817 return binary_transform_impl(rhs,
818 [](auto const & left_chunk, auto const & right_chunk)
819 {
820 return left_chunk & ~right_chunk;
821 });
822 }
823
825 constexpr bit_vector & flip() noexcept
826 {
827 std::ranges::for_each(*as_base(),
828 [](chunk_type & chunk)
829 {
830 chunk = ~chunk;
831 });
832 return *this;
833 }
834
836 constexpr bit_vector & flip(size_type position)
837 {
838 using namespace std::literals;
839
840 if (position >= size())
841 throw std::out_of_range{"The given posisiton "s + std::to_string(position) + " is out of the range [0, "s
842 + std::to_string(size()) + ")!"s};
843
844 (*this)[position].flip();
845 return *this;
846 }
847
849 constexpr void swap(bit_vector & other) noexcept
850 {
851 base_t::swap(*other.as_base());
852 std::swap(_size, other._size);
853 }
855
860 constexpr iterator begin() noexcept
861 {
862 return iterator{base_t::data()};
863 }
864
866 constexpr const_iterator begin() const noexcept
867 {
869 }
870
872 constexpr const_iterator cbegin() const noexcept
873 {
874 return begin();
875 }
876
878 constexpr iterator end() noexcept
879 {
880 return begin() + size();
881 }
882
884 constexpr const_iterator end() const noexcept
885 {
886 return begin() + size();
887 }
888
890 constexpr const_iterator cend() const noexcept
891 {
892 return end();
893 }
895
896 [[gnu::always_inline]] inline constexpr chunk_type * data() noexcept
897 {
899 }
900
901 [[gnu::always_inline]] inline constexpr chunk_type const * data() const noexcept
902 {
904 }
905
913 template <cereal_archive archive_t>
914 void CEREAL_LOAD_FUNCTION_NAME(archive_t & archive)
915 {
916 // Not using `cereal::make_size_tag(_size)`, because the size tag is inferred for text (XML/JSON) archives.
917 // For text archives, `cereal::make_size_tag(_size)` would be the number of elements serialised in the for-loop.
918 // E.g., `_size == 100` would store `2` (`== host_size_impl(_size)`).
919 archive(_size);
920 size_t const vector_size = host_size_impl(_size);
921
922 resize_for_overwrite(vector_size);
923
924 if constexpr (cereal_text_archive<archive_t>)
925 {
926 for (auto && v : *as_base())
927 archive(v);
928 }
929 else
930 {
931 archive(cereal::binary_data(data(), vector_size * sizeof(chunk_type)));
932 }
933 }
934
936 template <cereal_archive archive_t>
937 void CEREAL_SAVE_FUNCTION_NAME(archive_t & archive) const
938 {
939 // Not using `cereal::make_size_tag(_size)`, because the size tag is inferred for text (XML/JSON) archives.
940 // For text archives, `cereal::make_size_tag(_size)` would be the number of elements serialised in the for-loop.
941 // E.g., `_size == 100` would store `2` (`== host_size_impl(_size)`).
942 archive(_size);
943
944 if constexpr (cereal_text_archive<archive_t>)
945 {
946 for (auto && v : *as_base())
947 archive(v);
948 }
949 else
950 {
951 archive(cereal::binary_data(data(), base_t::size() * sizeof(chunk_type)));
952 }
953 }
955
956private:
957// If nothing else works: Just use `resize`.
958#ifndef HIBF_UNINITIALISED_RESIZE
959 inline constexpr void resize_for_overwrite(size_t const size)
960 {
962 }
963#else
964// libc++: reinterpret_cast to a struct that has the same layout as std::vector.
965// All internal members are private.
966# if defined(_LIBCPP_VERSION)
967 inline void resize_for_overwrite(size_t const size)
968 {
969 struct fake_vector
970 {
971 using allocator_t = typename base_t::allocator_type;
972 using pointer = typename std::allocator_traits<allocator_t>::pointer;
973
974 pointer begin;
975 pointer end;
976# pragma GCC diagnostic push
977# pragma GCC diagnostic ignored "-Wgnu-anonymous-struct" // Warning since clang-21
978 _LIBCPP_COMPRESSED_PAIR(pointer, end_cap = nullptr, allocator_type, allocator);
979# pragma GCC diagnostic pop
980 };
981
982 static_assert(sizeof(fake_vector) == sizeof(base_t));
983 static_assert(alignof(fake_vector) == alignof(base_t));
984
985 if (size > base_t::capacity())
987// Annotate the new memory as contiguous container for llvm's address sanitizer.
988# if __has_feature(address_sanitizer)
992 base_t::data() + size);
993# endif
994 fake_vector & vec = reinterpret_cast<fake_vector &>(*this);
995 vec.end = vec.begin + size;
996 }
997// libstdc++: The internal members are protected, so we can access them.
998# else
999 inline constexpr void resize_for_overwrite(size_t const size)
1000 {
1001 if (size > base_t::capacity())
1003
1004 this->_M_impl._M_finish = this->_M_impl._M_start + size;
1005 }
1006# endif
1007#endif
1008
1010 template <typename binary_operator_t>
1011 constexpr bit_vector & binary_transform_impl(bit_vector const & rhs, binary_operator_t && op) noexcept
1012 {
1013 chunk_type * const lhs_data = data();
1014 chunk_type const * const rhs_data = rhs.data();
1015 size_type const size = host_size_impl(this->size());
1016
1017 for (size_t i = 0; i < size; ++i)
1018 lhs_data[i] = op(lhs_data[i], rhs_data[i]);
1019
1020 return *this;
1021 }
1022
1025 constexpr size_type host_size_impl(size_type const count) const noexcept
1026 {
1027 return chunks_needed(count);
1028 }
1029
1031 constexpr void set_new_size(size_type const new_size) noexcept
1032 {
1033 _size = new_size;
1034 }
1035
1037 constexpr base_t const * as_base() const noexcept
1038 {
1039 return static_cast<base_t const *>(this);
1040 }
1041
1043 constexpr base_t * as_base() noexcept
1044 {
1045 return static_cast<base_t *>(this);
1046 }
1047
1049 constexpr size_type chunks_needed(size_type const count) const noexcept
1050 {
1051 return (count + 63u) >> 6; // ceil(count/64)
1052 }
1053
1061 constexpr chunk_type last_chunk_mask() const noexcept
1062 {
1063 assert(!empty());
1064
1065 size_type const bits_in_last_chunk = to_local_chunk_position(size());
1066 return bits_in_last_chunk ? (chunk_type{1u} << bits_in_last_chunk) - 1u : ~chunk_type{};
1067 }
1068
1070 constexpr chunk_type fill_chunk(bool const bit) const noexcept
1071 {
1072 return (bit) ? ~chunk_type{} : chunk_type{};
1073 }
1074
1076 static constexpr size_type to_local_chunk_position(size_type const position) noexcept
1077 {
1078 return position & modulo_mask; // e.g. position % 64
1079 }
1080
1082 static constexpr size_type to_chunk_position(size_type const position) noexcept
1083 {
1084 return position >> division_mask; // e.g. position / 64
1085 }
1086};
1087
1088} // namespace seqan::hibf
1089
1091// See https://uscilab.github.io/cereal/serialization_functions.html#inheritance
1092// seqan::hibf::bit_vector's base class is std::vector
1093// If we include <cereal/types/vector.hpp> for std::vector serialisation (e.g., HIBF),
1094// cereal provides these as non-member load/save functions.
1095// Since both load/save non-member functions (std::vector) and load/save member functions (bit_vector) are available,
1096// cereal needs to be told which one to use.
1097namespace cereal
1098{
1099
1100template <typename archive_t>
1101struct specialize<archive_t, seqan::hibf::bit_vector, cereal::specialization::member_load_save>
1102{};
1103
1104} // namespace cereal
T back_inserter(T... args)
T begin(T... args)
T capacity(T... args)
An bit vector.
Definition bit_vector.hpp:66
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:725
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:849
allocator_t allocator_type
The allocator type to use.
Definition bit_vector.hpp:380
constexpr bit_vector operator~() const noexcept
Performs binary NOT.
Definition bit_vector.hpp:781
constexpr bit_vector & flip(size_type position)
Flips the bit at the given position.
Definition bit_vector.hpp:836
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:399
constexpr friend bit_vector operator|(bit_vector lhs, bit_vector const &rhs) noexcept
Performs binary OR.
Definition bit_vector.hpp:801
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:813
constexpr size_type size() const noexcept
Returns the number of elements.
Definition bit_vector.hpp:651
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:424
constexpr size_t count() const noexcept
Returns the number of bits that are set to true.
Definition bit_vector.hpp:630
bit_iterator< false > iterator
The iterator over the bits.
Definition bit_vector.hpp:366
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:878
constexpr friend bit_vector operator^(bit_vector lhs, bit_vector const &rhs) noexcept
Performs binary XOR.
Definition bit_vector.hpp:807
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:890
constexpr iterator begin() noexcept
Returns an iterator to the beginning.
Definition bit_vector.hpp:860
constexpr bit_vector & flip() noexcept
Flips all bits in-place.
Definition bit_vector.hpp:825
constexpr bool any() const noexcept
Checks if any bit is set to true.
Definition bit_vector.hpp:607
constexpr bool none() const noexcept
Checks if none of the bits is set to true.
Definition bit_vector.hpp:624
constexpr friend bit_vector operator&(bit_vector lhs, bit_vector const &rhs) noexcept
Performs binary AND.
Definition bit_vector.hpp:795
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:884
constexpr bit_vector & operator=(bit_vector &&)=default
Default.
bit_iterator< true > const_iterator
The const iterator over the bits.
Definition bit_vector.hpp:368
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:866
constexpr void push_back(bool bit)
Adds an element to the end.
Definition bit_vector.hpp:715
size_t size_type
The size_type.
Definition bit_vector.hpp:376
constexpr bit_vector & operator|=(bit_vector const &rhs) noexcept
Performs binary OR between this and rhs.
Definition bit_vector.hpp:757
constexpr bool empty() const noexcept
Checks wether the container is empty.
Definition bit_vector.hpp:657
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:872
constexpr bit_vector & operator^=(bit_vector const &rhs) noexcept
Performs binary XOR between this and rhs.
Definition bit_vector.hpp:769
constexpr void reserve(size_type const new_capacity)
Reserves storage.
Definition bit_vector.hpp:685
constexpr bit_vector & operator&=(bit_vector const &rhs) noexcept
Performs binary AND between this and rhs.
Definition bit_vector.hpp:745
constexpr void clear() noexcept
Erases all elements. After this call, size() returns zero. capacity() remains unchanged.
Definition bit_vector.hpp:738
constexpr size_type capacity() const noexcept
Returns the capacity.
Definition bit_vector.hpp:663
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: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)