Skip to content

Commit b256638

Browse files
authored
Merge pull request #1269 from trcrsired/next
implement sized prepend_range and append_range (although there are still rooms for further optimizations)
2 parents 3cfbdd5 + bf6258b commit b256638

2 files changed

Lines changed: 203 additions & 51 deletions

File tree

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
#include <fast_io.h>
2+
#include <fast_io_dsal/deque.h>
3+
#include <deque>
4+
#include <cstddef>
5+
#include <cstdint>
6+
#include <cstring>
7+
#include <ranges>
8+
#include <vector>
9+
10+
extern "C" int LLVMFuzzerTestOneInput(uint8_t const *data, size_t size)
11+
{
12+
::fast_io::deque<std::size_t> dq;
13+
std::deque<std::size_t> ref;
14+
15+
for (size_t i{}; i != size; ++i)
16+
{
17+
uint8_t b = data[i];
18+
19+
uint8_t op = b & 0x7u; // now 8 operations (0–7)
20+
std::size_t len = (b >> 3) & 0x7u; // insert 0–7 elements
21+
22+
// Always valid position: [0, size]
23+
std::size_t pos = dq.size() == 0 ? 0 : (static_cast<std::size_t>(b) * 37u) % (dq.size() + 1);
24+
25+
// Build deterministic range
26+
std::vector<std::size_t> rg;
27+
rg.reserve(len);
28+
for (std::size_t j{}; j < len; ++j)
29+
{
30+
rg.push_back(i * 1315423911ull + j);
31+
}
32+
33+
switch (op)
34+
{
35+
case 0: // insert_range_index
36+
{
37+
dq.insert_range_index(pos, rg);
38+
ref.insert(ref.begin() + pos, rg.begin(), rg.end());
39+
break;
40+
}
41+
42+
case 1: // insert_range using iterator
43+
{
44+
auto it = dq.insert_range(dq.cbegin() + pos, rg);
45+
(void)it;
46+
ref.insert(ref.begin() + pos, rg.begin(), rg.end());
47+
break;
48+
}
49+
50+
case 2: // erase single element
51+
{
52+
if (!ref.empty())
53+
{
54+
std::size_t p = pos % ref.size();
55+
dq.erase_index(p);
56+
ref.erase(ref.begin() + p);
57+
}
58+
break;
59+
}
60+
61+
case 3: // erase small range
62+
{
63+
if (!ref.empty())
64+
{
65+
std::size_t p = pos % ref.size();
66+
std::size_t rlen = len % (ref.size() - p);
67+
dq.erase_index(p, p + rlen);
68+
ref.erase(ref.begin() + p, ref.begin() + p + rlen);
69+
}
70+
break;
71+
}
72+
73+
case 4: // append_range
74+
{
75+
dq.append_range(rg);
76+
ref.insert(ref.end(), rg.begin(), rg.end());
77+
break;
78+
}
79+
80+
case 5: // prepend_range
81+
{
82+
dq.prepend_range(rg);
83+
ref.insert(ref.begin(), rg.begin(), rg.end());
84+
break;
85+
}
86+
87+
case 6: // push_back single (optional extra fuzz)
88+
{
89+
dq.push_back(i);
90+
ref.push_back(i);
91+
break;
92+
}
93+
94+
case 7: // push_front single (optional extra fuzz)
95+
{
96+
dq.push_front(i);
97+
ref.push_front(i);
98+
break;
99+
}
100+
}
101+
102+
// Validate correctness
103+
if (dq.size() != ref.size())
104+
{
105+
__builtin_trap();
106+
}
107+
108+
if (!std::ranges::equal(dq, ref))
109+
{
110+
__builtin_trap();
111+
}
112+
}
113+
114+
return 0;
115+
}

include/fast_io_dsal/impl/deque.h

