HIBF 1.0.0-rc.1
All Classes Namespaces Files Functions Variables Typedefs Friends Macros Modules Pages Concepts
bit_vector.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2006-2025, Knut Reinert & Freie Universität Berlin
2// SPDX-FileCopyrightText: 2016-2025, 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 <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_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 *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:
402 {}
408
416 bit_vector(size_type const count, bool const bit, allocator_type const & alloc = allocator_type{}) : base_t{alloc}
417 {
418 assign(count, bit);
419 }
420
427 allocator_type const & alloc = allocator_type{}) :
428 base_t{alloc}
429 {
430 assign(list);
431 }
432
439 bit_vector{count, bool{}, alloc}
440 {}
442
471 template <std::input_iterator iterator_t, std::sentinel_for<iterator_t> sentinel_t>
473 constexpr void assign(iterator_t first, sentinel_t last)
474 {
475 bit_vector tmp{}; // To ensure strong exception guarantee.
477 tmp.reserve(std::ranges::distance(first, last));
478
479 std::ranges::copy(first, last, std::back_inserter(tmp));
480
481 // ----- no exception after this.
482 swap(tmp);
483 set_new_size(std::ranges::distance(begin(), end()));
484 }
485
505 constexpr void assign(std::initializer_list<bool> const & ilist)
506 {
507 assign(std::ranges::begin(ilist), std::ranges::end(ilist));
508 }
509
530 HIBF_CONSTEXPR_VECTOR void assign(size_type const count, bool const bit)
531 {
532 resize(count, bit);
533 std::ranges::for_each(*as_base(),
534 [value = fill_chunk(bit)](chunk_type & chunk)
535 {
536 chunk = value;
537 });
538 }
540
546 {
547 assert(position < size());
548
549 return *std::ranges::next(begin(), position);
550 }
551
554 {
555 assert(position < size());
556
557 return *std::ranges::next(begin(), position);
558 }
559
577 {
578 assert(!empty()); // Calling on empty container is undefined behaviour.
579
580 return (*this)[size() - 1u];
581 }
582
585 {
586 assert(!empty()); // Calling on empty container is undefined behaviour.
587
588 return (*this)[size() - 1u];
589 }
590
592 constexpr bool all() const noexcept
593 {
594 constexpr chunk_type mask = ~static_cast<chunk_type>(0);
595 return std::ranges::all_of(*as_base(),
596 [](chunk_type const & chunk)
597 {
598 return chunk == mask;
599 });
600 }
601
603 constexpr bool any() const noexcept
604 {
605 constexpr chunk_type mask = static_cast<chunk_type>(0);
606 return std::ranges::any_of(*as_base(),
607 [](chunk_type const & chunk)
608 {
609 return chunk | mask;
610 });
611 }
612
614 constexpr bool none() const noexcept
615 {
616 return !any();
617 }
619
624 constexpr size_type size() const noexcept
625 {
626 return _size;
627 }
628
630 constexpr bool empty() const noexcept
631 {
632 return _size == 0u;
633 }
634
637 {
638 return base_t::capacity() * chunk_size;
639 }
640
658 HIBF_CONSTEXPR_VECTOR void reserve(size_type const new_capacity)
659 {
660 base_t::reserve(host_size_impl(new_capacity));
661 }
663
689 {
690 size_t const new_size = size() + 1u;
691 resize(new_size);
692 // ---- no exception after this point.
693 set_new_size(new_size);
694 back() = bit; // set the bit.
695 }
696
698 HIBF_CONSTEXPR_VECTOR void resize(size_type const count, bool const bit = {})
699 {
700 base_t::resize(host_size_impl(count));
701
702 size_t const old_size = size();
703 set_new_size(count);
704
705 // If bit is true and we increase the size.
706 if (bit && size() > old_size)
707 std::ranges::fill(begin() + old_size, end(), bit);
708 }
709
712 {
714 _size = 0u;
715 }
716
718 constexpr bit_vector & operator&=(bit_vector const & rhs) noexcept
719 {
720 assert(rhs.size() == size());
721
722 return binary_transform_impl(rhs,
723 [](auto const & left_chunk, auto const & right_chunk)
724 {
725 return left_chunk & right_chunk;
726 });
727 }
728
730 constexpr bit_vector & operator|=(bit_vector const & rhs) noexcept
731 {
732 assert(rhs.size() == size());
733
734 return binary_transform_impl(rhs,
735 [](auto const & left_chunk, auto const & right_chunk)
736 {
737 return left_chunk | right_chunk;
738 });
739 }
740
742 constexpr bit_vector & operator^=(bit_vector const & rhs) noexcept
743 {
744 assert(rhs.size() == size());
745
746 return binary_transform_impl(rhs,
747 [](auto const & left_chunk, auto const & right_chunk)
748 {
749 return left_chunk ^ right_chunk;
750 });
751 }
752
755 {
756 bit_vector tmp(size());
757
758 tmp.binary_transform_impl(*this,
759 [](auto const &, auto const & right_chunk)
760 {
761 return ~right_chunk;
762 });
763
764 return tmp;
765 }
766
769 {
770 return lhs &= rhs;
771 }
772
775 {
776 return lhs |= rhs;
777 }
778
781 {
782 return lhs ^= rhs;
783 }
784
786 constexpr bit_vector & and_not(bit_vector const & rhs) noexcept
787 {
788 assert(rhs.size() == size());
789
790 return binary_transform_impl(rhs,
791 [](auto const & left_chunk, auto const & right_chunk)
792 {
793 return left_chunk & ~right_chunk;
794 });
795 }
796
798 constexpr bit_vector & flip() noexcept
799 {
800 std::ranges::for_each(*as_base(),
801 [](chunk_type & chunk)
802 {
803 chunk = ~chunk;
804 });
805 return *this;
806 }
807
810 {
811 using namespace std::literals;
812
813 if (position >= size())
814 throw std::out_of_range{"The given posisiton "s + std::to_string(position) + " is out of the range [0, "s
815 + std::to_string(size()) + ")!"s};
816
817 (*this)[position].flip();
818 return *this;
819 }
820
822 HIBF_CONSTEXPR_VECTOR void swap(bit_vector & other) noexcept
823 {
824 base_t::swap(*other.as_base());
825 std::swap(_size, other._size);
826 }
828
834 {
835 return iterator{base_t::data()};
836 }
837
840 {
842 }
843
846 {
847 return begin();
848 }
849
852 {
853 return begin() + size();
854 }
855
858 {
859 return begin() + size();
860 }
861
864 {
865 return end();
866 }
868
869 [[gnu::always_inline]] inline HIBF_CONSTEXPR_VECTOR chunk_type * data() noexcept
870 {
872 }
873
874 [[gnu::always_inline]] inline HIBF_CONSTEXPR_VECTOR chunk_type const * data() const noexcept
875 {
877 }
878
886 template <cereal_archive archive_t>
887 void CEREAL_LOAD_FUNCTION_NAME(archive_t & archive)
888 {
889 // Not using `cereal::make_size_tag(_size)`, because the size tag is inferred for text (XML/JSON) archives.
890 // For text archives, `cereal::make_size_tag(_size)` would be the number of elements serialised in the for-loop.
891 // E.g., `_size == 100` would store `2` (`== host_size_impl(_size)`).
892 archive(_size);
893 size_t const vector_size = host_size_impl(_size);
894
895 resize_for_overwrite(vector_size);
896
897 if constexpr (cereal_text_archive<archive_t>)
898 {
899 for (auto && v : *as_base())
900 archive(v);
901 }
902 else
903 {
904 archive(cereal::binary_data(data(), vector_size * sizeof(chunk_type)));
905 }
906 }
907
909 template <cereal_archive archive_t>
910 void CEREAL_SAVE_FUNCTION_NAME(archive_t & archive) const
911 {
912 // Not using `cereal::make_size_tag(_size)`, because the size tag is inferred for text (XML/JSON) archives.
913 // For text archives, `cereal::make_size_tag(_size)` would be the number of elements serialised in the for-loop.
914 // E.g., `_size == 100` would store `2` (`== host_size_impl(_size)`).
915 archive(_size);
916
917 if constexpr (cereal_text_archive<archive_t>)
918 {
919 for (auto && v : *as_base())
920 archive(v);
921 }
922 else
923 {
924 archive(cereal::binary_data(data(), base_t::size() * sizeof(chunk_type)));
925 }
926 }
928
929private:
930// If nothing else works: Just use `resize`.
931#ifndef HIBF_UNINITIALISED_RESIZE
932 HIBF_CONSTEXPR_VECTOR inline void resize_for_overwrite(size_t const size)
933 {
935 }
936#else
937// libc++: reinterpret_cast to a struct that has the same layout as std::vector.
938// All internal members are private.
939# if defined(_LIBCPP_VERSION)
940 inline void resize_for_overwrite(size_t const size)
941 {
942 struct fake_vector
943 {
944 using allocator_t = typename base_t::allocator_type;
945 using pointer = typename std::allocator_traits<allocator_t>::pointer;
946
947 pointer begin;
948 pointer end;
950 };
951
952 static_assert(sizeof(fake_vector) == sizeof(base_t));
953 static_assert(alignof(fake_vector) == alignof(base_t));
954
955 if (size > base_t::capacity())
957
958// Annotate the new memory as contiguous container for llvm's address sanitizer.
959# ifndef _LIBCPP_HAS_NO_ASAN
960 __sanitizer_annotate_contiguous_container(base_t::data(),
963 base_t::data() + size);
964# endif
965
966 fake_vector & vec = reinterpret_cast<fake_vector &>(*this);
967 vec.end = vec.begin + size;
968 }
969// libstdc++: The internal members are protected, so we can access them.
970# else
971 HIBF_CONSTEXPR_VECTOR inline void resize_for_overwrite(size_t const size)
972 {
973 if (size > base_t::capacity())
975
976 this->_M_impl._M_finish = this->_M_impl._M_start + size;
977 }
978# endif
979#endif
980
982 template <typename binary_operator_t>
983 constexpr bit_vector & binary_transform_impl(bit_vector const & rhs, binary_operator_t && op) noexcept
984 {
985 chunk_type * const lhs_data = data();
986 chunk_type const * const rhs_data = rhs.data();
987 size_type const size = host_size_impl(this->size());
988
989 for (size_t i = 0; i < size; ++i)
990 lhs_data[i] = op(lhs_data[i], rhs_data[i]);
991
992 return *this;
993 }
994
997 constexpr size_type host_size_impl(size_type const count) const noexcept
998 {
999 return chunks_needed(count);
1000 }
1001
1003 constexpr void set_new_size(size_type const new_size) noexcept
1004 {
1005 _size = new_size;
1006 }
1007
1009 constexpr base_t const * as_base() const noexcept
1010 {
1011 return static_cast<base_t const *>(this);
1012 }
1013
1015 constexpr base_t * as_base() noexcept
1016 {
1017 return static_cast<base_t *>(this);
1018 }
1019
1021 constexpr size_type chunks_needed(size_type const count) const noexcept
1022 {
1023 return (count + 63u) >> 6; // ceil(count/64)
1024 }
1025
1027 constexpr chunk_type fill_chunk(bool const bit) const noexcept
1028 {
1029 return (bit) ? ~chunk_type{} : chunk_type{};
1030 }
1031
1033 static constexpr size_type to_local_chunk_position(size_type const position) noexcept
1034 {
1035 return position & modulo_mask; // e.g. position % 64
1036 }
1037
1039 static constexpr size_type to_chunk_position(size_type const position) noexcept
1040 {
1041 return position >> division_mask; // e.g. position / 64
1042 }
1043};
1044
1045} // namespace seqan::hibf
1046
1048// See https://uscilab.github.io/cereal/serialization_functions.html#inheritance
1049// seqan::hibf::bit_vector's base class is std::vector
1050// If we include <cereal/types/vector.hpp> for std::vector serialisation (e.g., HIBF),
1051// cereal provides these as non-member load/save functions.
1052// Since both load/save non-member functions (std::vector) and load/save member functions (bit_vector) are available,
1053// cereal needs to be told which one to use.
1054namespace cereal
1055{
1056
1057template <typename archive_t>
1058struct specialize<archive_t, seqan::hibf::bit_vector, cereal::specialization::member_load_save>
1059{};
1060
1061} // 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:698
constexpr reference back() noexcept
Access the last element.
Definition bit_vector.hpp:576
constexpr void swap(bit_vector &other) noexcept
Exchanges the contents of the container with those of others.
Definition bit_vector.hpp:822
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:754
constexpr bit_vector & flip(size_type position)
Flips the bit at the given position.
Definition bit_vector.hpp:809
constexpr reference operator[](size_type const position) noexcept
Access specified element.
Definition bit_vector.hpp:545
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:774
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:416
constexpr bit_vector & and_not(bit_vector const &rhs) noexcept
Computes the bitwise a &= ~b operator without an additional copy.
Definition bit_vector.hpp:786
constexpr size_type size() const noexcept
Returns the number of elements.
Definition bit_vector.hpp:624
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
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:584
constexpr iterator end() noexcept
Returns an iterator to the end.
Definition bit_vector.hpp:851
constexpr friend bit_vector operator^(bit_vector lhs, bit_vector const &rhs) noexcept
Performs binary XOR.
Definition bit_vector.hpp:780
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:863
constexpr iterator begin() noexcept
Returns an iterator to the beginning.
Definition bit_vector.hpp:833
constexpr bit_vector & flip() noexcept
Flips all bits in-place.
Definition bit_vector.hpp:798
constexpr bool any() const noexcept
Checks if any bit is set to true.
Definition bit_vector.hpp:603
constexpr bool none() const noexcept
Checks if none of the bits is set to true.
Definition bit_vector.hpp:614
constexpr friend bit_vector operator&(bit_vector lhs, bit_vector const &rhs) noexcept
Performs binary AND.
Definition bit_vector.hpp:768
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:438
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:857
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:530
constexpr void assign(std::initializer_list< bool > const &ilist)
Assigns values to the container.
Definition bit_vector.hpp:505
constexpr bool all() const noexcept
Checks if all bits are set to true.
Definition bit_vector.hpp:592
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:839
constexpr void push_back(bool bit)
Adds an element to the end.
Definition bit_vector.hpp:688
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:730
constexpr bool empty() const noexcept
Checks wether the container is empty.
Definition bit_vector.hpp:630
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:473
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:845
constexpr bit_vector & operator^=(bit_vector const &rhs) noexcept
Performs binary XOR between this and rhs.
Definition bit_vector.hpp:742
constexpr void reserve(size_type const new_capacity)
Reserves storage.
Definition bit_vector.hpp:658
constexpr bit_vector & operator&=(bit_vector const &rhs) noexcept
Performs binary AND between this and rhs.
Definition bit_vector.hpp:718
constexpr void clear() noexcept
Erases all elements. After this call, size() returns zero. capacity() remains unchanged.
Definition bit_vector.hpp:711
constexpr size_type capacity() const noexcept
Returns the capacity.
Definition bit_vector.hpp:636
constexpr const_reference operator[](size_type const position) const noexcept
Access specified element.
Definition bit_vector.hpp:553
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.
#define HIBF_CONSTEXPR_VECTOR
std::vector constexpr support.
Definition platform.hpp:120
T reserve(T... args)
T resize(T... args)
T size(T... args)
T swap(T... args)
T to_string(T... args)