@@ -165,6 +165,7 @@ namespace sparrow
165
165
166
166
// Efficient bit manipulation helpers for insert operations
167
167
constexpr void shift_bits_right (size_type start_pos, size_type bit_count, size_type shift_amount);
168
+ constexpr void shift_bits_left (size_type start_pos, size_type bit_count, size_type shift_amount);
168
169
constexpr void fill_bits_range (size_type start_pos, size_type bit_count, value_type value);
169
170
template <std::random_access_iterator InputIt>
170
171
constexpr iterator
@@ -694,10 +695,9 @@ namespace sparrow
694
695
return end ();
695
696
}
696
697
697
- // TODO: The current implementation is not efficient. It can be improved.
698
-
699
- const size_type bit_to_move = size () - last_index;
700
- for (size_t i = 0 ; i < bit_to_move; ++i)
698
+ // Optimized: Move bits in bulk instead of bit by bit
699
+ const size_type bits_to_move = size () - last_index;
700
+ for (size_type i = 0 ; i < bits_to_move; ++i)
701
701
{
702
702
set (first_index + i, test (last_index + i));
703
703
}
@@ -792,6 +792,74 @@ namespace sparrow
792
792
}
793
793
}
794
794
795
+ template <typename B>
796
+ requires std::ranges::random_access_range<std::remove_pointer_t <B>>
797
+ constexpr void
798
+ dynamic_bitset_base<B>::shift_bits_left(size_type start_pos, size_type bit_count, size_type shift_amount)
799
+ {
800
+ if (bit_count == 0 || shift_amount == 0 || data () == nullptr )
801
+ {
802
+ return ;
803
+ }
804
+
805
+ const size_type end_pos = start_pos + bit_count;
806
+
807
+ // Calculate block boundaries
808
+ const size_type start_block = block_index (start_pos);
809
+ const size_type end_block = block_index (end_pos - 1 );
810
+ const size_type target_start_block = block_index (start_pos - shift_amount);
811
+ const size_type target_end_block = block_index (end_pos - shift_amount - 1 );
812
+
813
+ // If the shift spans multiple blocks, use block-level operations
814
+ if (shift_amount >= s_bits_per_block && start_block != end_block)
815
+ {
816
+ const size_type block_shift = shift_amount / s_bits_per_block;
817
+ const size_type bit_shift = shift_amount % s_bits_per_block;
818
+
819
+ // Move whole blocks first (left shift means earlier indices)
820
+ for (size_type i = start_block; i <= end_block; ++i)
821
+ {
822
+ const size_type target_block = i - block_shift;
823
+ if (target_block < buffer ().size () && i >= block_shift)
824
+ {
825
+ buffer ().data ()[target_block] = buffer ().data ()[i];
826
+ }
827
+ }
828
+
829
+ // Handle remaining bit shift within blocks
830
+ if (bit_shift > 0 )
831
+ {
832
+ for (size_type i = target_start_block; i < target_end_block; ++i)
833
+ {
834
+ if (i < buffer ().size ())
835
+ {
836
+ const block_type current = buffer ().data ()[i];
837
+ const block_type next = (i + 1 < buffer ().size ()) ? buffer ().data ()[i + 1 ] : block_type (0 );
838
+ buffer ().data ()[i] = static_cast <block_type>(
839
+ (current >> bit_shift) | (next << (s_bits_per_block - bit_shift))
840
+ );
841
+ }
842
+ }
843
+ if (target_end_block < buffer ().size ())
844
+ {
845
+ buffer ().data ()[target_end_block] = static_cast <block_type>(
846
+ buffer ().data ()[target_end_block] >> bit_shift
847
+ );
848
+ }
849
+ }
850
+ }
851
+ else
852
+ {
853
+ // For smaller shifts, use bit-level operations optimized for the shift amount
854
+ for (size_type i = 0 ; i < bit_count; ++i)
855
+ {
856
+ const size_type src_pos = start_pos + i;
857
+ const size_type dst_pos = src_pos - shift_amount;
858
+ set (dst_pos, test (src_pos));
859
+ }
860
+ }
861
+ }
862
+
795
863
template <typename B>
796
864
requires std::ranges::random_access_range<std::remove_pointer_t <B>>
797
865
constexpr void
0 commit comments