Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 115 additions & 0 deletions fuzzing/0007.containers/deque/fuzz_deque_append.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#include <fast_io.h>
#include <fast_io_dsal/deque.h>
#include <deque>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <ranges>
#include <vector>

extern "C" int LLVMFuzzerTestOneInput(uint8_t const *data, size_t size)
{
::fast_io::deque<std::size_t> dq;
std::deque<std::size_t> ref;

for (size_t i{}; i != size; ++i)
{
uint8_t b = data[i];

uint8_t op = b & 0x7u; // now 8 operations (0–7)
std::size_t len = (b >> 3) & 0x7u; // insert 0–7 elements

// Always valid position: [0, size]
std::size_t pos = dq.size() == 0 ? 0 : (static_cast<std::size_t>(b) * 37u) % (dq.size() + 1);

// Build deterministic range
std::vector<std::size_t> rg;
rg.reserve(len);
for (std::size_t j{}; j < len; ++j)
{
rg.push_back(i * 1315423911ull + j);
}

switch (op)
{
case 0: // insert_range_index
{
dq.insert_range_index(pos, rg);
ref.insert(ref.begin() + pos, rg.begin(), rg.end());
break;
}

case 1: // insert_range using iterator
{
auto it = dq.insert_range(dq.cbegin() + pos, rg);
(void)it;
ref.insert(ref.begin() + pos, rg.begin(), rg.end());
break;
}

case 2: // erase single element
{
if (!ref.empty())
{
std::size_t p = pos % ref.size();
dq.erase_index(p);
ref.erase(ref.begin() + p);
}
break;
}

case 3: // erase small range
{
if (!ref.empty())
{
std::size_t p = pos % ref.size();
std::size_t rlen = len % (ref.size() - p);
dq.erase_index(p, p + rlen);
ref.erase(ref.begin() + p, ref.begin() + p + rlen);
}
break;
}

case 4: // append_range
{
dq.append_range(rg);
ref.insert(ref.end(), rg.begin(), rg.end());
break;
}

case 5: // prepend_range
{
dq.prepend_range(rg);
ref.insert(ref.begin(), rg.begin(), rg.end());
break;
}

case 6: // push_back single (optional extra fuzz)
{
dq.push_back(i);
ref.push_back(i);
break;
}

case 7: // push_front single (optional extra fuzz)
{
dq.push_front(i);
ref.push_front(i);
break;
}
}

// Validate correctness
if (dq.size() != ref.size())
{
__builtin_trap();
}

if (!std::ranges::equal(dq, ref))
{
__builtin_trap();
}
}

return 0;
}
139 changes: 88 additions & 51 deletions include/fast_io_dsal/impl/deque.h
Original file line number Diff line number Diff line change
Expand Up @@ -2363,6 +2363,44 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE
size_type pos;
iterator it;
};
template <::std::ranges::range R>
requires ::std::constructible_from<value_type, ::std::ranges::range_value_t<R>>
inline constexpr insert_range_result insert_range_front_impl(size_type pos, R &&rg, size_type rgsize) noexcept(::std::is_nothrow_constructible_v<value_type, ::std::ranges::range_value_t<R>>)
{
::fast_io::containers::details::deque_reserve_front_spaces<allocator,
alignof(value_type), sizeof(value_type), block_size>(this->controller, rgsize);
auto thisbg{this->begin()};
auto posit{thisbg + pos};
auto thisbgrgsize{thisbg - rgsize};
auto thisbgrgsizenew{::fast_io::freestanding::uninitialized_relocate(thisbg,
posit, thisbgrgsize)};
::fast_io::freestanding::uninitialized_copy_n(::std::ranges::cbegin(rg), rgsize, thisbgrgsizenew);

this->controller.front_block = thisbgrgsize.itercontent;
this->controller.front_end_ptr = thisbgrgsize.itercontent.begin_ptr + block_size;
return {pos, thisbgrgsizenew};
}
template <::std::ranges::range R>
requires ::std::constructible_from<value_type, ::std::ranges::range_value_t<R>>
inline constexpr insert_range_result insert_range_back_impl(size_type pos, R &&rg, size_type rgsize) noexcept(::std::is_nothrow_constructible_v<value_type, ::std::ranges::range_value_t<R>>)
{
::fast_io::containers::details::deque_reserve_back_spaces<allocator,
alignof(value_type), sizeof(value_type), block_size>(this->controller, rgsize);
auto posit{this->begin() + pos};
auto thisend{this->end()};
auto thisendrgsize{thisend + rgsize};
::fast_io::freestanding::uninitialized_relocate_backward(posit,
thisend, thisendrgsize);
::fast_io::freestanding::uninitialized_copy_n(::std::ranges::cbegin(rg), rgsize, posit);
if (thisendrgsize.itercontent.begin_ptr == thisendrgsize.itercontent.curr_ptr)
{
thisendrgsize.itercontent.curr_ptr =
(thisendrgsize.itercontent.begin_ptr = *--thisendrgsize.itercontent.controller_ptr) + block_size;
}
this->controller.back_block = thisendrgsize.itercontent;
this->controller.back_end_ptr = thisendrgsize.itercontent.begin_ptr + block_size;
return {pos, posit};
}
template <::std::ranges::range R>
requires ::std::constructible_from<value_type, ::std::ranges::range_value_t<R>>
inline constexpr insert_range_result insert_range_impl(size_type pos, R &&rg, size_type old_size) noexcept(::std::is_nothrow_constructible_v<value_type, ::std::ranges::range_value_t<R>>)
Expand All @@ -2377,37 +2415,11 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE
size_type const half_size{old_size >> 1u};
if (pos < half_size)
{
::fast_io::containers::details::deque_reserve_front_spaces<allocator,
alignof(value_type), sizeof(value_type), block_size>(this->controller, rgsize);
auto thisbg{this->begin()};
auto posit{thisbg + pos};
auto thisbgrgsize{thisbg - rgsize};
auto thisbgrgsizenew{::fast_io::freestanding::uninitialized_relocate(thisbg,
posit, thisbgrgsize)};
::fast_io::freestanding::uninitialized_copy_n(::std::ranges::cbegin(rg), rgsize, thisbgrgsizenew);

this->controller.front_block = thisbgrgsize.itercontent;
this->controller.front_end_ptr = thisbgrgsize.itercontent.begin_ptr + block_size;
return {pos, thisbgrgsizenew};
return this->insert_range_front_impl(pos, ::std::forward<R>(rg), rgsize);
}
else
{
::fast_io::containers::details::deque_reserve_back_spaces<allocator,
alignof(value_type), sizeof(value_type), block_size>(this->controller, rgsize);
auto posit{this->begin() + pos};
auto thisend{this->end()};
auto thisendrgsize{thisend + rgsize};
::fast_io::freestanding::uninitialized_relocate_backward(posit,
thisend, thisendrgsize);
::fast_io::freestanding::uninitialized_copy_n(::std::ranges::cbegin(rg), rgsize, posit);
if (thisendrgsize.itercontent.begin_ptr == thisendrgsize.itercontent.curr_ptr)
{
thisendrgsize.itercontent.curr_ptr =
(thisendrgsize.itercontent.begin_ptr = *--thisendrgsize.itercontent.controller_ptr) + block_size;
}
this->controller.back_block = thisendrgsize.itercontent;
this->controller.back_end_ptr = thisendrgsize.itercontent.begin_ptr + block_size;
return {pos, posit};
return this->insert_range_back_impl(pos, ::std::forward<R>(rg), rgsize);
}
}
else
Expand Down Expand Up @@ -2447,7 +2459,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE
inline constexpr iterator insert_range(const_iterator pos, R &&rg) noexcept(::std::is_nothrow_constructible_v<value_type, ::std::ranges::range_value_t<R>>)
{
return this->insert_range_impl(
::fast_io::containers::details::deque_iter_difference_unsigned_common(pos.itercontent, this->controller.front_block), rg, this->size())
::fast_io::containers::details::deque_iter_difference_unsigned_common(pos.itercontent, this->controller.front_block), ::std::forward<R>(rg), this->size())
.it;
}