Lines changed: 88 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -2363,6 +2363,44 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE
23632363
size_type pos;
23642364
iterator it;
23652365
};
2366+
template <::std::ranges::range R>
2367+
requires ::std::constructible_from<value_type, ::std::ranges::range_value_t<R>>
2368+
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>>)
2369+
{
2370+
::fast_io::containers::details::deque_reserve_front_spaces<allocator,
2371+
alignof(value_type), sizeof(value_type), block_size>(this->controller, rgsize);
2372+
auto thisbg{this->begin()};
2373+
auto posit{thisbg + pos};
2374+
auto thisbgrgsize{thisbg - rgsize};
2375+
auto thisbgrgsizenew{::fast_io::freestanding::uninitialized_relocate(thisbg,
2376+
posit, thisbgrgsize)};
2377+
::fast_io::freestanding::uninitialized_copy_n(::std::ranges::cbegin(rg), rgsize, thisbgrgsizenew);
2378+
2379+
this->controller.front_block = thisbgrgsize.itercontent;
2380+
this->controller.front_end_ptr = thisbgrgsize.itercontent.begin_ptr + block_size;
2381+
return {pos, thisbgrgsizenew};
2382+
}
2383+
template <::std::ranges::range R>
2384+
requires ::std::constructible_from<value_type, ::std::ranges::range_value_t<R>>
2385+
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>>)
2386+
{
2387+
::fast_io::containers::details::deque_reserve_back_spaces<allocator,
2388+
alignof(value_type), sizeof(value_type), block_size>(this->controller, rgsize);
2389+
auto posit{this->begin() + pos};
2390+
auto thisend{this->end()};
2391+
auto thisendrgsize{thisend + rgsize};
2392+
::fast_io::freestanding::uninitialized_relocate_backward(posit,
2393+
thisend, thisendrgsize);
2394+
::fast_io::freestanding::uninitialized_copy_n(::std::ranges::cbegin(rg), rgsize, posit);
2395+
if (thisendrgsize.itercontent.begin_ptr == thisendrgsize.itercontent.curr_ptr)
2396+
{
2397+
thisendrgsize.itercontent.curr_ptr =
2398+
(thisendrgsize.itercontent.begin_ptr = *--thisendrgsize.itercontent.controller_ptr) + block_size;
2399+
}
2400+
this->controller.back_block = thisendrgsize.itercontent;
2401+
this->controller.back_end_ptr = thisendrgsize.itercontent.begin_ptr + block_size;
2402+
return {pos, posit};
2403+
}
23662404
template <::std::ranges::range R>
23672405
requires ::std::constructible_from<value_type, ::std::ranges::range_value_t<R>>
23682406
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>>)
@@ -2377,37 +2415,11 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE
23772415
size_type const half_size{old_size >> 1u};
23782416
if (pos < half_size)
23792417
{
2380-
::fast_io::containers::details::deque_reserve_front_spaces<allocator,
2381-
alignof(value_type), sizeof(value_type), block_size>(this->controller, rgsize);
2382-
auto thisbg{this->begin()};
2383-
auto posit{thisbg + pos};
2384-
auto thisbgrgsize{thisbg - rgsize};
2385-
auto thisbgrgsizenew{::fast_io::freestanding::uninitialized_relocate(thisbg,
2386-
posit, thisbgrgsize)};
2387-
::fast_io::freestanding::uninitialized_copy_n(::std::ranges::cbegin(rg), rgsize, thisbgrgsizenew);
2388-
2389-
this->controller.front_block = thisbgrgsize.itercontent;
2390-
this->controller.front_end_ptr = thisbgrgsize.itercontent.begin_ptr + block_size;
2391-
return {pos, thisbgrgsizenew};
2418+
return this->insert_range_front_impl(pos, ::std::forward<R>(rg), rgsize);
23922419
}
23932420
else
23942421
{
2395-
::fast_io::containers::details::deque_reserve_back_spaces<allocator,
2396-
alignof(value_type), sizeof(value_type), block_size>(this->controller, rgsize);
2397-
auto posit{this->begin() + pos};
2398-
auto thisend{this->end()};
2399-
auto thisendrgsize{thisend + rgsize};
2400-
::fast_io::freestanding::uninitialized_relocate_backward(posit,
2401-
thisend, thisendrgsize);
2402-
::fast_io::freestanding::uninitialized_copy_n(::std::ranges::cbegin(rg), rgsize, posit);
2403-
if (thisendrgsize.itercontent.begin_ptr == thisendrgsize.itercontent.curr_ptr)
2404-
{
2405-
thisendrgsize.itercontent.curr_ptr =
2406-
(thisendrgsize.itercontent.begin_ptr = *--thisendrgsize.itercontent.controller_ptr) + block_size;
2407-
}
2408-
this->controller.back_block = thisendrgsize.itercontent;
2409-
this->controller.back_end_ptr = thisendrgsize.itercontent.begin_ptr + block_size;
2410-
return {pos, posit};
2422+
return this->insert_range_back_impl(pos, ::std::forward<R>(rg), rgsize);
24112423
}
24122424
}
24132425
else
@@ -2447,7 +2459,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE
24472459
inline constexpr iterator insert_range(const_iterator pos, R &&rg) noexcept(::std::is_nothrow_constructible_v<value_type, ::std::ranges::range_value_t<R>>)
24482460
{
24492461
return this->insert_range_impl(
2450-
::fast_io::containers::details::deque_iter_difference_unsigned_common(pos.itercontent, this->controller.front_block), rg, this->size())
2462+
::fast_io::containers::details::deque_iter_difference_unsigned_common(pos.itercontent, this->controller.front_block), ::std::forward<R>(rg), this->size())
24512463
.it;
24522464
}
24532465

