Skip to content

Commit edf3fad

Browse files
committed
Optimize the erasure
1 parent 28bafd3 commit edf3fad

File tree

1 file changed

+72
-4
lines changed

1 file changed

+72
-4
lines changed

include/sparrow/buffer/dynamic_bitset/dynamic_bitset_base.hpp

Lines changed: 72 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ namespace sparrow
165165

166166
// Efficient bit manipulation helpers for insert operations
167167
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);
168169
constexpr void fill_bits_range(size_type start_pos, size_type bit_count, value_type value);
169170
template <std::random_access_iterator InputIt>
170171
constexpr iterator
@@ -694,10 +695,9 @@ namespace sparrow
694695
return end();
695696
}
696697

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)
701701
{
702702
set(first_index + i, test(last_index + i));
703703
}
@@ -792,6 +792,74 @@ namespace sparrow
792792
}
793793
}
794794

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+
795863
template <typename B>
796864
requires std::ranges::random_access_range<std::remove_pointer_t<B>>
797865
constexpr void

0 commit comments

Comments
 (0)