Skip to content

Commit ffa8f4d

Browse files
committed
Add flip to bitvec
1 parent edcadd8 commit ffa8f4d

3 files changed

Lines changed: 175 additions & 5 deletions

File tree

fuzzing/0007.containers/bitvec/bitvec.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
#include<cstdint>
2-
#include<fast_io_dsal/bitvec.h>
1+
#include <cstdint>
2+
#include <fast_io_dsal/bitvec.h>
33

44
extern "C" int LLVMFuzzerTestOneInput(uint8_t const *data, size_t size)
55
{

include/fast_io_dsal/impl/bitvec.h

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,92 @@ class bitvec
516516
this->reset_back_unchecked();
517517
}
518518

519+
inline constexpr void flip_unchecked(size_type pos) noexcept
520+
{
521+
if constexpr (underlying_digits == 8)
522+
{
523+
size_type byte_index{pos >> 3}; // pos / 8
524+
size_type bit_index{pos & 7}; // pos % 8
525+
526+
underlying_type &byteval = imp.begin_ptr[byte_index];
527+
underlying_type mask = static_cast<underlying_type>(1u << bit_index);
528+
529+
// Toggle the bit (branchless)
530+
byteval ^= mask;
531+
}
532+
else
533+
{
534+
size_type byte_index{pos / underlying_digits};
535+
size_type bit_index{pos % underlying_digits};
536+
537+
underlying_type &byteval = imp.begin_ptr[byte_index];
538+
underlying_type mask =
539+
static_cast<underlying_type>(1u << bit_index);
540+
541+
byteval ^= mask;
542+
}
543+
}
544+
545+
inline constexpr void flip(size_type pos) noexcept
546+
{
547+
if (this->imp.curr_pos <= pos) [[unlikely]]
548+
{
549+
::fast_io::fast_terminate();
550+
}
551+
this->flip_unchecked(pos);
552+
}
553+
554+
inline constexpr void flip_front_unchecked() noexcept
555+
{
556+
// front bit is always bit 0 of byte 0
557+
constexpr underlying_type mask = static_cast<underlying_type>(1u);
558+
(*imp.begin_ptr) ^= mask;
559+
}
560+
inline constexpr void flip_front() noexcept
561+
{
562+
if (!this->imp.curr_pos) [[unlikely]]
563+
{
564+
::fast_io::fast_terminate();
565+
}
566+
this->flip_front_unchecked();
567+
}
568+
569+
inline constexpr void flip_back_unchecked() noexcept
570+
{
571+
size_type bitpos{imp.curr_pos - 1};
572+
573+
if constexpr (underlying_digits == 8)
574+
{
575+
size_type byte_index{bitpos >> 3}; // bitpos / 8
576+
size_type bit_index{bitpos & 7}; // bitpos % 8
577+
578+
underlying_type &byteval = imp.begin_ptr[byte_index];
579+
underlying_type mask = static_cast<underlying_type>(1u << bit_index);
580+
581+
byteval ^= mask;
582+
}
583+
else
584+
{
585+
size_type byte_index{bitpos / underlying_digits};
586+
size_type bit_index{bitpos % underlying_digits};
587+
588+
underlying_type &byteval = imp.begin_ptr[byte_index];
589+
underlying_type mask =
590+
static_cast<underlying_type>(1u << bit_index);
591+
592+
byteval ^= mask;
593+
}
594+
}
595+
596+
inline constexpr void flip_back() noexcept
597+
{
598+
if (!this->imp.curr_pos) [[unlikely]]
599+
{
600+
::fast_io::fast_terminate();
601+
}
602+
this->flip_back_unchecked();
603+
}
604+
519605
constexpr bitvec(bitvec &&other) noexcept : imp{other.imp}
520606
{
521607
other.imp = {};

tests/0026.container/0014.bitvec/bitvec.cc

Lines changed: 87 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -238,9 +238,10 @@ inline void test_bitvec_copy_assignment()
238238
::fast_io::bitvec src;
239239
::fast_io::bitvec dst;
240240

241+
// Use a valid mask: (i & 7u) can equal 2u
241242
for (::std::size_t i{}; i != 3000u; ++i)
242243
{
243-
src.push_back((i & 5u) == 2u);
244+
src.push_back((i & 7u) == 2u);
244245
}
245246

246247
// Fill dst with garbage first
@@ -273,7 +274,7 @@ inline void test_bitvec_copy_assignment()
273274
// dst must remain unchanged
274275
for (::std::size_t i{}; i != dst.size(); ++i)
275276
{
276-
bool expected = ((i & 5u) == 2u);
277+
bool expected = ((i & 7u) == 2u);
277278
if (dst.test(i) != expected)
278279
{
279280
::fast_io::io::panicln("ERROR: deep copy violated in assignment at index ", i);
@@ -285,7 +286,7 @@ inline void test_bitvec_copy_assignment()
285286

286287
for (::std::size_t i{}; i != dst.size(); ++i)
287288
{
288-
bool expected = ((i & 5u) == 2u);
289+
bool expected = ((i & 7u) == 2u);
289290
if (dst.test(i) != expected)
290291
{
291292
::fast_io::io::panicln("ERROR: self-assignment changed data at index ", i);
@@ -331,6 +332,88 @@ inline void test_bitvec_move()
331332
::fast_io::io::print("bitvec move test finished\n");
332333
}
333334

335+
inline void test_bitvec_flip()
336+
{
337+
::fast_io::io::perr("=== bitvec flip test ===\n");
338+
339+
::fast_io::bitvec bv;
340+
341+
// Push 64 bits: 0 1 0 1 0 1 ...
342+
for (::std::size_t i{}; i != 64u; ++i)
343+
{
344+
bv.push_back((i & 1u) != 0u);
345+
}
346+
347+
// Flip all bits using checked flip()
348+
for (::std::size_t i{}; i != 64u; ++i)
349+
{
350+
bv.flip(i);
351+
}
352+
353+
// Verify: all bits should now be inverted
354+
for (::std::size_t i{}; i != 64u; ++i)
355+
{
356+
bool expected = ((i & 1u) == 0u); // original was (i&1)!=0, so flipped
357+
if (bv.test(i) != expected)
358+
{
359+
::fast_io::io::panicln("ERROR: flip() mismatch at index ", i);
360+
}
361+
}
362+
363+
// Flip again using unchecked version → should restore original pattern
364+
for (::std::size_t i{}; i != 64u; ++i)
365+
{
366+
bv.flip_unchecked(i);
367+
}
368+
369+
for (::std::size_t i{}; i != 64u; ++i)
370+
{
371+
bool expected = (i & 1u) != 0u;
372+
if (bv.test(i) != expected)
373+
{
374+
::fast_io::io::panicln("ERROR: flip_unchecked() mismatch at index ", i);
375+
}
376+
}
377+
378+
// Test flip_front and flip_back
379+
// Current front = 0, back = 1
380+
if (bv.test_front() != false)
381+
{
382+
::fast_io::io::panic("ERROR: test_front mismatch before flip_front\n");
383+
}
384+
if (bv.test_back() != true)
385+
{
386+
::fast_io::io::panic("ERROR: test_back mismatch before flip_back\n");
387+
}
388+
389+
bv.flip_front();
390+
if (bv.test_front() != true)
391+
{
392+
::fast_io::io::panic("ERROR: flip_front failed\n");
393+
}
394+
395+
bv.flip_back();
396+
if (bv.test_back() != false)
397+
{
398+
::fast_io::io::panic("ERROR: flip_back failed\n");
399+
}
400+
401+
// Now test unchecked versions
402+
bv.flip_front_unchecked();
403+
if (bv.test_front() != false)
404+
{
405+
::fast_io::io::panic("ERROR: flip_front_unchecked failed\n");
406+
}
407+
408+
bv.flip_back_unchecked();
409+
if (bv.test_back() != true)
410+
{
411+
::fast_io::io::panic("ERROR: flip_back_unchecked failed\n");
412+
}
413+
414+
::fast_io::io::print("bitvec flip test finished\n");
415+
}
416+
334417
int main()
335418
{
336419
test_bitvec_basic();
@@ -340,6 +423,7 @@ int main()
340423
test_bitvec_copy_constructor();
341424
test_bitvec_copy_assignment();
342425
test_bitvec_move();
426+
test_bitvec_flip();
343427

344428
::fast_io::io::print("All bitvec tests finished\n");
345429
}

0 commit comments

Comments
 (0)