diff --git a/include/sparrow/buffer/dynamic_bitset.hpp b/include/sparrow/buffer/dynamic_bitset.hpp index ea73919a..a92b8538 100644 --- a/include/sparrow/buffer/dynamic_bitset.hpp +++ b/include/sparrow/buffer/dynamic_bitset.hpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include "sparrow/buffer/buffer.hpp" @@ -58,31 +59,41 @@ namespace sparrow using reference = bitset_reference; using const_reference = bool; using size_type = typename storage_type::size_type; + using difference_type = typename storage_type::difference_type; using iterator = bitset_iterator; using const_iterator = bitset_iterator; - size_type size() const noexcept; - size_type null_count() const noexcept; + constexpr size_type size() const noexcept; + [[nodiscard]] constexpr bool empty() const noexcept; + constexpr size_type null_count() const noexcept; - bool test(size_type pos) const; - void set(size_type pos, value_type value); + constexpr bool test(size_type pos) const; + constexpr void set(size_type pos, value_type value); - reference operator[](size_type i); - const_reference operator[](size_type i) const; + constexpr const_reference at(size_type pos) const; + constexpr reference at(size_type pos); - block_type* data() noexcept; - const block_type* data() const noexcept; - size_type block_count() const noexcept; + constexpr reference operator[](size_type i); + constexpr const_reference operator[](size_type i) const; - void swap(self_type&) noexcept; + constexpr block_type* data() noexcept; + constexpr const block_type* data() const noexcept; + constexpr size_type block_count() const noexcept; - iterator begin(); - iterator end(); + constexpr void swap(self_type&) noexcept; - const_iterator begin() const; - const_iterator end() const; - const_iterator cbegin() const; - const_iterator cend() const; + constexpr iterator begin(); + constexpr iterator end(); + + constexpr const_iterator begin() const; + constexpr const_iterator end() const; + constexpr const_iterator cbegin() const; + constexpr const_iterator cend() const; + + constexpr reference front(); + constexpr const_reference front() const; + constexpr reference back(); + constexpr const_reference back() const; const storage_type& buffer() const noexcept { @@ -96,31 +107,45 @@ namespace sparrow protected: - dynamic_bitset_base(storage_type&& buffer, size_type size); - dynamic_bitset_base(storage_type&& buffer, size_type size, size_type null_count); - ~dynamic_bitset_base() = default; + constexpr dynamic_bitset_base(storage_type&& buffer, size_type size); + constexpr dynamic_bitset_base(storage_type&& buffer, size_type size, size_type null_count); + constexpr ~dynamic_bitset_base() = default; + + constexpr dynamic_bitset_base(const dynamic_bitset_base&) = default; + constexpr dynamic_bitset_base(dynamic_bitset_base&&) noexcept = default; + + constexpr dynamic_bitset_base& operator=(const dynamic_bitset_base&) = default; + constexpr dynamic_bitset_base& operator=(dynamic_bitset_base&&) noexcept = default; - dynamic_bitset_base(const dynamic_bitset_base&) = default; - dynamic_bitset_base(dynamic_bitset_base&&) = default; + constexpr void resize(size_type n, value_type b = false); + constexpr void clear() noexcept; - dynamic_bitset_base& operator=(const dynamic_bitset_base&) = default; - dynamic_bitset_base& operator=(dynamic_bitset_base&&) = default; + constexpr iterator insert(const_iterator pos, value_type value); + constexpr iterator insert(const_iterator pos, size_type count, value_type value); + template + constexpr iterator insert(const_iterator pos, InputIt first, InputIt last); + constexpr iterator insert(const_iterator pos, std::initializer_list ilist); + constexpr iterator emplace(const_iterator pos, value_type value); + constexpr iterator erase(const_iterator pos); + constexpr iterator erase(const_iterator first, const_iterator last); - void resize(size_type n, value_type b = false); + constexpr void push_back(value_type value); + constexpr void pop_back(); + + constexpr size_type compute_block_count(size_type bits_count) const noexcept; - size_type compute_block_count(size_type bits_count) const noexcept; private: static constexpr std::size_t s_bits_per_block = sizeof(block_type) * CHAR_BIT; - static size_type block_index(size_type pos) noexcept; - static size_type bit_index(size_type pos) noexcept; - static block_type bit_mask(size_type pos) noexcept; + static constexpr size_type block_index(size_type pos) noexcept; + static constexpr size_type bit_index(size_type pos) noexcept; + static constexpr block_type bit_mask(size_type pos) noexcept; size_type count_non_null() const noexcept; - size_type count_extra_bits() const noexcept; - void zero_unused_bits(); - void update_null_count(bool old_value, bool new_value); + constexpr size_type count_extra_bits() const noexcept; + constexpr void zero_unused_bits(); + constexpr void update_null_count(bool old_value, bool new_value); storage_type m_buffer; size_type m_size; @@ -149,19 +174,25 @@ namespace sparrow using value_type = typename base_type::value_type; using size_type = typename base_type::size_type; - dynamic_bitset(); - explicit dynamic_bitset(size_type n); - dynamic_bitset(size_type n, value_type v); - dynamic_bitset(block_type* p, size_type n); - dynamic_bitset(block_type* p, size_type n, size_type null_count); - - ~dynamic_bitset() = default; - dynamic_bitset(const dynamic_bitset&) = default; - dynamic_bitset(dynamic_bitset&&) = default; - - dynamic_bitset& operator=(const dynamic_bitset&) = default; - dynamic_bitset& operator=(dynamic_bitset&&) = default; - + constexpr dynamic_bitset(); + constexpr explicit dynamic_bitset(size_type n); + constexpr dynamic_bitset(size_type n, value_type v); + constexpr dynamic_bitset(block_type* p, size_type n); + constexpr dynamic_bitset(block_type* p, size_type n, size_type null_count); + + constexpr ~dynamic_bitset() = default; + constexpr dynamic_bitset(const dynamic_bitset&) = default; + constexpr dynamic_bitset(dynamic_bitset&&) noexcept = default; + + constexpr dynamic_bitset& operator=(const dynamic_bitset&) = default; + constexpr dynamic_bitset& operator=(dynamic_bitset&&) noexcept = default; + + using base_type::clear; + using base_type::emplace; + using base_type::erase; + using base_type::insert; + using base_type::pop_back; + using base_type::push_back; using base_type::resize; }; @@ -182,15 +213,15 @@ namespace sparrow using block_type = typename base_type::block_type; using size_type = typename base_type::size_type; - dynamic_bitset_view(block_type* p, size_type n); - dynamic_bitset_view(block_type* p, size_type n, size_type null_count); - ~dynamic_bitset_view() = default; + constexpr dynamic_bitset_view(block_type* p, size_type n); + constexpr dynamic_bitset_view(block_type* p, size_type n, size_type null_count); + constexpr ~dynamic_bitset_view() = default; - dynamic_bitset_view(const dynamic_bitset_view&) = default; - dynamic_bitset_view(dynamic_bitset_view&&) = default; + constexpr dynamic_bitset_view(const dynamic_bitset_view&) = default; + constexpr dynamic_bitset_view(dynamic_bitset_view&&) noexcept = default; - dynamic_bitset_view& operator=(const dynamic_bitset_view&) = default; - dynamic_bitset_view& operator=(dynamic_bitset_view&&) = default; + constexpr dynamic_bitset_view& operator=(const dynamic_bitset_view&) = default; + constexpr dynamic_bitset_view& operator=(dynamic_bitset_view&&) noexcept = default; }; /** @@ -208,20 +239,20 @@ namespace sparrow using self_type = bitset_reference; - bitset_reference(const bitset_reference&) = default; - bitset_reference(bitset_reference&&) = default; + constexpr bitset_reference(const bitset_reference&) noexcept = default; + constexpr bitset_reference(bitset_reference&&) noexcept = default; - self_type& operator=(const self_type&) noexcept; - self_type& operator=(self_type&&) noexcept; - self_type& operator=(bool) noexcept; + constexpr self_type& operator=(const self_type&) noexcept; + constexpr self_type& operator=(self_type&&) noexcept; + constexpr self_type& operator=(bool) noexcept; - operator bool() const noexcept; + constexpr operator bool() const noexcept; - bool operator~() const noexcept; + constexpr bool operator~() const noexcept; - self_type& operator&=(bool) noexcept; - self_type& operator|=(bool) noexcept; - self_type& operator^=(bool) noexcept; + constexpr self_type& operator&=(bool) noexcept; + constexpr self_type& operator|=(bool) noexcept; + constexpr self_type& operator^=(bool) noexcept; private: @@ -230,9 +261,9 @@ namespace sparrow bitset_reference(bitset_type& bitset, block_type& block, block_type mask); - void assign(bool) noexcept; - void set() noexcept; - void reset() noexcept; + constexpr void assign(bool) noexcept; + constexpr void set() noexcept; + constexpr void reset() noexcept; bitset_type& m_bitset; block_type& m_block; @@ -281,21 +312,21 @@ namespace sparrow using bitset_type = mpl::constify_t; using size_type = typename B::size_type; - bitset_iterator() noexcept = default; - bitset_iterator(bitset_type* bitset, block_type* block, size_type index); + constexpr bitset_iterator() noexcept = default; + constexpr bitset_iterator(bitset_type* bitset, block_type* block, size_type index); private: - reference dereference() const; - void increment(); - void decrement(); - void advance(difference_type n); - difference_type distance_to(const self_type& rhs) const; - bool equal(const self_type& rhs) const; - bool less_than(const self_type& rhs) const; + constexpr reference dereference() const noexcept; + constexpr void increment(); + constexpr void decrement(); + constexpr void advance(difference_type n); + constexpr difference_type distance_to(const self_type& rhs) const noexcept; + constexpr bool equal(const self_type& rhs) const noexcept; + constexpr bool less_than(const self_type& rhs) const noexcept; - bool is_first_bit_of_block(size_type index) const; - difference_type distance_to_begin() const; + constexpr bool is_first_bit_of_block(size_type index) const noexcept; + constexpr difference_type distance_to_begin() const; bitset_type* p_bitset = nullptr; block_type* p_block = nullptr; @@ -311,40 +342,45 @@ namespace sparrow **************************************/ template - auto dynamic_bitset_base::size() const noexcept -> size_type + constexpr auto dynamic_bitset_base::size() const noexcept -> size_type { return m_size; } template - auto dynamic_bitset_base::null_count() const noexcept -> size_type + constexpr bool dynamic_bitset_base::empty() const noexcept + { + return m_size == 0; + } + + template + constexpr auto dynamic_bitset_base::null_count() const noexcept -> size_type { return m_null_count; } template - auto dynamic_bitset_base::operator[](size_type pos) -> reference + constexpr auto dynamic_bitset_base::operator[](size_type pos) -> reference { SPARROW_ASSERT_TRUE(pos < size()); return reference(*this, m_buffer.data()[block_index(pos)], bit_mask(pos)); } template - bool dynamic_bitset_base::operator[](size_type pos) const + constexpr bool dynamic_bitset_base::operator[](size_type pos) const { - SPARROW_ASSERT_TRUE(pos < size()); - return !m_null_count || m_buffer.data()[block_index(pos)] & bit_mask(pos); + return test(pos); } template - bool dynamic_bitset_base::test(size_type pos) const + constexpr bool dynamic_bitset_base::test(size_type pos) const { SPARROW_ASSERT_TRUE(pos < size()); return !m_null_count || m_buffer.data()[block_index(pos)] & bit_mask(pos); } template - void dynamic_bitset_base::set(size_type pos, value_type value) + constexpr void dynamic_bitset_base::set(size_type pos, value_type value) { SPARROW_ASSERT_TRUE(pos < size()); block_type& block = m_buffer.data()[block_index(pos)]; @@ -361,25 +397,25 @@ namespace sparrow } template - auto dynamic_bitset_base::data() noexcept -> block_type* + constexpr auto dynamic_bitset_base::data() noexcept -> block_type* { return m_buffer.data(); } template - auto dynamic_bitset_base::data() const noexcept -> const block_type* + constexpr auto dynamic_bitset_base::data() const noexcept -> const block_type* { return m_buffer.data(); } template - auto dynamic_bitset_base::block_count() const noexcept -> size_type + constexpr auto dynamic_bitset_base::block_count() const noexcept -> size_type { return m_buffer.size(); } template - void dynamic_bitset_base::swap(self_type& rhs) noexcept + constexpr void dynamic_bitset_base::swap(self_type& rhs) noexcept { using std::swap; swap(m_buffer, rhs.m_buffer); @@ -388,45 +424,99 @@ namespace sparrow } template - auto dynamic_bitset_base::begin() -> iterator + constexpr auto dynamic_bitset_base::begin() -> iterator { return iterator(this, data(), 0u); } template - auto dynamic_bitset_base::end() -> iterator + constexpr auto dynamic_bitset_base::end() -> iterator { block_type* block = m_buffer.size() ? data() + m_buffer.size() - 1 : data(); return iterator(this, block, size() % s_bits_per_block); } template - auto dynamic_bitset_base::begin() const -> const_iterator + constexpr auto dynamic_bitset_base::begin() const -> const_iterator { return cbegin(); } template - auto dynamic_bitset_base::end() const -> const_iterator + constexpr auto dynamic_bitset_base::end() const -> const_iterator { return cend(); } template - auto dynamic_bitset_base::cbegin() const -> const_iterator + constexpr auto dynamic_bitset_base::cbegin() const -> const_iterator { return const_iterator(this, data(), 0u); } template - auto dynamic_bitset_base::cend() const -> const_iterator + constexpr auto dynamic_bitset_base::cend() const -> const_iterator { const block_type* block = m_buffer.size() ? data() + m_buffer.size() - 1 : data(); return const_iterator(this, block, size() % s_bits_per_block); } template - dynamic_bitset_base::dynamic_bitset_base(storage_type&& buf, size_type size) + constexpr auto dynamic_bitset_base::at(size_type pos) -> reference + { + if (pos >= size()) + { + throw std::out_of_range( + "dynamic_bitset_base::at: index out of range for dynamic_bitset_base of size" + + std::to_string(size()) + " at index " + std::to_string(pos) + ); + } + return (*this)[pos]; + } + + template + constexpr auto dynamic_bitset_base::at(size_type pos) const -> const_reference + { + if (pos >= size()) + { + throw std::out_of_range( + "dynamic_bitset_base::at: index out of range for dynamic_bitset_base of size" + + std::to_string(size()) + " at index " + std::to_string(pos) + ); + } + return test(pos); + } + + template + constexpr auto dynamic_bitset_base::front() -> reference + { + SPARROW_ASSERT_TRUE(size() >= 1); + return (*this)[0]; + } + + template + constexpr auto dynamic_bitset_base::front() const -> const_reference + { + SPARROW_ASSERT_TRUE(size() >= 1); + return (*this)[0]; + } + + template + constexpr auto dynamic_bitset_base::back() -> reference + { + SPARROW_ASSERT_TRUE(size() >= 1); + return (*this)[size() - 1]; + } + + template + constexpr auto dynamic_bitset_base::back() const -> const_reference + { + SPARROW_ASSERT_TRUE(size() >= 1); + return (*this)[size() - 1]; + } + + template + constexpr dynamic_bitset_base::dynamic_bitset_base(storage_type&& buf, size_type size) : m_buffer(std::move(buf)) , m_size(size) , m_null_count(m_size - count_non_null()) @@ -438,7 +528,7 @@ namespace sparrow } template - dynamic_bitset_base::dynamic_bitset_base(storage_type&& buf, size_type size, size_type null_count) + constexpr dynamic_bitset_base::dynamic_bitset_base(storage_type&& buf, size_type size, size_type null_count) : m_buffer(std::move(buf)) , m_size(size) , m_null_count(null_count) @@ -451,25 +541,25 @@ namespace sparrow } template - auto dynamic_bitset_base::compute_block_count(size_type bits_count) const noexcept -> size_type + constexpr auto dynamic_bitset_base::compute_block_count(size_type bits_count) const noexcept -> size_type { return bits_count / s_bits_per_block + static_cast(bits_count % s_bits_per_block != 0); } template - auto dynamic_bitset_base::block_index(size_type pos) noexcept -> size_type + constexpr auto dynamic_bitset_base::block_index(size_type pos) noexcept -> size_type { return pos / s_bits_per_block; } template - auto dynamic_bitset_base::bit_index(size_type pos) noexcept -> size_type + constexpr auto dynamic_bitset_base::bit_index(size_type pos) noexcept -> size_type { return pos % s_bits_per_block; } template - auto dynamic_bitset_base::bit_mask(size_type pos) noexcept -> block_type + constexpr auto dynamic_bitset_base::bit_mask(size_type pos) noexcept -> block_type { const size_type bit = bit_index(pos); return static_cast(block_type(1) << bit); @@ -507,13 +597,13 @@ namespace sparrow } template - auto dynamic_bitset_base::count_extra_bits() const noexcept -> size_type + constexpr auto dynamic_bitset_base::count_extra_bits() const noexcept -> size_type { return bit_index(size()); } template - void dynamic_bitset_base::zero_unused_bits() + constexpr void dynamic_bitset_base::zero_unused_bits() { const size_type extra_bits = count_extra_bits(); if (extra_bits != 0) @@ -523,7 +613,7 @@ namespace sparrow } template - void dynamic_bitset_base::update_null_count(bool old_value, bool new_value) + constexpr void dynamic_bitset_base::update_null_count(bool old_value, bool new_value) { if (new_value && !old_value) { @@ -536,7 +626,7 @@ namespace sparrow } template - void dynamic_bitset_base::resize(size_type n, value_type b) + constexpr void dynamic_bitset_base::resize(size_type n, value_type b) { const size_type old_block_count = m_buffer.size(); const size_type new_block_count = compute_block_count(n); @@ -561,24 +651,158 @@ namespace sparrow zero_unused_bits(); } + template + constexpr void dynamic_bitset_base::clear() noexcept + { + m_buffer.clear(); + m_size = 0; + m_null_count = 0; + } + + template + constexpr dynamic_bitset_base::iterator + dynamic_bitset_base::insert(const_iterator pos, value_type value) + { + return insert(pos, 1, value); + } + + template + constexpr dynamic_bitset_base::iterator + dynamic_bitset_base::insert(const_iterator pos, size_type count, value_type value) + { + SPARROW_ASSERT_TRUE(cbegin() <= pos); + SPARROW_ASSERT_TRUE(pos <= cend()); + const auto index = static_cast(std::distance(cbegin(), pos)); + const size_type old_size = size(); + const size_type new_size = old_size + count; + + // TODO: The current implementation is not efficient. It can be improved. + + resize(new_size); + + for (size_type i = old_size + count - 1; i >= index + count; --i) + { + set(i, test(i - count)); + } + + for (size_type i = 0; i < count; ++i) + { + set(index + i, value); + } + + auto block = data() + block_index(index); + return iterator(this, block, bit_index(index)); + } + + template + template + constexpr dynamic_bitset_base::iterator + dynamic_bitset_base::insert(const_iterator pos, InputIt first, InputIt last) + { + SPARROW_ASSERT_TRUE(cbegin() <= pos); + SPARROW_ASSERT_TRUE(pos <= cend()); + const auto index = static_cast(std::distance(cbegin(), pos)); + const size_type old_size = size(); + const size_type count = static_cast(std::distance(first, last)); + const size_type new_size = old_size + count; + + resize(new_size); + + // TODO: The current implementation is not efficient. It can be improved. + + for (size_type i = old_size + count - 1; i >= index + count; --i) + { + set(i, test(i - count)); + } + + for (size_type i = 0; i < count; ++i) + { + set(index + i, *first++); + } + + auto block = data() + block_index(index); + return iterator(this, block, bit_index(index)); + } + + template + constexpr dynamic_bitset_base::iterator + dynamic_bitset_base::emplace(const_iterator pos, value_type value) + { + return insert(pos, value); + } + + template + constexpr dynamic_bitset_base::iterator dynamic_bitset_base::erase(const_iterator pos) + { + SPARROW_ASSERT_TRUE(cbegin() <= pos); + SPARROW_ASSERT_TRUE(pos < cend()); + + return erase(pos, pos + 1); + } + + template + constexpr dynamic_bitset_base::iterator + dynamic_bitset_base::erase(const_iterator first, const_iterator last) + { + SPARROW_ASSERT_TRUE(cbegin() <= first); + SPARROW_ASSERT_TRUE(first <= last); + SPARROW_ASSERT_TRUE(last <= cend()); + + const auto first_index = static_cast(std::distance(cbegin(), first)); + + if (last == cend()) + { + resize(first_index); + return end(); + } + + // TODO: The current implementation is not efficient. It can be improved. + + const auto last_index = static_cast(std::distance(cbegin(), last)); + const size_type count = last_index - first_index; + + const size_type bit_to_move = size() - last_index; + for (size_type i = 0; i < bit_to_move; ++i) + { + set(first_index + i, test(last_index + i)); + } + + resize(size() - count); + + auto block = data() + block_index(first_index); + return iterator(this, block, bit_index(first_index)); + } + + template + constexpr void dynamic_bitset_base::push_back(value_type value) + { + resize(size() + 1, value); + } + + template + constexpr void dynamic_bitset_base::pop_back() + { + resize(size() - 1); + } + /********************************* * dynamic_bitset implementation * *********************************/ template - dynamic_bitset::dynamic_bitset() + constexpr dynamic_bitset::dynamic_bitset() : base_type(storage_type(), 0u) { } template - dynamic_bitset::dynamic_bitset(size_type n) + constexpr dynamic_bitset::dynamic_bitset(size_type n) : dynamic_bitset(n, false) { } template - dynamic_bitset::dynamic_bitset(size_type n, value_type value) + constexpr dynamic_bitset::dynamic_bitset(size_type n, value_type value) : base_type( storage_type(this->compute_block_count(n), value ? block_type(~block_type(0)) : block_type(0)), n, @@ -588,13 +812,13 @@ namespace sparrow } template - dynamic_bitset::dynamic_bitset(block_type* p, size_type n) + constexpr dynamic_bitset::dynamic_bitset(block_type* p, size_type n) : base_type(storage_type(p, this->compute_block_count(n)), n) { } template - dynamic_bitset::dynamic_bitset(block_type* p, size_type n, size_type null_count) + constexpr dynamic_bitset::dynamic_bitset(block_type* p, size_type n, size_type null_count) : base_type(storage_type(p, this->compute_block_count(n)), n, null_count) { } @@ -604,56 +828,56 @@ namespace sparrow *************************************/ template - dynamic_bitset_view::dynamic_bitset_view(block_type* p, size_type n) + constexpr dynamic_bitset_view::dynamic_bitset_view(block_type* p, size_type n) : base_type(storage_type(p, this->compute_block_count(n)), n) { } template - dynamic_bitset_view::dynamic_bitset_view(block_type* p, size_type n, size_type null_count) + constexpr dynamic_bitset_view::dynamic_bitset_view(block_type* p, size_type n, size_type null_count) : base_type(storage_type(p, this->compute_block_count(n)), n, null_count) { } - + /*********************************** * bitset_reference implementation * ***********************************/ template - auto bitset_reference::operator=(const self_type& rhs) noexcept -> self_type& + constexpr auto bitset_reference::operator=(const self_type& rhs) noexcept -> self_type& { assign(rhs); return *this; } template - auto bitset_reference::operator=(self_type&& rhs) noexcept -> self_type& + constexpr auto bitset_reference::operator=(self_type&& rhs) noexcept -> self_type& { assign(rhs); return *this; } template - auto bitset_reference::operator=(bool rhs) noexcept -> self_type& + constexpr auto bitset_reference::operator=(bool rhs) noexcept -> self_type& { assign(rhs); return *this; } template - bitset_reference::operator bool() const noexcept + constexpr bitset_reference::operator bool() const noexcept { return (m_block & m_mask) != 0; } template - bool bitset_reference::operator~() const noexcept + constexpr bool bitset_reference::operator~() const noexcept { return (m_block & m_mask) == 0; } template - auto bitset_reference::operator&=(bool rhs) noexcept -> self_type& + constexpr auto bitset_reference::operator&=(bool rhs) noexcept -> self_type& { if (!rhs) { @@ -663,7 +887,7 @@ namespace sparrow } template - auto bitset_reference::operator|=(bool rhs) noexcept -> self_type& + constexpr auto bitset_reference::operator|=(bool rhs) noexcept -> self_type& { if (rhs) { @@ -673,7 +897,7 @@ namespace sparrow } template - auto bitset_reference::operator^=(bool rhs) noexcept -> self_type& + constexpr auto bitset_reference::operator^=(bool rhs) noexcept -> self_type& { if (rhs) { @@ -693,13 +917,13 @@ namespace sparrow } template - void bitset_reference::assign(bool rhs) noexcept + constexpr void bitset_reference::assign(bool rhs) noexcept { rhs ? set() : reset(); } template - void bitset_reference::set() noexcept + constexpr void bitset_reference::set() noexcept { bool old_value = m_block & m_mask; m_block |= m_mask; @@ -707,7 +931,7 @@ namespace sparrow } template - void bitset_reference::reset() noexcept + constexpr void bitset_reference::reset() noexcept { bool old_value = m_block & m_mask; m_block &= ~m_mask; @@ -731,7 +955,7 @@ namespace sparrow **********************************/ template - bitset_iterator::bitset_iterator(bitset_type* bitset, block_type* block, size_type index) + constexpr bitset_iterator::bitset_iterator(bitset_type* bitset, block_type* block, size_type index) : p_bitset(bitset) , p_block(block) , m_index(index) @@ -740,7 +964,7 @@ namespace sparrow } template - auto bitset_iterator::dereference() const -> reference + constexpr auto bitset_iterator::dereference() const noexcept -> reference { if constexpr (is_const) { @@ -753,7 +977,7 @@ namespace sparrow } template - void bitset_iterator::increment() + constexpr void bitset_iterator::increment() { ++m_index; // If we have reached next block @@ -766,7 +990,7 @@ namespace sparrow } template - void bitset_iterator::decrement() + constexpr void bitset_iterator::decrement() { // decreasing moves to previous block if (is_first_bit_of_block(m_index)) @@ -782,7 +1006,7 @@ namespace sparrow } template - void bitset_iterator::advance(difference_type n) + constexpr void bitset_iterator::advance(difference_type n) { if (n >= 0) { @@ -828,7 +1052,8 @@ namespace sparrow } template - auto bitset_iterator::distance_to(const self_type& rhs) const -> difference_type + constexpr auto + bitset_iterator::distance_to(const self_type& rhs) const noexcept -> difference_type { if (p_block == rhs.p_block) { @@ -843,25 +1068,25 @@ namespace sparrow } template - bool bitset_iterator::equal(const self_type& rhs) const + constexpr bool bitset_iterator::equal(const self_type& rhs) const noexcept { return p_block == rhs.p_block && m_index == rhs.m_index; } template - bool bitset_iterator::less_than(const self_type& rhs) const + constexpr bool bitset_iterator::less_than(const self_type& rhs) const noexcept { return (p_block < rhs.p_block) || (p_block == rhs.p_block && m_index < rhs.m_index); } template - bool bitset_iterator::is_first_bit_of_block(size_type index) const + constexpr bool bitset_iterator::is_first_bit_of_block(size_type index) const noexcept { return index % bitset_type::s_bits_per_block == 0; } template - auto bitset_iterator::distance_to_begin() const -> difference_type + constexpr auto bitset_iterator::distance_to_begin() const -> difference_type { const difference_type distance = p_block - p_bitset->begin().p_block; SPARROW_ASSERT_TRUE(distance >= 0); diff --git a/test/test_dynamic_bitset.cpp b/test/test_dynamic_bitset.cpp index f0b29f06..bce48a3e 100644 --- a/test/test_dynamic_bitset.cpp +++ b/test/test_dynamic_bitset.cpp @@ -57,8 +57,8 @@ namespace sparrow buffer_type p_buffer; buffer_type p_expected_buffer; - std::size_t m_block_count = 4; - std::size_t m_size = 29; + static constexpr std::size_t m_block_count = 4; + static constexpr std::size_t m_size = 29; std::size_t m_null_count; }; @@ -284,6 +284,243 @@ namespace sparrow CHECK_EQ(citer_end, b.cend()); }; + TEST_CASE_FIXTURE(bitmap_fixture, "insert") + { + SUBCASE("const_iterator and value_type") + { + SUBCASE("begin") + { + bitmap b(release_buffer(), m_size); + const auto pos = b.cbegin(); + auto iter = b.insert(pos, false); + CHECK_EQ(b.size(), m_size + 1); + CHECK_EQ(b.null_count(), m_null_count + 1); + CHECK_EQ(*iter, false); + + iter = b.insert(pos, true); + CHECK_EQ(b.size(), m_size + 2); + CHECK_EQ(b.null_count(), m_null_count + 1); + CHECK_EQ(*iter, true); + } + + SUBCASE("middle") + { + bitmap b(release_buffer(), m_size); + const auto pos = std::next(b.cbegin(), 14); + auto iter = b.insert(pos, false); + CHECK_EQ(b.size(), m_size + 1); + CHECK_EQ(b.null_count(), m_null_count + 1); + CHECK_EQ(*iter, false); + + iter = b.insert(pos, true); + CHECK_EQ(b.size(), m_size + 2); + CHECK_EQ(b.null_count(), m_null_count + 1); + CHECK_EQ(*iter, true); + } + + SUBCASE("end") + { + bitmap b(release_buffer(), m_size); + const auto pos = b.cend(); + auto iter = b.insert(pos, false); + CHECK_EQ(b.size(), m_size + 1); + CHECK_EQ(b.null_count(), m_null_count + 1); + CHECK_EQ(*iter, false); + + iter = b.insert(pos, true); + CHECK_EQ(b.size(), m_size + 2); + CHECK_EQ(b.null_count(), m_null_count + 1); + CHECK_EQ(*iter, true); + } + } + + SUBCASE("const_iterator and count/value_type") + { + SUBCASE("begin") + { + bitmap b(release_buffer(), m_size); + const auto pos = b.cbegin(); + auto iter = b.insert(pos, 3, false); + CHECK_EQ(b.size(), m_size + 3); + CHECK_EQ(b.null_count(), m_null_count + 3); + CHECK_EQ(*iter, false); + CHECK_EQ(*(++iter), false); + CHECK_EQ(*(++iter), false); + + iter = b.insert(pos, 3, true); + CHECK_EQ(b.size(), m_size + 6); + CHECK_EQ(b.null_count(), m_null_count + 3); + CHECK_EQ(*iter, true); + CHECK_EQ(*(++iter), true); + CHECK_EQ(*(++iter), true); + } + + SUBCASE("middle") + { + bitmap b(release_buffer(), m_size); + const auto pos = std::next(b.cbegin(), 14); + auto iter = b.insert(pos, 3, false); + CHECK_EQ(b.size(), m_size + 3); + CHECK_EQ(b.null_count(), m_null_count + 3); + CHECK_EQ(*iter, false); + CHECK_EQ(*(++iter), false); + CHECK_EQ(*(++iter), false); + + iter = b.insert(pos, 3, true); + CHECK_EQ(b.size(), m_size + 6); + CHECK_EQ(b.null_count(), m_null_count + 3); + CHECK_EQ(*iter, true); + CHECK_EQ(*(++iter), true); + CHECK_EQ(*(++iter), true); + } + + SUBCASE("end") + { + bitmap b(release_buffer(), m_size); + ; + auto iter = b.insert(b.cend(), 3, false); + CHECK_EQ(b.size(), m_size + 3); + CHECK_EQ(b.null_count(), m_null_count + 3); + CHECK_EQ(*iter, false); + CHECK_EQ(*(++iter), false); + CHECK_EQ(*(++iter), false); + + iter = b.insert(b.cend(), 3, true); + CHECK_EQ(b.size(), m_size + 6); + CHECK_EQ(b.null_count(), m_null_count + 3); + CHECK_EQ(*iter, true); + CHECK_EQ(*(++iter), true); + CHECK_EQ(*(++iter), true); + } + } + } + + TEST_CASE("emplace") + { + SUBCASE("begin") + { + bitmap b(3, false); + auto iter = b.emplace(b.cbegin(), true); + CHECK_EQ(b.size(), 4); + CHECK_EQ(b.null_count(), 3); + CHECK_EQ(*iter, true); + } + + SUBCASE("middle") + { + bitmap b(3, false); + auto iter = b.emplace(std::next(b.cbegin()), true); + CHECK_EQ(b.size(), 4); + CHECK_EQ(b.null_count(), 3); + CHECK_EQ(*iter, true); + } + + SUBCASE("end") + { + bitmap b(3, false); + auto iter = b.emplace(b.cend(), true); + CHECK_EQ(b.size(), 4); + CHECK_EQ(b.null_count(), 3); + CHECK_EQ(*iter, true); + } + } + + TEST_CASE("erase") + { + SUBCASE("const_iterator") + { + SUBCASE("begin") + { + bitmap b(5, false); + auto iter = b.erase(b.cbegin()); + CHECK_EQ(b.size(), 4); + CHECK_EQ(b.null_count(), 4); + CHECK_EQ(iter, b.begin()); + CHECK_EQ(*iter, false); + } + + SUBCASE("middle") + { + bitmap b(5, false); + const auto pos = std::next(b.cbegin(), 2); + auto iter = b.erase(pos); + CHECK_EQ(b.size(), 4); + CHECK_EQ(b.null_count(), 4); + CHECK_EQ(iter, std::next(b.begin(), 2)); + CHECK_EQ(*iter, false); + } + } + + SUBCASE("const_iterator range") + { + SUBCASE("begin") + { + bitmap b(3, false); + auto iter = b.erase(b.cbegin(), std::next(b.cbegin())); + CHECK_EQ(b.size(), 2); + CHECK_EQ(b.null_count(), 2); + CHECK_EQ(*iter, false); + } + + SUBCASE("middle") + { + bitmap b(3, false); + const auto pos = std::next(b.cbegin()); + auto iter = b.erase(pos, std::next(pos, 1)); + CHECK_EQ(b.size(), 2); + CHECK_EQ(b.null_count(), 2); + CHECK_EQ(*iter, false); + } + + SUBCASE("all") + { + bitmap b(3, false); + auto iter = b.erase(b.cbegin(), b.cend()); + CHECK_EQ(b.size(), 0); + CHECK_EQ(b.null_count(), 0); + CHECK_EQ(iter, b.end()); + } + } + } + + TEST_CASE("at") + { + bitmap b(3, true); + CHECK_EQ(b.at(0), true); + CHECK_EQ(b.at(1), true); + CHECK_EQ(b.at(2), true); + CHECK_THROWS_AS(b.at(3), std::out_of_range); + } + + TEST_CASE("front") + { + bitmap b(3, true); + CHECK_EQ(b.front(), true); + } + + TEST_CASE("back") + { + bitmap b(3, true); + CHECK_EQ(b.back(), true); + } + + TEST_CASE("push_back") + { + bitmap b(3, true); + b.push_back(false); + CHECK_EQ(b.size(), 4); + CHECK_EQ(b.null_count(), 1); + CHECK_EQ(b.back(), false); + } + + TEST_CASE("pop_back") + { + bitmap b(3, false); + b.pop_back(); + CHECK_EQ(b.size(), 2); + CHECK_EQ(b.null_count(), 2); + } + TEST_CASE_FIXTURE(bitmap_fixture, "bitset_reference") { // as a reminder: p_buffer[0] = 38; // 00100110 @@ -315,7 +552,7 @@ namespace sparrow } } - TEST_SUITE("dyamic_bitset_view") + TEST_SUITE("dynamic_bitset_view") { using bitmap_view = dynamic_bitset_view;