@@ -2460,7 +2472,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE
24602472
{
24612473
::fast_io::fast_terminate();
24622474
}
2463-
return this->insert_range_impl(pos, rg, n).pos;
2475+
return this->insert_range_impl(pos, ::std::forward<R>(rg), n).pos;
24642476
}
24652477

24662478
private:
@@ -2492,22 +2504,35 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE
24922504
requires ::std::constructible_from<value_type, ::std::ranges::range_value_t<R>>
24932505
inline constexpr void append_range(R &&rg) noexcept(::std::is_nothrow_constructible_v<value_type, ::std::ranges::range_value_t<R>>)
24942506
{
2495-
// To do: cleanup code
2496-
if constexpr (::std::is_nothrow_constructible_v<value_type, ::std::ranges::range_value_t<R>>)
2507+
if constexpr (::std::ranges::sized_range<R>)
24972508
{
2498-
for (auto &e : rg)
2509+
size_type const rgsize{::std::ranges::size(rg)};
2510+
if (!rgsize)
24992511
{
2500-
this->push_back(e);
2512+
return;
25012513
}
2514+
// To do write append specific code without using insert_range
2515+
this->insert_range_back_impl(this->size(), ::std::forward<R>(rg), rgsize);
25022516
}
25032517
else
25042518
{
2505-
append_range_guard guard{this, this->size()};
2506-
for (auto &e : rg)
2519+
// To do: cleanup code
2520+
if constexpr (::std::is_nothrow_constructible_v<value_type, ::std::ranges::range_value_t<R>>)
25072521
{
2508-
this->push_back(e);
2522+
for (auto &e : rg)
2523+
{
2524+
this->push_back(e);
2525+
}
2526+
}
2527+
else
2528+
{
2529+
append_range_guard guard{this, this->size()};
2530+
for (auto &e : rg)
2531+
{
2532+
this->push_back(e);
2533+
}
2534+
guard.thisdeq = nullptr;
25092535
}
2510-
guard.thisdeq = nullptr;
25112536
}
25122537
}
25132538
#if 0
@@ -2531,27 +2556,39 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE
25312556
::std::is_nothrow_constructible_v<value_type, ::std::ranges::range_value_t<R>> &&
25322557
::std::is_nothrow_swappable_v<value_type>)
25332558
{
2534-
// To do: cleanup code
2535-
size_type oldn{this->size()};
2536-
if constexpr (
2537-
::std::is_nothrow_constructible_v<value_type, ::std::ranges::range_value_t<R>> &&
2538-
::std::is_nothrow_swappable_v<value_type>)
2559+
if constexpr (::std::ranges::sized_range<R>)
25392560
{
2540-
for (auto &e : rg)
2561+
size_type const rgsize{::std::ranges::size(rg)};
2562+
if (!rgsize)
25412563
{
2542-
this->push_front(e);
2564+
return;
25432565
}
2544-
::std::reverse(this->begin(), this->end() - oldn);
2566+
this->insert_range_front_impl(0, ::std::forward<R>(rg), rgsize);
25452567
}
25462568
else
25472569
{
2548-
prepend_range_guard guard{this, oldn};
2549-
for (auto &e : rg)
2570+
// To do: cleanup code
2571+
size_type oldn{this->size()};
2572+
if constexpr (
2573+
::std::is_nothrow_constructible_v<value_type, ::std::ranges::range_value_t<R>> &&
2574+
::std::is_nothrow_swappable_v<value_type>)
25502575
{
2551-
this->push_front(e);
2576+
for (auto &e : rg)
2577+
{
2578+
this->push_front(e);
2579+
}
2580+
::std::reverse(this->begin(), this->end() - oldn);
2581+
}
2582+
else
2583+
{
2584+
prepend_range_guard guard{this, oldn};
2585+
for (auto &e : rg)
2586+
{
2587+
this->push_front(e);
2588+
}
2589+
::std::reverse(this->begin(), this->end() - oldn);
2590+
guard.thisdeq = nullptr;
25522591
}
2553-
::std::reverse(this->begin(), this->end() - oldn);
2554-
guard.thisdeq = nullptr;
25552592
}
25562593
}
25572594

0 commit comments

Comments
 (0)