From b5b3a31754e943e53bcb3dc52abea7f47171404f Mon Sep 17 00:00:00 2001 From: Peter McLean Date: Wed, 6 Aug 2025 13:00:10 -0400 Subject: [PATCH 01/22] Explicitly cast inside _mask --- include/bitlib/bit-iterator/bit_details.hpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/include/bitlib/bit-iterator/bit_details.hpp b/include/bitlib/bit-iterator/bit_details.hpp index dda2b30..172b18f 100644 --- a/include/bitlib/bit-iterator/bit_details.hpp +++ b/include/bitlib/bit-iterator/bit_details.hpp @@ -299,18 +299,19 @@ enum class _mask_len { template constexpr T _mask(const size_type len) { - constexpr std::make_unsigned_t one = std::make_unsigned_t(1); + using unsigned_t = std::make_unsigned_t; + constexpr unsigned_t one = unsigned_t(1); if constexpr (len_in_range != _mask_len::unknown) { #ifdef BITLIB_DETECT_UNDEFINED_SHIFT assert(len < bitsof()); #endif - return static_cast((one << len) - one); + return static_cast((one << static_cast(len)) - one); } else { // The digits_mask is solely here to prevent Undefined Sanitizer // complaining about shift of len >= digits // Note: on -O1 the (len & digits_mask) is optimized to simply (len) - constexpr std::make_unsigned_t digits_mask = bitsof() - one; - return static_cast((one << (len & digits_mask)) * (len < bitsof()) - one); + constexpr unsigned_t digits_mask = static_cast(bitsof()) - one; + return static_cast((one << (static_cast(len) & digits_mask)) * static_cast(len < bitsof()) - one); } } From a4bc8a0288455b2c95a2ebf10926ef653f12966e Mon Sep 17 00:00:00 2001 From: Peter McLean Date: Wed, 6 Aug 2025 13:08:37 -0400 Subject: [PATCH 02/22] Name clang format workflow job --- .github/workflows/clang_format.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/clang_format.yaml b/.github/workflows/clang_format.yaml index 59c0c12..babe06b 100644 --- a/.github/workflows/clang_format.yaml +++ b/.github/workflows/clang_format.yaml @@ -14,6 +14,7 @@ on: jobs: clang-format: + name: Clang Format Check runs-on: ubuntu-latest steps: From 888a94d81b4300a4a63e9379e0111a8849a19904 Mon Sep 17 00:00:00 2001 From: Peter McLean Date: Thu, 7 Aug 2025 21:51:45 -0400 Subject: [PATCH 03/22] Default is detail::uninitialized. Fix from_string --- .../bitlib/bit-algorithms/to_from_string.hpp | 6 +- include/bitlib/bit-containers/bit_policy.hpp | 40 +++++++++++-- include/bitlib/bit-iterator/bit_details.hpp | 5 ++ test/src/test-to_from_string.cpp | 58 +++++++++++++++++++ 4 files changed, 102 insertions(+), 7 deletions(-) diff --git a/include/bitlib/bit-algorithms/to_from_string.hpp b/include/bitlib/bit-algorithms/to_from_string.hpp index d3f04d7..4bdfdcf 100644 --- a/include/bitlib/bit-algorithms/to_from_string.hpp +++ b/include/bitlib/bit-algorithms/to_from_string.hpp @@ -318,11 +318,13 @@ constexpr void from_string( } else if ((store_bits > bits) && (cursor < 0)) { const bit_iterator p_integral(&work); bit_it = ::bit::copy(p_integral, p_integral + bits, bit_it); - Policy::extension::template from_integral( - work, bit_it, bit_last); + // TODO: policy + ::bit::fill(bit_it, bit_last, meta.is_signed ? bit_it[-1] : bit0); // Clear the rest + return; } else if (store_bits >= bits) { const bit_iterator p_integral(&work); bit_it = ::bit::copy(p_integral, p_integral + bits, bit_it); + store_bits -= bits; } } } else { diff --git a/include/bitlib/bit-containers/bit_policy.hpp b/include/bitlib/bit-containers/bit_policy.hpp index 306d175..0a4d31f 100644 --- a/include/bitlib/bit-containers/bit_policy.hpp +++ b/include/bitlib/bit-containers/bit_policy.hpp @@ -64,6 +64,7 @@ struct truncate { struct sign_extend { template constexpr static void to_integral( + detail::initialized_t, const bit_iterator& first, const bit_iterator& last, U& integral) noexcept { @@ -84,7 +85,8 @@ struct sign_extend { } template - constexpr static void to_integral(const bit_sized_range auto& value, U& integral) noexcept { + constexpr static void to_integral( + detail::initialized_t, const bit_sized_range auto& value, U& integral) noexcept { bit_pointer integral_begin(&integral); if constexpr (N == std::dynamic_extent) { if constexpr (std::is_signed_v) { @@ -139,8 +141,22 @@ struct sign_extend { } } + template + constexpr static void to_integral(const bit_sized_range auto& value, U& integral) noexcept { + return to_integral(detail::uninitialized, value, integral); + } + + template + constexpr static void to_integral( + const bit_iterator& first, + const bit_iterator& last, + U& integral) noexcept { + return to_integral(detail::uninitialized, first, last, integral); + } + template constexpr static void from_integral( + detail::initialized_t, const U& integral, const bit_iterator& first, const bit_iterator& last) noexcept { @@ -158,10 +174,6 @@ struct sign_extend { } } } - template - constexpr static void from_integral(const U& integral, bit_sized_range auto& value) noexcept { - from_integral(integral, value.begin(), value.end()); - } template constexpr static void from_integral( @@ -176,6 +188,14 @@ struct sign_extend { } } + template + constexpr static void from_integral( + const U& integral, + const bit_iterator& first, + const bit_iterator& last) noexcept { + from_integral(detail::uninitialized, integral, first, last); + } + template constexpr static void from_integral( detail::uninitialized_t, @@ -183,6 +203,16 @@ struct sign_extend { bit_sized_range auto& value) noexcept { from_integral(detail::uninitialized, integral, value.begin(), value.end()); } + + template + constexpr static void from_integral(detail::initialized_t, const U& integral, bit_sized_range auto& value) noexcept { + from_integral(detail::initialized, integral, value.begin(), value.end()); + } + + template + constexpr static void from_integral(const U& integral, bit_sized_range auto& value) noexcept { + from_integral(detail::uninitialized, integral, value.begin(), value.end()); + } }; } // namespace bit::policy diff --git a/include/bitlib/bit-iterator/bit_details.hpp b/include/bitlib/bit-iterator/bit_details.hpp index 172b18f..316b6fa 100644 --- a/include/bitlib/bit-iterator/bit_details.hpp +++ b/include/bitlib/bit-iterator/bit_details.hpp @@ -888,6 +888,11 @@ struct uninitialized_t { }; inline constexpr uninitialized_t uninitialized{}; +struct initialized_t { + explicit initialized_t() = default; +}; +inline constexpr initialized_t initialized{}; + template struct container_size_storage { constexpr size_type size() const noexcept { diff --git a/test/src/test-to_from_string.cpp b/test/src/test-to_from_string.cpp index 839e925..b76ff38 100644 --- a/test/src/test-to_from_string.cpp +++ b/test/src/test-to_from_string.cpp @@ -50,4 +50,62 @@ TEST(FromString, Blah) { EXPECT_EQ(arr_18, 0x12'0BEEF_b); bit::from_string("123", arr_16); EXPECT_EQ(arr_16, 16'123_b); +} + +TEST(FromString, IntoBookendRange) { + for (const auto word : get_random_vec(64)) { + for (int i = 1; i < 8; i++) { + auto bits = bit::bit_array<32>(word); + auto bits2 = bits; + bit::from_string( + "123ABC", bits(i, i + 4 * 6)); + bits2(i, i + 4 * 6) = 0x18'123ABC_b; + EXPECT_EQ(bits, bits2); + } + for (int i = 1; i < 8; i++) { + auto bits = bit::bit_array<32>(word); + auto bits2 = bits; + bit::from_string( + "F0000F", bits(i, i + 4 * 6)); + bits2(i, i + 4 * 6) = 0x18'F0000F_b; + EXPECT_EQ(bits, bits2); + } + } +} + +TEST(FromString, IntoBookendRangeOverflow) { + for (int i = 1; i < 8; i++) { + auto bits = 0x20'DEADBEEF_b; + auto bits2 = bits; + bit::from_string( + "F123ABC", bits(i, i + 4 * 6)); + bits2(i, i + 4 * 6) = 0x18'123ABC_b; + EXPECT_EQ(bits, bits2); + } + for (int i = 1; i < 8; i++) { + auto bits = 0x20'00000000_b; + auto bits2 = bits; + bit::from_string( + "F123ABC", bits(i, i + 4 * 6)); + bits2(i, i + 4 * 6) = 0x18'123ABC_b; + EXPECT_EQ(bits, bits2); + } +} + +TEST(FromString, IntoBookendRangeLarge) { + for (int i = 0; i < 128; i++) { + for (auto b : {bit::bit0, bit::bit1}) { + auto bits = bit::bit_array<>(200 + i, b); + auto bits2 = bits; + auto setbits = bit::bit_array<>(200 + i, b ? bit::bit0 : bit::bit1); + auto str = bit::to_string(setbits); + for (int j = 64 / 4; j < 128 / 4; j++) { + for (int k = 0; k < 64; k++) { + bit::from_string(str.substr(str.length() - 1 - j, j), bits(k, k + j * 4)); + bits2(k, k + j * 4) = setbits(0, j * 4); + EXPECT_EQ(bits, bits2); + } + } + } + } } \ No newline at end of file From 14ecb62b1a903653add588aeeaaa1c05d6d71db4 Mon Sep 17 00:00:00 2001 From: Peter McLean Date: Thu, 7 Aug 2025 22:17:41 -0400 Subject: [PATCH 04/22] Manually promote short or char types --- include/bitlib/bit-iterator/bit_details.hpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/include/bitlib/bit-iterator/bit_details.hpp b/include/bitlib/bit-iterator/bit_details.hpp index 316b6fa..f9ae1a3 100644 --- a/include/bitlib/bit-iterator/bit_details.hpp +++ b/include/bitlib/bit-iterator/bit_details.hpp @@ -250,7 +250,7 @@ Logical shift right template constexpr T lsr(const T val, const size_type shift) { #ifdef BITLIB_DETECT_UNDEFINED_SHIFT - assert(shift < bitsof()); + assert(static_cast(shift) < bitsof()); #endif return static_cast(static_cast>(val) >> shift); } @@ -439,12 +439,14 @@ constexpr exact_floor_integral_t _bitblend( const exact_floor_integral_t len) noexcept requires(std::is_same_v, exact_floor_integral_t>) { + using resolved_t = exact_floor_integral_t; + using promoted_t = std::conditional_t() < bitsof(), int, resolved_t>; static_assert(binary_digits>::value, ""); - constexpr exact_floor_integral_t digits = bitsof>(); - const exact_floor_integral_t src0 = static_cast>(src0_); - const exact_floor_integral_t src1 = static_cast>(src1_); - const exact_floor_integral_t msk = _mask, _mask_len::unknown>(len) << start; - return src0 ^ ((src0 ^ src1) & msk * (start < digits)); + constexpr resolved_t digits = static_cast(bitsof()); + const promoted_t src0 = static_cast(src0_); + const promoted_t src1 = static_cast(src1_); + const promoted_t msk = _mask(len) << static_cast(start); + return static_cast(src0 ^ ((src0 ^ src1) & (msk * (start < digits)))); } // -------------------------------------------------------------------------- // From 2390f64127915df6bfd0deb960bcefa1cf78173b Mon Sep 17 00:00:00 2001 From: Peter McLean Date: Thu, 7 Aug 2025 22:23:54 -0400 Subject: [PATCH 05/22] Remove some other pedantic conversion warnings --- include/bitlib/bit-iterator/bit_details.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/bitlib/bit-iterator/bit_details.hpp b/include/bitlib/bit-iterator/bit_details.hpp index f9ae1a3..c280e17 100644 --- a/include/bitlib/bit-iterator/bit_details.hpp +++ b/include/bitlib/bit-iterator/bit_details.hpp @@ -263,7 +263,7 @@ constexpr exact_floor_integral_t lsr(const T val, const size_type shift) { static_assert(!std::is_same_v, void>, "Type T must be convertible to an integral type"); #ifdef BITLIB_DETECT_UNDEFINED_SHIFT - assert(shift < bitsof>()); + assert(static_cast(shift) < bitsof>()); #endif return static_cast>(static_cast>>(val) >> shift); } @@ -274,7 +274,7 @@ Logical shift left template constexpr T lsl(const T val, const size_type shift) { #ifdef BITLIB_DETECT_UNDEFINED_SHIFT - assert(shift < bitsof()); + assert(static_cast(shift) < bitsof()); #endif return static_cast(static_cast>(val) << shift); } @@ -287,7 +287,7 @@ constexpr exact_floor_integral_t lsl(const T val, const size_type shift) { static_assert(!std::is_same_v, void>, "Type T must be convertible to an integral type"); #ifdef BITLIB_DETECT_UNDEFINED_SHIFT - assert(shift < bitsof>()); + assert(static_cast(shift) < bitsof>()); #endif return static_cast>(static_cast>>(val) << shift); } @@ -303,7 +303,7 @@ constexpr T _mask(const size_type len) { constexpr unsigned_t one = unsigned_t(1); if constexpr (len_in_range != _mask_len::unknown) { #ifdef BITLIB_DETECT_UNDEFINED_SHIFT - assert(len < bitsof()); + assert(static_cast(len) < bitsof()); #endif return static_cast((one << static_cast(len)) - one); } else { From bfbb1ee0d6f5ffb622db4562808ab15b26bab584 Mon Sep 17 00:00:00 2001 From: Peter McLean Date: Thu, 7 Aug 2025 22:46:20 -0400 Subject: [PATCH 06/22] Simplify the types into bitblend --- include/bitlib/bit-iterator/bit_details.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/bitlib/bit-iterator/bit_details.hpp b/include/bitlib/bit-iterator/bit_details.hpp index c280e17..9dfb6cd 100644 --- a/include/bitlib/bit-iterator/bit_details.hpp +++ b/include/bitlib/bit-iterator/bit_details.hpp @@ -435,17 +435,17 @@ template constexpr exact_floor_integral_t _bitblend( const T src0_, const U src1_, - const exact_floor_integral_t start, - const exact_floor_integral_t len) noexcept + const unsigned int start, + const unsigned int len) noexcept requires(std::is_same_v, exact_floor_integral_t>) { using resolved_t = exact_floor_integral_t; using promoted_t = std::conditional_t() < bitsof(), int, resolved_t>; static_assert(binary_digits>::value, ""); - constexpr resolved_t digits = static_cast(bitsof()); + constexpr unsigned int digits = static_cast(bitsof()); const promoted_t src0 = static_cast(src0_); const promoted_t src1 = static_cast(src1_); - const promoted_t msk = _mask(len) << static_cast(start); + const promoted_t msk = _mask(len) << start; return static_cast(src0 ^ ((src0 ^ src1) & (msk * (start < digits)))); } // -------------------------------------------------------------------------- // From e2ea9d579e3680ec66b65c676b4bf0d349b03504 Mon Sep 17 00:00:00 2001 From: Peter McLean Date: Thu, 7 Aug 2025 22:48:50 -0400 Subject: [PATCH 07/22] Remove unnecessary casts in bitblend calls --- include/bitlib/bit-algorithms/copy.hpp | 4 ++-- include/bitlib/bit-algorithms/shift.hpp | 4 ++-- include/bitlib/bit-algorithms/transform.hpp | 4 ++-- include/bitlib/bit-algorithms/transform_accumulate.hpp | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/bitlib/bit-algorithms/copy.hpp b/include/bitlib/bit-algorithms/copy.hpp index adc55f5..2cfe823 100644 --- a/include/bitlib/bit-algorithms/copy.hpp +++ b/include/bitlib/bit-algorithms/copy.hpp @@ -89,8 +89,8 @@ struct copy_impl { static_cast( get_word(first, partial_bits_to_copy) << static_cast(d_first.position())), - static_cast(d_first.position()), - static_cast(partial_bits_to_copy)); + d_first.position(), + partial_bits_to_copy); remaining_bits_to_copy -= partial_bits_to_copy; advance(first, partial_bits_to_copy); it++; diff --git a/include/bitlib/bit-algorithms/shift.hpp b/include/bitlib/bit-algorithms/shift.hpp index ab36dd9..1ed7093 100644 --- a/include/bitlib/bit-algorithms/shift.hpp +++ b/include/bitlib/bit-algorithms/shift.hpp @@ -246,8 +246,8 @@ bit_iterator shift_right( static_cast( (*first.base() & (static_cast(-1) << first.position())) << n), - static_cast(first.position()), - static_cast((is_last_aligned ? digits : last.position()) - first.position())); + first.position(), + ((is_last_aligned ? digits : last.position()) - first.position())); return first + n; } diff --git a/include/bitlib/bit-algorithms/transform.hpp b/include/bitlib/bit-algorithms/transform.hpp index e343ffc..12a857c 100644 --- a/include/bitlib/bit-algorithms/transform.hpp +++ b/include/bitlib/bit-algorithms/transform.hpp @@ -191,8 +191,8 @@ constexpr bit_iterator transform( static_cast( get_masked_word(first2, partial_bits_to_op) << static_cast(d_first.position()))), - static_cast(d_first.position()), - static_cast(partial_bits_to_op)); + d_first.position(), + partial_bits_to_op); remaining_bits_to_op -= partial_bits_to_op; advance(first1, partial_bits_to_op); advance(first2, partial_bits_to_op); diff --git a/include/bitlib/bit-algorithms/transform_accumulate.hpp b/include/bitlib/bit-algorithms/transform_accumulate.hpp index 80b7ef3..32bebe7 100644 --- a/include/bitlib/bit-algorithms/transform_accumulate.hpp +++ b/include/bitlib/bit-algorithms/transform_accumulate.hpp @@ -58,8 +58,8 @@ constexpr auto transform_accumulate( *d_it = _bitblend( *d_it, word, - static_cast(d_first.position()), - static_cast(partial_bits_to_op)); + d_first.position(), + partial_bits_to_op); total_bits_to_op -= partial_bits_to_op; advance(first, partial_bits_to_op); advance(d_it, 1); @@ -77,8 +77,8 @@ constexpr auto transform_accumulate( *d_it = _bitblend( *d_it, word, - static_cast(d_first.position()), - static_cast(partial_bits_to_op)); + d_first.position(), + partial_bits_to_op); total_bits_to_op -= partial_bits_to_op; } } From 795bf174be853e356bf342c891e27850aaaf638a Mon Sep 17 00:00:00 2001 From: Peter McLean Date: Fri, 8 Aug 2025 07:58:43 -0400 Subject: [PATCH 08/22] Improve correctness when using unsigned size_type --- CMakePresets.json | 64 +++++++++++++++++++ include/bitlib/bit-algorithms/accumulate.hpp | 12 ++-- .../bit-algorithms/bit_algorithm_details.hpp | 40 ++++++------ .../bitlib/bit-algorithms/copy_backward.hpp | 54 ++++++++-------- include/bitlib/bit-algorithms/count.hpp | 7 +- .../bit-algorithms/transform_accumulate.hpp | 10 +-- include/bitlib/bit-iterator/bit_details.hpp | 6 +- include/bitlib/bit-iterator/bit_iterator.hpp | 5 +- include/bitlib/bit-iterator/bit_reference.hpp | 2 +- 9 files changed, 135 insertions(+), 65 deletions(-) diff --git a/CMakePresets.json b/CMakePresets.json index ec4a866..6e61349 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -628,6 +628,36 @@ "lhs": "${hostSystemName}", "rhs": "Linux" } + }, + { + "name": "warnings_linux_gcc_libstdcxx", + "configurePreset": "warnings_linux_gcc_libstdcxx", + "execution": { + "jobs": 1 + }, + "output": { + "verbosity": "verbose" + }, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Linux" + } + }, + { + "name": "warnings_linux_clang_libcxx", + "configurePreset": "warnings_linux_clang_libcxx", + "execution": { + "jobs": 1 + }, + "output": { + "verbosity": "verbose" + }, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Linux" + } } ], "workflowPresets": [ @@ -800,6 +830,40 @@ "name": "benchmark_linux_clang_libcxx" } ] + }, + { + "name": "warnings_linux_gcc_libstdcxx", + "steps": [ + { + "type": "configure", + "name": "warnings_linux_gcc_libstdcxx" + }, + { + "type": "build", + "name": "warnings_linux_gcc_libstdcxx" + }, + { + "type": "test", + "name": "warnings_linux_gcc_libstdcxx" + } + ] + }, + { + "name": "warnings_linux_clang_libcxx", + "steps": [ + { + "type": "configure", + "name": "warnings_linux_clang_libcxx" + }, + { + "type": "build", + "name": "warnings_linux_clang_libcxx" + }, + { + "type": "test", + "name": "warnings_linux_clang_libcxx" + } + ] } ] } diff --git a/include/bitlib/bit-algorithms/accumulate.hpp b/include/bitlib/bit-algorithms/accumulate.hpp index 62b77ad..e70c76d 100644 --- a/include/bitlib/bit-algorithms/accumulate.hpp +++ b/include/bitlib/bit-algorithms/accumulate.hpp @@ -48,7 +48,7 @@ constexpr auto accumulate( } else { sub_digits = std::min(last.position(), total_bits_to_op); if (sub_digits != 0) { - advance(last, -sub_digits); + reverse(last, sub_digits); acc = binary_op_subword(std::move(acc), get_masked_word(last, sub_digits), sub_digits); } } @@ -63,7 +63,7 @@ constexpr auto accumulate( acc = binary_op(std::move(acc), get_word(first)); advance(first, digits); } else { - advance(last, -digits); + reverse(last, digits); acc = binary_op(std::move(acc), get_word(last)); } } @@ -71,7 +71,7 @@ constexpr auto accumulate( if constexpr (forward) { acc = binary_op_subword(std::move(acc), get_masked_word(first, remaining_bits_to_op), remaining_bits_to_op); } else { - advance(last, -remaining_bits_to_op); + reverse(last, remaining_bits_to_op); acc = binary_op_subword(std::move(acc), get_masked_word(last, remaining_bits_to_op), remaining_bits_to_op); } } @@ -106,7 +106,7 @@ constexpr auto accumulate_while( } else { sub_digits = std::min(last.position(), total_bits_to_op); if (sub_digits != 0) { - advance(last, -sub_digits); + reverse(last, sub_digits); std::tie(keep_going, acc) = binary_op_subword(std::move(acc), get_masked_word(first, sub_digits), sub_digits); } } @@ -125,7 +125,7 @@ constexpr auto accumulate_while( std::tie(keep_going, acc) = binary_op(std::move(acc), get_word(first)); advance(first, digits); } else { - advance(last, -digits); + reverse(last, digits); std::tie(keep_going, acc) = binary_op(std::move(acc), get_word(last)); } if (!keep_going) { @@ -136,7 +136,7 @@ constexpr auto accumulate_while( if constexpr (forward) { std::tie(std::ignore, acc) = binary_op_subword(std::move(acc), get_masked_word(first, remaining_bits_to_op), remaining_bits_to_op); } else { - advance(last, -remaining_bits_to_op); + reverse(last, remaining_bits_to_op); std::tie(std::ignore, acc) = binary_op_subword(std::move(acc), get_masked_word(last, remaining_bits_to_op), remaining_bits_to_op); } } diff --git a/include/bitlib/bit-algorithms/bit_algorithm_details.hpp b/include/bitlib/bit-algorithms/bit_algorithm_details.hpp index f23abea..4945310 100644 --- a/include/bitlib/bit-algorithms/bit_algorithm_details.hpp +++ b/include/bitlib/bit-algorithms/bit_algorithm_details.hpp @@ -29,31 +29,33 @@ namespace bit { // May be negative if last comes before first (Only when input is RAI) template typename bit_iterator::difference_type - distance(bit_iterator first, - bit_iterator last -) -{ - _assert_range_viability(first, last); - using word_type = typename bit_iterator::word_type; - using size_type = typename bit_iterator::size_type; - constexpr size_type digits = binary_digits::value; - return std::distance(first.base(), last.base())*digits - + (last.position() - first.position()); +distance(bit_iterator first, + bit_iterator last) { + _assert_range_viability(first, last); + using word_type = typename bit_iterator::word_type; + using difference_type = typename bit_iterator::difference_type; + constexpr difference_type digits = binary_digits::value; + return std::distance(first.base(), last.base()) * digits + + static_cast(last.position()) - + static_cast(first.position()); } // Increments the iterator n times. (If n is negative, the iterator is decremented n times) -template -void advance(bit_iterator& first, Distance n) -{ - first += n; +template +void advance(bit_iterator& first, typename bit_iterator::difference_type n) { + first += n; } -template +template +void reverse(InputIt& it, const T& n) { + ::std::advance(it, -static_cast>(n)); +} + +template bit_iterator next( - bit_iterator bit_it, - typename bit_iterator::difference_type n = 1 -) { - return bit_it + n; + bit_iterator bit_it, + typename bit_iterator::difference_type n = 1) { + return bit_it + n; } // -------------------------------------------------------------------------- // diff --git a/include/bitlib/bit-algorithms/copy_backward.hpp b/include/bitlib/bit-algorithms/copy_backward.hpp index 6c255a0..04b617b 100644 --- a/include/bitlib/bit-algorithms/copy_backward.hpp +++ b/include/bitlib/bit-algorithms/copy_backward.hpp @@ -61,38 +61,38 @@ constexpr bit_iterator copy_backward(bit_iterator(last - partial_bits_to_copy, partial_bits_to_copy) << (d_last.position() - partial_bits_to_copy)), d_last.position() - partial_bits_to_copy, - static_cast(partial_bits_to_copy)); + partial_bits_to_copy); remaining_bits_to_copy -= partial_bits_to_copy; - advance(last, -partial_bits_to_copy); + reverse(last, partial_bits_to_copy); } if (remaining_bits_to_copy > 0) { - const bool is_last_aligned = last.position() == 0; - //size_type words_to_copy = ::std::ceil(remaining_bits_to_copy / static_cast(digits)); - // d_last will be aligned at this point - if (is_last_aligned && remaining_bits_to_copy >= digits) { - auto N = ::std::distance(first.base(), last.base()) - 1; - it = ::std::copy_backward(first.base() + 1, last.base(), it); - last -= digits * N; - remaining_bits_to_copy -= digits * N; - } else { - // TODO benchmark if its faster to ::std::copy the entire range then shift - while (remaining_bits_to_copy >= digits) { - *(--it) = get_word(last - digits, digits); - remaining_bits_to_copy -= digits; - advance(last, -digits); - } - } - if (remaining_bits_to_copy > 0) { - it--; - *it = _bitblend( - *it, - static_cast(get_word(last - remaining_bits_to_copy, remaining_bits_to_copy) - << (digits - remaining_bits_to_copy)), - digits - remaining_bits_to_copy, - remaining_bits_to_copy); - remaining_bits_to_copy = 0; + const bool is_last_aligned = last.position() == 0; + //size_type words_to_copy = ::std::ceil(remaining_bits_to_copy / static_cast(digits)); + // d_last will be aligned at this point + if (is_last_aligned && remaining_bits_to_copy >= digits) { + auto N = ::std::distance(first.base(), last.base()) - 1; + it = ::std::copy_backward(first.base() + 1, last.base(), it); + last -= digits * N; + remaining_bits_to_copy -= digits * N; + } else { + // TODO benchmark if its faster to ::std::copy the entire range then shift + while (remaining_bits_to_copy >= digits) { + *(--it) = get_word(last - digits, digits); + remaining_bits_to_copy -= digits; + reverse(last, digits); } + } + if (remaining_bits_to_copy > 0) { + it--; + *it = _bitblend( + *it, + static_cast(get_word(last - remaining_bits_to_copy, remaining_bits_to_copy) + << (digits - remaining_bits_to_copy)), + digits - remaining_bits_to_copy, + remaining_bits_to_copy); + remaining_bits_to_copy = 0; + } } return d_last - total_bits_to_copy; } diff --git a/include/bitlib/bit-algorithms/count.hpp b/include/bitlib/bit-algorithms/count.hpp index 4bcc5b4..6b60a86 100644 --- a/include/bitlib/bit-algorithms/count.hpp +++ b/include/bitlib/bit-algorithms/count.hpp @@ -104,10 +104,13 @@ count( word_type last_value = *last.base() << (digits - last.position()); result += std::popcount(static_cast>(last_value)); } - // Computation when bits belong to the same underlying word + // Computation when bits belong to the same underlying word } else { result = std::popcount(static_cast>( - _bextr(*first.base(), first.position(), last.position() - first.position()))); + _bextr( + *first.base(), + first.position(), + last.position() - first.position()))); } // Negates when the number of zero bits is requested diff --git a/include/bitlib/bit-algorithms/transform_accumulate.hpp b/include/bitlib/bit-algorithms/transform_accumulate.hpp index 32bebe7..445fb36 100644 --- a/include/bitlib/bit-algorithms/transform_accumulate.hpp +++ b/include/bitlib/bit-algorithms/transform_accumulate.hpp @@ -71,7 +71,7 @@ constexpr auto transform_accumulate( total_bits_to_op, d_last.position()); if (partial_bits_to_op != 0) { - advance(last, -partial_bits_to_op); + reverse(last, partial_bits_to_op); word_type word; std::tie(word, acc) = binary_op_subword(std::move(acc), get_masked_word(last, partial_bits_to_op), partial_bits_to_op); *d_it = _bitblend( @@ -96,8 +96,8 @@ constexpr auto transform_accumulate( advance(first, digits); std::advance(d_it, 1); } else { - advance(last, -digits); - std::advance(d_it, -1); + reverse(last, digits); + reverse(d_it, 1); word_type word; std::tie(word, acc) = binary_op(std::move(acc), get_word(last)); *d_it = word; @@ -114,8 +114,8 @@ constexpr auto transform_accumulate( remaining_bits_to_op); } else { - advance(last, -remaining_bits_to_op); - std::advance(d_it, -1); + reverse(last, remaining_bits_to_op); + reverse(d_it, 1); word_type word; std::tie(word, acc) = binary_op_subword(std::move(acc), get_masked_word(last, remaining_bits_to_op), remaining_bits_to_op); *d_it = _bitblend( diff --git a/include/bitlib/bit-iterator/bit_details.hpp b/include/bitlib/bit-iterator/bit_details.hpp index 9dfb6cd..9c12304 100644 --- a/include/bitlib/bit-iterator/bit_details.hpp +++ b/include/bitlib/bit-iterator/bit_details.hpp @@ -435,14 +435,14 @@ template constexpr exact_floor_integral_t _bitblend( const T src0_, const U src1_, - const unsigned int start, - const unsigned int len) noexcept + const size_t start, + const size_t len) noexcept requires(std::is_same_v, exact_floor_integral_t>) { using resolved_t = exact_floor_integral_t; using promoted_t = std::conditional_t() < bitsof(), int, resolved_t>; static_assert(binary_digits>::value, ""); - constexpr unsigned int digits = static_cast(bitsof()); + constexpr size_t digits = bitsof(); const promoted_t src0 = static_cast(src0_); const promoted_t src1 = static_cast(src1_); const promoted_t msk = _mask(len) << start; diff --git a/include/bitlib/bit-iterator/bit_iterator.hpp b/include/bitlib/bit-iterator/bit_iterator.hpp index 859bbff..e9f340e 100644 --- a/include/bitlib/bit-iterator/bit_iterator.hpp +++ b/include/bitlib/bit-iterator/bit_iterator.hpp @@ -315,7 +315,8 @@ template constexpr bit_iterator::difference_type bit_iterator::operator-(const bit_iterator& other) const { constexpr difference_type digits = binary_digits::value; - return (_current - other._current) * digits + (_position - other._position); + return (_current - other._current) * digits + + (static_cast(_position) - static_cast(other._position)); } // -------------------- BIT ITERATOR: UNDERLYING DETAILS -------------------- // @@ -359,7 +360,7 @@ operator-(const bit_iterator& lhs, const bit_iterator& rhs) { constexpr difference_type digits = rhs_digits; static_assert(lhs_digits == rhs_digits, ""); const difference_type main = lhs._current - rhs._current; - return main * digits + (lhs._position - rhs._position); + return main * digits + (static_cast(lhs._position) - static_cast(rhs._position)); } static_assert(bit_iterator_c>, "bit_iterator does not satisfy bit_iterator_c concept!"); diff --git a/include/bitlib/bit-iterator/bit_reference.hpp b/include/bitlib/bit-iterator/bit_reference.hpp index 6884432..ae95dd0 100644 --- a/include/bitlib/bit-iterator/bit_reference.hpp +++ b/include/bitlib/bit-iterator/bit_reference.hpp @@ -46,7 +46,7 @@ class bit_reference { // Types public: using word_type = WordType; - using size_type = std::size_t; + using size_type = unsigned int; using mask_type = std::make_unsigned_t; // Lifecycle From 75d3e149c7f47edc34e2bc0996f557f59af90470 Mon Sep 17 00:00:00 2001 From: Peter McLean Date: Fri, 8 Aug 2025 08:10:17 -0400 Subject: [PATCH 09/22] clang format --- include/bitlib/bit-algorithms/bit_algorithm_details.hpp | 4 ---- include/bitlib/bit-algorithms/copy_backward.hpp | 2 -- include/bitlib/bit-algorithms/count.hpp | 4 ++-- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/include/bitlib/bit-algorithms/bit_algorithm_details.hpp b/include/bitlib/bit-algorithms/bit_algorithm_details.hpp index 4945310..c6e566b 100644 --- a/include/bitlib/bit-algorithms/bit_algorithm_details.hpp +++ b/include/bitlib/bit-algorithms/bit_algorithm_details.hpp @@ -22,8 +22,6 @@ namespace bit { // ========================================================================== // - - // -------------------------- Iterator Algorithms --------------------------- // // Returns the number of increments needed to get to last from first. // May be negative if last comes before first (Only when input is RAI) @@ -60,8 +58,6 @@ bit_iterator next( // -------------------------------------------------------------------------- // - - // --------------------------- Utility Functions ---------------------------- // // Returns distance(first, last) <= n diff --git a/include/bitlib/bit-algorithms/copy_backward.hpp b/include/bitlib/bit-algorithms/copy_backward.hpp index 04b617b..5f4e023 100644 --- a/include/bitlib/bit-algorithms/copy_backward.hpp +++ b/include/bitlib/bit-algorithms/copy_backward.hpp @@ -97,8 +97,6 @@ constexpr bit_iterator copy_backward(bit_iterator>(last_value)); + word_type last_value = *last.base() << (digits - last.position()); + result += std::popcount(static_cast>(last_value)); } // Computation when bits belong to the same underlying word } else { From 441aad9a166d8a3f39457adb253849101d2dedf3 Mon Sep 17 00:00:00 2001 From: Peter McLean Date: Fri, 8 Aug 2025 08:16:55 -0400 Subject: [PATCH 10/22] size_type back to size_t --- include/bitlib/bit-iterator/bit_reference.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/bitlib/bit-iterator/bit_reference.hpp b/include/bitlib/bit-iterator/bit_reference.hpp index ae95dd0..6884432 100644 --- a/include/bitlib/bit-iterator/bit_reference.hpp +++ b/include/bitlib/bit-iterator/bit_reference.hpp @@ -46,7 +46,7 @@ class bit_reference { // Types public: using word_type = WordType; - using size_type = unsigned int; + using size_type = std::size_t; using mask_type = std::make_unsigned_t; // Lifecycle From d08a426b44ec4c22dfee9f5c2063cbd4aa1ddf60 Mon Sep 17 00:00:00 2001 From: Peter McLean Date: Fri, 8 Aug 2025 08:32:41 -0400 Subject: [PATCH 11/22] clang format --- .../bitlib/bit-algorithms/bit_algorithm_details.hpp | 2 +- include/bitlib/bit-algorithms/copy_backward.hpp | 2 +- include/bitlib/bit-algorithms/count.hpp | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/bitlib/bit-algorithms/bit_algorithm_details.hpp b/include/bitlib/bit-algorithms/bit_algorithm_details.hpp index c6e566b..18e3ad4 100644 --- a/include/bitlib/bit-algorithms/bit_algorithm_details.hpp +++ b/include/bitlib/bit-algorithms/bit_algorithm_details.hpp @@ -420,6 +420,6 @@ typename bit_iterator::word_type _padded_read(bit_iterator first, // ========================================================================== // -} // namespace bit +} // namespace bit #endif // _BIT_ALGORITHM_DETAILS_HPP_INCLUDED // ========================================================================== // diff --git a/include/bitlib/bit-algorithms/copy_backward.hpp b/include/bitlib/bit-algorithms/copy_backward.hpp index 5f4e023..885f8cd 100644 --- a/include/bitlib/bit-algorithms/copy_backward.hpp +++ b/include/bitlib/bit-algorithms/copy_backward.hpp @@ -98,7 +98,7 @@ constexpr bit_iterator copy_backward(bit_iterator>(last_value)); - } - // Computation when bits belong to the same underlying word + if (last.position() != 0) { + word_type last_value = *last.base() << (digits - last.position()); + result += std::popcount(static_cast>(last_value)); + } + // Computation when bits belong to the same underlying word } else { result = std::popcount(static_cast>( _bextr( From e5718e6ebd451ff01455e7c6a3805f0c92756606 Mon Sep 17 00:00:00 2001 From: Peter McLean Date: Fri, 8 Aug 2025 08:39:54 -0400 Subject: [PATCH 12/22] More conversion warning reduction --- .../bit-algorithms/bit_algorithm_details.hpp | 38 ++++++++----------- .../bitlib/bit-algorithms/copy_backward.hpp | 2 +- include/bitlib/bit-containers/bit_vector.hpp | 2 +- include/bitlib/bit-iterator/bit_details.hpp | 12 +++--- 4 files changed, 23 insertions(+), 31 deletions(-) diff --git a/include/bitlib/bit-algorithms/bit_algorithm_details.hpp b/include/bitlib/bit-algorithms/bit_algorithm_details.hpp index 18e3ad4..103641d 100644 --- a/include/bitlib/bit-algorithms/bit_algorithm_details.hpp +++ b/include/bitlib/bit-algorithms/bit_algorithm_details.hpp @@ -104,10 +104,10 @@ constexpr bool is_within( template T get_word(const bit_iterator& first, size_t len = binary_digits::value) { using native_word_type = typename bit_iterator::word_type; - constexpr T digits = binary_digits::value; + constexpr size_t digits = binary_digits::value; assert(digits >= len); using non_const_T = std::remove_cvref_t; - non_const_T offset = digits - first.position(); + size_t offset = digits - first.position(); non_const_T ret_word = lsr(*first.base(), first.position()); // We've already assigned enough bits @@ -210,16 +210,14 @@ T get_masked_word(const bit_iterator& first, size_t len = binary_digits //return ret_word; //} - // Writes len bits from src beginning at dstIt template void write_word(src_type src, bit_iterator dst_bit_it, - src_type len=binary_digits::value - ) -{ + size_t len = binary_digits::value) { using dst_type = typename bit_iterator::word_type; - constexpr dst_type dst_digits = binary_digits::value; - constexpr dst_type src_digits = binary_digits::value; + using size_type = typename bit_iterator::size_type; + constexpr size_type dst_digits = binary_digits::value; + constexpr size_type src_digits = binary_digits::value; if constexpr (dst_digits >= src_digits) { if (dst_bit_it.position() == 0 && len == dst_digits) { @@ -268,26 +266,22 @@ void write_word(src_type src, bit_iterator dst_bit_it, _mask(len)); } } - return; + return; } - // Shifts the range [first, last) to the left by n, filling the empty // bits with 0 template RandomAccessIt word_shift_left(RandomAccessIt first, - RandomAccessIt last, - typename RandomAccessIt::difference_type n -) -{ - if (n <= 0) return last; - if (n >= distance(first, last)) return first; - RandomAccessIt mid = first + n; - auto ret = std::move(mid, last, first); - return ret; + RandomAccessIt last, + typename RandomAccessIt::difference_type n) { + if (n <= 0) return last; + if (n >= distance(first, last)) return first; + RandomAccessIt mid = first + n; + auto ret = std::move(mid, last, first); + return ret; } - // Shifts the range [first, right) to the left by n, filling the empty // bits with 0 // NOT OPTIMIZED. Will be replaced with std::shift eventually. @@ -417,9 +411,7 @@ typename bit_iterator::word_type _padded_read(bit_iterator first, } // -------------------------------------------------------------------------- // - - // ========================================================================== // } // namespace bit -#endif // _BIT_ALGORITHM_DETAILS_HPP_INCLUDED +#endif // _BIT_ALGORITHM_DETAILS_HPP_INCLUDED // ========================================================================== // diff --git a/include/bitlib/bit-algorithms/copy_backward.hpp b/include/bitlib/bit-algorithms/copy_backward.hpp index 885f8cd..cd463b6 100644 --- a/include/bitlib/bit-algorithms/copy_backward.hpp +++ b/include/bitlib/bit-algorithms/copy_backward.hpp @@ -100,5 +100,5 @@ constexpr bit_iterator copy_backward(bit_iterator -constexpr T _shld(T dst, T src, T cnt) noexcept; +constexpr T _shld(T dst, T src, size_t cnt) noexcept; // Double precision shift right template -constexpr T _shrd(T dst, T src, T cnt) noexcept; +constexpr T _shrd(T dst, T src, size_t cnt) noexcept; // Multiword multiply template @@ -524,9 +524,9 @@ constexpr void _bitexch(T& src0, T& src1, S start0, S start1, S len) noexcept // --- IMPLEMENTATION DETAILS: INSTRUCTIONS: DOUBLE PRECISION SHIFT LEFT ---- // // Left shifts dst by cnt bits, filling the lsbs of dst by the msbs of src template -constexpr T _shld(T dst, T src, T cnt) noexcept { +constexpr T _shld(T dst, T src, size_t cnt) noexcept { static_assert(binary_digits::value, ""); - constexpr T digits = binary_digits::value; + constexpr size_t digits = binary_digits::value; if (cnt < digits) { dst = lsl(dst, cnt) | (lsr(src, (digits - cnt))); } else { @@ -539,9 +539,9 @@ constexpr T _shld(T dst, T src, T cnt) noexcept { // --- IMPLEMENTATION DETAILS: INSTRUCTIONS: DOUBLE PRECISION SHIFT RIGHT --- // // Right shifts dst by cnt bits, filling the msbs of dst by the lsbs of src template -constexpr T _shrd(T dst, T src, T cnt) noexcept { +constexpr T _shrd(T dst, T src, size_t cnt) noexcept { static_assert(binary_digits::value, ""); - constexpr T digits = binary_digits::value; + constexpr size_t digits = binary_digits::value; if (cnt < digits) { dst = (lsr(dst, cnt)) | lsl(src, (digits - cnt)); } else { From eb850d03b30663b2491763abc50f570796cad2c3 Mon Sep 17 00:00:00 2001 From: Peter McLean Date: Fri, 8 Aug 2025 08:58:02 -0400 Subject: [PATCH 13/22] No floats allowed --- include/bitlib/bit-containers/bit_vector.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/bitlib/bit-containers/bit_vector.hpp b/include/bitlib/bit-containers/bit_vector.hpp index 5dcbeaa..2bfe737 100644 --- a/include/bitlib/bit-containers/bit_vector.hpp +++ b/include/bitlib/bit-containers/bit_vector.hpp @@ -541,7 +541,7 @@ bit_vector::insert( if (count == 0) { return begin() + d; } - const float bits_available = word_vector.size() * digits; + const size_t bits_available = word_vector.size() * digits; const bool need_to_add = length_ + count > bits_available; if (need_to_add) { const auto words_to_add = word_count(length_ + count - bits_available); @@ -565,7 +565,7 @@ bit_vector::insert( if (count == 0) { return begin() + d; } - const float bits_available = word_vector.size() * digits; + const size_t bits_available = word_vector.size() * digits; const auto need_to_add = length_ + count > bits_available; if (need_to_add) { const auto words_to_add = word_count(length_ + count - bits_available); From 5bd5749e54830c0a4044d6537503980b73f44266 Mon Sep 17 00:00:00 2001 From: Peter McLean Date: Fri, 8 Aug 2025 09:04:16 -0400 Subject: [PATCH 14/22] Squash more conversion warnings --- .../bit-algorithms/bit_algorithm_details.hpp | 75 +----- include/bitlib/bit-algorithms/equal.hpp | 2 +- .../bitlib/bit-algorithms/multiplication.hpp | 2 +- include/bitlib/bit-algorithms/shift.hpp | 231 +++++++++--------- .../bitlib/bit-algorithms/to_from_string.hpp | 13 +- include/bitlib/bit-containers/bit_vector.hpp | 34 +-- include/bitlib/bit-iterator/bit_details.hpp | 18 +- 7 files changed, 156 insertions(+), 219 deletions(-) diff --git a/include/bitlib/bit-algorithms/bit_algorithm_details.hpp b/include/bitlib/bit-algorithms/bit_algorithm_details.hpp index 103641d..3895ecd 100644 --- a/include/bitlib/bit-algorithms/bit_algorithm_details.hpp +++ b/include/bitlib/bit-algorithms/bit_algorithm_details.hpp @@ -145,71 +145,6 @@ T get_masked_word(const bit_iterator& first, size_t len = binary_digits return get_word(first, len) & _mask(len); } -// Get next len bits beginning at start and store them in a word of type T -// If we reach `last` before we get len bits, break and return the current word -// bits_read will store the number of bits that we read. -//template -//T get_word(bit_iterator first, bit_iterator last, - //T& bits_read, T len=binary_digits::value - //) -//{ - //using native_word_type = typename bit_iterator::word_type; - //constexpr T native_digits = binary_digits::value; - //constexpr T ret_digits = binary_digits::value; - //assert(ret_digits >= len); - //bits_read = native_digits - first.position(); - //T ret_word = *first.base() >> first.position(); - - //// TODO vincent mentioned that we should aim for only 1 return function - //// per function. However I'm not sure how that can be accomplished here - //// without suffering a minor performance loss - - //// We have reached the last iterator - //if (first.base() == last.base()) { - //bits_read -= (native_digits - last.position()); - //return ret_word; - //} - //// We've already assigned enough bits - //if (len <= bits_read) { - //return ret_word; - //} - - //InputIt it = std::next(first.base()); - //len -= bits_read; - //// Fill up ret_word starting at bit [bits_read] using it - //// TODO define a mask and use the _bitblend that takes in the extra mask - //while (len > native_digits && it != last.base()) { - //ret_word = _bitblend( - //ret_word, - //static_cast(static_cast(*it) << bits_read), - //bits_read, - //native_digits - //); - //++it; - //bits_read += native_digits; - //len -= native_digits; - //} - - //// Assign remaining len bits of last word - //if (it == last.base()) { - //bits_read -= (native_digits - last.position()); - //ret_word = _bitblend( - //ret_word, - //static_cast(static_cast(*it) << bits_read), - //bits_read, - //last.position() - //); - //} else { - //ret_word = _bitblend( - //ret_word, - //static_cast(static_cast(*it) << bits_read), - //bits_read, - //len - //); - //} - //return ret_word; -//} - // Writes len bits from src beginning at dstIt template void write_word(src_type src, bit_iterator dst_bit_it, @@ -227,7 +162,7 @@ void write_word(src_type src, bit_iterator dst_bit_it, *dst_bit_it.base(), static_cast(src << dst_bit_it.position()), dst_bit_it.position(), - std::min( + std::min( dst_digits - dst_bit_it.position(), len)); if (len > dst_digits - dst_bit_it.position()) { @@ -275,8 +210,12 @@ template RandomAccessIt word_shift_left(RandomAccessIt first, RandomAccessIt last, typename RandomAccessIt::difference_type n) { - if (n <= 0) return last; - if (n >= distance(first, last)) return first; + if (n <= 0) { + return last; + } + if (n >= distance(first, last)) { + return first; + } RandomAccessIt mid = first + n; auto ret = std::move(mid, last, first); return ret; diff --git a/include/bitlib/bit-algorithms/equal.hpp b/include/bitlib/bit-algorithms/equal.hpp index 60642d8..db79501 100644 --- a/include/bitlib/bit-algorithms/equal.hpp +++ b/include/bitlib/bit-algorithms/equal.hpp @@ -64,7 +64,7 @@ struct equal_impl { const size_type partial_bits_to_check = ::std::min( remaining_bits_to_check, digits - d_first.position()); - const word_type mask = _mask(partial_bits_to_check) << d_first.position(); + const word_type mask = static_cast(_mask(partial_bits_to_check) << d_first.position()); const word_type comp = static_cast( get_word(first, partial_bits_to_check) << d_first.position()); diff --git a/include/bitlib/bit-algorithms/multiplication.hpp b/include/bitlib/bit-algorithms/multiplication.hpp index 01b3234..20b246a 100644 --- a/include/bitlib/bit-algorithms/multiplication.hpp +++ b/include/bitlib/bit-algorithms/multiplication.hpp @@ -35,7 +35,7 @@ constexpr typename bit_iterator::word_type multiplication( [&carry, integral_operand](auto word, auto bits = bitsof()) -> word_type { word_type result_word = (carry + _mulx(static_cast(integral_operand), word, &carry)); if (bits < bitsof()) { - carry = (carry << (bitsof() - bits)) | lsr(result_word, bits); + carry = static_cast((carry << (bitsof() - bits)) | lsr(result_word, bits)); } return result_word; }); diff --git a/include/bitlib/bit-algorithms/shift.hpp b/include/bitlib/bit-algorithms/shift.hpp index 1ed7093..2d72104 100644 --- a/include/bitlib/bit-algorithms/shift.hpp +++ b/include/bitlib/bit-algorithms/shift.hpp @@ -87,133 +87,133 @@ bit_iterator shift_left( ); return first + d - n; } - // clang-format on + // clang-format on - // Triggered if all remaining bits can fit in a word - if (d - n <= digits) { - word_type new_word = get_word(middle, d - n); - write_word(new_word, first, d - n); - return first + d - n; - } + // Triggered if all remaining bits can fit in a word + if (d - n <= static_cast(digits)) { + word_type new_word = get_word(middle, d - n); + write_word(new_word, first, d - n); + return first + d - n; + } - // Align first - if (!is_first_aligned) { - if (first.position() >= middle.position()) { - *first.base() = _bitblend( - *first.base(), - static_cast((*middle.base()) << (first.position() - middle.position())), - first.position(), - digits - first.position()); - } else { - const int n1 = digits - middle.position(); - const int n2 = digits - first.position() - n1; - *first.base() = _bitblend( - *first.base(), - lsr(*middle.base(), (middle.position() - first.position())), - first.position(), - n1); - *first.base() = _bitblend( - *first.base(), - static_cast((*std::next(middle.base())) << (digits - n2)), - first.position() + n1, - n2); + // Align first + if (!is_first_aligned) { + if (first.position() >= middle.position()) { + *first.base() = _bitblend( + *first.base(), + static_cast((*middle.base()) << (first.position() - middle.position())), + first.position(), + digits - first.position()); + } else { + const int n1 = digits - middle.position(); + const int n2 = digits - first.position() - n1; + *first.base() = _bitblend( + *first.base(), + lsr(*middle.base(), (middle.position() - first.position())), + first.position(), + n1); + *first.base() = _bitblend( + *first.base(), + static_cast((*std::next(middle.base())) << (digits - n2)), + first.position() + n1, + n2); + } + const int shifted = std::min(d - n, (digits - first.position())); + first += shifted; + middle += shifted; } - const int shifted = std::min(d - n, (digits - first.position())); - first += shifted; - middle += shifted; - } - if (middle.base() == last.base()) { - const int bits_left = last.position() - middle.position(); - if (bits_left > 0) { - *first.base() = _bitblend( - *first.base(), - lsr(*middle.base(), middle.position()), - 0, - bits_left); - first += bits_left; + if (middle.base() == last.base()) { + const int bits_left = last.position() - middle.position(); + if (bits_left > 0) { + *first.base() = _bitblend( + *first.base(), + lsr(*middle.base(), middle.position()), + 0, + bits_left); + first += bits_left; + } + // https://en.cppreference.com/w/cpp/algorithm/shift + // "Elements that are in the original range but not the new range + // are left in a valid but unspecified state." + // + //bit::fill(first, last, bit::bit0); + return first; } - // https://en.cppreference.com/w/cpp/algorithm/shift - // "Elements that are in the original range but not the new range - // are left in a valid but unspecified state." - // - //bit::fill(first, last, bit::bit0); - return first; - } - // More initialization - d = bit::distance(first, last); - const size_type word_shifts = n / digits; - const size_type offset = middle.position(); - - // At this point, first is aligned - if (offset == 0) { - first = bit::bit_iterator( - STD_SHIFT_LEFT(first.base(), - last.base(), - word_shifts), - 0); - if (!is_last_aligned) { - write_word(*last.base(), first, last.position()); - first += last.position(); + // More initialization + d = bit::distance(first, last); + const size_type word_shifts = n / digits; + const size_type offset = middle.position(); + + // At this point, first is aligned + if (offset == 0) { + first = bit::bit_iterator( + STD_SHIFT_LEFT(first.base(), + last.base(), + word_shifts), + 0); + if (!is_last_aligned) { + write_word(*last.base(), first, last.position()); + first += last.position(); + } + // https://en.cppreference.com/w/cpp/algorithm/shift + // "Elements that are in the original range but not the new range + // are left in a valid but unspecified state." + // + //bit::fill(first, last, bit::bit0); + return first; } - // https://en.cppreference.com/w/cpp/algorithm/shift - // "Elements that are in the original range but not the new range - // are left in a valid but unspecified state." - // - //bit::fill(first, last, bit::bit0); - return first; - } - // Shift bit sequence to the lsb + // Shift bit sequence to the lsb #ifdef BITLIB_HWY - // Align to 64 bit boundary - while (std::next(middle.base()) < last.base() && !is_aligned(&*first.base(), 64)) { - *first.base() = _shrd(*middle.base(), *std::next(middle.base()), offset); - first += digits; - middle += digits; - } + // Align to 64 bit boundary + while (std::next(middle.base()) < last.base() && !is_aligned(&*first.base(), 64)) { + *first.base() = _shrd(*middle.base(), *std::next(middle.base()), offset); + first += digits; + middle += digits; + } - const hn::ScalableTag d_tag; - while (std::distance(middle.base(), last.base()) >= hn::Lanes(d_tag) + 10 + !is_last_aligned) { - const auto v = hn::ShiftRightSame(hn::LoadU(d_tag, &*middle.base()), offset); - const auto v_plus1 = hn::ShiftLeftSame(hn::LoadU(d_tag, &*(middle.base() + 1)), digits - offset); - hn::Store(v | v_plus1, d_tag, &*first.base()); - first += hn::Lanes(d_tag) * digits; - middle += hn::Lanes(d_tag) * digits; - } + const hn::ScalableTag d_tag; + while (std::distance(middle.base(), last.base()) >= hn::Lanes(d_tag) + 10 + !is_last_aligned) { + const auto v = hn::ShiftRightSame(hn::LoadU(d_tag, &*middle.base()), offset); + const auto v_plus1 = hn::ShiftLeftSame(hn::LoadU(d_tag, &*(middle.base() + 1)), digits - offset); + hn::Store(v | v_plus1, d_tag, &*first.base()); + first += hn::Lanes(d_tag) * digits; + middle += hn::Lanes(d_tag) * digits; + } #endif - auto first_base = first.base(); - auto middle_base = middle.base(); - - while (std::next(middle_base) < last.base()) { - *first_base = _shrd(*middle_base, *std::next(middle_base), offset); - first_base++; - middle_base++; - ; - } - first = bit_iterator(first_base, 0); - middle = bit_iterator(middle_base, middle.position()); + auto first_base = first.base(); + auto middle_base = middle.base(); + + while (std::next(middle_base) < last.base()) { + *first_base = _shrd(*middle_base, *std::next(middle_base), offset); + first_base++; + middle_base++; + ; + } + first = bit_iterator(first_base, 0); + middle = bit_iterator(middle_base, middle.position()); - // If middle is now penultimate word - if (std::next(middle.base()) == last.base()) { - *first.base() = _bitblend( - *first.base(), - lsr(*middle.base(), offset), - 0, - digits - offset); - first += digits - offset; - middle += digits - offset; - } + // If middle is now penultimate word + if (std::next(middle.base()) == last.base()) { + *first.base() = _bitblend( + *first.base(), + lsr(*middle.base(), offset), + 0, + digits - offset); + first += digits - offset; + middle += digits - offset; + } - if (!is_last_aligned) { - const difference_type bits_left = last.position() - middle.position(); - const word_type new_word = get_word(middle, bits_left); - write_word(new_word, first, bits_left); - first += bits_left; - } + if (!is_last_aligned) { + const difference_type bits_left = last.position() - middle.position(); + const word_type new_word = get_word(middle, bits_left); + write_word(new_word, first, bits_left); + first += bits_left; + } - //bit::fill(first, last, bit::bit0); - return first; + //bit::fill(first, last, bit::bit0); + return first; } template @@ -224,6 +224,7 @@ bit_iterator shift_right( // Types and constants using word_type = typename bit_iterator::word_type; using size_type = typename bit_iterator::size_type; + using difference_type = typename bit_iterator::difference_type; // Initialization const bool is_last_aligned = last.position() == 0; @@ -293,7 +294,7 @@ bit_iterator shift_right( return first + n; } - if (bit::distance(first, middle) >= digits) { + if (bit::distance(first, middle) >= static_cast(digits)) { #ifdef BITLIB_HWY // Align to 64 bit boundary const hn::ScalableTag d; diff --git a/include/bitlib/bit-algorithms/to_from_string.hpp b/include/bitlib/bit-algorithms/to_from_string.hpp index 4bdfdcf..1df5fc6 100644 --- a/include/bitlib/bit-algorithms/to_from_string.hpp +++ b/include/bitlib/bit-algorithms/to_from_string.hpp @@ -156,8 +156,7 @@ constexpr CharIt to_string( policy::AccumulateNoInitialSubword{}, bit_first, bit_last, str_last, [meta, base_bits, base_digits, str_first](CharIt cursor, auto word, const size_t bits = bitsof()) { - const int characters = ((bits + base_bits - 1) / base_bits); - for (int i = characters - 1; i >= 0; i--) { + for (size_t i = 0; i < ((bits + base_bits - 1) / base_bits); i++) { if (cursor == str_first) { return std::make_pair(false, cursor); } @@ -203,17 +202,17 @@ constexpr size_t estimate_length( if (std::has_single_bit(base)) { const auto base_bits = std::bit_width(base - 1); - int skip_leading_bits = str_sign_extend_zeros ? 0 : count_msb(first, last, bit0); + size_t skip_leading_bits = str_sign_extend_zeros ? 0 : count_msb(first, last, bit0); - int str_len = (distance(first, last) - skip_leading_bits); + size_t str_len = (distance(first, last) - skip_leading_bits); str_len = (str_len + base_bits - 1) / base_bits; // Round up to nearest base digit - return static_cast(std::max(1, str_len)); + return static_cast(std::max(static_cast(1), str_len)); } else { const uint32_t LOG2BASE = static_cast(std::ceil(static_cast(1 << 16) / std::logbf(static_cast(base)))); - int skip_leading_bits = str_sign_extend_zeros ? 0 : count_msb(first, last, bit0); + size_t skip_leading_bits = str_sign_extend_zeros ? 0 : count_msb(first, last, bit0); const auto bits = distance(first, last) - skip_leading_bits; const auto fixed_point = (bits * LOG2BASE); - const auto max_len = (fixed_point >> 16) + ((fixed_point & ((1 << 16) - 1)) != 0); + const size_t max_len = (fixed_point >> 16) + ((fixed_point & ((1 << 16) - 1)) != 0); return static_cast(std::max(max_len, static_cast(1))); } } diff --git a/include/bitlib/bit-containers/bit_vector.hpp b/include/bitlib/bit-containers/bit_vector.hpp index 2bfe737..bc8450b 100644 --- a/include/bitlib/bit-containers/bit_vector.hpp +++ b/include/bitlib/bit-containers/bit_vector.hpp @@ -531,26 +531,26 @@ bit_vector::insert( } // TODO should use std::insert to maintain the constant amortized time. -template +template constexpr typename bit_vector::iterator bit_vector::insert( - const_iterator pos, - size_type count, - const bit_vector::value_type& value) { - const auto d = distance(cbegin(), pos); - if (count == 0) { - return begin() + d; - } - const size_t bits_available = word_vector.size() * digits; - const bool need_to_add = length_ + count > bits_available; - if (need_to_add) { - const auto words_to_add = word_count(length_ + count - bits_available); - word_vector.resize(word_vector.size() + words_to_add); - } - length_ += count; - shift_right(begin() + d, begin() + length_, count); - fill(begin() + d, begin() + d + count, value); + const_iterator pos, + size_type count, + const bit_vector::value_type& value) { + const auto d = distance(cbegin(), pos); + if (count == 0) { return begin() + d; + } + const size_t bits_available = word_vector.size() * digits; + const bool need_to_add = length_ + count > bits_available; + if (need_to_add) { + const auto words_to_add = word_count(length_ + count - bits_available); + word_vector.resize(word_vector.size() + words_to_add); + } + length_ += count; + shift_right(begin() + d, begin() + length_, count); + fill(begin() + d, begin() + d + count, value); + return begin() + d; } template diff --git a/include/bitlib/bit-iterator/bit_details.hpp b/include/bitlib/bit-iterator/bit_details.hpp index 50fd5b5..6a377da 100644 --- a/include/bitlib/bit-iterator/bit_details.hpp +++ b/include/bitlib/bit-iterator/bit_details.hpp @@ -227,11 +227,11 @@ constexpr void _bitexch(T& src0, T& src1, S start0, S start1, S len) noexcept; // Double precision shift left template -constexpr T _shld(T dst, T src, size_t cnt) noexcept; +constexpr T _shld(const T& dst, const T& src, const size_t& cnt) noexcept; // Double precision shift right template -constexpr T _shrd(T dst, T src, size_t cnt) noexcept; +constexpr T _shrd(const T& dst, const T& src, const size_t& cnt) noexcept; // Multiword multiply template @@ -524,30 +524,28 @@ constexpr void _bitexch(T& src0, T& src1, S start0, S start1, S len) noexcept // --- IMPLEMENTATION DETAILS: INSTRUCTIONS: DOUBLE PRECISION SHIFT LEFT ---- // // Left shifts dst by cnt bits, filling the lsbs of dst by the msbs of src template -constexpr T _shld(T dst, T src, size_t cnt) noexcept { +constexpr T _shld(const T& dst, const T& src, const size_t& cnt) noexcept { static_assert(binary_digits::value, ""); constexpr size_t digits = binary_digits::value; if (cnt < digits) { - dst = lsl(dst, cnt) | (lsr(src, (digits - cnt))); + return static_cast(lsl(dst, cnt) | (lsr(src, (digits - cnt)))); } else { - dst = lsl(src, cnt - digits) * (cnt < (digits + digits)); + return static_cast(lsl(src, cnt - digits) * (cnt < (digits + digits))); } - return dst; } // -------------------------------------------------------------------------- // // --- IMPLEMENTATION DETAILS: INSTRUCTIONS: DOUBLE PRECISION SHIFT RIGHT --- // // Right shifts dst by cnt bits, filling the msbs of dst by the lsbs of src template -constexpr T _shrd(T dst, T src, size_t cnt) noexcept { +constexpr T _shrd(const T& dst, const T& src, const size_t& cnt) noexcept { static_assert(binary_digits::value, ""); constexpr size_t digits = binary_digits::value; if (cnt < digits) { - dst = (lsr(dst, cnt)) | lsl(src, (digits - cnt)); + return static_cast((lsr(dst, cnt)) | lsl(src, (digits - cnt))); } else { - dst = (lsr(src, (cnt - digits))) * (cnt < (digits + digits)); + return static_cast((lsr(src, (cnt - digits))) * (cnt < (digits + digits))); } - return dst; } // -------------------------------------------------------------------------- // From ca2a3f9864942fef2107a744fcc7fc66e5f794fc Mon Sep 17 00:00:00 2001 From: Peter McLean Date: Fri, 8 Aug 2025 09:52:48 -0400 Subject: [PATCH 15/22] Even more warnings --- include/bitlib/bit-algorithms/equal.hpp | 2 +- include/bitlib/bit-algorithms/rotate.hpp | 5 +- include/bitlib/bit-algorithms/shift.hpp | 6 +-- .../bitlib/bit-algorithms/to_from_string.hpp | 5 +- include/bitlib/bit-iterator/bit_details.hpp | 46 +++++++++++-------- 5 files changed, 36 insertions(+), 28 deletions(-) diff --git a/include/bitlib/bit-algorithms/equal.hpp b/include/bitlib/bit-algorithms/equal.hpp index db79501..0b3c0e9 100644 --- a/include/bitlib/bit-algorithms/equal.hpp +++ b/include/bitlib/bit-algorithms/equal.hpp @@ -64,7 +64,7 @@ struct equal_impl { const size_type partial_bits_to_check = ::std::min( remaining_bits_to_check, digits - d_first.position()); - const word_type mask = static_cast(_mask(partial_bits_to_check) << d_first.position()); + const word_type mask = _mask(partial_bits_to_check, d_first.position()); const word_type comp = static_cast( get_word(first, partial_bits_to_check) << d_first.position()); diff --git a/include/bitlib/bit-algorithms/rotate.hpp b/include/bitlib/bit-algorithms/rotate.hpp index 1d5ecb2..e4e81c3 100644 --- a/include/bitlib/bit-algorithms/rotate.hpp +++ b/include/bitlib/bit-algorithms/rotate.hpp @@ -219,15 +219,14 @@ bit_iterator rotate( size_type p = last_pos - n_first.position(); size_type d = last_pos - first.position(); - word_type mask = _mask(d) << first.position(); + word_type mask = _mask(d, first.position()); word_type rotated = *first.base() & mask; rotated = static_cast(lsr(rotated, k)) | static_cast(rotated << p); *first.base() = _bitblend( *first.base(), rotated, first.position(), - d - ); + d); return std::next(first, p); } } diff --git a/include/bitlib/bit-algorithms/shift.hpp b/include/bitlib/bit-algorithms/shift.hpp index 2d72104..883bf2a 100644 --- a/include/bitlib/bit-algorithms/shift.hpp +++ b/include/bitlib/bit-algorithms/shift.hpp @@ -105,8 +105,8 @@ bit_iterator shift_left( first.position(), digits - first.position()); } else { - const int n1 = digits - middle.position(); - const int n2 = digits - first.position() - n1; + const size_t n1 = digits - middle.position(); + const size_t n2 = digits - first.position() - n1; *first.base() = _bitblend( *first.base(), lsr(*middle.base(), (middle.position() - first.position())), @@ -114,7 +114,7 @@ bit_iterator shift_left( n1); *first.base() = _bitblend( *first.base(), - static_cast((*std::next(middle.base())) << (digits - n2)), + static_cast((*std::next(middle.base()) << (digits - n2))), first.position() + n1, n2); } diff --git a/include/bitlib/bit-algorithms/to_from_string.hpp b/include/bitlib/bit-algorithms/to_from_string.hpp index 1df5fc6..00dfe06 100644 --- a/include/bitlib/bit-algorithms/to_from_string.hpp +++ b/include/bitlib/bit-algorithms/to_from_string.hpp @@ -213,7 +213,7 @@ constexpr size_t estimate_length( const auto bits = distance(first, last) - skip_leading_bits; const auto fixed_point = (bits * LOG2BASE); const size_t max_len = (fixed_point >> 16) + ((fixed_point & ((1 << 16) - 1)) != 0); - return static_cast(std::max(max_len, static_cast(1))); + return static_cast(std::max(static_cast(1), max_len)); } } @@ -332,14 +332,13 @@ constexpr void from_string( } using word_type = typename bit_iterator::word_type; std::vector vec; - size_t store_bits = distance(bit_first, bit_last); // TODO: template with uninitialized_t ::bit::fill(bit_first, bit_last, bit0); // Clear the bits first CharIt cursor = str_first; while (cursor != str_last) { - unsigned char c = (*cursor - '0'); + unsigned char c = static_cast(*cursor - '0'); if (c <= 9) { auto overflow_mult = ::bit::multiplication(bit_first, bit_last, word_type{10}); auto overflow_add = ::bit::addition(bit_first, bit_last, c); diff --git a/include/bitlib/bit-iterator/bit_details.hpp b/include/bitlib/bit-iterator/bit_details.hpp index 6a377da..1b821ee 100644 --- a/include/bitlib/bit-iterator/bit_details.hpp +++ b/include/bitlib/bit-iterator/bit_details.hpp @@ -205,9 +205,9 @@ constexpr bool _assert_range_viability(Iterator first, Iterator last); // Bit field extraction template -constexpr T _bextr(T src, T start, T len) noexcept; +constexpr T _bextr(T src, size_t start, size_t len) noexcept; template -constexpr T _bextr(T src, T start, T len, X...) noexcept; +constexpr T _bextr(T src, size_t start, size_t len, X...) noexcept; // Bit swap template @@ -296,6 +296,10 @@ enum class _mask_len { unknown, in_range }; +enum class _mask_start { + unknown, + in_range +}; template constexpr T _mask(const size_type len) { @@ -314,6 +318,17 @@ constexpr T _mask(const size_type len) { return static_cast((one << (static_cast(len) & digits_mask)) * static_cast(len < bitsof()) - one); } } +template +constexpr T _mask(const size_type len, const size_type start) { + if constexpr (start_in_range != _mask_start::unknown) { + return static_cast(_mask(len) << start); + } else { + return static_cast((_mask(len) << start) * (start < bitsof())); + } +} // ------------- IMPLEMENTATION DETAILS: UTILITIES: ASSERTIONS -------------- // // If the range allows multipass iteration, checks if last - first >= 0 @@ -332,9 +347,9 @@ constexpr bool _assert_range_viability(Iterator first, Iterator last) { // ------- IMPLEMENTATION DETAILS: INSTRUCTIONS: BIT FIELD EXTRACTION ------- // // Extacts to lsbs a field of contiguous bits with compiler intrinsics template -constexpr T _bextr(T src, T start, T len) noexcept { +constexpr T _bextr(T src, size_t start, size_t len) noexcept { static_assert(binary_digits::value, ""); - constexpr T digits = binary_digits::value; + constexpr size_t digits = binary_digits::value; T dst = T(); if (digits <= std::numeric_limits::digits) { dst = __builtin_ia32_bextr_u32(src, start, len); @@ -348,12 +363,10 @@ constexpr T _bextr(T src, T start, T len) noexcept { // Extacts to lsbs a field of contiguous bits without compiler intrinsics template -constexpr T _bextr(T src, T start, T len, X...) noexcept { +constexpr T _bextr(T src, size_t start, size_t len, X...) noexcept { static_assert(binary_digits::value, ""); - constexpr T digits = binary_digits::value; - constexpr T one = 1; - const T msk = (one << len) * (len < digits) - one; - return (lsr(src, start)) & msk * (start < digits); + const T msk = _mask(len); + return (lsr(src, start))&msk; } // -------------------------------------------------------------------------- // @@ -395,7 +408,7 @@ constexpr T _bitswap(T src) noexcept { static_assert(binary_digits::value, ""); constexpr T cnt = N >> 1; constexpr T msk = _bitswap(); - src = ((lsr(src, cnt)) & msk) | ((src << cnt) & ~msk); + src = static_cast(((lsr(src, cnt))&msk) | ((src << cnt) & ~msk)); return cnt > 1 ? _bitswap(src) : src; } @@ -408,7 +421,7 @@ constexpr T _bitswap() noexcept { T msk = ~T(); while (cnt != N) { cnt = lsr(cnt, 1); - msk ^= (msk << cnt); + msk ^= static_cast(msk << cnt); } return msk; } @@ -445,8 +458,8 @@ constexpr exact_floor_integral_t _bitblend( constexpr size_t digits = bitsof(); const promoted_t src0 = static_cast(src0_); const promoted_t src1 = static_cast(src1_); - const promoted_t msk = _mask(len) << start; - return static_cast(src0 ^ ((src0 ^ src1) & (msk * (start < digits)))); + const promoted_t msk = _mask(len, start); + return (src0 ^ ((src0 ^ src1) & msk)); } // -------------------------------------------------------------------------- // @@ -465,13 +478,10 @@ template constexpr void _bitexch(T& src0, T& src1, S start, S len) noexcept { static_assert(binary_digits::value, ""); constexpr auto digits = binary_digits::value; - const T msk = (len < digits) - ? _mask(len) << start - : -1; // TODO: What if start > 0 here? + const T msk = _mask(len, start); src0 = src0 ^ static_cast(src1 & msk); src1 = src1 ^ static_cast(src0 & msk); src0 = src0 ^ static_cast(src1 & msk); - return; } // Replaces len bits of src0 by the ones of src1 starting at start0 @@ -784,7 +794,7 @@ constexpr T _mulx(T src0, T src1, T* hi, X...) noexcept { using wider_t = ceil_integral() + bitsof()>; if constexpr ((digits + digits) <= bitsof()) { wider_t tmp = static_cast(src0) * static_cast(src1); - *hi = tmp >> digits; + *hi = static_cast(tmp >> digits); return static_cast(tmp); } else { // Multiplies src0 and src1 and gets the full result without compiler intrinsics From 2f264a2337d64bc7cdda71571f4a8b4a9ce73dd3 Mon Sep 17 00:00:00 2001 From: Peter McLean Date: Fri, 8 Aug 2025 09:56:38 -0400 Subject: [PATCH 16/22] Annoying that promotion happens even for bitwise of same type --- include/bitlib/bit-iterator/bit_details.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/bitlib/bit-iterator/bit_details.hpp b/include/bitlib/bit-iterator/bit_details.hpp index 1b821ee..20406e6 100644 --- a/include/bitlib/bit-iterator/bit_details.hpp +++ b/include/bitlib/bit-iterator/bit_details.hpp @@ -455,11 +455,10 @@ constexpr exact_floor_integral_t _bitblend( using resolved_t = exact_floor_integral_t; using promoted_t = std::conditional_t() < bitsof(), int, resolved_t>; static_assert(binary_digits>::value, ""); - constexpr size_t digits = bitsof(); const promoted_t src0 = static_cast(src0_); const promoted_t src1 = static_cast(src1_); const promoted_t msk = _mask(len, start); - return (src0 ^ ((src0 ^ src1) & msk)); + return static_cast(src0 ^ ((src0 ^ src1) & msk)); } // -------------------------------------------------------------------------- // From d368c2d62d630554edc221f99c9c4ca437cb9e26 Mon Sep 17 00:00:00 2001 From: Peter McLean Date: Fri, 8 Aug 2025 10:01:41 -0400 Subject: [PATCH 17/22] Narrowing in on double digit warnings --- include/bitlib/bit-algorithms/to_from_string.hpp | 2 +- include/bitlib/bit-iterator/bit_details.hpp | 3 +-- include/bitlib/bit-iterator/bit_reference.hpp | 2 +- test/src/vector_test.cpp | 6 +++--- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/include/bitlib/bit-algorithms/to_from_string.hpp b/include/bitlib/bit-algorithms/to_from_string.hpp index 00dfe06..5d5e430 100644 --- a/include/bitlib/bit-algorithms/to_from_string.hpp +++ b/include/bitlib/bit-algorithms/to_from_string.hpp @@ -299,7 +299,7 @@ constexpr void from_string( for (; (bits < bitsof()) && (cursor >= 0); cursor--) { char c = str_first[cursor]; // TODO: This should be a policy - if (c >= base_from_digits.size()) { + if (static_cast(c) >= base_from_digits.size()) { continue; } auto digit = base_from_digits[c]; diff --git a/include/bitlib/bit-iterator/bit_details.hpp b/include/bitlib/bit-iterator/bit_details.hpp index 20406e6..664ed47 100644 --- a/include/bitlib/bit-iterator/bit_details.hpp +++ b/include/bitlib/bit-iterator/bit_details.hpp @@ -457,7 +457,7 @@ constexpr exact_floor_integral_t _bitblend( static_assert(binary_digits>::value, ""); const promoted_t src0 = static_cast(src0_); const promoted_t src1 = static_cast(src1_); - const promoted_t msk = _mask(len, start); + const resolved_t msk = _mask(len, start); return static_cast(src0 ^ ((src0 ^ src1) & msk)); } // -------------------------------------------------------------------------- // @@ -476,7 +476,6 @@ constexpr void _bitexch(T& src0, T& src1, T msk) noexcept { template constexpr void _bitexch(T& src0, T& src1, S start, S len) noexcept { static_assert(binary_digits::value, ""); - constexpr auto digits = binary_digits::value; const T msk = _mask(len, start); src0 = src0 ^ static_cast(src1 & msk); src1 = src1 ^ static_cast(src0 & msk); diff --git a/include/bitlib/bit-iterator/bit_reference.hpp b/include/bitlib/bit-iterator/bit_reference.hpp index 6884432..17af860 100644 --- a/include/bitlib/bit-iterator/bit_reference.hpp +++ b/include/bitlib/bit-iterator/bit_reference.hpp @@ -276,7 +276,7 @@ constexpr bit_reference& bit_reference::set() const noexcept { // Resets the value of the referenced bit to 0 template constexpr bit_reference& bit_reference::reset() const noexcept { - _ref &= ~_mask; + _ref &= static_cast(~_mask); return const_cast&>(*this); } diff --git a/test/src/vector_test.cpp b/test/src/vector_test.cpp index d78a603..0ca20ec 100644 --- a/test/src/vector_test.cpp +++ b/test/src/vector_test.cpp @@ -270,13 +270,13 @@ TYPED_TEST(VectorTest, AtRead) { constexpr auto digits = bit::binary_digits::value; EXPECT_EQ(this->v3_.at(0), bit::bit0); EXPECT_EQ(this->v3_.at(8), bit::bit1); - for (unsigned int vec_idx = 0; vec_idx < this->random_bitvecs.size(); ++vec_idx) { + for (size_t vec_idx = 0; vec_idx < this->random_bitvecs.size(); ++vec_idx) { auto& bitvec = this->random_bitvecs[vec_idx]; auto& boolvec = this->random_boolvecs[vec_idx]; - for (unsigned int i = 0; i < boolvec.size(); i++) { + for (size_t i = 0; i < boolvec.size(); i++) { EXPECT_TRUE(comparator(bitvec.at(i), boolvec.at(i))); } - for (unsigned int i = boolvec.size(); i < boolvec.size() + 4 * digits; i++) { + for (size_t i = boolvec.size(); i < boolvec.size() + 4 * digits; i++) { EXPECT_THROW(bitvec.at(i), std::out_of_range); } } From 50241d76439644f542dbd734db96e8d9c4fe968d Mon Sep 17 00:00:00 2001 From: Peter McLean Date: Fri, 8 Aug 2025 11:53:43 -0400 Subject: [PATCH 18/22] More warnings --- include/bitlib/bit-algorithms/count.hpp | 2 +- include/bitlib/bit-algorithms/division.hpp | 1 + include/bitlib/bit-algorithms/to_from_string.hpp | 2 +- test/src/vector_test.cpp | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/bitlib/bit-algorithms/count.hpp b/include/bitlib/bit-algorithms/count.hpp index 2afc214..31db939 100644 --- a/include/bitlib/bit-algorithms/count.hpp +++ b/include/bitlib/bit-algorithms/count.hpp @@ -101,7 +101,7 @@ count( } } if (last.position() != 0) { - word_type last_value = *last.base() << (digits - last.position()); + word_type last_value = static_cast(*last.base() << (digits - last.position())); result += std::popcount(static_cast>(last_value)); } // Computation when bits belong to the same underlying word diff --git a/include/bitlib/bit-algorithms/division.hpp b/include/bitlib/bit-algorithms/division.hpp index 48f5d2a..d7cfa28 100644 --- a/include/bitlib/bit-algorithms/division.hpp +++ b/include/bitlib/bit-algorithms/division.hpp @@ -37,6 +37,7 @@ constexpr typename bit_iterator::word_type division( const word_type& remainder, const word_type& word, size_t bits = bitsof()) { + static_cast(bits); // Suppress unused variable warning word_type next_remainder; word_type result_word = _divx(remainder, word, static_cast(integral_operand), &next_remainder); return std::make_pair(result_word, next_remainder); diff --git a/include/bitlib/bit-algorithms/to_from_string.hpp b/include/bitlib/bit-algorithms/to_from_string.hpp index 5d5e430..11ab6e8 100644 --- a/include/bitlib/bit-algorithms/to_from_string.hpp +++ b/include/bitlib/bit-algorithms/to_from_string.hpp @@ -161,7 +161,7 @@ constexpr CharIt to_string( return std::make_pair(false, cursor); } *(--cursor) = base_digits[word & (meta.base - 1)]; - word >>= base_bits; + word >>= static_cast(base_bits); } return std::make_pair(cursor != str_first, cursor); }); diff --git a/test/src/vector_test.cpp b/test/src/vector_test.cpp index 0ca20ec..6bf3b27 100644 --- a/test/src/vector_test.cpp +++ b/test/src/vector_test.cpp @@ -149,7 +149,7 @@ TYPED_TEST(VectorTest, StringConstructor) { std::string rand_bs(strlen, 0); this->empty_vec_bool.clear(); for (auto& pos : rand_bs) { - pos = generate_random_number('0', '1'); + pos = static_cast(generate_random_number('0', '1')); this->empty_vec_bool.push_back(pos == '1'); } this->empty_vec = bit::bit_vector(rand_bs); From 0fbbc7ba4f9bef6296f4ad5482ff52da415bdcb9 Mon Sep 17 00:00:00 2001 From: Peter McLean Date: Fri, 8 Aug 2025 12:21:05 -0400 Subject: [PATCH 19/22] Turn on Werror --- CMakePresets.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakePresets.json b/CMakePresets.json index 6e61349..ca824f0 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -77,7 +77,7 @@ "name": "warnings_base", "hidden": true, "environment": { - "TARGET_FLAGS": "-Wall -Wextra -Wpedantic -Wold-style-cast -Wconversion -Wshadow -Wno-error" + "TARGET_FLAGS": "-Wall -Wextra -Wpedantic -Wshadow -Werror" } }, { From ed13e5ac48802d1110594781ef6afbccdd813693 Mon Sep 17 00:00:00 2001 From: Peter McLean Date: Fri, 8 Aug 2025 12:26:35 -0400 Subject: [PATCH 20/22] Fix clang warnings --- include/bitlib/bit-algorithms/to_from_string.hpp | 2 +- include/bitlib/bit-containers/bit_span.hpp | 3 ++- test/src/test-iterator_adapter.cpp | 2 -- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/include/bitlib/bit-algorithms/to_from_string.hpp b/include/bitlib/bit-algorithms/to_from_string.hpp index 11ab6e8..e2d5eb1 100644 --- a/include/bitlib/bit-algorithms/to_from_string.hpp +++ b/include/bitlib/bit-algorithms/to_from_string.hpp @@ -380,7 +380,7 @@ constexpr std::vector from_string( for (; (bits < bitsof()) && (last >= first); last--) { char c = *last; // TODO: This should be a policy - if (c >= base_from_digits.size()) { + if (static_cast(c) >= base_from_digits.size()) { continue; } auto digit = base_from_digits[c]; diff --git a/include/bitlib/bit-containers/bit_span.hpp b/include/bitlib/bit-containers/bit_span.hpp index 7eaf466..cd4b61e 100644 --- a/include/bitlib/bit-containers/bit_span.hpp +++ b/include/bitlib/bit-containers/bit_span.hpp @@ -335,7 +335,8 @@ template constexpr bit_span bit_span::last(size_type offset) const noexcept requires(Extent == std::dynamic_extent) { + return bit_span(begin() + size() - offset); } -} // namespace bit +} // namespace bit #endif diff --git a/test/src/test-iterator_adapter.cpp b/test/src/test-iterator_adapter.cpp index 81b94f7..8f35b79 100644 --- a/test/src/test-iterator_adapter.cpp +++ b/test/src/test-iterator_adapter.cpp @@ -180,8 +180,6 @@ TEST(BitIteratorAdapter_BigToSmall, OperatorSubscript) { // Negative index: it[ -1 ] => moves to previous base word; // but since there's no previous word, behavior is UB. We skip testing negative here. - // If we do it + 4, then subscript( it + 4 )[0] should be same as it[4] - auto it_shift = it + 4; // rolls into next base (out-of-bounds, but for test allocate two words) // For safety, create two‐element array: uint32_t arr2[2] = {0x01020304u, 0x05060708u}; Adapter8_32 it2(arr2, 0); From a45dd617feff61a28f3554ea0f6ca24ff66baf2a Mon Sep 17 00:00:00 2001 From: Peter McLean Date: Fri, 8 Aug 2025 12:40:11 -0400 Subject: [PATCH 21/22] Add a single status check for all matrix jobs --- .github/workflows/cmake-multi-platform.yml | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cmake-multi-platform.yml b/.github/workflows/cmake-multi-platform.yml index b8264d7..94241ab 100644 --- a/.github/workflows/cmake-multi-platform.yml +++ b/.github/workflows/cmake-multi-platform.yml @@ -15,7 +15,6 @@ on: jobs: run-matrix: - name: Run CMake Build and Test Matrix uses: ./.github/workflows/cmake_build_and_test.yml strategy: # Set fail-fast to false to ensure that feedback is delivered for all matrix combinations. Consider changing this to true when your workflow is stable. @@ -107,4 +106,18 @@ jobs: build_type: ${{ matrix.build_type || matrix.preset == 'benchmark' && 'Release' || 'Debug' }} head_ref: ${{ github.event.pull_request.head.ref }} base_ref: ${{ github.event.pull_request.base.ref }} - secrets: inherit \ No newline at end of file + secrets: inherit + status_check: + runs-on: ubuntu-latest + needs: run-matrix + if: ${{ always() }} + steps: + - name: Check for failed jobs + shell: bash + run: | + if [ -n "${{ needs.run-matrix.result }}" != "success" ]; then + echo "Some jobs failed. Please check the logs." + exit 1 + else + echo "All jobs completed successfully." + fi \ No newline at end of file From 2e89198d0b0105a31e4d37cee3a369dc33f48488 Mon Sep 17 00:00:00 2001 From: Peter McLean Date: Fri, 8 Aug 2025 12:43:04 -0400 Subject: [PATCH 22/22] Filter C/C++ sources for clang format check --- .github/workflows/clang_format.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/clang_format.yaml b/.github/workflows/clang_format.yaml index babe06b..24a2e0b 100644 --- a/.github/workflows/clang_format.yaml +++ b/.github/workflows/clang_format.yaml @@ -40,10 +40,10 @@ jobs: run: | if [[ "${{ github.event_name }}" == "pull_request" ]]; then echo "Getting diff for pull request" - git diff origin/${{ github.base_ref }}...HEAD > diff.patch + git diff origin/${{ github.base_ref }}...HEAD -- '*.c' '*.cpp' '*.hpp' '*.cc' '*.cxx' '*.h' '*.hh' '*.hxx' > diff.patch else echo "Getting diff for commit" - git diff ${{ github.event.before }} ${{ github.event.after }} > diff.patch + git diff ${{ github.event.before }} ${{ github.event.after }} -- '*.c' '*.cpp' '*.hpp' '*.cc' '*.cxx' '*.h' '*.hh' '*.hxx' > diff.patch fi - name: Check formatting