Expand All @@ -2460,7 +2472,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE
{
::fast_io::fast_terminate();
}
return this->insert_range_impl(pos, rg, n).pos;
return this->insert_range_impl(pos, ::std::forward<R>(rg), n).pos;
}

private:
Expand Down Expand Up @@ -2492,22 +2504,35 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE
requires ::std::constructible_from<value_type, ::std::ranges::range_value_t<R>>
inline constexpr void append_range(R &&rg) noexcept(::std::is_nothrow_constructible_v<value_type, ::std::ranges::range_value_t<R>>)
{
// To do: cleanup code
if constexpr (::std::is_nothrow_constructible_v<value_type, ::std::ranges::range_value_t<R>>)
if constexpr (::std::ranges::sized_range<R>)
{
for (auto &e : rg)
size_type const rgsize{::std::ranges::size(rg)};
if (!rgsize)
{
this->push_back(e);
return;
}
// To do write append specific code without using insert_range
this->insert_range_back_impl(this->size(), ::std::forward<R>(rg), rgsize);
}
else
{
append_range_guard guard{this, this->size()};
for (auto &e : rg)
// To do: cleanup code
if constexpr (::std::is_nothrow_constructible_v<value_type, ::std::ranges::range_value_t<R>>)
{
this->push_back(e);
for (auto &e : rg)
{
this->push_back(e);
}
}
else
{
append_range_guard guard{this, this->size()};
for (auto &e : rg)
{
this->push_back(e);
}
guard.thisdeq = nullptr;
}
guard.thisdeq = nullptr;
}
}
#if 0
Expand All @@ -2531,27 +2556,39 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE
::std::is_nothrow_constructible_v<value_type, ::std::ranges::range_value_t<R>> &&
::std::is_nothrow_swappable_v<value_type>)
{
// To do: cleanup code
size_type oldn{this->size()};
if constexpr (
::std::is_nothrow_constructible_v<value_type, ::std::ranges::range_value_t<R>> &&
::std::is_nothrow_swappable_v<value_type>)
if constexpr (::std::ranges::sized_range<R>)
{
for (auto &e : rg)
size_type const rgsize{::std::ranges::size(rg)};
if (!rgsize)
{
this->push_front(e);
return;
}
::std::reverse(this->begin(), this->end() - oldn);
this->insert_range_front_impl(0, ::std::forward<R>(rg), rgsize);
}
else
{
prepend_range_guard guard{this, oldn};
for (auto &e : rg)
// To do: cleanup code
size_type oldn{this->size()};
if constexpr (
::std::is_nothrow_constructible_v<value_type, ::std::ranges::range_value_t<R>> &&
::std::is_nothrow_swappable_v<value_type>)
{
this->push_front(e);
for (auto &e : rg)
{
this->push_front(e);
}
::std::reverse(this->begin(), this->end() - oldn);
}
else
{
prepend_range_guard guard{this, oldn};
for (auto &e : rg)
{
this->push_front(e);
}
::std::reverse(this->begin(), this->end() - oldn);
guard.thisdeq = nullptr;
}
::std::reverse(this->begin(), this->end() - oldn);
guard.thisdeq = nullptr;
}
}

Expand Down
Loading