From 2f689aa24a26f1002e8711f296ff21fb3a607497 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Wed, 29 Apr 2026 06:52:52 +0800 Subject: [PATCH 01/82] [deque] add placeholders for remaining 7 functions that are not yet implemented --- include/fast_io_dsal/impl/deque.h | 33 ++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index ec46a2ce8..0aa8f2c5c 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -2853,12 +2853,32 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE } #if 0 +/* +Todo: +*/ inline constexpr iterator insert(const_iterator iter, size_type count, const_reference val) noexcept(::std::is_nothrow_copy_constructible_v) { } inline constexpr iterator insert_index(size_type idx, size_type count, const_reference val) noexcept(::std::is_nothrow_copy_constructible_v) { - + } + + inline constexpr void assign(size_type count, const_reference val) noexcept(::std::is_nothrow_copy_constructible_v) + { + } + template <::std::ranges::range R> + requires ::std::constructible_from> + inline constexpr void assign_range(R &&rg) noexcept(::std::is_nothrow_constructible_v>) + { + } + inline constexpr void shrink_to_fit() noexcept(::std::is_nothrow_move_constructible_v) + { + } + inline constexpr void resize(size_type count) noexcept(::std::is_nothrow_default_constructible_v&&::std::is_nothrow_move_constructible_v) + { + } + inline constexpr void resize(size_type count, const_reference value) noexcept(::std::is_nothrow_copy_constructible_v&&::std::is_nothrow_move_constructible_v) + { } #endif private: @@ -2993,8 +3013,19 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { destroy_deque_controller(this->controller); } + + inline constexpr void swap(deque &rhs) noexcept + { + ::std::swap(this->controller, rhs.controller); + } }; +template +inline constexpr void swap(::fast_io::containers::deque &lhs, ::fast_io::containers::deque &rhs) noexcept +{ + lhs.swap(rhs); +} + template requires ::std::equality_comparable inline constexpr bool operator==(::fast_io::containers::deque const &lhs, ::fast_io::containers::deque const &rhs) noexcept From b45eeb69170b1c502995e11ce8706b4da7a06a6e Mon Sep 17 00:00:00 2001 From: trcrsired Date: Wed, 29 Apr 2026 07:10:01 +0800 Subject: [PATCH 02/82] [deque] operator= should optimize for assign_range for deque --- include/fast_io_dsal/impl/deque.h | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index 0aa8f2c5c..2daa596f3 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -1625,11 +1625,23 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { return *this; } - deque temp(other); - destroy_deque_controller(this->controller); - this->controller = temp.controller; - temp.controller = {}; - return *this; +#if 0 + if constexpr (::std::is_nothrow_copy_constructible_v && + ::std::is_nothrow_copy_assignable_v) + { +// Path A: High-performance reuse of existing blocks + this->assign(other.begin(), other.end()); + } + else +#endif + { + // Path B: Strong Exception Guarantee via Creating a Temporary + deque temp(other); + destroy_deque_controller(this->controller); + this->controller = temp.controller; + temp.controller = {}; + return *this; + } } inline constexpr deque(deque &&other) noexcept : controller(other.controller) From dbb152a725a8143cb00105c1691b401d0aa1d88b Mon Sep 17 00:00:00 2001 From: trcrsired Date: Wed, 29 Apr 2026 07:11:31 +0800 Subject: [PATCH 03/82] [deque] other did not get written fully --- include/fast_io_dsal/impl/deque.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index 2daa596f3..6b5280806 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -1630,7 +1630,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE ::std::is_nothrow_copy_assignable_v) { // Path A: High-performance reuse of existing blocks - this->assign(other.begin(), other.end()); + this->assign_range(other); } else #endif From 7898be1284c4064a7558a618324506c155324af4 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Wed, 29 Apr 2026 07:15:13 +0800 Subject: [PATCH 04/82] [deque] remove a redundant empty line for emplace_index_decision_common --- include/fast_io_dsal/impl/deque.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index 6b5280806..9b7beebf0 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -2730,7 +2730,6 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE [[unreachable]]; #endif } -#if 1 else if (idx == oldsize) { if (this->controller.back_block.curr_ptr != controller.back_end_ptr) [[likely]] @@ -2761,7 +2760,6 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE } } } -#endif auto result{this->emplace_index_impl(idx, oldsize)}; pointer retptr{result.it.itercontent.curr_ptr}; if constexpr (isnothrow) From 6cb8f5371ef2ca7da1a9f1d64d783196fc3eb1cc Mon Sep 17 00:00:00 2001 From: trcrsired Date: Thu, 30 Apr 2026 05:37:18 +0800 Subject: [PATCH 05/82] [deque] implement insert for many elements --- include/fast_io_dsal/impl/deque.h | 48 +++- .../0003.deque/insert_middle.cc | 214 ++++++++++++++++++ 2 files changed, 255 insertions(+), 7 deletions(-) create mode 100644 tests/0026.container/0003.deque/insert_middle.cc diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index 9b7beebf0..7e6761806 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -2721,7 +2721,6 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE pointer, emplace_index_decision> emplace_index_decision_common(::std::size_t idx) noexcept { - auto oldsize{this->size()}; if (oldsize < idx) [[unlikely]] { @@ -2862,17 +2861,52 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE return this->emplace_index(idx, ::std::move(val)); } -#if 0 -/* -Todo: -*/ + +private: + struct insert_index_guard + { + deque *thisdeq; + size_type pos, count; + constexpr ~insert_index_guard() + { + if (thisdeq) [[unlikely]] + { + thisdeq->erase_index(pos, pos + count); + } + } + }; + + inline constexpr insert_range_result insert_index_impl(size_type idx, size_type count, const_reference val, size_type oldn) noexcept(::std::is_nothrow_copy_constructible_v) + { + insert_range_result res{this->emplace_index_n_impl(idx, count, oldn)}; + if constexpr (::std::is_nothrow_copy_constructible_v) + { + ::fast_io::freestanding::uninitialized_fill_n(res.it, count, val); + } + else + { + insert_index_guard g{this, res.pos, count}; + ::fast_io::freestanding::uninitialized_fill_n(res.it, count, val); + g.thisdeq = nullptr; + } + return res; + } + +public: inline constexpr iterator insert(const_iterator iter, size_type count, const_reference val) noexcept(::std::is_nothrow_copy_constructible_v) { + return this->insert_index_impl(::fast_io::containers::details::deque_iter_difference_unsigned_common(iter.itercontent, this->controller.front_block), count, val, this->size()).it; } - inline constexpr iterator insert_index(size_type idx, size_type count, const_reference val) noexcept(::std::is_nothrow_copy_constructible_v) + inline constexpr size_type insert_index(size_type idx, size_type count, const_reference val) noexcept(::std::is_nothrow_copy_constructible_v) { + size_type const n{this->size()}; + if (n < idx) [[unlikely]] + { + ::fast_io::fast_terminate(); + } + return this->insert_index_impl(idx, count, val, n).pos; } - +#if 0 inline constexpr void assign(size_type count, const_reference val) noexcept(::std::is_nothrow_copy_constructible_v) { } diff --git a/tests/0026.container/0003.deque/insert_middle.cc b/tests/0026.container/0003.deque/insert_middle.cc new file mode 100644 index 000000000..f369d2c73 --- /dev/null +++ b/tests/0026.container/0003.deque/insert_middle.cc @@ -0,0 +1,214 @@ +#include +#include +#include + +namespace +{ + +inline void test_insert_middle() +{ + ::fast_io::io::perr("=== deque insert middle test ===\n"); + + ::fast_io::deque<::std::size_t> dq; + ::std::deque<::std::size_t> ref; + + // Add some elements + for (::std::size_t i = 0; i < 100; ++i) + { + dq.push_back(i); + ref.push_back(i); + } + + auto check_equal = [&](auto const &msg, + ::std::source_location src = ::std::source_location::current()) { + if (dq.size() != ref.size()) + { + ::fast_io::io::panicln(src, "\tERROR: size mismatch: ", msg); + } + for (::std::size_t i = 0; i < dq.size(); ++i) + { + if (dq[i] != ref[i]) + { + ::fast_io::io::panicln(src, "\tERROR: value mismatch at ", i, " dq=", dq[i], " ref=", ref[i], " : ", msg); + } + } + }; + + // Insert at position 50 (middle) + dq.insert_index(50, 999); + ref.insert(ref.begin() + 50, 999); + check_equal("insert at middle"); + + // Insert at position 0 (front) + dq.insert_index(0, 888); + ref.insert(ref.begin(), 888); + check_equal("insert at front"); + + // Insert at end + dq.insert_index(dq.size(), 777); + ref.insert(ref.end(), 777); + check_equal("insert at end"); + + // Randomized insertions + for (::std::size_t iter = 0; iter < 200; ++iter) + { + ::std::size_t pos = iter % (dq.size() + 1); + dq.insert_index(pos, iter + 1000); + ref.insert(ref.begin() + pos, iter + 1000); + check_equal("randomized insert"); + } + + ::fast_io::io::print("deque insert middle test finished\n"); +} + +inline void test_insert_count_value() +{ + ::fast_io::io::perr("=== deque insert(count, value) test ===\n"); + + using T = std::size_t; + ::fast_io::deque dq; + std::deque ref; + + // Fill initial data + for (std::size_t i{}; i != 200u; ++i) + { + dq.push_back(i); + ref.push_back(i); + } + + auto check_equal = [&](auto const &msg, + std::source_location src = std::source_location::current()) { + if (dq.size() != ref.size()) + { + ::fast_io::io::panicln(src, "\tERROR: size mismatch: ", msg); + } + for (std::size_t i{}; i != dq.size(); ++i) + { + if (dq[i] != ref[i]) + { + ::fast_io::io::panicln(src, + "\tERROR: value mismatch at index ", i, + "\tdq[i]=", dq[i], "\tref[i]=", ref[i], + " : ", msg); + } + } + }; + + // 1. Insert at front + { + dq.insert(dq.begin(), 5, 9999); + ref.insert(ref.begin(), 5, 9999); + check_equal("insert(count,val) at front"); + } + + // 2. Insert at middle + { + std::size_t pos = dq.size() / 2; + dq.insert(dq.begin() + pos, 3, 7777); + ref.insert(ref.begin() + pos, 3, 7777); + check_equal("insert(count,val) at middle"); + } + + // 3. Insert at back + { + dq.insert(dq.end(), 4, 5555); + ref.insert(ref.end(), 4, 5555); + check_equal("insert(count,val) at back"); + } + + // 4. Randomized insertions + for (std::size_t iter{}; iter != 200u; ++iter) + { + std::size_t pos = iter % (dq.size() + 1); + std::size_t count = (iter % 4) + 1; + std::size_t val = iter + 3000; + + dq.insert(dq.begin() + pos, count, val); + ref.insert(ref.begin() + pos, count, val); + + check_equal("randomized insert(count,val)"); + } + + ::fast_io::io::print("deque insert(count,val) test finished\n"); +} + +inline void test_insert_index_count_value() +{ + ::fast_io::io::perr("=== deque insert_index(count, value) test ===\n"); + + using T = std::size_t; + ::fast_io::deque dq; + std::deque ref; + + // Fill initial data + for (std::size_t i{}; i != 200u; ++i) + { + dq.push_back(i); + ref.push_back(i); + } + + auto check_equal = [&](auto const &msg, + std::source_location src = std::source_location::current()) { + if (dq.size() != ref.size()) + { + ::fast_io::io::panicln(src, "\tERROR: size mismatch: ", msg); + } + for (std::size_t i{}; i != dq.size(); ++i) + { + if (dq[i] != ref[i]) + { + ::fast_io::io::panicln(src, + "\tERROR: value mismatch at index ", i, + "\tdq[i]=", dq[i], "\tref[i]=", ref[i], + " : ", msg); + } + } + }; + + // 1. Insert at front + { + dq.insert_index(0, 5, 9999); + ref.insert(ref.begin(), 5, 9999); + check_equal("insert_index(count,val) at front"); + } + + // 2. Insert at middle + { + std::size_t pos = dq.size() / 2; + dq.insert_index(pos, 3, 7777); + ref.insert(ref.begin() + pos, 3, 7777); + check_equal("insert_index(count,val) at middle"); + } + + // 3. Insert at back + { + std::size_t pos = dq.size(); + dq.insert_index(pos, 4, 5555); + ref.insert(ref.end(), 4, 5555); + check_equal("insert_index(count,val) at back"); + } + + // 4. Randomized insertions + for (std::size_t iter{}; iter != 200u; ++iter) + { + std::size_t pos = iter % (dq.size() + 1); + std::size_t count = (iter % 4) + 1; + std::size_t val = iter + 4000; + + dq.insert_index(pos, count, val); + ref.insert(ref.begin() + pos, count, val); + + check_equal("randomized insert_index(count,val)"); + } + + ::fast_io::io::print("deque insert_index(count,val) test finished\n"); +} + +} // namespace + +int main() +{ + test_insert_middle(); + test_insert_count_value(); + test_insert_index_count_value(); +} \ No newline at end of file From 66cd6148ef7be52f27549c1f00191d85f20e1e64 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Thu, 30 Apr 2026 05:50:45 +0800 Subject: [PATCH 06/82] [deque] erase needs some special treatment for insert --- include/fast_io_dsal/impl/deque.h | 41 +++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index 7e6761806..981024a92 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -2871,7 +2871,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { if (thisdeq) [[unlikely]] { - thisdeq->erase_index(pos, pos + count); + thisdeq->erase_unchecked_nodestroy_for_insert_counts_impl(pos, count); } } }; @@ -2950,16 +2950,9 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE this->controller.back_end_ptr = back_block.begin_ptr + block_size; return first; } - inline constexpr iterator erase_unchecked_impl(iterator first, iterator last, bool moveleft) noexcept + + inline constexpr iterator erase_unchecked_nodestroy_impl(iterator first, iterator last, bool moveleft) noexcept { - if (first == last) - { - return first; - } - if constexpr (!::std::is_trivially_destructible_v) - { - this->destroy_elements_range(first, last); - } if constexpr (::fast_io::freestanding::is_trivially_copyable_or_relocatable_v) { if !consteval @@ -2975,6 +2968,34 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE } return this->erase_no_destroy_common_impl(first, last, moveleft); } + inline constexpr void erase_unchecked_nodestroy_for_insert_counts_impl(iterator first, ::std::size_t count) noexcept + { + if (!count) + { + return; + } + + ::std::size_t const distofront{ + ::fast_io::containers::details::deque_iter_difference_unsigned_common(first, this->controller.front_block)}; + + auto last{first + count}; + ::std::size_t const distoback{ + ::fast_io::containers::details::deque_iter_difference_unsigned_common(this->controller.last_block, last)}; + + this->erase_unchecked_nodestroy_impl(first, last, distofront < distoback); + } + inline constexpr iterator erase_unchecked_impl(iterator first, iterator last, bool moveleft) noexcept + { + if (first == last) + { + return first; + } + if constexpr (!::std::is_trivially_destructible_v) + { + this->destroy_elements_range(first, last); + } + this->erase_unchecked_nodestroy_impl(first, last, moveleft); + } inline constexpr iterator erase_unchecked_single_nodestroy_impl(iterator pos, bool moveleft) noexcept { if constexpr (::fast_io::freestanding::is_trivially_copyable_or_relocatable_v) From 8e4dfbc1490227b9033a64d0a3cb03aad8e4e866 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Thu, 30 Apr 2026 05:56:46 +0800 Subject: [PATCH 07/82] [deque] add fuzzing for insert with counts --- .../deque/fuzz_deque_insert_counts.cc | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 fuzzing/0007.containers/deque/fuzz_deque_insert_counts.cc diff --git a/fuzzing/0007.containers/deque/fuzz_deque_insert_counts.cc b/fuzzing/0007.containers/deque/fuzz_deque_insert_counts.cc new file mode 100644 index 000000000..e7d595aa7 --- /dev/null +++ b/fuzzing/0007.containers/deque/fuzz_deque_insert_counts.cc @@ -0,0 +1,85 @@ +#include +#include +#include +#include +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(uint8_t const *data, size_t size) +{ + ::fast_io::deque dq; + std::deque ref; + + for (size_t i{}; i != size; ++i) + { + uint8_t b = data[i]; + + // 4 operations: insert counts, erase, etc. + uint8_t op = b & 0x3u; + + // Position: [0, size] + std::size_t pos = + dq.size() == 0 ? 0 : (static_cast(b) * 131u) % (dq.size() + 1); + + // Count: small to avoid explosion + std::size_t count = (b >> 2) % 4; // 0–3 + if (count == 0) + { + count = 1; // avoid no‑op + } + + std::size_t value = i * 2654435761ull; + + switch (op) + { + case 0: // insert_index(count, value) + { + dq.insert_index(pos, count, value); + ref.insert(ref.begin() + pos, count, value); + break; + } + + case 1: // insert(iterator, count, value) + { + auto it = dq.insert(dq.cbegin() + pos, count, value); + (void)it; + ref.insert(ref.begin() + pos, count, value); + 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: // mix: insert_index with larger count + { + std::size_t big_count = (b % 5) + 1; // 1–5 + dq.insert_index(pos, big_count, value ^ 0x9E3779B97F4A7C15ull); + ref.insert(ref.begin() + pos, big_count, + value ^ 0x9E3779B97F4A7C15ull); + break; + } + } + + // Validate correctness + if (dq.size() != ref.size()) + { + __builtin_trap(); + } + + if (!std::ranges::equal(dq, ref)) + { + __builtin_trap(); + } + } + + return 0; +} From cb52690eb2c10311160e57ee588893d873331976 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Thu, 30 Apr 2026 05:59:24 +0800 Subject: [PATCH 08/82] [deque] return should not be missed in erase_unchecked_impl --- include/fast_io_dsal/impl/deque.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index 981024a92..352bbaa1a 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -2994,7 +2994,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { this->destroy_elements_range(first, last); } - this->erase_unchecked_nodestroy_impl(first, last, moveleft); + return this->erase_unchecked_nodestroy_impl(first, last, moveleft); } inline constexpr iterator erase_unchecked_single_nodestroy_impl(iterator pos, bool moveleft) noexcept { From 1c0f9222dcc9782b4f2628ba396f33c4ff2ea899 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Thu, 30 Apr 2026 07:08:15 +0800 Subject: [PATCH 09/82] [deque] shrink_to_fit not yet finished --- .../deque/fuzz_deque_shrink_to_fit.cc | 87 ++++++++++++++++ include/fast_io_dsal/impl/deque.h | 99 ++++++++++++++++++- 2 files changed, 183 insertions(+), 3 deletions(-) create mode 100644 fuzzing/0007.containers/deque/fuzz_deque_shrink_to_fit.cc diff --git a/fuzzing/0007.containers/deque/fuzz_deque_shrink_to_fit.cc b/fuzzing/0007.containers/deque/fuzz_deque_shrink_to_fit.cc new file mode 100644 index 000000000..a97a116a5 --- /dev/null +++ b/fuzzing/0007.containers/deque/fuzz_deque_shrink_to_fit.cc @@ -0,0 +1,87 @@ +#include +#include +#include +#include +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(uint8_t const *data, size_t size) +{ + ::fast_io::deque dq; + std::deque ref; + + for (size_t i{}; i != size; ++i) + { + uint8_t b = data[i]; + + // 0–3 → insert/erase + // 4–7 → shrink_to_fit + uint8_t op = b & 0x7u; + + // Position: [0, size] + std::size_t pos = + dq.size() == 0 ? 0 : (static_cast(b) * 131u) % (dq.size() + 1); + + std::size_t value = i * 11400714819323198485ull; + + switch (op) + { + case 0: // insert_index + { + dq.insert_index(pos, value); + ref.insert(ref.begin() + pos, value); + break; + } + + case 1: // insert(iterator) + { + dq.insert(dq.cbegin() + pos, value); + ref.insert(ref.begin() + pos, value); + break; + } + + case 2: // erase single + { + if (!ref.empty()) + { + std::size_t p = pos % ref.size(); + dq.erase_index(p); + ref.erase(ref.begin() + p); + } + break; + } + + case 3: // emplace_index + { + dq.emplace_index(pos, value); + ref.emplace(ref.begin() + pos, value); + break; + } + + case 4: // shrink_to_fit + case 5: + case 6: + case 7: + { + dq.shrink_to_fit(); + // std::deque::shrink_to_fit is non-binding but safe to call + ref.shrink_to_fit(); + break; + } + } + + // Validate correctness + if (dq.size() != ref.size()) + { + __builtin_trap(); + } + + if (!std::ranges::equal(dq, ref)) + { + __builtin_trap(); + } + } + + return 0; +} diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index 352bbaa1a..3848b09d9 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -745,6 +745,90 @@ inline constexpr void deque_init_space_common(dequecontroltype &controller, ::st back_curr_ptr += offset_for_back; } +template +inline constexpr void deque_shrink_to_fit_common(dequecontroltype &controller, ::std::size_t align, ::std::size_t block_bytes) noexcept +{ + if (controller.front_block.curr_ptr == controller.back_block.curr_ptr) + { + if (controller.front_block.curr_ptr == nullptr) + { + return; + } + ::fast_io::containers::details::deque_destroy_trivial_common_align(controller.controller_block, align, block_bytes); + controller = dequecontroltype{}; + return; + } + + auto &cb{controller.controller_block}; + auto start_reserved{cb.controller_start_reserved_ptr}; + auto const after_reserved{cb.controller_after_reserved_ptr}; + auto const front_ptr{controller.front_block.controller_ptr}; + auto const back_ptr{controller.back_block.controller_ptr}; + + auto const start_ptr{cb.controller_start_ptr}; + auto const after_ptr{cb.controller_after_ptr + 1}; + + // 1. Check if deallocation is needed for data blocks + // We use after_reserved vs back_ptr + 1 safely by checking boundaries + bool const needs_block_shrink = (start_reserved != front_ptr) || (after_reserved != (back_ptr + 1)); + + if (needs_block_shrink) + { + for (; start_reserved != front_ptr; ++start_reserved) + { + allocator::deallocate_aligned_n(*start_reserved, align, block_bytes); + } + // it is safe to start from back_ptr + 1 because if we are here, + // back_ptr must be within [start_ptr, after_ptr - 1] + for (auto it{back_ptr + 1}; it != after_reserved; ++it) + { + allocator::deallocate_aligned_n(*it, align, block_bytes); + } + } + + // 2. Controller Shrink Check + // If blocks were already tight AND the controller array is already tight, return + ::std::size_t const used_blocks_count{static_cast<::std::size_t>(back_ptr + 1 - front_ptr)}; + ::std::size_t const current_controller_size{static_cast<::std::size_t>(after_ptr - start_ptr)}; + + if (!needs_block_shrink && current_controller_size <= (used_blocks_count + 1u)) + { + return; + } + + // 3. Reallocate Controller + ::std::size_t const new_controller_size_least{used_blocks_count + 1u}; + using block_ptr_allocator = ::fast_io::typed_generic_allocator_adapter; + + // Note: reallocate_at_least_aligned_n might copy old pointers for us + auto [new_start_ptr, new_actual_count] = block_ptr_allocator::reallocate_n_at_least( + start_ptr, + current_controller_size, + new_controller_size_least); + + // 4. Pointer Patching (The Safe Way) + // We want the new reserved range to start at the very beginning of the new allocation + // Therefore, the front_block.controller_ptr is just new_start_ptr + // The back_block.controller_ptr is new_start_ptr + (used_blocks_count - 1) + + controller.front_block.controller_ptr = new_start_ptr; + controller.back_block.controller_ptr = new_start_ptr + (used_blocks_count - 1u); + + cb.controller_start_ptr = new_start_ptr; + cb.controller_start_reserved_ptr = new_start_ptr; + cb.controller_after_reserved_ptr = new_start_ptr + used_blocks_count; + cb.controller_after_ptr = new_start_ptr + new_actual_count - 1u; + + // 5. Set Sentinel + *(cb.controller_after_reserved_ptr) = nullptr; +} + +template +inline constexpr void deque_shrink_to_fit_impl(dequecontroltype &controller) noexcept +{ + ::fast_io::containers::details::deque_shrink_to_fit_common(controller, align, blockbytes); +} + template struct uninitialized_copy_n_for_deque_guard { @@ -2906,6 +2990,18 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE } return this->insert_index_impl(idx, count, val, n).pos; } + inline constexpr void shrink_to_fit() noexcept(::std::is_nothrow_move_constructible_v) + { + if consteval + { + ::fast_io::containers::details::deque_shrink_to_fit_impl(this->controller); + } + else + { + ::fast_io::containers::details::deque_shrink_to_fit_impl(*reinterpret_cast<::fast_io::containers::details::deque_controller_common *>(__builtin_addressof( + this->controller))); + } + } #if 0 inline constexpr void assign(size_type count, const_reference val) noexcept(::std::is_nothrow_copy_constructible_v) { @@ -2915,9 +3011,6 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE inline constexpr void assign_range(R &&rg) noexcept(::std::is_nothrow_constructible_v>) { } - inline constexpr void shrink_to_fit() noexcept(::std::is_nothrow_move_constructible_v) - { - } inline constexpr void resize(size_type count) noexcept(::std::is_nothrow_default_constructible_v&&::std::is_nothrow_move_constructible_v) { } From 819f1cf0aa61175a88776765db7a8c7765afdeba Mon Sep 17 00:00:00 2001 From: trcrsired Date: Thu, 30 Apr 2026 07:14:00 +0800 Subject: [PATCH 10/82] [deque] shrink to fit disable reallocating first --- include/fast_io_dsal/impl/deque.h | 40 +++++++++++++++++-------------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index 3848b09d9..8dcbff30e 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -784,6 +784,7 @@ inline constexpr void deque_shrink_to_fit_common(dequecontroltype &controller, : { allocator::deallocate_aligned_n(*it, align, block_bytes); } + back_ptr[1] = nullptr; } // 2. Controller Shrink Check @@ -796,28 +797,31 @@ inline constexpr void deque_shrink_to_fit_common(dequecontroltype &controller, : return; } - // 3. Reallocate Controller - ::std::size_t const new_controller_size_least{used_blocks_count + 1u}; - using block_ptr_allocator = ::fast_io::typed_generic_allocator_adapter; + if constexpr (false) + { + // 3. Reallocate Controller + ::std::size_t const new_controller_size_least{used_blocks_count + 1u}; + using block_ptr_allocator = ::fast_io::typed_generic_allocator_adapter; - // Note: reallocate_at_least_aligned_n might copy old pointers for us - auto [new_start_ptr, new_actual_count] = block_ptr_allocator::reallocate_n_at_least( - start_ptr, - current_controller_size, - new_controller_size_least); + // Note: reallocate_at_least_aligned_n might copy old pointers for us + auto [new_start_ptr, new_actual_count] = block_ptr_allocator::reallocate_n_at_least( + start_ptr, + current_controller_size, + new_controller_size_least); - // 4. Pointer Patching (The Safe Way) - // We want the new reserved range to start at the very beginning of the new allocation - // Therefore, the front_block.controller_ptr is just new_start_ptr - // The back_block.controller_ptr is new_start_ptr + (used_blocks_count - 1) + // 4. Pointer Patching (The Safe Way) + // We want the new reserved range to start at the very beginning of the new allocation + // Therefore, the front_block.controller_ptr is just new_start_ptr + // The back_block.controller_ptr is new_start_ptr + (used_blocks_count - 1) - controller.front_block.controller_ptr = new_start_ptr; - controller.back_block.controller_ptr = new_start_ptr + (used_blocks_count - 1u); + controller.front_block.controller_ptr = new_start_ptr; + controller.back_block.controller_ptr = new_start_ptr + (used_blocks_count - 1u); - cb.controller_start_ptr = new_start_ptr; - cb.controller_start_reserved_ptr = new_start_ptr; - cb.controller_after_reserved_ptr = new_start_ptr + used_blocks_count; - cb.controller_after_ptr = new_start_ptr + new_actual_count - 1u; + cb.controller_start_ptr = new_start_ptr; + cb.controller_start_reserved_ptr = new_start_ptr; + cb.controller_after_reserved_ptr = new_start_ptr + used_blocks_count; + cb.controller_after_ptr = new_start_ptr + new_actual_count - 1u; + } // 5. Set Sentinel *(cb.controller_after_reserved_ptr) = nullptr; From ebce68f88f96120ee34326ff4eae44c979e18541 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Thu, 30 Apr 2026 07:21:04 +0800 Subject: [PATCH 11/82] [deque] shrink_to_fit should always update the pointers --- include/fast_io_dsal/impl/deque.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index 8dcbff30e..b73e09949 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -778,13 +778,14 @@ inline constexpr void deque_shrink_to_fit_common(dequecontroltype &controller, : { allocator::deallocate_aligned_n(*start_reserved, align, block_bytes); } + cb.controller_start_reserved_ptr = front_ptr; // it is safe to start from back_ptr + 1 because if we are here, // back_ptr must be within [start_ptr, after_ptr - 1] for (auto it{back_ptr + 1}; it != after_reserved; ++it) { allocator::deallocate_aligned_n(*it, align, block_bytes); } - back_ptr[1] = nullptr; + *(cb.controller_after_reserved_ptr = back_ptr + 1) = nullptr; } // 2. Controller Shrink Check @@ -821,10 +822,11 @@ inline constexpr void deque_shrink_to_fit_common(dequecontroltype &controller, : cb.controller_start_reserved_ptr = new_start_ptr; cb.controller_after_reserved_ptr = new_start_ptr + used_blocks_count; cb.controller_after_ptr = new_start_ptr + new_actual_count - 1u; - } - // 5. Set Sentinel - *(cb.controller_after_reserved_ptr) = nullptr; + + // 5. Set Sentinel + *(cb.controller_after_reserved_ptr) = nullptr; + } } template From 71414d665d67c68c4fca57a145a0b145960dd971 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Thu, 30 Apr 2026 07:27:54 +0800 Subject: [PATCH 12/82] [deque] try to fully implement shrink_to_fit --- include/fast_io_dsal/impl/deque.h | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index b73e09949..8eab31db5 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -798,34 +798,33 @@ inline constexpr void deque_shrink_to_fit_common(dequecontroltype &controller, : return; } - if constexpr (false) + if constexpr (true) { // 3. Reallocate Controller ::std::size_t const new_controller_size_least{used_blocks_count + 1u}; + // 3. Manually Reallocate and Move Controller Array using block_ptr_allocator = ::fast_io::typed_generic_allocator_adapter; - // Note: reallocate_at_least_aligned_n might copy old pointers for us - auto [new_start_ptr, new_actual_count] = block_ptr_allocator::reallocate_n_at_least( - start_ptr, - current_controller_size, - new_controller_size_least); + // Allocate new, smaller controller array + auto [new_start_ptr, new_actual_count] = block_ptr_allocator::allocate_at_least(new_controller_size_least); - // 4. Pointer Patching (The Safe Way) - // We want the new reserved range to start at the very beginning of the new allocation - // Therefore, the front_block.controller_ptr is just new_start_ptr - // The back_block.controller_ptr is new_start_ptr + (used_blocks_count - 1) - - controller.front_block.controller_ptr = new_start_ptr; - controller.back_block.controller_ptr = new_start_ptr + (used_blocks_count - 1u); + // Move the pointers (non-overlapped because it's a new allocation) + ::fast_io::freestanding::non_overlapped_copy_n(front_ptr, used_blocks_count, new_start_ptr); + // 4. Update controller metadata and pointers + // We align the new reserved range to the start of the new allocation cb.controller_start_ptr = new_start_ptr; cb.controller_start_reserved_ptr = new_start_ptr; cb.controller_after_reserved_ptr = new_start_ptr + used_blocks_count; cb.controller_after_ptr = new_start_ptr + new_actual_count - 1u; + // Patch the front and back block references + controller.front_block.controller_ptr = new_start_ptr; + controller.back_block.controller_ptr = new_start_ptr + (used_blocks_count - 1u); - // 5. Set Sentinel + // 5. Set sentinel and clean up old controller *(cb.controller_after_reserved_ptr) = nullptr; + block_ptr_allocator::deallocate_n(start_ptr, current_controller_size); } } From 5c61b745001a371e212416214a62f7f5a2bd15cf Mon Sep 17 00:00:00 2001 From: trcrsired Date: Thu, 30 Apr 2026 16:44:52 +0800 Subject: [PATCH 13/82] [deque] add apis for accessing segments inside deque --- include/fast_io_dsal/deque.h | 1 + include/fast_io_dsal/impl/deque.h | 253 +++++++++++++++++++++++++++++- include/fast_io_dsal/impl/span.h | 10 +- 3 files changed, 258 insertions(+), 6 deletions(-) diff --git a/include/fast_io_dsal/deque.h b/include/fast_io_dsal/deque.h index e3af9db9e..928c313dd 100644 --- a/include/fast_io_dsal/deque.h +++ b/include/fast_io_dsal/deque.h @@ -24,6 +24,7 @@ #include "impl/freestanding.h" #include "impl/common.h" +#include "span.h" #include "impl/deque.h" #if ((__STDC_HOSTED__ == 1 && (!defined(_GLIBCXX_HOSTED) || _GLIBCXX_HOSTED == 1) && \ diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index 8eab31db5..de06b850d 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -1601,10 +1601,62 @@ template (controller, align, blockbytes); } +template +inline constexpr ::std::size_t deque_get_front_capacity_bytes_impl(dequecontroltype &controller, ::std::size_t block_bytes) noexcept +{ + return block_bytes * static_cast<::std::size_t>(controller.back_block.controller_ptr - controller.controller_start_reserved_ptr) + + static_cast<::std::size_t>(controller.back_block.curr_ptr - controller.back_block.begin_ptr); +} + +template <::std::size_t sz, ::std::size_t block_bytes, typename dequecontroltype> +inline constexpr ::std::size_t deque_get_front_capacity(dequecontroltype &controller) noexcept +{ + auto ret{::fast_io::containers::details::deque_get_front_capacity_bytes_impl(controller, sz, block_bytes)}; + if constexpr (sz != 1u) + { + ret /= sz; + } + return ret; +} + +template +inline constexpr ::std::size_t deque_get_back_capacity_bytes_impl(dequecontroltype &controller, ::std::size_t block_bytes) noexcept +{ + return block_bytes * static_cast<::std::size_t>(controller.controller_after_reserved_ptr - controller.front_block.controller_ptr) - + static_cast<::std::size_t>(controller.front_block.curr_ptr - controller.front_block.begin_ptr); +} + +template <::std::size_t sz, ::std::size_t block_bytes, typename dequecontroltype> +inline constexpr ::std::size_t deque_get_back_capacity(dequecontroltype &controller) noexcept +{ + auto ret{::fast_io::containers::details::deque_get_back_capacity_bytes_impl(controller, sz, block_bytes)}; + if constexpr (sz != 1u) + { + ret /= sz; + } + return ret; +} + +template +inline constexpr ::std::size_t deque_get_capacity_bytes_impl(dequecontroltype &controller, ::std::size_t block_bytes) noexcept +{ + return block_bytes * static_cast<::std::size_t>(controller.controller_after_reserved_ptr - controller.controller_start_reserved_ptr); +} + +template <::std::size_t sz, ::std::size_t block_bytes, typename dequecontroltype> +inline constexpr ::std::size_t deque_get_capacity(dequecontroltype &controller) noexcept +{ + auto ret{::fast_io::containers::details::deque_get_capacity_bytes_impl(controller, sz, block_bytes)}; + if constexpr (sz != 1u) + { + ret /= sz; + } + return ret; +} + template struct is_fast_io_deque_iterator_impl : ::std::false_type {}; @@ -1671,6 +1723,64 @@ inline constexpr Iter uninitialized_relocate_backward_define( ::fast_io::containers::details::deque_block_size)); } +template +struct +#if __has_cpp_attribute(__gnu__::__may_alias__) + [[__gnu__::__may_alias__]] +#endif + deque_nth_element_result +{ + ptrtype start_ptr, end_ptr; +}; + +template +inline constexpr ::fast_io::containers::details::deque_nth_element_result deque_nth_element_common_impl(dequecontroltype &controller, ::std::size_t pos, ::std::size_t block_size) noexcept +{ + auto front_controller_ptr{controller.front_block.controller_ptr}; + auto back_controller_ptr{controller.back_block.controller_ptr}; + + ::std::size_t lastsegidx{static_cast<::std::size_t>(static_cast<::std::size_t>(back_controller_ptr - front_controller_ptr))}; + if (lastsegidx < pos) [[unlikely]] + { + ::fast_io::fast_terminate(); +#if __has_cpp_attribute(unreachable) + [[unreachable]]; +#endif + } + using pointer = typename dequecontroltype::controlreplacetype; + pointer start_ptr, end_ptr; + if (!pos) + { + start_ptr = controller.front_block.curr_ptr; + if (lastsegidx) + { + end_ptr = controller.front_end_ptr; + } + else + { + end_ptr = controller.back_block.curr_ptr; + } + } + else if (pos == lastsegidx) + { + start_ptr = controller.back_block.front_ptr; + end_ptr = controller.back_block.curr_ptr; + } + else + { + start_ptr = front_controller_ptr[pos]; + end_ptr = start_ptr + block_size; + } + + return {start_ptr, end_ptr}; +} + +template <::std::size_t block_size, typename dequecontroltype> +inline constexpr ::fast_io::containers::details::deque_nth_element_result deque_nth_element_common(dequecontroltype &controller, ::std::size_t pos) noexcept +{ + return ::fast_io::containers::details::deque_nth_element_common_impl(controller, pos, block_size); +} + } // namespace details template <::std::forward_iterator ForwardIt> @@ -1685,6 +1795,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE public: using value_type = T; using pointer = value_type *; + using const_pointer = value_type const *; using reference = value_type &; using const_reference = value_type const &; using size_type = ::std::size_t; @@ -2353,6 +2464,131 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE return size() * sizeof(value_type); } + inline constexpr size_type front_capacity_bytes() const noexcept + { + if consteval + { + return ::fast_io::containers::details::deque_get_front_capacity<1u, block_size>(this->controller) * sizeof(value_type); + } + else + { + return ::fast_io::containers::details::deque_get_front_capacity<1u, block_size * sizeof(value_type)>( + *reinterpret_cast<::fast_io::containers::details::deque_controller_common *>(this->controller)); + } + } + + inline constexpr size_type front_capacity() const noexcept + { + if consteval + { + return ::fast_io::containers::details::deque_get_front_capacity<1u, block_size>(this->controller); + } + else + { + return ::fast_io::containers::details::deque_get_front_capacity( + *reinterpret_cast<::fast_io::containers::details::deque_controller_common *>(this->controller)); + } + } + + inline constexpr size_type back_capacity_bytes() const noexcept + { + if consteval + { + return ::fast_io::containers::details::deque_get_back_capacity<1u, block_size>(this->controller) * sizeof(value_type); + } + else + { + return ::fast_io::containers::details::deque_get_back_capacity<1u, block_size * sizeof(value_type)>( + *reinterpret_cast<::fast_io::containers::details::deque_controller_common *>(this->controller)); + } + } + + inline constexpr size_type back_capacity() const noexcept + { + if consteval + { + return ::fast_io::containers::details::deque_get_back_capacity<1u, block_size>(this->controller); + } + else + { + return ::fast_io::containers::details::deque_get_back_capacity( + *reinterpret_cast<::fast_io::containers::details::deque_controller_common *>(this->controller)); + } + } + + inline constexpr size_type capacity_bytes() const noexcept + { + if consteval + { + return ::fast_io::containers::details::deque_get_capacity<1u, block_size>(this->controller) * sizeof(value_type); + } + else + { + return ::fast_io::containers::details::deque_get_capacity<1u, block_size * sizeof(value_type)>( + *reinterpret_cast<::fast_io::containers::details::deque_controller_common *>(this->controller)); + } + } + + inline constexpr size_type capacity() const noexcept + { + if consteval + { + return ::fast_io::containers::details::deque_get_capacity<1u, block_size>(this->controller); + } + else + { + return ::fast_io::containers::details::deque_get_capacity( + *reinterpret_cast<::fast_io::containers::details::deque_controller_common *>(this->controller)); + } + } + + inline static constexpr size_type size_per_segment() noexcept + { + return block_size; + } + + inline static constexpr size_type size_bytes_per_segment() noexcept + { + constexpr size_type sz{block_size * sizeof(value_type)}; + return sz; + } + + inline constexpr size_type segments_count() noexcept + { + return static_cast(static_cast(this->controller.back_block.controller_ptr - this->controller.front_block.controller_ptr) + 1u); + } + + inline constexpr ::fast_io::containers::span nth_segment(size_type pos) noexcept + { + if consteval + { + auto [start_ptr, end_ptr] = ::fast_io::containers::details::deque_nth_element_common(this->controller); + return ::fast_io::containers::span(start_ptr, static_cast(end_ptr - start_ptr)); + } + else + { + auto [start_ptr, end_ptr] = ::std::bit_cast<::fast_io::containers::details::deque_nth_element_result>(::fast_io::containers::details::deque_nth_element_common(*reinterpret_cast<::fast_io::containers::details::deque_controller_common *>(this->controller))); + return ::fast_io::containers::span(start_ptr, static_cast(end_ptr - start_ptr)); + } + } + inline constexpr ::fast_io::containers::span const_nth_segment(size_type pos) const noexcept + { + if consteval + { + auto [start_ptr, end_ptr] = ::fast_io::containers::details::deque_nth_element_common(this->controller); + return ::fast_io::containers::span(start_ptr, static_cast(end_ptr - start_ptr)); + } + else + { + auto [start_ptr, end_ptr] = ::std::bit_cast<::fast_io::containers::details::deque_nth_element_result>(::fast_io::containers::details::deque_nth_element_common(*reinterpret_cast<::fast_io::containers::details::deque_controller_common *>(this->controller))); + return ::fast_io::containers::span(start_ptr, static_cast(end_ptr - start_ptr)); + } + } + inline constexpr ::fast_io::containers::span nth_segment(size_type pos) const noexcept + { + return this->const_nth_segment(pos); + } + inline constexpr iterator begin() noexcept { return {this->controller.front_block}; @@ -2438,6 +2674,21 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE return controller.front_block.curr_ptr == controller.back_block.curr_ptr; } + inline constexpr size_type index_of(const_iterator it) const noexcept + { + return ::fast_io::containers::details::deque_iter_difference_unsigned_common(it.itercontent, this->controller.front_block); + } + + inline constexpr size_type segment_nth_of(const_iterator it) const noexcept + { + auto controllerptr{it.itercontent.controller_ptr}; + if (this->controller.back_block.controller_ptr < controllerptr) [[unlikely]] + { + --controllerptr; + } + return static_cast(controllerptr - this->controller.front_controller_ptr); + } + inline constexpr void clear_destroy() noexcept { destroy_deque_controller(this->controller); diff --git a/include/fast_io_dsal/impl/span.h b/include/fast_io_dsal/impl/span.h index 1f0cd152f..a1615b7cc 100644 --- a/include/fast_io_dsal/impl/span.h +++ b/include/fast_io_dsal/impl/span.h @@ -8,7 +8,7 @@ class span { public: using element_type = T; - using value_type = std::remove_cv_t; + using value_type = ::std::remove_cv_t; using size_type = ::std::size_t; using difference_type = ::std::ptrdiff_t; using pointer = element_type *; @@ -31,20 +31,20 @@ class span #endif pointer ptr{}; size_type n{}; - inline constexpr span() noexcept = default; + inline constexpr explicit span() noexcept = default; template <::std::contiguous_iterator Iter> requires ::std::same_as> - inline constexpr span(Iter first, size_type count) noexcept(noexcept(::std::to_address(first))) + inline constexpr explicit span(Iter first, size_type count) noexcept(noexcept(::std::to_address(first))) : ptr{::std::to_address(first)}, n{count} {} template <::std::contiguous_iterator Iter, ::std::sentinel_for S> requires ::std::same_as> - inline constexpr span(Iter first, S snt) noexcept(noexcept(::std::to_address(first))) + inline constexpr explicit span(Iter first, S snt) noexcept(noexcept(::std::to_address(first))) : ptr{::std::to_address(first)}, n{static_cast(snt - first)} {} template <::std::ranges::contiguous_range R> requires(::std::same_as> && !::std::same_as<::std::remove_cvref_t, ::fast_io::containers::span>) - inline constexpr span(R &&range) noexcept(noexcept(::std::ranges::data(range)) && noexcept(::std::ranges::size(range))) + inline constexpr explicit span(R &&range) noexcept(noexcept(::std::ranges::data(range)) && noexcept(::std::ranges::size(range))) : ptr{::std::ranges::data(range)}, n{::std::ranges::size(range)} {} From 68dbf53b69c3674caa76b4f818f3022f59a5314a Mon Sep 17 00:00:00 2001 From: trcrsired Date: Thu, 30 Apr 2026 17:01:15 +0800 Subject: [PATCH 14/82] [deque] add a benchmark for segments api --- .../deque/0001.push_back/fast_io.cc | 2 +- .../deque/0001.push_back/fast_io_segments.cc | 29 +++++++++++++++++++ include/fast_io_dsal/impl/deque.h | 12 ++++---- 3 files changed, 37 insertions(+), 6 deletions(-) create mode 100644 benchmark/0011.containers/deque/0001.push_back/fast_io_segments.cc diff --git a/benchmark/0011.containers/deque/0001.push_back/fast_io.cc b/benchmark/0011.containers/deque/0001.push_back/fast_io.cc index 7b5193105..781792796 100644 --- a/benchmark/0011.containers/deque/0001.push_back/fast_io.cc +++ b/benchmark/0011.containers/deque/0001.push_back/fast_io.cc @@ -22,5 +22,5 @@ int main() sum += e; } } - ::fast_io::io::perrln("sum=",sum); + ::fast_io::io::perrln("sum=", sum); } diff --git a/benchmark/0011.containers/deque/0001.push_back/fast_io_segments.cc b/benchmark/0011.containers/deque/0001.push_back/fast_io_segments.cc new file mode 100644 index 000000000..778fe3bf1 --- /dev/null +++ b/benchmark/0011.containers/deque/0001.push_back/fast_io_segments.cc @@ -0,0 +1,29 @@ +#include +#include +#include + +int main() +{ + fast_io::timer tm(u8"fast_io::deque segments"); + fast_io::deque deq; + constexpr std::size_t n{100000000}; + { + fast_io::timer tm1(u8"push_back"); + for (std::size_t i{}; i != n; ++i) + { + deq.push_back(i); + } + } + ::std::size_t sum{}; + { + fast_io::timer tm1(u8"loop"); + for (::std::size_t i{}, n{deq.segments_count()}; i != n; ++i) + { + for (auto const e : deq.const_nth_segment(i)) + { + sum += e; + } + } + } + ::fast_io::io::perrln("sum=", sum); +} diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index de06b850d..b7df35e8a 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -1763,7 +1763,7 @@ inline constexpr ::fast_io::containers::details::deque_nth_element_result(this->controller); + auto [start_ptr, end_ptr] = ::fast_io::containers::details::deque_nth_element_common(this->controller, pos); return ::fast_io::containers::span(start_ptr, static_cast(end_ptr - start_ptr)); } else { - auto [start_ptr, end_ptr] = ::std::bit_cast<::fast_io::containers::details::deque_nth_element_result>(::fast_io::containers::details::deque_nth_element_common(*reinterpret_cast<::fast_io::containers::details::deque_controller_common *>(this->controller))); + auto [start_ptr, end_ptr] = ::std::bit_cast<::fast_io::containers::details::deque_nth_element_result>(::fast_io::containers::details::deque_nth_element_common(*reinterpret_cast<::fast_io::containers::details::deque_controller_common *>(__builtin_addressof(this->controller)), pos)); return ::fast_io::containers::span(start_ptr, static_cast(end_ptr - start_ptr)); } } @@ -2575,12 +2575,14 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { if consteval { - auto [start_ptr, end_ptr] = ::fast_io::containers::details::deque_nth_element_common(this->controller); + auto [start_ptr, end_ptr] = ::fast_io::containers::details::deque_nth_element_common(this->controller, pos); return ::fast_io::containers::span(start_ptr, static_cast(end_ptr - start_ptr)); } else { - auto [start_ptr, end_ptr] = ::std::bit_cast<::fast_io::containers::details::deque_nth_element_result>(::fast_io::containers::details::deque_nth_element_common(*reinterpret_cast<::fast_io::containers::details::deque_controller_common *>(this->controller))); + auto [start_ptr, end_ptr] = ::std::bit_cast<::fast_io::containers::details::deque_nth_element_result>(::fast_io::containers::details::deque_nth_element_common(*reinterpret_cast<::fast_io::containers::details::deque_controller_common *>( + const_cast(__builtin_addressof(this->controller))), + pos)); return ::fast_io::containers::span(start_ptr, static_cast(end_ptr - start_ptr)); } } From 36ffc4e7c9b02861a174aa1ab97de3c347ff351d Mon Sep 17 00:00:00 2001 From: trcrsired Date: Thu, 30 Apr 2026 17:15:37 +0800 Subject: [PATCH 15/82] [deque] benchmark for segments should use segs as the variable name --- .../0011.containers/deque/0001.push_back/fast_io_segments.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark/0011.containers/deque/0001.push_back/fast_io_segments.cc b/benchmark/0011.containers/deque/0001.push_back/fast_io_segments.cc index 778fe3bf1..4af6241e3 100644 --- a/benchmark/0011.containers/deque/0001.push_back/fast_io_segments.cc +++ b/benchmark/0011.containers/deque/0001.push_back/fast_io_segments.cc @@ -17,7 +17,7 @@ int main() ::std::size_t sum{}; { fast_io::timer tm1(u8"loop"); - for (::std::size_t i{}, n{deq.segments_count()}; i != n; ++i) + for (::std::size_t i{}, segs{deq.segments_count()}; i != segs; ++i) { for (auto const e : deq.const_nth_segment(i)) { From ad9905b77b3059f544ab3639b0adf7bb79ad6161 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Thu, 30 Apr 2026 17:30:58 +0800 Subject: [PATCH 16/82] [deque] use if constexpr(true) instead of just macro for guarding __builtin_add_overflow --- include/fast_io_dsal/impl/deque.h | 148 ++++++++++++++++++++---------- 1 file changed, 97 insertions(+), 51 deletions(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index b7df35e8a..eab524eda 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -470,21 +470,27 @@ inline constexpr void deque_grow_to_new_blocks_count_impl(dequecontroltype &cont using block_typed_allocator = ::fast_io::typed_generic_allocator_adapter; -#if (defined(__GNUC__) || defined(__clang__)) ::std::size_t new_blocks_count_least_p1; - if (__builtin_add_overflow(new_blocks_count_least, 1zu, __builtin_addressof(new_blocks_count_least_p1))) [[unlikely]] +#if (defined(__GNUC__) || defined(__clang__)) + if constexpr (true) { - ::fast_io::fast_terminate(); + if (__builtin_add_overflow(new_blocks_count_least, 1zu, __builtin_addressof(new_blocks_count_least_p1))) [[unlikely]] + { + ::fast_io::fast_terminate(); + } } -#else - constexpr ::std::size_t mx{::std::numeric_limits<::std::size_t>::max()}; - ::std::size_t new_blocks_count_least_p1{new_blocks_count_least}; - if (mx == new_blocks_count_least) + else +#endif { - ::fast_io::fast_terminate(); + constexpr ::std::size_t mx{::std::numeric_limits<::std::size_t>::max()}; + new_blocks_count_least_p1 = new_blocks_count_least; + if (mx == new_blocks_count_least) + { + ::fast_io::fast_terminate(); + } + ++new_blocks_count_least_p1; } - ++new_blocks_count_least_p1; -#endif + auto [new_start_ptr, new_blocks_count] = block_typed_allocator::allocate_at_least(new_blocks_count_least_p1); auto const old_reserved_blocks_count{ @@ -597,21 +603,26 @@ template inline constexpr void deque_allocate_on_empty_common_with_n_impl(dequecontroltype &controller, ::std::size_t align, ::std::size_t bytes, ::std::size_t initial_allocated_block_counts) noexcept { -#if (defined(__GNUC__) || defined(__clang__)) ::std::size_t initial_allocated_block_counts_with_sentinel; - if (__builtin_add_overflow(initial_allocated_block_counts, 1u, - __builtin_addressof(initial_allocated_block_counts_with_sentinel))) +#if (defined(__GNUC__) || defined(__clang__)) + if constexpr (true) { - ::fast_io::fast_terminate(); + if (__builtin_add_overflow(initial_allocated_block_counts, 1u, + __builtin_addressof(initial_allocated_block_counts_with_sentinel))) + { + ::fast_io::fast_terminate(); + } } -#else - constexpr ::std::size_t maxval{::std::numeric_limits<::std::size_t>::max()}; - if (initial_allocated_block_counts == maxval) [[unlikely]] + else +#endif { - ::fast_io::fast_terminate(); + constexpr ::std::size_t maxval{::std::numeric_limits<::std::size_t>::max()}; + if (initial_allocated_block_counts == maxval) [[unlikely]] + { + ::fast_io::fast_terminate(); + } + initial_allocated_block_counts_with_sentinel = initial_allocated_block_counts + 1u; } - ::std::size_t initial_allocated_block_counts_with_sentinel{initial_allocated_block_counts + 1u}; -#endif using block_typed_allocator = ::fast_io::typed_generic_allocator_adapter; auto [allocated_blocks_ptr, allocated_blocks_count] = block_typed_allocator::allocate_at_least(initial_allocated_block_counts_with_sentinel); @@ -1252,50 +1263,60 @@ inline constexpr void deque_rebalance_or_grow_insertation_impl(dequecontroltype auto const total_slots_count{ static_cast<::std::size_t>(controller.controller_block.controller_after_ptr - controller.controller_block.controller_start_ptr)}; auto const half_slots_count{static_cast<::std::size_t>(total_slots_count >> 1u)}; -#if defined(__GNUC__) || defined(__clang__) ::std::size_t new_used_blocks_count; - if (__builtin_add_overflow(used_blocks_count, extrablocks, __builtin_addressof(new_used_blocks_count))) [[unlikely]] - { - ::fast_io::fast_terminate(); - } -#else - constexpr ::std::size_t mx{::std::numeric_limits<::std::size_t>::max()}; - ::std::size_t const mx_sub_extrablocks{mx - extrablocks}; - if (mx_sub_extrablocks < used_blocks_count) - { - ::fast_io::fast_terminate(); - } - - auto const new_used_blocks_count{used_blocks_count + extrablocks}; -#endif - if (half_slots_count < new_used_blocks_count) // grow blocks +#if (defined(__GNUC__) || defined(__clang__)) + if constexpr (true) { -#if defined(__GNUC__) || defined(__clang__) - ::std::size_t doubleslotsextra; - if (__builtin_add_overflow(total_slots_count, extrablocks, __builtin_addressof(doubleslotsextra))) + if (__builtin_add_overflow(used_blocks_count, extrablocks, __builtin_addressof(new_used_blocks_count))) [[unlikely]] { ::fast_io::fast_terminate(); } - if (__builtin_add_overflow(doubleslotsextra, doubleslotsextra, __builtin_addressof(doubleslotsextra))) + } + else +#endif + { + constexpr ::std::size_t mx{::std::numeric_limits<::std::size_t>::max()}; + ::std::size_t const mx_sub_extrablocks{mx - extrablocks}; + if (mx_sub_extrablocks < used_blocks_count) { ::fast_io::fast_terminate(); } -#else - ::std::size_t mx_total_slots{mx - extrablocks}; - if (mx_total_slots < total_slots_count) + new_used_blocks_count = used_blocks_count + extrablocks; + } + + if (half_slots_count < new_used_blocks_count) // grow blocks + { + ::std::size_t doubleslotsextra; +#if (defined(__GNUC__) || defined(__clang__)) + if constexpr (true) { - ::fast_io::fast_terminate(); + if (__builtin_add_overflow(total_slots_count, extrablocks, __builtin_addressof(doubleslotsextra))) + { + ::fast_io::fast_terminate(); + } + if (__builtin_add_overflow(doubleslotsextra, doubleslotsextra, __builtin_addressof(doubleslotsextra))) + { + ::fast_io::fast_terminate(); + } } - ::std::size_t doubleslotsextra{extrablocks + total_slots_count}; - constexpr ::std::size_t mxdv2m1{(mx >> 1u)}; - if (mxdv2m1 < doubleslotsextra) + else +#endif { - ::fast_io::fast_terminate(); + constexpr ::std::size_t mx{::std::numeric_limits<::std::size_t>::max()}; + ::std::size_t mx_total_slots{mx - extrablocks}; + if (mx_total_slots < total_slots_count) + { + ::fast_io::fast_terminate(); + } + doubleslotsextra = extrablocks + total_slots_count; + constexpr ::std::size_t mxdv2m1{(mx >> 1u)}; + if (mxdv2m1 < doubleslotsextra) + { + ::fast_io::fast_terminate(); + } + doubleslotsextra <<= 1u; } - doubleslotsextra <<= 1u; -#endif - ::fast_io::containers::details::deque_grow_to_new_blocks_count_impl(controller, doubleslotsextra); } else @@ -3271,10 +3292,35 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE } inline constexpr void resize(size_type count) noexcept(::std::is_nothrow_default_constructible_v&&::std::is_nothrow_move_constructible_v) { + ::std::size_t sz{this->size()}; + ::std::size_t backcap{this->back_capacity()}; + ::std::size_t new_blocks_count_least_p1; +#if (defined(__GNUC__) || defined(__clang__)) + if constexpr(true) + { + if (__builtin_add_overflow(new_blocks_count_least, 1zu, __builtin_addressof(new_blocks_count_least_p1))) [[unlikely]] + { + ::fast_io::fast_terminate(); + } + } + else +#endif + { + constexpr ::std::size_t mx{::std::numeric_limits<::std::size_t>::max()}; + new_blocks_count_least_p1 = new_blocks_count_least; + if (mx == new_blocks_count_least) + { + ::fast_io::fast_terminate(); + } + } } inline constexpr void resize(size_type count, const_reference value) noexcept(::std::is_nothrow_copy_constructible_v&&::std::is_nothrow_move_constructible_v) { } +#if 0 + inline constexpr void resize(size_type count, ::fast_io::for_overwrite_t) noexcept(::fast_io::freestanding::is_zero_default_constructible_v || + ::std::is_nothrow_default_constructible_v) +#endif #endif private: inline constexpr iterator erase_no_destroy_common_impl(iterator first, iterator last, bool moveleft) noexcept From d8a0aa16542ee7e5c05d12dd10912ed1651542b3 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Thu, 30 Apr 2026 18:10:09 +0800 Subject: [PATCH 17/82] [deque] try to implement deque resize but we would need reserve_back and reserve_front first --- include/fast_io_dsal/impl/deque.h | 37 +++++++++++++++++++------------ 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index eab524eda..b696b36c6 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -3292,27 +3292,36 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE } inline constexpr void resize(size_type count) noexcept(::std::is_nothrow_default_constructible_v&&::std::is_nothrow_move_constructible_v) { - ::std::size_t sz{this->size()}; - ::std::size_t backcap{this->back_capacity()}; - ::std::size_t new_blocks_count_least_p1; -#if (defined(__GNUC__) || defined(__clang__)) - if constexpr(true) + size_type oldsz{this->size()}; + if (count == oldsz) { - if (__builtin_add_overflow(new_blocks_count_least, 1zu, __builtin_addressof(new_blocks_count_least_p1))) [[unlikely]] - { - ::fast_io::fast_terminate(); - } + return; + } + iterator newed{this->end()}; + if (count < oldsz) + { + auto ed{newed}; + newed-=static_cast(oldsz-count); + newed = this->erase(newed, ed); } else -#endif { - constexpr ::std::size_t mx{::std::numeric_limits<::std::size_t>::max()}; - new_blocks_count_least_p1 = new_blocks_count_least; - if (mx == new_blocks_count_least) + size_type backcap{this->back_capacity()}; + if (backup < count) { - ::fast_io::fast_terminate(); + this->reserve_back(count); } + ed = newed; + newed = ed+count; + ::fast_io::freestanding::uninitialized_default_construct(ed, newed); + } + if (newed.curr_ptr == newed.begin_ptr) + { + newed.itercontent.curr_ptr = (newed.itercontent.begin_ptr=*--newed.itercontent.controller_ptr) + block_size; } + this->controller.back_block.controller_ptr = newed.itercontent.controller_ptr; + this->controller.back_end_ptr = (this->controller.back_block.begin_ptr = newed.itercontent.begin_ptr) + block_size; + this->controller.back_block.curr_ptr = newed.itercontent.curr_ptr; } inline constexpr void resize(size_type count, const_reference value) noexcept(::std::is_nothrow_copy_constructible_v&&::std::is_nothrow_move_constructible_v) { From 59d434187c636dc634163cd6d6af2cd718b15531 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Sun, 3 May 2026 19:07:36 +0800 Subject: [PATCH 18/82] [skip ci]try to implement reserve_back/reserve_front (unfinished) --- include/fast_io_dsal/impl/deque.h | 101 ++++++++++++++++----- tests/0026.container/0003.deque/reserve.cc | 12 +++ 2 files changed, 89 insertions(+), 24 deletions(-) create mode 100644 tests/0026.container/0003.deque/reserve.cc diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index b696b36c6..e715208e5 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -1456,8 +1456,8 @@ inline constexpr void deque_grow_back_common(dequecontroltype &controller) noexc ::fast_io::containers::details::deque_grow_back_common_impl(controller, align, blockbytes); } -template -inline constexpr void deque_reserve_back_spaces(dequecontroltype &controller, ::std::size_t n) +template +inline constexpr void deque_reserve_back_spaces_impl(dequecontroltype &controller, ::std::size_t n, ::std::size_t align, ::std::size_t sz, ::std::size_t block_size) { if (!n) { @@ -1484,13 +1484,19 @@ inline constexpr void deque_reserve_back_spaces(dequecontroltype &controller, :: } else { - constexpr ::std::size_t block_bytes{block_size * sz}; + ::std::size_t const block_bytes{block_size * sz}; ::fast_io::containers::details::deque_reserve_back_blocks_impl(*reinterpret_cast<::fast_io::containers::details::deque_controller_common *>( __builtin_addressof(controller)), toallocate, align, block_bytes); } } +template +inline constexpr void deque_reserve_back_spaces(dequecontroltype &controller, ::std::size_t n) +{ + ::fast_io::containers::details::deque_reserve_back_spaces_impl(controller, n, align, sz, block_size); +} + template inline constexpr bool deque_reserve_front_blocks_impl(dequecontroltype &controller, ::std::size_t nb, ::std::size_t align, ::std::size_t blockbytes) noexcept { @@ -1566,9 +1572,10 @@ inline constexpr bool deque_reserve_front_blocks_impl(dequecontroltype &controll return true; } -template -inline constexpr void deque_reserve_front_spaces(dequecontroltype &controller, ::std::size_t n) +template +inline constexpr void deque_reserve_front_spaces_impl(dequecontroltype &controller, ::std::size_t n, ::std::size_t align, ::std::size_t sz, ::std::size_t block_size) { + if (!n) { return; @@ -1594,13 +1601,19 @@ inline constexpr void deque_reserve_front_spaces(dequecontroltype &controller, : } else { - constexpr ::std::size_t block_bytes{block_size * sz}; + ::std::size_t const block_bytes{block_size * sz}; ::fast_io::containers::details::deque_reserve_front_blocks_impl(*reinterpret_cast<::fast_io::containers::details::deque_controller_common *>( __builtin_addressof(controller)), toallocate, align, block_bytes); } } +template +inline constexpr void deque_reserve_front_spaces(dequecontroltype &controller, ::std::size_t n) +{ + ::fast_io::containers::details::deque_reserve_front_spaces_impl(controller, n, align, sz, block_size); +} + template inline constexpr void deque_grow_front_common_impl( dequecontroltype &controller, @@ -1626,16 +1639,16 @@ inline constexpr void deque_grow_front_common(dequecontroltype &controller) noex } template -inline constexpr ::std::size_t deque_get_front_capacity_bytes_impl(dequecontroltype &controller, ::std::size_t block_bytes) noexcept +inline constexpr ::std::size_t deque_get_front_capacity_bytes_impl(dequecontroltype const &controller, ::std::size_t block_bytes) noexcept { return block_bytes * static_cast<::std::size_t>(controller.back_block.controller_ptr - controller.controller_start_reserved_ptr) + static_cast<::std::size_t>(controller.back_block.curr_ptr - controller.back_block.begin_ptr); } template <::std::size_t sz, ::std::size_t block_bytes, typename dequecontroltype> -inline constexpr ::std::size_t deque_get_front_capacity(dequecontroltype &controller) noexcept +inline constexpr ::std::size_t deque_get_front_capacity(dequecontroltype const &controller) noexcept { - auto ret{::fast_io::containers::details::deque_get_front_capacity_bytes_impl(controller, sz, block_bytes)}; + auto ret{::fast_io::containers::details::deque_get_front_capacity_bytes_impl(controller, block_bytes)}; if constexpr (sz != 1u) { ret /= sz; @@ -1644,16 +1657,16 @@ inline constexpr ::std::size_t deque_get_front_capacity(dequecontroltype &contro } template -inline constexpr ::std::size_t deque_get_back_capacity_bytes_impl(dequecontroltype &controller, ::std::size_t block_bytes) noexcept +inline constexpr ::std::size_t deque_get_back_capacity_bytes_impl(dequecontroltype const &controller, ::std::size_t block_bytes) noexcept { return block_bytes * static_cast<::std::size_t>(controller.controller_after_reserved_ptr - controller.front_block.controller_ptr) - static_cast<::std::size_t>(controller.front_block.curr_ptr - controller.front_block.begin_ptr); } template <::std::size_t sz, ::std::size_t block_bytes, typename dequecontroltype> -inline constexpr ::std::size_t deque_get_back_capacity(dequecontroltype &controller) noexcept +inline constexpr ::std::size_t deque_get_back_capacity(dequecontroltype const &controller) noexcept { - auto ret{::fast_io::containers::details::deque_get_back_capacity_bytes_impl(controller, sz, block_bytes)}; + auto ret{::fast_io::containers::details::deque_get_back_capacity_bytes_impl(controller, block_bytes)}; if constexpr (sz != 1u) { ret /= sz; @@ -1670,7 +1683,7 @@ inline constexpr ::std::size_t deque_get_capacity_bytes_impl(dequecontroltype &c template <::std::size_t sz, ::std::size_t block_bytes, typename dequecontroltype> inline constexpr ::std::size_t deque_get_capacity(dequecontroltype &controller) noexcept { - auto ret{::fast_io::containers::details::deque_get_capacity_bytes_impl(controller, sz, block_bytes)}; + auto ret{::fast_io::containers::details::deque_get_capacity_bytes_impl(controller, block_bytes)}; if constexpr (sz != 1u) { ret /= sz; @@ -1802,6 +1815,42 @@ inline constexpr ::fast_io::containers::details::deque_nth_element_result +inline constexpr void deque_reserve_back_impl(dequecontroltype &controller, ::std::size_t newbackcap, ::std::size_t align, ::std::size_t sz, ::std::size_t block_size) noexcept +{ + ::std::size_t const backcap{::fast_io::containers::details::deque_get_back_capacity_bytes_impl(controller, block_size * sz) / sz}; + if (newbackcap <= backcap) [[unlikely]] + { + return; + } + ::fast_io::containers::details::deque_reserve_back_spaces_impl(controller, + static_cast<::std::size_t>(newbackcap - backcap), align, sz, block_size); +} + +template +inline constexpr void deque_reserve_back_common(dequecontroltype &controller, ::std::size_t newbackcap) noexcept +{ + ::fast_io::containers::details::deque_reserve_back_impl(controller, newbackcap, align, sz, block_size); +} + +template +inline constexpr void deque_reserve_front_impl(dequecontroltype &controller, ::std::size_t newfrontcap, ::std::size_t align, ::std::size_t sz, ::std::size_t block_size) noexcept +{ + ::std::size_t const frontcap{::fast_io::containers::details::deque_get_front_capacity_bytes_impl(controller, block_size * sz) / sz}; + if (newfrontcap <= frontcap) [[unlikely]] + { + return; + } + ::fast_io::containers::details::deque_reserve_front_spaces_impl(controller, + static_cast<::std::size_t>(newfrontcap - frontcap), align, sz, block_size); +} + +template +inline constexpr void deque_reserve_front_common(dequecontroltype &controller, ::std::size_t newfrontcap) noexcept +{ + ::fast_io::containers::details::deque_reserve_front_impl(controller, newfrontcap, align, sz, block_size); +} + } // namespace details template <::std::forward_iterator ForwardIt> @@ -2494,7 +2543,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE else { return ::fast_io::containers::details::deque_get_front_capacity<1u, block_size * sizeof(value_type)>( - *reinterpret_cast<::fast_io::containers::details::deque_controller_common *>(this->controller)); + *reinterpret_cast<::fast_io::containers::details::deque_controller_common const *>(this->controller)); } } @@ -2507,7 +2556,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE else { return ::fast_io::containers::details::deque_get_front_capacity( - *reinterpret_cast<::fast_io::containers::details::deque_controller_common *>(this->controller)); + *reinterpret_cast<::fast_io::containers::details::deque_controller_common const *>(this->controller)); } } @@ -2520,7 +2569,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE else { return ::fast_io::containers::details::deque_get_back_capacity<1u, block_size * sizeof(value_type)>( - *reinterpret_cast<::fast_io::containers::details::deque_controller_common *>(this->controller)); + *reinterpret_cast<::fast_io::containers::details::deque_controller_common const *>(this->controller)); } } @@ -2533,7 +2582,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE else { return ::fast_io::containers::details::deque_get_back_capacity( - *reinterpret_cast<::fast_io::containers::details::deque_controller_common *>(this->controller)); + *reinterpret_cast<::fast_io::containers::details::deque_controller_common const *>(__builtin_addressof(this->controller))); } } @@ -2546,7 +2595,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE else { return ::fast_io::containers::details::deque_get_capacity<1u, block_size * sizeof(value_type)>( - *reinterpret_cast<::fast_io::containers::details::deque_controller_common *>(this->controller)); + *reinterpret_cast<::fast_io::containers::details::deque_controller_common const *>(this->controller)); } } @@ -2559,7 +2608,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE else { return ::fast_io::containers::details::deque_get_capacity( - *reinterpret_cast<::fast_io::containers::details::deque_controller_common *>(this->controller)); + *reinterpret_cast<::fast_io::containers::details::deque_controller_common const *>(this->controller)); } } @@ -3281,6 +3330,14 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE this->controller))); } } + inline constexpr void reserve_back(size_type backcap) noexcept + { + ::fast_io::containers::details::deque_reserve_back_common(this->controller, backcap); + } + inline constexpr void reserve_front(size_type frontcap) noexcept + { + ::fast_io::containers::details::deque_reserve_front_common(this->controller, frontcap); + } #if 0 inline constexpr void assign(size_type count, const_reference val) noexcept(::std::is_nothrow_copy_constructible_v) { @@ -3306,11 +3363,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE } else { - size_type backcap{this->back_capacity()}; - if (backup < count) - { - this->reserve_back(count); - } + this->reserve_back(count); ed = newed; newed = ed+count; ::fast_io::freestanding::uninitialized_default_construct(ed, newed); diff --git a/tests/0026.container/0003.deque/reserve.cc b/tests/0026.container/0003.deque/reserve.cc new file mode 100644 index 000000000..1e8bf9938 --- /dev/null +++ b/tests/0026.container/0003.deque/reserve.cc @@ -0,0 +1,12 @@ +#include +#include + +int main() +{ + ::fast_io::deque<::std::size_t> deq; + ::fast_io::io::println(::std::source_location::current(), " ", deq.back_capacity(), " ", deq.size()); + deq.push_back(30); + ::fast_io::io::println(::std::source_location::current(), " ", deq.back_capacity(), " ", deq.size()); + deq.reserve_back(6000); + ::fast_io::io::println(::std::source_location::current(), " ", deq.back_capacity(), " ", deq.size()); +} From 3a7970fd14d6082ac2b861250bafc48cbfa798dc Mon Sep 17 00:00:00 2001 From: trcrsired Date: Mon, 4 May 2026 04:24:04 +0800 Subject: [PATCH 19/82] [deque] make compilation works for reserve first --- include/fast_io_dsal/impl/deque.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index e715208e5..9163868d5 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -1641,7 +1641,7 @@ inline constexpr void deque_grow_front_common(dequecontroltype &controller) noex template inline constexpr ::std::size_t deque_get_front_capacity_bytes_impl(dequecontroltype const &controller, ::std::size_t block_bytes) noexcept { - return block_bytes * static_cast<::std::size_t>(controller.back_block.controller_ptr - controller.controller_start_reserved_ptr) + + return block_bytes * static_cast<::std::size_t>(controller.back_block.controller_ptr - controller.controller_block.controller_start_reserved_ptr) + static_cast<::std::size_t>(controller.back_block.curr_ptr - controller.back_block.begin_ptr); } @@ -1659,7 +1659,7 @@ inline constexpr ::std::size_t deque_get_front_capacity(dequecontroltype const & template inline constexpr ::std::size_t deque_get_back_capacity_bytes_impl(dequecontroltype const &controller, ::std::size_t block_bytes) noexcept { - return block_bytes * static_cast<::std::size_t>(controller.controller_after_reserved_ptr - controller.front_block.controller_ptr) - + return block_bytes * static_cast<::std::size_t>(controller.controller_block.controller_after_reserved_ptr - controller.front_block.controller_ptr) - static_cast<::std::size_t>(controller.front_block.curr_ptr - controller.front_block.begin_ptr); } @@ -1677,7 +1677,7 @@ inline constexpr ::std::size_t deque_get_back_capacity(dequecontroltype const &c template inline constexpr ::std::size_t deque_get_capacity_bytes_impl(dequecontroltype &controller, ::std::size_t block_bytes) noexcept { - return block_bytes * static_cast<::std::size_t>(controller.controller_after_reserved_ptr - controller.controller_start_reserved_ptr); + return block_bytes * static_cast<::std::size_t>(controller.controller_block.controller_after_reserved_ptr - controller.controller_start_reserved_ptr); } template <::std::size_t sz, ::std::size_t block_bytes, typename dequecontroltype> From e599a1d3d6a0775383fb7f2a556397589cec6aca Mon Sep 17 00:00:00 2001 From: trcrsired Date: Mon, 4 May 2026 04:58:53 +0800 Subject: [PATCH 20/82] [deque] implementing deque reserve correctly --- include/fast_io_dsal/impl/deque.h | 61 +++++++++++++++++----- tests/0026.container/0003.deque/reserve.cc | 15 ++++-- 2 files changed, 60 insertions(+), 16 deletions(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index 9163868d5..bf7cb3ada 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -1677,7 +1677,7 @@ inline constexpr ::std::size_t deque_get_back_capacity(dequecontroltype const &c template inline constexpr ::std::size_t deque_get_capacity_bytes_impl(dequecontroltype &controller, ::std::size_t block_bytes) noexcept { - return block_bytes * static_cast<::std::size_t>(controller.controller_block.controller_after_reserved_ptr - controller.controller_start_reserved_ptr); + return block_bytes * static_cast<::std::size_t>(controller.controller_block.controller_after_reserved_ptr - controller.controller_block.controller_start_reserved_ptr); } template <::std::size_t sz, ::std::size_t block_bytes, typename dequecontroltype> @@ -1815,16 +1815,37 @@ inline constexpr ::fast_io::containers::details::deque_nth_element_result +inline constexpr ::std::size_t deque_itercontent_diff_bytes_impl(T const &a, T const &b, ::std::size_t blockbytes) +{ + ::std::size_t controllerdiff{static_cast<::std::size_t>(a.controller_ptr - b.controller_ptr)}; + return controllerdiff * blockbytes + static_cast<::std::size_t>((a.curr_ptr - a.begin_ptr) + (b.begin_ptr - b.curr_ptr)); +} + template inline constexpr void deque_reserve_back_impl(dequecontroltype &controller, ::std::size_t newbackcap, ::std::size_t align, ::std::size_t sz, ::std::size_t block_size) noexcept { - ::std::size_t const backcap{::fast_io::containers::details::deque_get_back_capacity_bytes_impl(controller, block_size * sz) / sz}; - if (newbackcap <= backcap) [[unlikely]] + ::std::size_t const deqsz{::fast_io::containers::details::deque_itercontent_diff_bytes_impl(controller.back_block, controller.front_block, block_size * sz) / sz}; + + ::std::size_t toaddedsz; +#if defined(__GNUC__) || defined(__clang__) + if constexpr (true) { - return; + if (__builtin_sub_overflow(newbackcap, deqsz, __builtin_addressof(toaddedsz))) + { + return; + } + } + else +#endif + { + if (newbackcap <= deqsz) [[unlikely]] + { + return; + } + toaddedsz = static_cast<::std::size_t>(newbackcap - deqsz); } - ::fast_io::containers::details::deque_reserve_back_spaces_impl(controller, - static_cast<::std::size_t>(newbackcap - backcap), align, sz, block_size); + ::fast_io::containers::details::deque_reserve_back_spaces_impl(controller, toaddedsz, align, sz, block_size); } template @@ -1836,13 +1857,27 @@ inline constexpr void deque_reserve_back_common(dequecontroltype &controller, :: template inline constexpr void deque_reserve_front_impl(dequecontroltype &controller, ::std::size_t newfrontcap, ::std::size_t align, ::std::size_t sz, ::std::size_t block_size) noexcept { - ::std::size_t const frontcap{::fast_io::containers::details::deque_get_front_capacity_bytes_impl(controller, block_size * sz) / sz}; - if (newfrontcap <= frontcap) [[unlikely]] + ::std::size_t const deqsz{::fast_io::containers::details::deque_itercontent_diff_bytes_impl(controller.back_block, controller.front_block, block_size * sz) / sz}; + + ::std::size_t toaddedsz; +#if defined(__GNUC__) || defined(__clang__) + if constexpr (true) { - return; + if (__builtin_sub_overflow(newfrontcap, deqsz, __builtin_addressof(toaddedsz))) + { + return; + } } - ::fast_io::containers::details::deque_reserve_front_spaces_impl(controller, - static_cast<::std::size_t>(newfrontcap - frontcap), align, sz, block_size); + else +#endif + { + if (newfrontcap <= deqsz) [[unlikely]] + { + return; + } + toaddedsz = static_cast<::std::size_t>(newfrontcap - deqsz); + } + ::fast_io::containers::details::deque_reserve_front_spaces_impl(controller, toaddedsz, align, sz, block_size); } template @@ -2556,7 +2591,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE else { return ::fast_io::containers::details::deque_get_front_capacity( - *reinterpret_cast<::fast_io::containers::details::deque_controller_common const *>(this->controller)); + *reinterpret_cast<::fast_io::containers::details::deque_controller_common const *>(__builtin_addressof(this->controller))); } } @@ -2608,7 +2643,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE else { return ::fast_io::containers::details::deque_get_capacity( - *reinterpret_cast<::fast_io::containers::details::deque_controller_common const *>(this->controller)); + *reinterpret_cast<::fast_io::containers::details::deque_controller_common const *>(__builtin_addressof(this->controller))); } } diff --git a/tests/0026.container/0003.deque/reserve.cc b/tests/0026.container/0003.deque/reserve.cc index 1e8bf9938..b5fa712af 100644 --- a/tests/0026.container/0003.deque/reserve.cc +++ b/tests/0026.container/0003.deque/reserve.cc @@ -1,12 +1,21 @@ #include #include +template +inline void logging(T const &deq, ::std::source_location src = ::std::source_location::current()) +{ + ::fast_io::io::print(src, + "\n\tdeq.front_capacity()=", deq.front_capacity(), + "\n\tdeq.back_capacity()=", deq.back_capacity(), + "\n\tdeq.capacity()=", deq.capacity(), + "\n\tdeq.size()=", deq.size(), "\n\n"); +} + int main() { ::fast_io::deque<::std::size_t> deq; - ::fast_io::io::println(::std::source_location::current(), " ", deq.back_capacity(), " ", deq.size()); deq.push_back(30); - ::fast_io::io::println(::std::source_location::current(), " ", deq.back_capacity(), " ", deq.size()); + logging(deq); deq.reserve_back(6000); - ::fast_io::io::println(::std::source_location::current(), " ", deq.back_capacity(), " ", deq.size()); + logging(deq); } From 97cf24efcd86b771495ce4397ef4b8e3b7be7dff Mon Sep 17 00:00:00 2001 From: trcrsired Date: Tue, 5 May 2026 03:04:44 +0800 Subject: [PATCH 21/82] add keep wine alive --- examples/0041.keepwinealive/keepwinealive.cc | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 examples/0041.keepwinealive/keepwinealive.cc diff --git a/examples/0041.keepwinealive/keepwinealive.cc b/examples/0041.keepwinealive/keepwinealive.cc new file mode 100644 index 000000000..924fd13b8 --- /dev/null +++ b/examples/0041.keepwinealive/keepwinealive.cc @@ -0,0 +1,12 @@ +#include +#define NOMINMAX 1 +#define _WIN32_LEAN_AND_MEAN +#include +#undef min +#undef max + +int main() +{ + ::fast_io::io::perr("keep wine alive: ", utc(::fast_io::posix_clock_gettime(::fast_io::posix_clock_id::realtime))); + WaitForSingleObject(GetCurrentProcess(), INFINITE); +} From 3239c6bc3e2a3313cfaef3637bf21914c3517e0d Mon Sep 17 00:00:00 2001 From: trcrsired Date: Tue, 5 May 2026 03:07:41 +0800 Subject: [PATCH 22/82] should be \n for keepwinealive --- examples/0041.keepwinealive/keepwinealive.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/0041.keepwinealive/keepwinealive.cc b/examples/0041.keepwinealive/keepwinealive.cc index 924fd13b8..965ee51c5 100644 --- a/examples/0041.keepwinealive/keepwinealive.cc +++ b/examples/0041.keepwinealive/keepwinealive.cc @@ -7,6 +7,6 @@ int main() { - ::fast_io::io::perr("keep wine alive: ", utc(::fast_io::posix_clock_gettime(::fast_io::posix_clock_id::realtime))); + ::fast_io::io::perrln("keep wine alive: ", utc(::fast_io::posix_clock_gettime(::fast_io::posix_clock_id::realtime))); WaitForSingleObject(GetCurrentProcess(), INFINITE); } From 31c711d1a1501109fd8291f34c153790b4fbcb06 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Tue, 5 May 2026 03:40:32 +0800 Subject: [PATCH 23/82] avoid testing keep alive --- examples/.test_prop.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/.test_prop.toml b/examples/.test_prop.toml index 989d59389..6e1ed6c1e 100644 --- a/examples/.test_prop.toml +++ b/examples/.test_prop.toml @@ -43,5 +43,8 @@ ignore = true ["0040.wifianalyzer"] ignore = true +["0041.keepwinealive"] +ignore = true + ["0042.scn_ip_port"] interactive = true From 63de41854ca82752c32f45ddabc00aa42d300b5a Mon Sep 17 00:00:00 2001 From: trcrsired Date: Tue, 5 May 2026 06:19:41 +0800 Subject: [PATCH 24/82] [deque] add a resize implementation as placeholder --- include/fast_io_dsal/impl/deque.h | 30 ++++++++++++----------- tests/0026.container/0003.deque/resize.cc | 21 ++++++++++++++++ 2 files changed, 37 insertions(+), 14 deletions(-) create mode 100644 tests/0026.container/0003.deque/resize.cc diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index bf7cb3ada..ad129d9e4 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -3382,7 +3382,16 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE inline constexpr void assign_range(R &&rg) noexcept(::std::is_nothrow_constructible_v>) { } - inline constexpr void resize(size_type count) noexcept(::std::is_nothrow_default_constructible_v&&::std::is_nothrow_move_constructible_v) + inline constexpr void resize(size_type count, const_reference value) noexcept(::std::is_nothrow_copy_constructible_v&&::std::is_nothrow_move_constructible_v) + { + } +#if 0 + inline constexpr void resize(size_type count, ::fast_io::for_overwrite_t) noexcept(::fast_io::freestanding::is_zero_default_constructible_v || + ::std::is_nothrow_default_constructible_v) +#endif +#endif + + inline constexpr void resize(size_type count) noexcept(::std::is_nothrow_default_constructible_v && ::std::is_nothrow_move_constructible_v) { size_type oldsz{this->size()}; if (count == oldsz) @@ -3393,32 +3402,25 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE if (count < oldsz) { auto ed{newed}; - newed-=static_cast(oldsz-count); + newed -= static_cast(oldsz - count); newed = this->erase(newed, ed); } else { this->reserve_back(count); - ed = newed; - newed = ed+count; + auto ed{this->end()}; + newed = ed + static_cast(count - oldsz); ::fast_io::freestanding::uninitialized_default_construct(ed, newed); } - if (newed.curr_ptr == newed.begin_ptr) + if (newed.itercontent.curr_ptr == newed.itercontent.begin_ptr) { - newed.itercontent.curr_ptr = (newed.itercontent.begin_ptr=*--newed.itercontent.controller_ptr) + block_size; + newed.itercontent.curr_ptr = (newed.itercontent.begin_ptr = *--newed.itercontent.controller_ptr) + block_size; } this->controller.back_block.controller_ptr = newed.itercontent.controller_ptr; this->controller.back_end_ptr = (this->controller.back_block.begin_ptr = newed.itercontent.begin_ptr) + block_size; this->controller.back_block.curr_ptr = newed.itercontent.curr_ptr; } - inline constexpr void resize(size_type count, const_reference value) noexcept(::std::is_nothrow_copy_constructible_v&&::std::is_nothrow_move_constructible_v) - { - } -#if 0 - inline constexpr void resize(size_type count, ::fast_io::for_overwrite_t) noexcept(::fast_io::freestanding::is_zero_default_constructible_v || - ::std::is_nothrow_default_constructible_v) -#endif -#endif + private: inline constexpr iterator erase_no_destroy_common_impl(iterator first, iterator last, bool moveleft) noexcept { diff --git a/tests/0026.container/0003.deque/resize.cc b/tests/0026.container/0003.deque/resize.cc new file mode 100644 index 000000000..ba340f2db --- /dev/null +++ b/tests/0026.container/0003.deque/resize.cc @@ -0,0 +1,21 @@ +#include +#include + +template +inline void logging(T const &deq, ::std::source_location src = ::std::source_location::current()) +{ + ::fast_io::io::print(src, + "\n\tdeq.front_capacity()=", deq.front_capacity(), + "\n\tdeq.back_capacity()=", deq.back_capacity(), + "\n\tdeq.capacity()=", deq.capacity(), + "\n\tdeq.size()=", deq.size(), "\n\n"); +} + +int main() +{ + ::fast_io::deque<::std::size_t> deq; + deq.push_back(30); + logging(deq); + deq.resize(6000); + logging(deq); +} From 9473dbc769684551594d5644813916ce91ad5ba2 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Tue, 5 May 2026 06:41:57 +0800 Subject: [PATCH 25/82] [deque] draft for implementing resize. it is still buggy --- include/fast_io_dsal/impl/deque.h | 42 +++++++++++++++++------ tests/0026.container/0003.deque/resize.cc | 4 +++ 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index ad129d9e4..551f797fc 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -3382,26 +3382,21 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE inline constexpr void assign_range(R &&rg) noexcept(::std::is_nothrow_constructible_v>) { } - inline constexpr void resize(size_type count, const_reference value) noexcept(::std::is_nothrow_copy_constructible_v&&::std::is_nothrow_move_constructible_v) - { - } -#if 0 - inline constexpr void resize(size_type count, ::fast_io::for_overwrite_t) noexcept(::fast_io::freestanding::is_zero_default_constructible_v || - ::std::is_nothrow_default_constructible_v) -#endif + #endif - inline constexpr void resize(size_type count) noexcept(::std::is_nothrow_default_constructible_v && ::std::is_nothrow_move_constructible_v) +private: + inline constexpr void resize_impl(size_type count, T const *pval) noexcept(::std::is_nothrow_move_constructible_v) { size_type oldsz{this->size()}; if (count == oldsz) { return; } - iterator newed{this->end()}; + iterator newed; if (count < oldsz) { - auto ed{newed}; + auto ed{this->end()}; newed -= static_cast(oldsz - count); newed = this->erase(newed, ed); } @@ -3410,7 +3405,14 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE this->reserve_back(count); auto ed{this->end()}; newed = ed + static_cast(count - oldsz); - ::fast_io::freestanding::uninitialized_default_construct(ed, newed); + if (pval) + { + ::fast_io::freestanding::uninitialized_fill(ed, newed, *pval); + } + else + { + ::fast_io::freestanding::uninitialized_default_construct(ed, newed); + } } if (newed.itercontent.curr_ptr == newed.itercontent.begin_ptr) { @@ -3421,6 +3423,24 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE this->controller.back_block.curr_ptr = newed.itercontent.curr_ptr; } +public: + inline constexpr void resize(size_type count) noexcept(::std::is_nothrow_default_constructible_v && ::std::is_nothrow_move_constructible_v) + { + this->resize_impl(count, nullptr); + } + inline constexpr void resize(size_type count, ::fast_io::for_overwrite_t) noexcept(::fast_io::freestanding::is_zero_default_constructible_v || + ::std::is_nothrow_default_constructible_v) + { + /* + Todo + */ + this->resize(count); + } + inline constexpr void resize(size_type count, const_reference value) noexcept(::std::is_nothrow_copy_constructible_v && ::std::is_nothrow_move_constructible_v) + { + this->resize_impl(count, __builtin_addressof(value)); + } + private: inline constexpr iterator erase_no_destroy_common_impl(iterator first, iterator last, bool moveleft) noexcept { diff --git a/tests/0026.container/0003.deque/resize.cc b/tests/0026.container/0003.deque/resize.cc index ba340f2db..b7c0ef074 100644 --- a/tests/0026.container/0003.deque/resize.cc +++ b/tests/0026.container/0003.deque/resize.cc @@ -16,6 +16,10 @@ int main() ::fast_io::deque<::std::size_t> deq; deq.push_back(30); logging(deq); + deq.resize(265, 30); + logging(deq); deq.resize(6000); logging(deq); + deq.resize(6401); + logging(deq); } From c76063ddc9e996473dc1f6d050d9d146df663b2a Mon Sep 17 00:00:00 2001 From: trcrsired Date: Tue, 5 May 2026 07:15:34 +0800 Subject: [PATCH 26/82] [deque] reserve has not yet correctly implemented which of course breaks resize. First add its test and then do something --- tests/0026.container/0003.deque/reserve.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/0026.container/0003.deque/reserve.cc b/tests/0026.container/0003.deque/reserve.cc index b5fa712af..129e02f8b 100644 --- a/tests/0026.container/0003.deque/reserve.cc +++ b/tests/0026.container/0003.deque/reserve.cc @@ -16,6 +16,10 @@ int main() ::fast_io::deque<::std::size_t> deq; deq.push_back(30); logging(deq); + deq.reserve_back(265); + logging(deq); deq.reserve_back(6000); logging(deq); + deq.reserve_back(6401); + logging(deq); } From 2c7f7456d4b9a7fcaae45ac3fc486528056605c8 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Tue, 5 May 2026 07:21:20 +0800 Subject: [PATCH 27/82] using perr instead of print for test deque --- tests/0026.container/0003.deque/reserve.cc | 10 +++++----- tests/0026.container/0003.deque/resize.cc | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/0026.container/0003.deque/reserve.cc b/tests/0026.container/0003.deque/reserve.cc index 129e02f8b..aaa1f8043 100644 --- a/tests/0026.container/0003.deque/reserve.cc +++ b/tests/0026.container/0003.deque/reserve.cc @@ -4,11 +4,11 @@ template inline void logging(T const &deq, ::std::source_location src = ::std::source_location::current()) { - ::fast_io::io::print(src, - "\n\tdeq.front_capacity()=", deq.front_capacity(), - "\n\tdeq.back_capacity()=", deq.back_capacity(), - "\n\tdeq.capacity()=", deq.capacity(), - "\n\tdeq.size()=", deq.size(), "\n\n"); + ::fast_io::io::perr(src, + "\n\tdeq.front_capacity()=", deq.front_capacity(), + "\n\tdeq.back_capacity()=", deq.back_capacity(), + "\n\tdeq.capacity()=", deq.capacity(), + "\n\tdeq.size()=", deq.size(), "\n\n"); } int main() diff --git a/tests/0026.container/0003.deque/resize.cc b/tests/0026.container/0003.deque/resize.cc index b7c0ef074..d316925ae 100644 --- a/tests/0026.container/0003.deque/resize.cc +++ b/tests/0026.container/0003.deque/resize.cc @@ -4,11 +4,11 @@ template inline void logging(T const &deq, ::std::source_location src = ::std::source_location::current()) { - ::fast_io::io::print(src, - "\n\tdeq.front_capacity()=", deq.front_capacity(), - "\n\tdeq.back_capacity()=", deq.back_capacity(), - "\n\tdeq.capacity()=", deq.capacity(), - "\n\tdeq.size()=", deq.size(), "\n\n"); + ::fast_io::io::perr(src, + "\n\tdeq.front_capacity()=", deq.front_capacity(), + "\n\tdeq.back_capacity()=", deq.back_capacity(), + "\n\tdeq.capacity()=", deq.capacity(), + "\n\tdeq.size()=", deq.size(), "\n\n"); } int main() From 655f60782544f077dd248e3563098ecc48af2541 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Wed, 6 May 2026 13:09:10 +0800 Subject: [PATCH 28/82] [deque] prevent crashing of reserve_back first --- include/fast_io_dsal/impl/deque.h | 75 ++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 12 deletions(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index 551f797fc..050494030 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -13,6 +13,7 @@ struct #endif deque_control_block_common { + using value_type = ::std::byte; ::std::byte *begin_ptr, *curr_ptr; ::std::byte **controller_ptr; }; @@ -20,6 +21,7 @@ struct template struct deque_control_block { + using value_type = T; T *begin_ptr, *curr_ptr; T **controller_ptr; }; @@ -1477,6 +1479,9 @@ inline constexpr void deque_reserve_back_spaces_impl(dequecontroltype &controlle { ++toallocate; } +#if 0 + ::fast_io::io::debug_println(::std::source_location::current(),"\tblock_size=",block_size," toallocate=",toallocate); +#endif if consteval { ::fast_io::containers::details::deque_reserve_back_blocks_impl(controller, @@ -1816,16 +1821,25 @@ inline constexpr ::fast_io::containers::details::deque_nth_element_result -inline constexpr ::std::size_t deque_itercontent_diff_bytes_impl(T const &a, T const &b, ::std::size_t blockbytes) +inline constexpr ::std::size_t deque_itercontent_diff_impl(T const &a, T const &b, ::std::size_t block_size) { ::std::size_t controllerdiff{static_cast<::std::size_t>(a.controller_ptr - b.controller_ptr)}; - return controllerdiff * blockbytes + static_cast<::std::size_t>((a.curr_ptr - a.begin_ptr) + (b.begin_ptr - b.curr_ptr)); + return controllerdiff * block_size + static_cast<::std::size_t>((a.curr_ptr - a.begin_ptr) + (b.begin_ptr - b.curr_ptr)); } -template +template inline constexpr void deque_reserve_back_impl(dequecontroltype &controller, ::std::size_t newbackcap, ::std::size_t align, ::std::size_t sz, ::std::size_t block_size) noexcept { - ::std::size_t const deqsz{::fast_io::containers::details::deque_itercontent_diff_bytes_impl(controller.back_block, controller.front_block, block_size * sz) / sz}; + ::std::size_t deqsz; + + if constexpr (divsz) + { + deqsz = ::fast_io::containers::details::deque_itercontent_diff_impl(controller.back_block, controller.front_block, block_size * sz) / sz; + } + else + { + deqsz = ::fast_io::containers::details::deque_itercontent_diff_impl(controller.back_block, controller.front_block, block_size); + } ::std::size_t toaddedsz; #if defined(__GNUC__) || defined(__clang__) @@ -1845,19 +1859,35 @@ inline constexpr void deque_reserve_back_impl(dequecontroltype &controller, ::st } toaddedsz = static_cast<::std::size_t>(newbackcap - deqsz); } - ::fast_io::containers::details::deque_reserve_back_spaces_impl(controller, toaddedsz, align, sz, block_size); + if constexpr (divsz) + { + ::fast_io::containers::details::deque_reserve_back_spaces_impl(controller, toaddedsz, align, sz, block_size); + } + else + { + ::fast_io::containers::details::deque_reserve_back_spaces_impl(controller, toaddedsz, align, 1zu, block_size * sz); + } } -template +template inline constexpr void deque_reserve_back_common(dequecontroltype &controller, ::std::size_t newbackcap) noexcept { - ::fast_io::containers::details::deque_reserve_back_impl(controller, newbackcap, align, sz, block_size); + ::fast_io::containers::details::deque_reserve_back_impl(controller, newbackcap, align, sz, block_size); } -template +template inline constexpr void deque_reserve_front_impl(dequecontroltype &controller, ::std::size_t newfrontcap, ::std::size_t align, ::std::size_t sz, ::std::size_t block_size) noexcept { - ::std::size_t const deqsz{::fast_io::containers::details::deque_itercontent_diff_bytes_impl(controller.back_block, controller.front_block, block_size * sz) / sz}; + ::std::size_t deqsz; + + if constexpr (divsz) + { + deqsz = ::fast_io::containers::details::deque_itercontent_diff_impl(controller.back_block, controller.front_block, block_size * sz) / sz; + } + else + { + deqsz = ::fast_io::containers::details::deque_itercontent_diff_impl(controller.back_block, controller.front_block, block_size); + } ::std::size_t toaddedsz; #if defined(__GNUC__) || defined(__clang__) @@ -1877,7 +1907,14 @@ inline constexpr void deque_reserve_front_impl(dequecontroltype &controller, ::s } toaddedsz = static_cast<::std::size_t>(newfrontcap - deqsz); } - ::fast_io::containers::details::deque_reserve_front_spaces_impl(controller, toaddedsz, align, sz, block_size); + if constexpr (divsz) + { + ::fast_io::containers::details::deque_reserve_front_spaces_impl(controller, toaddedsz, align, sz, block_size); + } + else + { + ::fast_io::containers::details::deque_reserve_front_spaces_impl(controller, toaddedsz, align, 1zu, block_size * sz); + } } template @@ -3367,11 +3404,25 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE } inline constexpr void reserve_back(size_type backcap) noexcept { - ::fast_io::containers::details::deque_reserve_back_common(this->controller, backcap); + if consteval + { + ::fast_io::containers::details::deque_reserve_back_common(this->controller, backcap); + } + else + { + ::fast_io::containers::details::deque_reserve_back_common(*reinterpret_cast<::fast_io::containers::details::deque_controller_common *>(__builtin_addressof(this->controller)), backcap); + } } inline constexpr void reserve_front(size_type frontcap) noexcept { - ::fast_io::containers::details::deque_reserve_front_common(this->controller, frontcap); + if consteval + { + ::fast_io::containers::details::deque_reserve_front_common(this->controller, frontcap); + } + else + { + ::fast_io::containers::details::deque_reserve_front_common(*reinterpret_cast<::fast_io::containers::details::deque_controller_common *>(__builtin_addressof(this->controller)), frontcap); + } } #if 0 inline constexpr void assign(size_type count, const_reference val) noexcept(::std::is_nothrow_copy_constructible_v) From eccb10e76f1115914a12be5bb4a77a809c8d90dd Mon Sep 17 00:00:00 2001 From: trcrsired Date: Fri, 8 May 2026 04:46:03 +0800 Subject: [PATCH 29/82] scanpass.cc --- .../0043.scanwinprocesspasswords/scanpass.cc | 204 ++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 examples/0043.scanwinprocesspasswords/scanpass.cc diff --git a/examples/0043.scanwinprocesspasswords/scanpass.cc b/examples/0043.scanwinprocesspasswords/scanpass.cc new file mode 100644 index 000000000..d11ebd20d --- /dev/null +++ b/examples/0043.scanwinprocesspasswords/scanpass.cc @@ -0,0 +1,204 @@ +/** + * =============================================================== + * Edge Credential Memory Scanner (Educational Security Research) + * =============================================================== + * + * CONTEXT: + * In early 2026, security researchers identified that Microsoft Edge (and other + * Chromium-based browsers) may store sensitive data, including password vault + * entries and session cookies, in plaintext within the process heap (MEM_PRIVATE). + * While modern Windows OS provides process isolation, any process running with + * the same user privileges (like this tool) can utilize NtReadVirtualMemory + * (via ReadProcessMemory) to scrape these credentials. + * + * REFERENCE: + * https://isc.sans.edu/diary/Cleartext+Passwords+in+MS+Edge+In+2026/32954 + * + * FUNCTIONALITY: + * 1. Takes a process name (e.g., msedge.exe) and an optional search term. + * 2. Iterates through all running processes using ToolHelp32 snapshots. + * 3. For every matching process, it scans committed private read/write memory. + * 4. Utilizes the C++17 Boyer-Moore-Horspool algorithm for high-performance searching. + * 5. Uses fast_io for optimized I/O operations and memory-safe buffer handling. + * + * USAGE: + * scanpass.exe msedge.exe "your_email@outlook.com" + * scanpass.exe msedge.exe "your_known_password" + * + * ====================================================================================== + */ + +#define NOMINMAX 1 +#define _WIN32_LEAN_AND_MEAN 1 +#include +#include +#include +#include +#include +#include +#include +#include // Required for Boyer-Moore + +/** + * Prints a sanitized snippet of memory around a discovered match. + */ +template +inline void PrintSnippet(T &outstm, ::fast_io::string_view buffer, size_t offset, size_t contextSize = 100) +{ + using namespace ::fast_io::io; + size_t start = (offset > contextSize) ? offset - contextSize : 0; + size_t end = (offset + contextSize < buffer.size()) ? offset + contextSize : buffer.size(); + + print(outstm, " Snippet: ["); + for (size_t i = start; i < end; ++i) + { + if (i == offset) + { + print(outstm, " >>"); // Highlight start of match + } + + // Print printable ASCII, otherwise use a placeholder + auto chval{static_cast(buffer[i])}; + print(outstm, ::fast_io::mnp::chvw(::fast_io::char_category::is_c_graph(chval) ? chval : u8'.')); + + if (i == offset + contextSize / 2) + { + print(outstm, "<< "); + } + } + print(outstm, "]\n"); +} + +template +inline void ScanProcessMemory(T &outstm, DWORD pid, ::fast_io::string_view target) +{ + using namespace ::fast_io::io; + HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); + if (!hProcess) + { + ::fast_io::throw_win32_error(); + } + ::fast_io::win32_file hprocessfile(hProcess); + + SYSTEM_INFO si; + GetSystemInfo(__builtin_addressof(si)); + + MEMORY_BASIC_INFORMATION mbi; + unsigned char *addr = (unsigned char *)si.lpMinimumApplicationAddress; + // Pre-initialize the Boyer-Moore searcher if a target is provided + ::std::boyer_moore_horspool_searcher searcher(target.cbegin(), target.cend()); + + print(outstm, "[+] Scanning PID ", pid, "...\n"); + + while (addr < (unsigned char *)si.lpMaximumApplicationAddress) + { + if (VirtualQueryEx(hProcess, addr, ::std::addressof(mbi), sizeof(mbi)) == sizeof(mbi)) + { + // We search MEM_PRIVATE & PAGE_READWRITE because that's where + // heap data (passwords/strings) usually resides. + bool isDataRegion = (mbi.State == MEM_COMMIT) && + (mbi.Protect & PAGE_READWRITE) && + (mbi.Type == MEM_PRIVATE); + + if (isDataRegion && !target.is_empty()) + { + ::fast_io::vector buffer(mbi.RegionSize, ::fast_io::for_overwrite); + SIZE_T bytesRead; + + if (ReadProcessMemory(hProcess, addr, buffer.data(), mbi.RegionSize, __builtin_addressof(bytesRead))) + { + auto it = std::search(buffer.begin(), buffer.begin() + bytesRead, searcher); + + while (it != (buffer.begin() + bytesRead)) + { + size_t offset = std::distance(buffer.begin(), it); + println(outstm, "[!] Match found at 0x", + ::fast_io::mnp::pointervw(addr + offset)); + PrintSnippet(outstm, ::fast_io::string_view(buffer.data(), buffer.size()), offset); + + // Continue searching in the same block + it = std::search(it + target.size(), buffer.begin() + bytesRead, searcher); + } + } + } + addr += mbi.RegionSize; + } + else + { + break; + } + } + + print(outstm, "[+] Scan finished.\n"); +} + +inline void FindAndScanProcesses(auto &obf, ::fast_io::u16string_view processName, ::fast_io::string_view target) +{ + using namespace ::fast_io::io; + + HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (hSnap == INVALID_HANDLE_VALUE) + { + ::fast_io::throw_win32_error(); + } + ::fast_io::win32_file snap_file(hSnap); + + PROCESSENTRY32W pe32; + pe32.dwSize = sizeof(PROCESSENTRY32W); + + if (!Process32FirstW(hSnap, &pe32)) + { + return; + } + + do + { + // Convert WCHAR to a comparable format + ::fast_io::u16string_view current_name(::fast_io::mnp::os_c_str(reinterpret_cast(pe32.szExeFile))); + + // Use a wide search or conversion if necessary; here we do a simple match + // Note: For Edge, you'll see many "msedge.exe" entries + if (current_name == processName) + { + try + { + ScanProcessMemory(obf, pe32.th32ProcessID, target); + } + catch (::fast_io::error e) + { + println(obf, "[-] Failed: ", e); + } + } + } while (Process32NextW(hSnap, &pe32)); +} + +int main(int argc, char *argv[]) +{ + using namespace ::fast_io::io; + if (argc < 2) + { + if (argc == 0) + { + return 1; + } + perr("Usage: ", ::fast_io::mnp::os_c_str(*argv), " [search_term]\n"); + return 1; + } + + try + { + ::fast_io::out_buf_type obf(::fast_io::out()); + ::fast_io::string_view procName(::fast_io::mnp::os_c_str(argv[1])); + ::fast_io::string_view searchTerm(::fast_io::mnp::os_c_str((argc >= 3) ? argv[2] : "")); + + println(obf, "[*] Searching for all instances of: ", procName); + ::fast_io::u16string uProcName(::fast_io::u16concat_fast_io(::fast_io::mnp::code_cvt(procName))); + FindAndScanProcesses(obf, ::fast_io::u16string_view(::std::from_range, uProcName), searchTerm); + println(obf, "[*] All scans complete."); + } + catch (::fast_io::error e) + { + perrln(e); + return 1; + } +} \ No newline at end of file From d171eb34a7170576b85fe8087f9d79c1ac5d0ff3 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Fri, 8 May 2026 04:47:31 +0800 Subject: [PATCH 30/82] ignore scanpass --- examples/.test_prop.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/.test_prop.toml b/examples/.test_prop.toml index 6e1ed6c1e..f13689bf8 100644 --- a/examples/.test_prop.toml +++ b/examples/.test_prop.toml @@ -48,3 +48,6 @@ ignore = true ["0042.scn_ip_port"] interactive = true + +["0043.scanwinprocesspasswords"] +ignore = true From e8315e497614be768dc403e262f2facc831828a5 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Fri, 8 May 2026 05:26:36 +0800 Subject: [PATCH 31/82] allow cstring_view to be used directly for string but rvalue is forbidden --- .../0043.scanwinprocesspasswords/scanpass.cc | 6 +++--- include/fast_io_dsal/impl/cstring_view.h | 16 +++++++++++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/examples/0043.scanwinprocesspasswords/scanpass.cc b/examples/0043.scanwinprocesspasswords/scanpass.cc index d11ebd20d..1bd0acc24 100644 --- a/examples/0043.scanwinprocesspasswords/scanpass.cc +++ b/examples/0043.scanwinprocesspasswords/scanpass.cc @@ -132,7 +132,7 @@ inline void ScanProcessMemory(T &outstm, DWORD pid, ::fast_io::string_view targe print(outstm, "[+] Scan finished.\n"); } -inline void FindAndScanProcesses(auto &obf, ::fast_io::u16string_view processName, ::fast_io::string_view target) +inline void FindAndScanProcesses(auto &obf, ::fast_io::u16cstring_view processName, ::fast_io::string_view target) { using namespace ::fast_io::io; @@ -154,7 +154,7 @@ inline void FindAndScanProcesses(auto &obf, ::fast_io::u16string_view processNam do { // Convert WCHAR to a comparable format - ::fast_io::u16string_view current_name(::fast_io::mnp::os_c_str(reinterpret_cast(pe32.szExeFile))); + ::fast_io::u16string_view current_name(::fast_io::mnp::os_c_str(reinterpret_cast(pe32.szExeFile), processName.size())); // Use a wide search or conversion if necessary; here we do a simple match // Note: For Edge, you'll see many "msedge.exe" entries @@ -193,7 +193,7 @@ int main(int argc, char *argv[]) println(obf, "[*] Searching for all instances of: ", procName); ::fast_io::u16string uProcName(::fast_io::u16concat_fast_io(::fast_io::mnp::code_cvt(procName))); - FindAndScanProcesses(obf, ::fast_io::u16string_view(::std::from_range, uProcName), searchTerm); + FindAndScanProcesses(obf, ::fast_io::u16cstring_view(uProcName), searchTerm); println(obf, "[*] All scans complete."); } catch (::fast_io::error e) diff --git a/include/fast_io_dsal/impl/cstring_view.h b/include/fast_io_dsal/impl/cstring_view.h index 9b1e446c3..a583dd92d 100644 --- a/include/fast_io_dsal/impl/cstring_view.h +++ b/include/fast_io_dsal/impl/cstring_view.h @@ -60,9 +60,19 @@ class basic_cstring_view : private ::fast_io::containers::basic_string_view - requires(::std::constructible_from) - inline explicit constexpr basic_cstring_view(::fast_io::containers::null_terminated_t, ::fast_io::freestanding::from_range_t, rg const &&r) noexcept - : string_view_type(::std::forward(r)) + requires(::std::same_as<::std::ranges::range_value_t, char_type> && !::std::is_array_v<::std::remove_cvref_t> && + !::std::is_rvalue_reference_v) + inline explicit constexpr basic_cstring_view(::fast_io::containers::null_terminated_t, ::fast_io::freestanding::from_range_t, rg &&r) noexcept + : string_view_type(::fast_io::freestanding::from_range, ::std::forward(r)) + { + } + template <::std::ranges::contiguous_range rg> + requires(requires(rg r) { + { r.c_str() } -> ::std::convertible_to; + } && ::std::same_as<::std::ranges::range_value_t, char_type> && !::std::is_array_v<::std::remove_cvref_t> && + !::std::is_rvalue_reference_v) + inline explicit constexpr basic_cstring_view(rg &&r) noexcept + : string_view_type(::fast_io::freestanding::from_range, ::std::forward(r)) { } From a36f46f61fc261ea54568d016975a5ae71852c71 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Fri, 8 May 2026 05:31:08 +0800 Subject: [PATCH 32/82] [skip ci] even we know it has .c_str() we still require ::std::from_range for api consistency. construction must be thought thoroughly or it is extremely easy to cause memory safety bugs --- examples/0043.scanwinprocesspasswords/scanpass.cc | 2 +- include/fast_io_dsal/impl/cstring_view.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/0043.scanwinprocesspasswords/scanpass.cc b/examples/0043.scanwinprocesspasswords/scanpass.cc index 1bd0acc24..f3e08524f 100644 --- a/examples/0043.scanwinprocesspasswords/scanpass.cc +++ b/examples/0043.scanwinprocesspasswords/scanpass.cc @@ -193,7 +193,7 @@ int main(int argc, char *argv[]) println(obf, "[*] Searching for all instances of: ", procName); ::fast_io::u16string uProcName(::fast_io::u16concat_fast_io(::fast_io::mnp::code_cvt(procName))); - FindAndScanProcesses(obf, ::fast_io::u16cstring_view(uProcName), searchTerm); + FindAndScanProcesses(obf, ::fast_io::u16cstring_view(::std::from_range, uProcName), searchTerm); println(obf, "[*] All scans complete."); } catch (::fast_io::error e) diff --git a/include/fast_io_dsal/impl/cstring_view.h b/include/fast_io_dsal/impl/cstring_view.h index a583dd92d..2037a07c5 100644 --- a/include/fast_io_dsal/impl/cstring_view.h +++ b/include/fast_io_dsal/impl/cstring_view.h @@ -71,7 +71,7 @@ class basic_cstring_view : private ::fast_io::containers::basic_string_view ::std::convertible_to; } && ::std::same_as<::std::ranges::range_value_t, char_type> && !::std::is_array_v<::std::remove_cvref_t> && !::std::is_rvalue_reference_v) - inline explicit constexpr basic_cstring_view(rg &&r) noexcept + inline explicit constexpr basic_cstring_view(::fast_io::freestanding::from_range_t, rg &&r) noexcept : string_view_type(::fast_io::freestanding::from_range, ::std::forward(r)) { } From c86f9d4e89675995516a29995e2677043afb0937 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Fri, 8 May 2026 05:37:29 +0800 Subject: [PATCH 33/82] prevent rvalue reference passed into string_view and cstring_view we had the conditions before but it failed. also we probably need to do the same for span but i need to fix examples first --- include/fast_io_dsal/impl/cstring_view.h | 4 ++-- include/fast_io_dsal/impl/string_view.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/fast_io_dsal/impl/cstring_view.h b/include/fast_io_dsal/impl/cstring_view.h index 2037a07c5..046b96cac 100644 --- a/include/fast_io_dsal/impl/cstring_view.h +++ b/include/fast_io_dsal/impl/cstring_view.h @@ -61,7 +61,7 @@ class basic_cstring_view : private ::fast_io::containers::basic_string_view requires(::std::same_as<::std::ranges::range_value_t, char_type> && !::std::is_array_v<::std::remove_cvref_t> && - !::std::is_rvalue_reference_v) + !::std::is_rvalue_reference_v) inline explicit constexpr basic_cstring_view(::fast_io::containers::null_terminated_t, ::fast_io::freestanding::from_range_t, rg &&r) noexcept : string_view_type(::fast_io::freestanding::from_range, ::std::forward(r)) { @@ -70,7 +70,7 @@ class basic_cstring_view : private ::fast_io::containers::basic_string_view ::std::convertible_to; } && ::std::same_as<::std::ranges::range_value_t, char_type> && !::std::is_array_v<::std::remove_cvref_t> && - !::std::is_rvalue_reference_v) + !::std::is_rvalue_reference_v) inline explicit constexpr basic_cstring_view(::fast_io::freestanding::from_range_t, rg &&r) noexcept : string_view_type(::fast_io::freestanding::from_range, ::std::forward(r)) { diff --git a/include/fast_io_dsal/impl/string_view.h b/include/fast_io_dsal/impl/string_view.h index ac377d3c0..0b6f55b1e 100644 --- a/include/fast_io_dsal/impl/string_view.h +++ b/include/fast_io_dsal/impl/string_view.h @@ -44,7 +44,7 @@ class basic_string_view template <::std::ranges::contiguous_range rg> requires(::std::same_as<::std::ranges::range_value_t, char_type> && !::std::is_array_v<::std::remove_cvref_t> && - !::std::is_rvalue_reference_v) + !::std::is_rvalue_reference_v) inline explicit constexpr basic_string_view(::fast_io::freestanding::from_range_t, rg &&r) noexcept : ptr{::std::ranges::cdata(r)}, n{::std::ranges::size(r)} { From fe3ca945f709ec689303f44a592cf8f8e43a361b Mon Sep 17 00:00:00 2001 From: trcrsired Date: Fri, 8 May 2026 05:43:26 +0800 Subject: [PATCH 34/82] [skip ci] prevent strict aliasing violation for casting to char16_t const* --- examples/0043.scanwinprocesspasswords/scanpass.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/examples/0043.scanwinprocesspasswords/scanpass.cc b/examples/0043.scanwinprocesspasswords/scanpass.cc index f3e08524f..8bb853f0c 100644 --- a/examples/0043.scanwinprocesspasswords/scanpass.cc +++ b/examples/0043.scanwinprocesspasswords/scanpass.cc @@ -153,8 +153,14 @@ inline void FindAndScanProcesses(auto &obf, ::fast_io::u16cstring_view processNa do { - // Convert WCHAR to a comparable format - ::fast_io::u16string_view current_name(::fast_io::mnp::os_c_str(reinterpret_cast(pe32.szExeFile), processName.size())); + // Convert WCHAR to a comparable format. + // Prevent strict aliasing violation with [[__gnu__::__may_alias__]] attribute + using char16_const_may_alias_ptr +#if __has_cpp_attribute(__gnu__::__may_alias__) + [[__gnu__::__may_alias__]] +#endif + = char16_t const *; + ::fast_io::u16string_view current_name(::fast_io::mnp::os_c_str(reinterpret_cast(pe32.szExeFile), processName.size())); // Use a wide search or conversion if necessary; here we do a simple match // Note: For Edge, you'll see many "msedge.exe" entries From 71ee4badd1c5d5677a0e460d20b521a7c352c8a0 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Fri, 8 May 2026 05:47:59 +0800 Subject: [PATCH 35/82] [skip ci] span needs similar restrictions with ::std::from_range --- include/fast_io_dsal/impl/span.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/fast_io_dsal/impl/span.h b/include/fast_io_dsal/impl/span.h index a1615b7cc..48cec6f98 100644 --- a/include/fast_io_dsal/impl/span.h +++ b/include/fast_io_dsal/impl/span.h @@ -43,8 +43,9 @@ class span : ptr{::std::to_address(first)}, n{static_cast(snt - first)} {} template <::std::ranges::contiguous_range R> - requires(::std::same_as> && !::std::same_as<::std::remove_cvref_t, ::fast_io::containers::span>) - inline constexpr explicit span(R &&range) noexcept(noexcept(::std::ranges::data(range)) && noexcept(::std::ranges::size(range))) + requires(::std::same_as> && + !::std::is_rvalue_reference_v) + inline constexpr explicit span(::fast_io::freestanding::from_range_t, R &&range) noexcept(noexcept(::std::ranges::data(range)) && noexcept(::std::ranges::size(range))) : ptr{::std::ranges::data(range)}, n{::std::ranges::size(range)} {} From e452bd15983b8de07fbcb8802216a11a0e5f7a4e Mon Sep 17 00:00:00 2001 From: trcrsired Date: Fri, 8 May 2026 05:51:47 +0800 Subject: [PATCH 36/82] [skip ci] i forgot index_span. they should all use from_range --- include/fast_io_dsal/impl/index_span.h | 4 ++-- include/fast_io_dsal/impl/span.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/fast_io_dsal/impl/index_span.h b/include/fast_io_dsal/impl/index_span.h index 27e03a720..8184d8611 100644 --- a/include/fast_io_dsal/impl/index_span.h +++ b/include/fast_io_dsal/impl/index_span.h @@ -51,8 +51,8 @@ class index_span : ptr{::std::ranges::data(range)} {} template <::std::ranges::contiguous_range R> - requires(::std::same_as> && !::std::same_as<::std::remove_cvref_t, ::fast_io::containers::index_span>) - inline constexpr index_span(R &&range) noexcept(noexcept(::std::ranges::data(range)) && noexcept(::std::ranges::size(range))) + requires(::std::same_as> && !::std::is_rvalue_reference_v) + inline constexpr index_span(::fast_io::freestanding::from_range_t, R &&range) noexcept(noexcept(::std::ranges::data(range)) && noexcept(::std::ranges::size(range))) : ptr{::std::ranges::data(range)} { if (::std::ranges::size(range) < N) [[unlikely]] diff --git a/include/fast_io_dsal/impl/span.h b/include/fast_io_dsal/impl/span.h index 48cec6f98..915629c37 100644 --- a/include/fast_io_dsal/impl/span.h +++ b/include/fast_io_dsal/impl/span.h @@ -44,7 +44,7 @@ class span {} template <::std::ranges::contiguous_range R> requires(::std::same_as> && - !::std::is_rvalue_reference_v) + !::std::is_rvalue_reference_v) inline constexpr explicit span(::fast_io::freestanding::from_range_t, R &&range) noexcept(noexcept(::std::ranges::data(range)) && noexcept(::std::ranges::size(range))) : ptr{::std::ranges::data(range)}, n{::std::ranges::size(range)} {} From e3acb082c97047126c31acae0792fb5ca0d22ebf Mon Sep 17 00:00:00 2001 From: trcrsired Date: Fri, 8 May 2026 06:04:09 +0800 Subject: [PATCH 37/82] [skip ci]add from_range paramters to index_span and span too also deduction should also have from_range --- include/fast_io_dsal/impl/index_span.h | 5 +++-- include/fast_io_dsal/impl/span.h | 2 +- tests/0026.container/0010.span/index_span.cc | 2 +- tests/0026.container/0010.span/span.cc | 12 ++++++------ 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/include/fast_io_dsal/impl/index_span.h b/include/fast_io_dsal/impl/index_span.h index 8184d8611..2760e62c2 100644 --- a/include/fast_io_dsal/impl/index_span.h +++ b/include/fast_io_dsal/impl/index_span.h @@ -46,8 +46,9 @@ class index_span : ptr{::std::to_address(first)} {} template <::std::ranges::contiguous_range R> - requires(::std::same_as>) - inline explicit constexpr index_span(::fast_io::containers::index_unchecked_t, R &&range) noexcept(noexcept(::std::ranges::data(range))) + requires(::std::same_as> && + !::std::is_rvalue_reference_v) + inline explicit constexpr index_span(::fast_io::containers::index_unchecked_t, ::fast_io::freestanding::from_range_t, R &&range) noexcept(noexcept(::std::ranges::data(range))) : ptr{::std::ranges::data(range)} {} template <::std::ranges::contiguous_range R> diff --git a/include/fast_io_dsal/impl/span.h b/include/fast_io_dsal/impl/span.h index 915629c37..4035f5407 100644 --- a/include/fast_io_dsal/impl/span.h +++ b/include/fast_io_dsal/impl/span.h @@ -336,7 +336,7 @@ inline constexpr ::fast_io::containers::span<::std::byte> as_writable_bytes(::fa } template <::std::ranges::contiguous_range R> -span(R &&r) -> span<::std::remove_reference_t<::std::ranges::range_reference_t>>; +span(::fast_io::freestanding::from_range_t, R &&r) -> span<::std::remove_reference_t<::std::ranges::range_reference_t>>; template requires ::std::equality_comparable diff --git a/tests/0026.container/0010.span/index_span.cc b/tests/0026.container/0010.span/index_span.cc index ff9519e4c..2e6649946 100644 --- a/tests/0026.container/0010.span/index_span.cc +++ b/tests/0026.container/0010.span/index_span.cc @@ -5,7 +5,7 @@ int main() { ::fast_io::array<::std::size_t, 40> arr{4, 6, 7}; - ::fast_io::index_span<::std::size_t, 5> sp(arr); + ::fast_io::index_span<::std::size_t, 5> sp(::fast_io::freestanding::from_range, arr); for (auto const &e : sp) { ::fast_io::io::println(e); diff --git a/tests/0026.container/0010.span/span.cc b/tests/0026.container/0010.span/span.cc index fcac1e46d..c781e8070 100644 --- a/tests/0026.container/0010.span/span.cc +++ b/tests/0026.container/0010.span/span.cc @@ -1,12 +1,12 @@ -#include -#include -#include +#include +#include +#include int main() { - ::fast_io::array<::std::size_t, 40> arr{4,6,7}; - ::fast_io::span sp(arr); - for(auto const & e : sp) + ::fast_io::array<::std::size_t, 40> arr{4, 6, 7}; + ::fast_io::span sp(::fast_io::freestanding::from_range, arr); + for (auto const &e : sp) { ::fast_io::io::println(e); } From 7e87862917650f93f029aa544fc77302f4c42af4 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Fri, 8 May 2026 06:12:31 +0800 Subject: [PATCH 38/82] [skip ci] scan pass avoid C style cast --- examples/0043.scanwinprocesspasswords/scanpass.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/0043.scanwinprocesspasswords/scanpass.cc b/examples/0043.scanwinprocesspasswords/scanpass.cc index 8bb853f0c..1e1214f50 100644 --- a/examples/0043.scanwinprocesspasswords/scanpass.cc +++ b/examples/0043.scanwinprocesspasswords/scanpass.cc @@ -84,13 +84,13 @@ inline void ScanProcessMemory(T &outstm, DWORD pid, ::fast_io::string_view targe GetSystemInfo(__builtin_addressof(si)); MEMORY_BASIC_INFORMATION mbi; - unsigned char *addr = (unsigned char *)si.lpMinimumApplicationAddress; + auto addr{reinterpret_cast<::std::byte *>(si.lpMinimumApplicationAddress)}; // Pre-initialize the Boyer-Moore searcher if a target is provided ::std::boyer_moore_horspool_searcher searcher(target.cbegin(), target.cend()); print(outstm, "[+] Scanning PID ", pid, "...\n"); - while (addr < (unsigned char *)si.lpMaximumApplicationAddress) + while (addr < reinterpret_cast<::std::byte *>(si.lpMaximumApplicationAddress)) { if (VirtualQueryEx(hProcess, addr, ::std::addressof(mbi), sizeof(mbi)) == sizeof(mbi)) { From 94d0f3ce660991322d7446f7b90705b33e85e02b Mon Sep 17 00:00:00 2001 From: trcrsired Date: Fri, 8 May 2026 06:16:04 +0800 Subject: [PATCH 39/82] [skip ci] scanpass uses std::addressof and avoid & --- examples/0043.scanwinprocesspasswords/scanpass.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/0043.scanwinprocesspasswords/scanpass.cc b/examples/0043.scanwinprocesspasswords/scanpass.cc index 1e1214f50..3e8d018e5 100644 --- a/examples/0043.scanwinprocesspasswords/scanpass.cc +++ b/examples/0043.scanwinprocesspasswords/scanpass.cc @@ -146,7 +146,7 @@ inline void FindAndScanProcesses(auto &obf, ::fast_io::u16cstring_view processNa PROCESSENTRY32W pe32; pe32.dwSize = sizeof(PROCESSENTRY32W); - if (!Process32FirstW(hSnap, &pe32)) + if (!Process32FirstW(hSnap, ::std::addressof(pe32))) { return; } From 007e05e10a69be948bb6525836bfaee9f8c08b2c Mon Sep 17 00:00:00 2001 From: trcrsired Date: Fri, 8 May 2026 06:21:23 +0800 Subject: [PATCH 40/82] avoid using template in the code --- examples/0043.scanwinprocesspasswords/scanpass.cc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/0043.scanwinprocesspasswords/scanpass.cc b/examples/0043.scanwinprocesspasswords/scanpass.cc index 3e8d018e5..1fbdeafb4 100644 --- a/examples/0043.scanwinprocesspasswords/scanpass.cc +++ b/examples/0043.scanwinprocesspasswords/scanpass.cc @@ -42,8 +42,7 @@ /** * Prints a sanitized snippet of memory around a discovered match. */ -template -inline void PrintSnippet(T &outstm, ::fast_io::string_view buffer, size_t offset, size_t contextSize = 100) +inline void PrintSnippet(auto &outstm, ::fast_io::string_view buffer, size_t offset, size_t contextSize = 100) { using namespace ::fast_io::io; size_t start = (offset > contextSize) ? offset - contextSize : 0; @@ -69,8 +68,7 @@ inline void PrintSnippet(T &outstm, ::fast_io::string_view buffer, size_t offset print(outstm, "]\n"); } -template -inline void ScanProcessMemory(T &outstm, DWORD pid, ::fast_io::string_view target) +inline void ScanProcessMemory(auto &outstm, DWORD pid, ::fast_io::string_view target) { using namespace ::fast_io::io; HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); From b8905d48cad80eca260594c41e6c8c452391a898 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Fri, 8 May 2026 06:31:41 +0800 Subject: [PATCH 41/82] [skip ci] avoid & we use ::std::addressof --- examples/0043.scanwinprocesspasswords/scanpass.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/0043.scanwinprocesspasswords/scanpass.cc b/examples/0043.scanwinprocesspasswords/scanpass.cc index 1fbdeafb4..6adb06dd9 100644 --- a/examples/0043.scanwinprocesspasswords/scanpass.cc +++ b/examples/0043.scanwinprocesspasswords/scanpass.cc @@ -60,7 +60,7 @@ inline void PrintSnippet(auto &outstm, ::fast_io::string_view buffer, size_t off auto chval{static_cast(buffer[i])}; print(outstm, ::fast_io::mnp::chvw(::fast_io::char_category::is_c_graph(chval) ? chval : u8'.')); - if (i == offset + contextSize / 2) + if (i == offset + (contextSize >> 1u)) { print(outstm, "<< "); } @@ -105,7 +105,7 @@ inline void ScanProcessMemory(auto &outstm, DWORD pid, ::fast_io::string_view ta if (ReadProcessMemory(hProcess, addr, buffer.data(), mbi.RegionSize, __builtin_addressof(bytesRead))) { - auto it = std::search(buffer.begin(), buffer.begin() + bytesRead, searcher); + auto it = ::std::search(buffer.begin(), buffer.begin() + bytesRead, searcher); while (it != (buffer.begin() + bytesRead)) { @@ -173,7 +173,7 @@ inline void FindAndScanProcesses(auto &obf, ::fast_io::u16cstring_view processNa println(obf, "[-] Failed: ", e); } } - } while (Process32NextW(hSnap, &pe32)); + } while (Process32NextW(hSnap, ::std::addressof(pe32))); } int main(int argc, char *argv[]) From c809f078709f74a23008d7d42ee058b35dcc4623 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Fri, 8 May 2026 06:44:55 +0800 Subject: [PATCH 42/82] [skip ci] avoid ln when we ends it with literals --- examples/0043.scanwinprocesspasswords/scanpass.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/0043.scanwinprocesspasswords/scanpass.cc b/examples/0043.scanwinprocesspasswords/scanpass.cc index 6adb06dd9..1034cf979 100644 --- a/examples/0043.scanwinprocesspasswords/scanpass.cc +++ b/examples/0043.scanwinprocesspasswords/scanpass.cc @@ -198,11 +198,11 @@ int main(int argc, char *argv[]) println(obf, "[*] Searching for all instances of: ", procName); ::fast_io::u16string uProcName(::fast_io::u16concat_fast_io(::fast_io::mnp::code_cvt(procName))); FindAndScanProcesses(obf, ::fast_io::u16cstring_view(::std::from_range, uProcName), searchTerm); - println(obf, "[*] All scans complete."); + print(obf, "[*] All scans complete.\n"); } catch (::fast_io::error e) { perrln(e); return 1; } -} \ No newline at end of file +} From fc2846b19fa6e3342f4736f64662a5d4351c2ced Mon Sep 17 00:00:00 2001 From: trcrsired Date: Sat, 9 May 2026 06:32:17 +0800 Subject: [PATCH 43/82] [deque] try to finish reserve and resize the deque rebalancing logic is completely false. the bug should also exist in other code and unfortunately fuzzer cannot catch it until we implement reserve_back/reserve_front --- include/fast_io_dsal/impl/deque.h | 39 +++++++++++++--------- tests/0026.container/0003.deque/reserve.cc | 13 ++++++++ 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index 050494030..b09325b84 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -13,7 +13,6 @@ struct #endif deque_control_block_common { - using value_type = ::std::byte; ::std::byte *begin_ptr, *curr_ptr; ::std::byte **controller_ptr; }; @@ -21,7 +20,6 @@ struct template struct deque_control_block { - using value_type = T; T *begin_ptr, *curr_ptr; T **controller_ptr; }; @@ -1376,6 +1374,10 @@ inline constexpr bool deque_reserve_back_blocks_impl(dequecontroltype &controlle controller.back_block.controller_ptr); if (diff_to_after_ptr <= nb) { + if (1u < diff_to_after_ptr) + { + nb -= static_cast<::std::size_t>(diff_to_after_ptr - 1u); + } ::std::size_t distance_back_to_after{ static_cast<::std::size_t>(controller.controller_block.controller_after_ptr - controller.back_block.controller_ptr)}; @@ -1393,8 +1395,8 @@ inline constexpr bool deque_reserve_back_blocks_impl(dequecontroltype &controlle static_cast<::std::size_t>(controller.front_block.controller_ptr - controller.controller_block.controller_start_reserved_ptr)}; ::std::size_t front_borrowed_blocks_count{front_reserved_blocks}; - ::std::size_t to_allocate_blocks{nb}; - if (nb < front_reserved_blocks) + ::std::size_t to_allocate_blocks{static_cast<::std::size_t>(nb)}; + if (to_allocate_blocks < front_reserved_blocks) { front_borrowed_blocks_count = nb; to_allocate_blocks = 0u; @@ -1405,7 +1407,6 @@ inline constexpr bool deque_reserve_back_blocks_impl(dequecontroltype &controlle } auto controller_start_reserved_ptr{ controller.controller_block.controller_start_reserved_ptr}; - auto pos{ controller.controller_block.controller_after_reserved_ptr}; pos = ::fast_io::freestanding::non_overlapped_copy_n(controller_start_reserved_ptr, @@ -1458,7 +1459,7 @@ inline constexpr void deque_grow_back_common(dequecontroltype &controller) noexc ::fast_io::containers::details::deque_grow_back_common_impl(controller, align, blockbytes); } -template +template inline constexpr void deque_reserve_back_spaces_impl(dequecontroltype &controller, ::std::size_t n, ::std::size_t align, ::std::size_t sz, ::std::size_t block_size) { if (!n) @@ -1467,6 +1468,10 @@ inline constexpr void deque_reserve_back_spaces_impl(dequecontroltype &controlle } auto back_curr_ptr{controller.back_block.curr_ptr}; ::std::size_t blocksn{static_cast<::std::size_t>(controller.back_end_ptr - back_curr_ptr)}; + if constexpr (divsz) + { + blocksn /= sz; + } if (n <= blocksn) { return; @@ -1479,9 +1484,7 @@ inline constexpr void deque_reserve_back_spaces_impl(dequecontroltype &controlle { ++toallocate; } -#if 0 - ::fast_io::io::debug_println(::std::source_location::current(),"\tblock_size=",block_size," toallocate=",toallocate); -#endif + if consteval { ::fast_io::containers::details::deque_reserve_back_blocks_impl(controller, @@ -1499,7 +1502,7 @@ inline constexpr void deque_reserve_back_spaces_impl(dequecontroltype &controlle template inline constexpr void deque_reserve_back_spaces(dequecontroltype &controller, ::std::size_t n) { - ::fast_io::containers::details::deque_reserve_back_spaces_impl(controller, n, align, sz, block_size); + ::fast_io::containers::details::deque_reserve_back_spaces_impl(controller, n, align, sz, block_size); } template @@ -1520,6 +1523,10 @@ inline constexpr bool deque_reserve_front_blocks_impl(dequecontroltype &controll controller.controller_block.controller_start_reserved_ptr); if (diff_to_start_ptr < nb) { + if (diff_to_start_ptr) + { + nb -= diff_to_start_ptr; + } ::std::size_t distance_front_to_start{ static_cast<::std::size_t>(controller.front_block.controller_ptr - controller.controller_block.controller_start_ptr)}; @@ -1538,8 +1545,8 @@ inline constexpr bool deque_reserve_front_blocks_impl(dequecontroltype &controll controller.back_block.controller_ptr - 1)}; ::std::size_t back_borrowed_blocks_count{back_reserved_blocks}; - ::std::size_t to_allocate_blocks{nb}; - if (nb < back_reserved_blocks) + ::std::size_t to_allocate_blocks{static_cast<::std::size_t>(nb)}; + if (to_allocate_blocks < back_reserved_blocks) { back_borrowed_blocks_count = nb; to_allocate_blocks = 0u; @@ -1861,11 +1868,11 @@ inline constexpr void deque_reserve_back_impl(dequecontroltype &controller, ::st } if constexpr (divsz) { - ::fast_io::containers::details::deque_reserve_back_spaces_impl(controller, toaddedsz, align, sz, block_size); + ::fast_io::containers::details::deque_reserve_back_spaces_impl(controller, toaddedsz, align, sz, block_size); } else { - ::fast_io::containers::details::deque_reserve_back_spaces_impl(controller, toaddedsz, align, 1zu, block_size * sz); + ::fast_io::containers::details::deque_reserve_back_spaces_impl(controller, toaddedsz, align, 1zu, block_size * sz); } } @@ -1917,10 +1924,10 @@ inline constexpr void deque_reserve_front_impl(dequecontroltype &controller, ::s } } -template +template inline constexpr void deque_reserve_front_common(dequecontroltype &controller, ::std::size_t newfrontcap) noexcept { - ::fast_io::containers::details::deque_reserve_front_impl(controller, newfrontcap, align, sz, block_size); + ::fast_io::containers::details::deque_reserve_front_impl(controller, newfrontcap, align, sz, block_size); } } // namespace details diff --git a/tests/0026.container/0003.deque/reserve.cc b/tests/0026.container/0003.deque/reserve.cc index aaa1f8043..a68aa1c9a 100644 --- a/tests/0026.container/0003.deque/reserve.cc +++ b/tests/0026.container/0003.deque/reserve.cc @@ -1,5 +1,6 @@ #include #include +#include template inline void logging(T const &deq, ::std::source_location src = ::std::source_location::current()) @@ -9,6 +10,8 @@ inline void logging(T const &deq, ::std::source_location src = ::std::source_loc "\n\tdeq.back_capacity()=", deq.back_capacity(), "\n\tdeq.capacity()=", deq.capacity(), "\n\tdeq.size()=", deq.size(), "\n\n"); + ::fast_io::io::debug_perr(src, + "\n", ::fast_io::manipulators::debug_view(deq), "\n\n"); } int main() @@ -22,4 +25,14 @@ int main() logging(deq); deq.reserve_back(6401); logging(deq); + deq.clear_destroy(); + logging(deq); + deq.push_front(30); + logging(deq); + deq.reserve_front(265); + logging(deq); + deq.reserve_front(6000); + logging(deq); + deq.reserve_front(6401); + logging(deq); } From 9327fe79c9a790aa560d709ca87396ecad47b209 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Sat, 9 May 2026 06:36:01 +0800 Subject: [PATCH 44/82] [deque] no need use if for nb -= for front only for back --- include/fast_io_dsal/impl/deque.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index b09325b84..6f9fe29ae 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -1523,10 +1523,7 @@ inline constexpr bool deque_reserve_front_blocks_impl(dequecontroltype &controll controller.controller_block.controller_start_reserved_ptr); if (diff_to_start_ptr < nb) { - if (diff_to_start_ptr) - { - nb -= diff_to_start_ptr; - } + nb -= diff_to_start_ptr; ::std::size_t distance_front_to_start{ static_cast<::std::size_t>(controller.front_block.controller_ptr - controller.controller_block.controller_start_ptr)}; From 9daea33c0e27098d1597fae843a09a16832473fa Mon Sep 17 00:00:00 2001 From: trcrsired Date: Sat, 9 May 2026 06:42:25 +0800 Subject: [PATCH 45/82] [deque] segments apis just use end it for implementation since our span supports constructing from [begin,end) instead of just begin with a size --- include/fast_io_dsal/impl/deque.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index 6f9fe29ae..9e0c90d8d 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -2709,12 +2709,12 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE if consteval { auto [start_ptr, end_ptr] = ::fast_io::containers::details::deque_nth_element_common(this->controller, pos); - return ::fast_io::containers::span(start_ptr, static_cast(end_ptr - start_ptr)); + return ::fast_io::containers::span(start_ptr, end_ptr); } else { auto [start_ptr, end_ptr] = ::std::bit_cast<::fast_io::containers::details::deque_nth_element_result>(::fast_io::containers::details::deque_nth_element_common(*reinterpret_cast<::fast_io::containers::details::deque_controller_common *>(__builtin_addressof(this->controller)), pos)); - return ::fast_io::containers::span(start_ptr, static_cast(end_ptr - start_ptr)); + return ::fast_io::containers::span(start_ptr, end_ptr); } } inline constexpr ::fast_io::containers::span const_nth_segment(size_type pos) const noexcept @@ -2722,14 +2722,14 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE if consteval { auto [start_ptr, end_ptr] = ::fast_io::containers::details::deque_nth_element_common(this->controller, pos); - return ::fast_io::containers::span(start_ptr, static_cast(end_ptr - start_ptr)); + return ::fast_io::containers::span(start_ptr, end_ptr); } else { auto [start_ptr, end_ptr] = ::std::bit_cast<::fast_io::containers::details::deque_nth_element_result>(::fast_io::containers::details::deque_nth_element_common(*reinterpret_cast<::fast_io::containers::details::deque_controller_common *>( const_cast(__builtin_addressof(this->controller))), pos)); - return ::fast_io::containers::span(start_ptr, static_cast(end_ptr - start_ptr)); + return ::fast_io::containers::span(start_ptr, end_ptr); } } inline constexpr ::fast_io::containers::span nth_segment(size_type pos) const noexcept From 98dca2d4ba1105729512eaf4dca88f12365b9220 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Sat, 9 May 2026 09:36:10 +0800 Subject: [PATCH 46/82] [deque] reimplement empty back logic --- .../fast_io_resize_for_overwite.cc | 35 +++ include/fast_io_dsal/impl/deque.h | 229 +++++++++++++++--- tests/0026.container/0003.deque/reserve.cc | 3 + 3 files changed, 232 insertions(+), 35 deletions(-) create mode 100644 benchmark/0011.containers/deque/0001.push_back/fast_io_resize_for_overwite.cc diff --git a/benchmark/0011.containers/deque/0001.push_back/fast_io_resize_for_overwite.cc b/benchmark/0011.containers/deque/0001.push_back/fast_io_resize_for_overwite.cc new file mode 100644 index 000000000..0c8b6f140 --- /dev/null +++ b/benchmark/0011.containers/deque/0001.push_back/fast_io_resize_for_overwite.cc @@ -0,0 +1,35 @@ +#include +#include +#include + +int main() +{ + fast_io::timer tm(u8"fast_io::deque resize_for_overwrite"); + fast_io::deque deq; + constexpr std::size_t n{100000000}; + { + fast_io::timer tm1(u8"push_back"); + deq.resize(n, ::fast_io::for_overwrite); + ::std::size_t idx{}; + for (::std::size_t i{}, segs{deq.segments_count()}; i != segs; ++i) + { + for (auto &e : deq.nth_segment(i)) + { + e = idx; + ++idx; + } + } + } + ::std::size_t sum{}; + { + fast_io::timer tm1(u8"loop"); + for (::std::size_t i{}, segs{deq.segments_count()}; i != segs; ++i) + { + for (auto const e : deq.const_nth_segment(i)) + { + sum += e; + } + } + } + ::fast_io::io::perrln("sum=", sum); +} diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index 9e0c90d8d..1659f4bfa 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -600,8 +600,8 @@ inline constexpr void deque_rebalance_or_grow_2x_after_blocks_impl(dequecontrolt } template -inline constexpr void deque_allocate_on_empty_common_with_n_impl(dequecontroltype &controller, ::std::size_t align, ::std::size_t bytes, - ::std::size_t initial_allocated_block_counts) noexcept +inline constexpr void deque_allocate_on_empty_common_with_n_impl(dequecontroltype &controller, ::std::size_t initial_allocated_block_counts, ::std::size_t align, ::std::size_t bytes, + int position) noexcept { ::std::size_t initial_allocated_block_counts_with_sentinel; #if (defined(__GNUC__) || defined(__clang__)) @@ -634,22 +634,62 @@ inline constexpr void deque_allocate_on_empty_common_with_n_impl(dequecontroltyp using begin_ptrtype = typename dequecontroltype::replacetype *; - auto begin_ptr{static_cast(allocator::allocate_aligned(align, bytes))}; + controller.controller_block.controller_after_ptr = (controller.controller_block.controller_start_ptr = allocated_blocks_ptr) + allocated_blocks_count; - controller_block.controller_start_ptr = allocated_blocks_ptr; - auto allocated_mid_block{allocated_blocks_ptr + (allocated_blocks_count >> 1u)}; - back_block.controller_ptr = front_block.controller_ptr = controller_block.controller_start_reserved_ptr = ::std::construct_at(allocated_mid_block, begin_ptr); - *(controller_block.controller_after_reserved_ptr = allocated_mid_block + 1) = nullptr; // set nullptr as a sentinel + ::std::size_t const allocated_blocks_count_half{allocated_blocks_count >> 1u}; + ::std::size_t const initial_allocated_block_counts_half{initial_allocated_block_counts >> 1u}; - controller_block.controller_after_ptr = allocated_blocks_ptr + allocated_blocks_count; - ::std::size_t halfsize{bytes >> 1u}; + auto allocated_mid_block{allocated_blocks_ptr + allocated_blocks_count_half}; - back_block.begin_ptr = front_block.begin_ptr = begin_ptr; - controller.back_end_ptr = controller.front_end_ptr = (begin_ptr + bytes); - auto halfposptr{begin_ptr + halfsize}; - front_block.curr_ptr = halfposptr; - back_block.curr_ptr = halfposptr; + auto start_block_ptr{allocated_mid_block - initial_allocated_block_counts_half}; + + auto end_block_ptr{start_block_ptr + initial_allocated_block_counts}; + for (auto i{start_block_ptr}; i != end_block_ptr; ++i) + { + ::std::construct_at(i, static_cast(allocator::allocate_aligned(align, bytes))); + } + *end_block_ptr = nullptr; + controller.controller_block.controller_start_reserved_ptr = start_block_ptr; + controller.controller_block.controller_after_reserved_ptr = end_block_ptr; + + begin_ptrtype begin_ptr; + if (position < 0) + { + // place logical cursor at the first reserved block (front side) + auto first_block_ptr{start_block_ptr}; + begin_ptr = *first_block_ptr; + + front_block.controller_ptr = first_block_ptr; + back_block.controller_ptr = first_block_ptr; + + front_block.curr_ptr = back_block.curr_ptr = begin_ptr; + } + else if (position == 0) + { + // place logical cursor in the middle block, middle of that block + auto mid_block_ptr{allocated_mid_block}; + begin_ptr = *mid_block_ptr; + auto mid_ptr{begin_ptr + (bytes >> 1u)}; + + front_block.controller_ptr = mid_block_ptr; + back_block.controller_ptr = mid_block_ptr; + + front_block.curr_ptr = back_block.curr_ptr = mid_ptr; + } + else + { + // place logical cursor at the last reserved block (back side) + auto last_block_ptr{end_block_ptr - 1}; + begin_ptr = *last_block_ptr; + + front_block.controller_ptr = last_block_ptr; + back_block.controller_ptr = last_block_ptr; + front_block.curr_ptr = back_block.curr_ptr = begin_ptr + bytes; + } + + front_block.begin_ptr = back_block.begin_ptr = begin_ptr; + controller.front_end_ptr = controller.back_end_ptr = begin_ptr + bytes; } template @@ -1357,14 +1397,8 @@ inline constexpr void deque_rebalance_or_grow_insertation_impl(dequecontroltype } template -inline constexpr bool deque_reserve_back_blocks_impl(dequecontroltype &controller, ::std::size_t nb, ::std::size_t align, ::std::size_t blockbytes) noexcept +inline constexpr void deque_reserve_back_blocks_impl_none_empty(dequecontroltype &controller, ::std::size_t nb, ::std::size_t align, ::std::size_t blockbytes) noexcept { - if (controller.controller_block.controller_start_ptr == nullptr) - { - ::fast_io::containers::details::deque_allocate_on_empty_common_with_n_impl( - controller, align, blockbytes, nb); - return false; - } using replacetype = typename dequecontroltype::replacetype; using begin_ptrtype = replacetype *; @@ -1431,7 +1465,18 @@ inline constexpr bool deque_reserve_back_blocks_impl(dequecontroltype &controlle controller.front_block.curr_ptr = controller.front_block.begin_ptr = front_begin_ptr; controller.front_end_ptr = front_begin_ptr + blockbytes; } +} +template +inline constexpr bool deque_reserve_back_blocks_impl(dequecontroltype &controller, ::std::size_t nb, ::std::size_t align, ::std::size_t blockbytes) noexcept +{ + if (controller.controller_block.controller_start_ptr == nullptr) + { + ::fast_io::containers::details::deque_allocate_on_empty_common_with_n_impl( + controller, nb, align, blockbytes, -1); + return false; + } + ::fast_io::containers::details::deque_reserve_back_blocks_impl_none_empty(controller, nb, align, blockbytes); return true; } @@ -1441,10 +1486,12 @@ inline constexpr void deque_grow_back_common_impl( std::size_t align, std::size_t bytes) noexcept { - if (!::fast_io::containers::details::deque_reserve_back_blocks_impl(controller, 1zu, align, bytes)) + if (controller.controller_block.controller_start_ptr == nullptr) { + ::fast_io::containers::details::deque_allocate_on_empty_common_with_n_impl(controller, 1u, align, bytes, 0); return; } + ::fast_io::containers::details::deque_reserve_back_blocks_impl_none_empty(controller, 1u, align, bytes); ++controller.back_block.controller_ptr; auto begin_ptr{*controller.back_block.controller_ptr}; controller.back_block.begin_ptr = begin_ptr; @@ -1506,14 +1553,8 @@ inline constexpr void deque_reserve_back_spaces(dequecontroltype &controller, :: } template -inline constexpr bool deque_reserve_front_blocks_impl(dequecontroltype &controller, ::std::size_t nb, ::std::size_t align, ::std::size_t blockbytes) noexcept +inline constexpr void deque_reserve_front_blocks_none_empty_impl(dequecontroltype &controller, ::std::size_t nb, ::std::size_t align, ::std::size_t blockbytes) noexcept { - if (controller.controller_block.controller_start_ptr == nullptr) - { - ::fast_io::containers::details::deque_allocate_on_empty_common_with_n_impl( - controller, align, blockbytes, nb); - return false; - } using replacetype = typename dequecontroltype::replacetype; using begin_ptrtype = replacetype *; @@ -1578,7 +1619,19 @@ inline constexpr bool deque_reserve_front_blocks_impl(dequecontroltype &controll controller.controller_block.controller_start_reserved_ptr = new_controller_start_reserved_ptr; } } - return true; +} + +template +inline constexpr void deque_reserve_front_blocks_impl(dequecontroltype &controller, ::std::size_t nb, ::std::size_t align, ::std::size_t blockbytes) noexcept +{ + if (controller.controller_block.controller_start_ptr == nullptr) + { + ::fast_io::containers::details::deque_allocate_on_empty_common_with_n_impl( + controller, nb, align, blockbytes, 1); + return; + } + ::fast_io::containers::details::deque_reserve_front_blocks_none_empty_impl(controller, nb, align, blockbytes); + return; } template @@ -1606,14 +1659,14 @@ inline constexpr void deque_reserve_front_spaces_impl(dequecontroltype &controll if consteval { ::fast_io::containers::details::deque_reserve_front_blocks_impl(controller, - toallocate, align, block_size); + toallocate, align, block_size, true); } else { ::std::size_t const block_bytes{block_size * sz}; ::fast_io::containers::details::deque_reserve_front_blocks_impl(*reinterpret_cast<::fast_io::containers::details::deque_controller_common *>( __builtin_addressof(controller)), - toallocate, align, block_bytes); + toallocate, align, block_bytes, true); } } @@ -1629,10 +1682,12 @@ inline constexpr void deque_grow_front_common_impl( std::size_t align, std::size_t bytes) noexcept { - if (!::fast_io::containers::details::deque_reserve_front_blocks_impl(controller, 1zu, align, bytes)) + if (controller.controller_block.controller_start_ptr == nullptr) { + ::fast_io::containers::details::deque_allocate_on_empty_common_with_n_impl(controller, 1u, align, bytes, 0); return; } + ::fast_io::containers::details::deque_reserve_front_blocks_none_empty_impl(controller, 1zu, align, bytes); auto begin_ptr{*(--controller.front_block.controller_ptr)}; controller.front_block.begin_ptr = begin_ptr; auto end_ptr{begin_ptr + bytes}; @@ -1927,6 +1982,58 @@ inline constexpr void deque_reserve_front_common(dequecontroltype &controller, : ::fast_io::containers::details::deque_reserve_front_impl(controller, newfrontcap, align, sz, block_size); } +template +inline constexpr ::std::size_t deque_itercontent_difference_unsigned_common(T const &a, T const &b, ::std::size_t blocksizedf) noexcept +{ + ::std::size_t controllerdiff{static_cast<::std::size_t>(a.controller_ptr - b.controller_ptr)}; + return controllerdiff * blocksizedf + static_cast<::std::size_t>((a.curr_ptr - a.begin_ptr) + (b.begin_ptr - b.curr_ptr)); +} +#if 0 +template +inline constexpr void deque_resize_common_impl(dequecontroltype &controller, ::std::size_t newsize, + ::std::size_t align, ::std::size_t sz, ::std::size_t block_size) noexcept +{ + ::std::size_t blockbytes{block_size * sz}; + size_type oldsz{ + ::fast_io::containers::details::deque_itercontent_difference_unsigned_common(controller.back_block, controller.front_block, blockbytes); + }; + if constexpr(divsz) + { + oldsz/=sz; + } + if (count == oldsz) + { + return; + } + iterator newed; + if (count < oldsz) + { + auto ed{}; + newed = ed; + newed -= static_cast(oldsz - count); + } + else + { + this->reserve_back(count); + auto ed{this->end()}; + newed = ed + static_cast(count - oldsz); + + } + if (newed.curr_ptr == newed.begin_ptr) + { + newed.curr_ptr = (newed.begin_ptr = *--newed.controller_ptr) + block_size; + } + controller.back_block.controller_ptr = newed.controller_ptr; + controller.back_end_ptr = (this->controller.back_block.begin_ptr = newed.begin_ptr) + block_size; + controller.back_block.curr_ptr = newed.curr_ptr; +} + +template +inline constexpr void deque_resize_common(dequecontroltype &controller, ::std::size_t newsize) noexcept +{ + ::fast_io::containers::details::deque_resize_common_impl(controller, newsize, align, sz, block_size); +} +#endif } // namespace details template <::std::forward_iterator ForwardIt> @@ -3452,8 +3559,13 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE if (count < oldsz) { auto ed{this->end()}; + newed = ed; newed -= static_cast(oldsz - count); - newed = this->erase(newed, ed); + if constexpr (!::std::is_trivially_destructible_v) + { + this->erase(newed, ed); + return; + } } else { @@ -3477,6 +3589,39 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE this->controller.back_end_ptr = (this->controller.back_block.begin_ptr = newed.itercontent.begin_ptr) + block_size; this->controller.back_block.curr_ptr = newed.itercontent.curr_ptr; } + inline constexpr void resize_for_overwrite_impl(size_type count) noexcept(::std::is_nothrow_move_constructible_v) + { + size_type oldsz{this->size()}; + if (count == oldsz) + { + return; + } + iterator newed; + if (count < oldsz) + { + auto ed{this->end()}; + newed = ed; + newed -= static_cast(oldsz - count); + if constexpr (!::std::is_trivially_destructible_v) + { + this->erase(newed, ed); + return; + } + } + else + { + this->reserve_back(count); + auto ed{this->end()}; + newed = ed + static_cast(count - oldsz); + } + if (newed.itercontent.curr_ptr == newed.itercontent.begin_ptr) + { + newed.itercontent.curr_ptr = (newed.itercontent.begin_ptr = *--newed.itercontent.controller_ptr) + block_size; + } + this->controller.back_block.controller_ptr = newed.itercontent.controller_ptr; + this->controller.back_end_ptr = (this->controller.back_block.begin_ptr = newed.itercontent.begin_ptr) + block_size; + this->controller.back_block.curr_ptr = newed.itercontent.curr_ptr; + } public: inline constexpr void resize(size_type count) noexcept(::std::is_nothrow_default_constructible_v && ::std::is_nothrow_move_constructible_v) @@ -3489,7 +3634,21 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE /* Todo */ - this->resize(count); + if constexpr (::std::is_trivially_default_constructible_v && + ::std::is_trivially_destructible_v) + { + this->resize_for_overwrite_impl(count); + } +#if 0 + else if constexpr(::fast_io::freestanding::is_zero_default_constructible_v&& + ::std::is_trivially_destructible_v) + { + } +#endif + else + { + this->resize(count); + } } inline constexpr void resize(size_type count, const_reference value) noexcept(::std::is_nothrow_copy_constructible_v && ::std::is_nothrow_move_constructible_v) { diff --git a/tests/0026.container/0003.deque/reserve.cc b/tests/0026.container/0003.deque/reserve.cc index a68aa1c9a..d29adab54 100644 --- a/tests/0026.container/0003.deque/reserve.cc +++ b/tests/0026.container/0003.deque/reserve.cc @@ -17,6 +17,9 @@ inline void logging(T const &deq, ::std::source_location src = ::std::source_loc int main() { ::fast_io::deque<::std::size_t> deq; + deq.reserve_back(10000000); + logging(deq); + deq.clear_destroy(); deq.push_back(30); logging(deq); deq.reserve_back(265); From 1ac9151ca1ab9555457a658bc34421a295e7e8ff Mon Sep 17 00:00:00 2001 From: trcrsired Date: Sat, 9 May 2026 09:54:35 +0800 Subject: [PATCH 47/82] [deque] implement assign_range --- include/fast_io_dsal/impl/deque.h | 9 +- tests/0026.container/0003.deque/assign.cc | 153 ++++++++++++++++++++++ 2 files changed, 159 insertions(+), 3 deletions(-) create mode 100644 tests/0026.container/0003.deque/assign.cc diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index 1659f4bfa..25070d0ff 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -3538,15 +3538,18 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE #if 0 inline constexpr void assign(size_type count, const_reference val) noexcept(::std::is_nothrow_copy_constructible_v) { + deque temp(count,val); + this->swap(temp); } +#endif template <::std::ranges::range R> requires ::std::constructible_from> - inline constexpr void assign_range(R &&rg) noexcept(::std::is_nothrow_constructible_v>) + inline constexpr void assign_range(R &&rg) noexcept(::std::is_nothrow_constructible_v>) { + deque temp(::fast_io::freestanding::from_range, ::std::forward(rg)); + this->swap(temp); } -#endif - private: inline constexpr void resize_impl(size_type count, T const *pval) noexcept(::std::is_nothrow_move_constructible_v) { diff --git a/tests/0026.container/0003.deque/assign.cc b/tests/0026.container/0003.deque/assign.cc new file mode 100644 index 000000000..1bc266549 --- /dev/null +++ b/tests/0026.container/0003.deque/assign.cc @@ -0,0 +1,153 @@ +#include +#include +#include +#include +#include + +using fast_io::deque; + +// A type that throws on copy after N copies +struct ThrowOnCopy +{ + static inline int counter = 0; + int value; + + ThrowOnCopy(int v = 0) : value(v) + {} + + ThrowOnCopy(ThrowOnCopy const &other) : value(other.value) + { + if (++counter > 3) + { + throw std::runtime_error("copy fail"); + } + } + ThrowOnCopy &operator=(ThrowOnCopy const &) = default; +}; +#if 0 +inline void test_assign_basic() { + deque d; + d.push_back(1); + d.push_back(2); + d.push_back(3); + + d.assign(5, 42); + + assert(d.size() == 5); + for (auto& x : d) assert(x == 42); +} +#endif +inline void test_assign_range_basic() +{ + deque d; + std::vector v = {10, 20, 30, 40}; + + d.assign_range(v); + + assert(d.size() == 4); + for (int i = 0; i < 4; ++i) + { + assert(d[i] == v[i]); + } +} +#if 0 +inline void test_assign_strong_exception_guarantee() { + deque d; + d.push_back({1}); + d.push_back({2}); + d.push_back({3}); + + auto old = d; // snapshot + + ThrowOnCopy::counter = 0; + + try { + d.assign(10, ThrowOnCopy{7}); // will throw after 3 copies + assert(false); // should not reach + } catch (...) { + // strong exception guarantee: unchanged + assert(d.size() == old.size()); + for (size_t i = 0; i < d.size(); ++i) + assert(d[i].value == old[i].value); + } +} +#endif +inline void test_assign_range_exception_guarantee() +{ + deque d; + d.push_back({1}); + d.push_back({2}); + d.push_back({3}); + + auto old = d; + + std::vector v(10, ThrowOnCopy{9}); + ThrowOnCopy::counter = 0; + + try + { + d.assign_range(v); // throws + assert(false); + } + catch (...) + { + assert(d.size() == old.size()); + for (size_t i = 0; i < d.size(); ++i) + { + assert(d[i].value == old[i].value); + } + } +} + +inline void test_self_assign() +{ + deque d; + for (int i = 0; i < 10; ++i) + { + d.push_back(i); + } + + d.assign_range(d); // safe because you use temp + + assert(d.size() == 10); + for (int i = 0; i < 10; ++i) + { + assert(d[i] == i); + } +} + +inline void test_assign_from_subrange() +{ + deque d; + for (int i = 0; i < 10; ++i) + { + d.push_back(i); + } + + auto first = d.begin() + 2; + auto last = d.begin() + 7; + + d.assign_range(std::ranges::subrange(first, last)); + + assert(d.size() == 5); + for (int i = 0; i < 5; ++i) + { + assert(d[i] == i + 2); + } +} + +int main() +{ +#if 0 + test_assign_basic(); +#endif + test_assign_range_basic(); +#if 0 + test_assign_strong_exception_guarantee(); + test_assign_range_exception_guarantee(); +#endif + test_self_assign(); + test_assign_from_subrange(); + + ::fast_io::io::print("All tests passed.\n"); +} From 341e5f7b081d3c318a1b5ac0858bb1d4dbdf7681 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Sat, 9 May 2026 10:03:12 +0800 Subject: [PATCH 48/82] [deque] try to add fuzzing for deque resize --- .../deque/fuzz_deque_resize.cc | 130 ++++++++++++++++++ include/fast_io_dsal/impl/deque.h | 4 +- 2 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 fuzzing/0007.containers/deque/fuzz_deque_resize.cc diff --git a/fuzzing/0007.containers/deque/fuzz_deque_resize.cc b/fuzzing/0007.containers/deque/fuzz_deque_resize.cc new file mode 100644 index 000000000..1ccad3e6d --- /dev/null +++ b/fuzzing/0007.containers/deque/fuzz_deque_resize.cc @@ -0,0 +1,130 @@ +#include +#include +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(uint8_t const *data, size_t size) +{ + fast_io::deque fq; + std::deque sq; + + auto read_u8 = [&](size_t &i) -> uint8_t { + if (i >= size) + { + return 0; + } + return data[i++]; + }; + + size_t i = 0; + while (i < size) + { + uint8_t op = read_u8(i); + + switch (op % 8) + { + case 0: + { // push_back + int v = read_u8(i); + fq.push_back(v); + sq.push_back(v); + break; + } + case 1: + { // push_front + int v = read_u8(i); + fq.push_front(v); + sq.push_front(v); + break; + } + case 2: + { // reserve_back + size_t n = static_cast(read_u8(i)) * 256; + fq.reserve_back(n); + + // capacity checks + if (fq.back_capacity() < n) + { + __builtin_trap(); + } + break; + } + case 3: + { // reserve_front + size_t n = static_cast(read_u8(i)) * 256; + fq.reserve_front(n); + + if (fq.front_capacity() < n) + { + __builtin_trap(); + } + break; + } + case 4: + { // resize + size_t n = read_u8(i); + fq.resize(n); + sq.resize(n); + break; + } + case 5: + { // resize overwrite + size_t n = read_u8(i); + int v = read_u8(i); + fq.resize(n, v); + sq.resize(n, v); + break; + } + case 6: + { // assign_range + size_t n = read_u8(i); + std::vector tmp(n); + for (size_t k = 0; k < n; ++k) + { + tmp[k] = read_u8(i); + } + + fq.assign_range(tmp); + sq.assign(tmp.begin(), tmp.end()); + break; + } + case 7: + { // pop ops + if (!fq.empty()) + { + fq.pop_back(); + sq.pop_back(); + } + if (!fq.empty()) + { + fq.pop_front(); + sq.pop_front(); + } + break; + } + } + + // Validate element correctness + if (fq.size() != sq.size()) + { + __builtin_trap(); + } + + for (size_t k = 0; k < fq.size(); ++k) + { + if (fq[k] != sq[k]) + { + __builtin_trap(); + } + } + + // capacity must always be >= size + if (fq.capacity() < fq.size()) + { + __builtin_trap(); + } + } + + return 0; +} diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index 25070d0ff..538582814 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -1659,14 +1659,14 @@ inline constexpr void deque_reserve_front_spaces_impl(dequecontroltype &controll if consteval { ::fast_io::containers::details::deque_reserve_front_blocks_impl(controller, - toallocate, align, block_size, true); + toallocate, align, block_size); } else { ::std::size_t const block_bytes{block_size * sz}; ::fast_io::containers::details::deque_reserve_front_blocks_impl(*reinterpret_cast<::fast_io::containers::details::deque_controller_common *>( __builtin_addressof(controller)), - toallocate, align, block_bytes, true); + toallocate, align, block_bytes); } } From e26ef55b10c6cd7553631ec8156f2e72bd61575e Mon Sep 17 00:00:00 2001 From: trcrsired Date: Sat, 9 May 2026 10:06:42 +0800 Subject: [PATCH 49/82] [deque] try to solve the issue for CI compilation --- include/fast_io_dsal/impl/deque.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index 538582814..b8d3a7870 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -628,9 +628,6 @@ inline constexpr void deque_allocate_on_empty_common_with_n_impl(dequecontroltyp // we need a null terminator as sentinel like c style string does --allocated_blocks_count; - auto &controller_block{controller.controller_block}; - auto &front_block{controller.front_block}; - auto &back_block{controller.back_block}; using begin_ptrtype = typename dequecontroltype::replacetype *; From fa42187a15dc404e386ee493e94a1fc271e6816f Mon Sep 17 00:00:00 2001 From: trcrsired Date: Sat, 9 May 2026 10:09:25 +0800 Subject: [PATCH 50/82] [deque] compilation failure --- include/fast_io_dsal/impl/deque.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index b8d3a7870..daa863b45 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -628,10 +628,13 @@ inline constexpr void deque_allocate_on_empty_common_with_n_impl(dequecontroltyp // we need a null terminator as sentinel like c style string does --allocated_blocks_count; + auto &controller_block{controller.controller_block}; + auto &front_block{controller.front_block}; + auto &back_block{controller.back_block}; using begin_ptrtype = typename dequecontroltype::replacetype *; - controller.controller_block.controller_after_ptr = (controller.controller_block.controller_start_ptr = allocated_blocks_ptr) + allocated_blocks_count; + controller_block.controller_after_ptr = (controller_block.controller_start_ptr = allocated_blocks_ptr) + allocated_blocks_count; ::std::size_t const allocated_blocks_count_half{allocated_blocks_count >> 1u}; @@ -647,8 +650,8 @@ inline constexpr void deque_allocate_on_empty_common_with_n_impl(dequecontroltyp ::std::construct_at(i, static_cast(allocator::allocate_aligned(align, bytes))); } *end_block_ptr = nullptr; - controller.controller_block.controller_start_reserved_ptr = start_block_ptr; - controller.controller_block.controller_after_reserved_ptr = end_block_ptr; + controller_block.controller_start_reserved_ptr = start_block_ptr; + controller_block.controller_after_reserved_ptr = end_block_ptr; begin_ptrtype begin_ptr; if (position < 0) From 51aeb043730db23fccf557e73614219f78013c50 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Sat, 9 May 2026 19:53:30 +0800 Subject: [PATCH 51/82] [deque] reserve should avoid front_block issue --- include/fast_io_dsal/impl/deque.h | 105 ++++++++++++++++----- tests/0026.container/0003.deque/reserve.cc | 11 +++ 2 files changed, 90 insertions(+), 26 deletions(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index daa863b45..12ef4ac98 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -603,10 +603,22 @@ template inline constexpr void deque_allocate_on_empty_common_with_n_impl(dequecontroltype &controller, ::std::size_t initial_allocated_block_counts, ::std::size_t align, ::std::size_t bytes, int position) noexcept { + constexpr bool rightaddone{false}; ::std::size_t initial_allocated_block_counts_with_sentinel; #if (defined(__GNUC__) || defined(__clang__)) if constexpr (true) { + if constexpr (rightaddone) + { + if (0 < position) + { + if (__builtin_add_overflow(initial_allocated_block_counts, 1u, + __builtin_addressof(initial_allocated_block_counts))) + { + ::fast_io::fast_terminate(); + } + } + } if (__builtin_add_overflow(initial_allocated_block_counts, 1u, __builtin_addressof(initial_allocated_block_counts_with_sentinel))) { @@ -617,6 +629,17 @@ inline constexpr void deque_allocate_on_empty_common_with_n_impl(dequecontroltyp #endif { constexpr ::std::size_t maxval{::std::numeric_limits<::std::size_t>::max()}; + if constexpr (rightaddone) + { + if (0 < position) + { + if (initial_allocated_block_counts == maxval) + { + ::fast_io::fast_terminate(); + } + ++initial_allocated_block_counts; + } + } if (initial_allocated_block_counts == maxval) [[unlikely]] { ::fast_io::fast_terminate(); @@ -654,40 +677,68 @@ inline constexpr void deque_allocate_on_empty_common_with_n_impl(dequecontroltyp controller_block.controller_after_reserved_ptr = end_block_ptr; begin_ptrtype begin_ptr; - if (position < 0) + if constexpr (rightaddone) { - // place logical cursor at the first reserved block (front side) - auto first_block_ptr{start_block_ptr}; - begin_ptr = *first_block_ptr; + if (position == 0) + { + // place logical cursor in the middle block, middle of that block + auto mid_block_ptr{allocated_mid_block}; + begin_ptr = *mid_block_ptr; + auto mid_ptr{begin_ptr + (bytes >> 1u)}; - front_block.controller_ptr = first_block_ptr; - back_block.controller_ptr = first_block_ptr; + front_block.controller_ptr = mid_block_ptr; + back_block.controller_ptr = mid_block_ptr; - front_block.curr_ptr = back_block.curr_ptr = begin_ptr; - } - else if (position == 0) - { - // place logical cursor in the middle block, middle of that block - auto mid_block_ptr{allocated_mid_block}; - begin_ptr = *mid_block_ptr; - auto mid_ptr{begin_ptr + (bytes >> 1u)}; + front_block.curr_ptr = back_block.curr_ptr = mid_ptr; + } + else + { + // place logical cursor at the first reserved block (front side) + auto first_block_ptr{start_block_ptr}; + begin_ptr = *first_block_ptr; - front_block.controller_ptr = mid_block_ptr; - back_block.controller_ptr = mid_block_ptr; + front_block.controller_ptr = first_block_ptr; + back_block.controller_ptr = first_block_ptr; - front_block.curr_ptr = back_block.curr_ptr = mid_ptr; + front_block.curr_ptr = back_block.curr_ptr = begin_ptr; + } } else { - // place logical cursor at the last reserved block (back side) - auto last_block_ptr{end_block_ptr - 1}; - begin_ptr = *last_block_ptr; + if (position < 0) + { + // place logical cursor at the first reserved block (front side) + auto first_block_ptr{start_block_ptr}; + begin_ptr = *first_block_ptr; - front_block.controller_ptr = last_block_ptr; - back_block.controller_ptr = last_block_ptr; - front_block.curr_ptr = back_block.curr_ptr = begin_ptr + bytes; - } + front_block.controller_ptr = first_block_ptr; + back_block.controller_ptr = first_block_ptr; + + front_block.curr_ptr = back_block.curr_ptr = begin_ptr; + } + else if (position == 0) + { + // place logical cursor in the middle block, middle of that block + auto mid_block_ptr{allocated_mid_block}; + begin_ptr = *mid_block_ptr; + auto mid_ptr{begin_ptr + (bytes >> 1u)}; + front_block.controller_ptr = mid_block_ptr; + back_block.controller_ptr = mid_block_ptr; + + front_block.curr_ptr = back_block.curr_ptr = mid_ptr; + } + else + { + // place logical cursor at the last reserved block (back side) + auto last_block_ptr{end_block_ptr - 1}; + begin_ptr = *last_block_ptr; + + front_block.controller_ptr = last_block_ptr; + back_block.controller_ptr = last_block_ptr; + front_block.curr_ptr = back_block.curr_ptr = begin_ptr + bytes; + } + } front_block.begin_ptr = back_block.begin_ptr = begin_ptr; controller.front_end_ptr = controller.back_end_ptr = begin_ptr + bytes; } @@ -3584,7 +3635,8 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE ::fast_io::freestanding::uninitialized_default_construct(ed, newed); } } - if (newed.itercontent.curr_ptr == newed.itercontent.begin_ptr) + if (newed.itercontent.curr_ptr == newed.itercontent.begin_ptr && + newed.itercontent.controller_ptr != this->controller.front_block.controller_ptr) { newed.itercontent.curr_ptr = (newed.itercontent.begin_ptr = *--newed.itercontent.controller_ptr) + block_size; } @@ -3617,7 +3669,8 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE auto ed{this->end()}; newed = ed + static_cast(count - oldsz); } - if (newed.itercontent.curr_ptr == newed.itercontent.begin_ptr) + if (newed.itercontent.curr_ptr == newed.itercontent.begin_ptr && + newed.itercontent.controller_ptr != this->controller.front_block.controller_ptr) { newed.itercontent.curr_ptr = (newed.itercontent.begin_ptr = *--newed.itercontent.controller_ptr) + block_size; } diff --git a/tests/0026.container/0003.deque/reserve.cc b/tests/0026.container/0003.deque/reserve.cc index d29adab54..e0a844e23 100644 --- a/tests/0026.container/0003.deque/reserve.cc +++ b/tests/0026.container/0003.deque/reserve.cc @@ -38,4 +38,15 @@ int main() logging(deq); deq.reserve_front(6401); logging(deq); + deq.clear_destroy(); + logging(deq); + deq.reserve_front(512); + logging(deq); + deq.push_front(30); + deq.pop_back(); + logging(deq); + for (auto e : deq) + { + ::fast_io::io::println(e); + } } From 5cc37aefab0e8d4be2b5f5a2dc0aab4b90688618 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Thu, 14 May 2026 15:21:09 +0800 Subject: [PATCH 52/82] try to add conditional_zero apis --- .../fast_io_core_impl/allocation/adapters.h | 1806 +++++++++++++---- .../allocation/has_methods_detect.h | 120 ++ .../operations/readimpl/decay.h | 26 +- .../operations/writeimpl/decay.h | 25 +- 4 files changed, 1530 insertions(+), 447 deletions(-) diff --git a/include/fast_io_core_impl/allocation/adapters.h b/include/fast_io_core_impl/allocation/adapters.h index 9adcba2f3..3a8efc523 100644 --- a/include/fast_io_core_impl/allocation/adapters.h +++ b/include/fast_io_core_impl/allocation/adapters.h @@ -58,17 +58,17 @@ inline void *allocator_adjust_ptr_to_aligned_impl(void *p, ::std::size_t alignme return aligned_ptr; } -template -inline constexpr void *allocator_pointer_aligned_impl(::std::size_t, ::std::size_t) noexcept; +template +inline constexpr void *allocator_pointer_aligned_impl(::std::size_t, ::std::size_t, bool) noexcept; -template -inline constexpr ::fast_io::allocation_least_result allocator_pointer_aligned_at_least_impl(::std::size_t, ::std::size_t) noexcept; +template +inline constexpr ::fast_io::allocation_least_result allocator_pointer_aligned_at_least_impl(::std::size_t, ::std::size_t, bool) noexcept; -template -inline constexpr void *status_allocator_pointer_aligned_impl(typename alloc::handle_type, ::std::size_t, ::std::size_t) noexcept; +template +inline constexpr void *status_allocator_pointer_aligned_impl(typename alloc::handle_type, ::std::size_t, ::std::size_t, bool) noexcept; -template -inline constexpr ::fast_io::allocation_least_result status_allocator_pointer_aligned_at_least_impl(typename alloc::handle_type, ::std::size_t, ::std::size_t) noexcept; +template +inline constexpr ::fast_io::allocation_least_result status_allocator_pointer_aligned_at_least_impl(typename alloc::handle_type, ::std::size_t, ::std::size_t, bool) noexcept; } // namespace details @@ -102,7 +102,133 @@ class generic_allocator_adapter ::fast_io::details::has_allocate_impl || ::fast_io::details::has_allocate_aligned_impl || ::fast_io::details::has_allocate_zero_impl || - ::fast_io::details::has_allocate_aligned_zero_impl)}; + ::fast_io::details::has_allocate_aligned_zero_impl || + ::fast_io::details::has_allocate_conditional_zero_impl || + ::fast_io::details::has_allocate_aligned_conditional_zero_impl || + ::fast_io::details::has_allocate_conditional_zero_at_least_impl || + ::fast_io::details::has_allocate_aligned_conditional_zero_at_least_impl)}; + +#if __has_cpp_attribute(__gnu__::__returns_nonnull__) + [[__gnu__::__returns_nonnull__]] +#endif + static inline void *allocate_conditional_zero(::std::size_t n, bool zero) noexcept + requires(!has_status) + { +#if __cpp_if_consteval >= 202106L + if consteval +#elif __cpp_lib_is_constant_evaluated >= 201811L && __cpp_constexpr_dynamic_alloc >= 201907L + if (__builtin_is_constant_evaluated()) +#else + if (false) +#endif + { + auto p{::operator new(n)}; + if (zero) + { + ::fast_io::freestanding::bytes_clear_n(reinterpret_cast<::std::byte *>(p), n); + } + return p; + } + else + { + if constexpr (::fast_io::details::has_allocate_conditional_zero_impl) + { + return allocator_type::allocate_conditional_zero(n, zero); + } + else if constexpr (::fast_io::details::has_allocate_conditional_zero_at_least_impl) + { + return allocator_type::allocate_conditional_zero_at_least(n, zero).ptr; + } + else if constexpr (::fast_io::details::has_allocate_aligned_conditional_zero_impl) + { + return allocator_type::allocate_aligned_conditional_zero(default_alignment, n, zero); + } + else if constexpr (::fast_io::details::has_allocate_aligned_conditional_zero_at_least_impl) + { + return allocator_type::allocate_aligned_conditional_zero_at_least(default_alignment, n, zero).ptr; + } + else if constexpr (::fast_io::details::has_allocate_impl || + ::fast_io::details::has_allocate_at_least_impl || + ::fast_io::details::has_allocate_aligned_impl || + ::fast_io::details::has_allocate_aligned_at_least_impl) + { + // Non-zero APIs exist - need runtime branch + if (zero) + { + if constexpr (::fast_io::details::has_allocate_zero_impl) + { + return allocator_type::allocate_zero(n); + } + else if constexpr (::fast_io::details::has_allocate_zero_at_least_impl) + { + return allocator_type::allocate_zero_at_least(n).ptr; + } + else if constexpr (::fast_io::details::has_allocate_aligned_zero_impl) + { + return allocator_type::allocate_aligned_zero(default_alignment, n); + } + else if constexpr (::fast_io::details::has_allocate_aligned_zero_at_least_impl) + { + return allocator_type::allocate_aligned_zero_at_least(default_alignment, n).ptr; + } + else + { + auto p{generic_allocator_adapter::allocate(n)}; + ::fast_io::freestanding::bytes_clear_n(reinterpret_cast<::std::byte *>(p), n); + return p; + } + } + else + { + if constexpr (::fast_io::details::has_allocate_impl) + { + return allocator_type::allocate(n); + } + else if constexpr (::fast_io::details::has_allocate_at_least_impl) + { + return allocator_type::allocate_at_least(n).ptr; + } + else if constexpr (::fast_io::details::has_allocate_aligned_impl) + { + return allocator_type::allocate_aligned(default_alignment, n); + } + else + { + return allocator_type::allocate_aligned_at_least(default_alignment, n).ptr; + } + } + } + else + { + // Only zero APIs exist (or nothing) - use zero API for both cases (harmless extra zeroing) + if constexpr (::fast_io::details::has_allocate_zero_impl) + { + return allocator_type::allocate_zero(n); + } + else if constexpr (::fast_io::details::has_allocate_zero_at_least_impl) + { + return allocator_type::allocate_zero_at_least(n).ptr; + } + else if constexpr (::fast_io::details::has_allocate_aligned_zero_impl) + { + return allocator_type::allocate_aligned_zero(default_alignment, n); + } + else if constexpr (::fast_io::details::has_allocate_aligned_zero_at_least_impl) + { + return allocator_type::allocate_aligned_zero_at_least(default_alignment, n).ptr; + } + else + { + auto p{::operator new(n)}; + if (zero) + { + ::fast_io::freestanding::bytes_clear_n(reinterpret_cast<::std::byte *>(p), n); + } + return p; + } + } + } + } #if __has_cpp_attribute(__gnu__::__returns_nonnull__) [[__gnu__::__returns_nonnull__]] @@ -129,25 +255,9 @@ class generic_allocator_adapter { return allocator_type::allocate_at_least(n).ptr; } - else if constexpr (::fast_io::details::has_allocate_aligned_impl) - { - return allocator_type::allocate_aligned(default_alignment, n); - } - else if constexpr (::fast_io::details::has_allocate_zero_impl) - { - return allocator_type::allocate_zero(n); - } - else if constexpr (::fast_io::details::has_allocate_zero_at_least_impl) - { - return allocator_type::allocate_zero_at_least(n).ptr; - } - else if constexpr (::fast_io::details::has_allocate_aligned_zero_impl) - { - return allocator_type::allocate_aligned_zero(default_alignment, n); - } else { - static_assert(::fast_io::details::has_allocate_impl); + return generic_allocator_adapter::allocate_conditional_zero(n, false); } } } @@ -166,19 +276,9 @@ class generic_allocator_adapter { return allocator_type::allocate_zero_at_least(n).ptr; } - else if constexpr (::fast_io::details::has_allocate_aligned_zero_impl) - { - return allocator_type::allocate_aligned_zero(default_alignment, n); - } - else if constexpr (::fast_io::details::has_allocate_aligned_zero_at_least_impl) - { - return allocator_type::allocate_aligned_zero_at_least(default_alignment, n).ptr; - } else { - auto p{generic_allocator_adapter::allocate(n)}; - ::fast_io::freestanding::bytes_clear_n(reinterpret_cast<::std::byte *>(p), n); - return p; + return generic_allocator_adapter::allocate_conditional_zero(n, true); } } @@ -189,45 +289,126 @@ class generic_allocator_adapter ::fast_io::details::has_reallocate_zero_impl || ::fast_io::details::has_reallocate_zero_at_least_impl || ::fast_io::details::has_reallocate_aligned_zero_impl || - ::fast_io::details::has_reallocate_aligned_zero_at_least_impl); + ::fast_io::details::has_reallocate_aligned_zero_at_least_impl || + ::fast_io::details::has_reallocate_conditional_zero_impl || + ::fast_io::details::has_reallocate_aligned_conditional_zero_impl || + ::fast_io::details::has_reallocate_conditional_zero_at_least_impl || + ::fast_io::details::has_reallocate_aligned_conditional_zero_at_least_impl); #if __has_cpp_attribute(__gnu__::__returns_nonnull__) [[__gnu__::__returns_nonnull__]] #endif - static inline void *reallocate(void *p, ::std::size_t n) noexcept + static inline void *reallocate_conditional_zero(void *p, ::std::size_t n, bool zero) noexcept requires(!has_status && has_reallocate) { - if constexpr (::fast_io::details::has_reallocate_impl) + if constexpr (::fast_io::details::has_reallocate_conditional_zero_impl) { - return allocator_type::reallocate(p, n); + return allocator_type::reallocate_conditional_zero(p, n, zero); } - else if constexpr (::fast_io::details::has_reallocate_at_least_impl) + else if constexpr (::fast_io::details::has_reallocate_conditional_zero_at_least_impl) { - return allocator_type::reallocate_at_least(p, n).ptr; + return allocator_type::reallocate_conditional_zero_at_least(p, n, zero).ptr; } - else if constexpr (::fast_io::details::has_reallocate_aligned_impl) + else if constexpr (::fast_io::details::has_reallocate_aligned_conditional_zero_impl) { - return allocator_type::reallocate_aligned(p, default_alignment, n); + return allocator_type::reallocate_aligned_conditional_zero(p, default_alignment, n, zero); } - else if constexpr (::fast_io::details::has_reallocate_aligned_at_least_impl) + else if constexpr (::fast_io::details::has_reallocate_aligned_conditional_zero_at_least_impl) { - return allocator_type::reallocate_aligned_at_least(p, default_alignment, n).ptr; + return allocator_type::reallocate_aligned_conditional_zero_at_least(p, default_alignment, n, zero).ptr; } - else if constexpr (::fast_io::details::has_reallocate_zero_impl) + else if constexpr (::fast_io::details::has_reallocate_impl || + ::fast_io::details::has_reallocate_at_least_impl || + ::fast_io::details::has_reallocate_aligned_impl || + ::fast_io::details::has_reallocate_aligned_at_least_impl) { - return allocator_type::reallocate_zero(p, n); + // Non-zero APIs exist - need runtime branch + if (zero) + { + if constexpr (::fast_io::details::has_reallocate_zero_impl) + { + return allocator_type::reallocate_zero(p, n); + } + else if constexpr (::fast_io::details::has_reallocate_zero_at_least_impl) + { + return allocator_type::reallocate_zero_at_least(p, n).ptr; + } + else if constexpr (::fast_io::details::has_reallocate_aligned_zero_impl) + { + return allocator_type::reallocate_aligned_zero(p, default_alignment, n); + } + else if constexpr (::fast_io::details::has_reallocate_aligned_zero_at_least_impl) + { + return allocator_type::reallocate_aligned_zero_at_least(p, default_alignment, n).ptr; + } + else + { + ::fast_io::fast_terminate(); + } + } + else + { + if constexpr (::fast_io::details::has_reallocate_impl) + { + return allocator_type::reallocate(p, n); + } + else if constexpr (::fast_io::details::has_reallocate_at_least_impl) + { + return allocator_type::reallocate_at_least(p, n).ptr; + } + else if constexpr (::fast_io::details::has_reallocate_aligned_impl) + { + return allocator_type::reallocate_aligned(p, default_alignment, n); + } + else + { + return allocator_type::reallocate_aligned_at_least(p, default_alignment, n).ptr; + } + } } - else if constexpr (::fast_io::details::has_reallocate_zero_at_least_impl) + else { - return allocator_type::reallocate_zero_at_least(p, n).ptr; + // Only zero APIs exist - use zero API for both cases + if constexpr (::fast_io::details::has_reallocate_zero_impl) + { + return allocator_type::reallocate_zero(p, n); + } + else if constexpr (::fast_io::details::has_reallocate_zero_at_least_impl) + { + return allocator_type::reallocate_zero_at_least(p, n).ptr; + } + else if constexpr (::fast_io::details::has_reallocate_aligned_zero_impl) + { + return allocator_type::reallocate_aligned_zero(p, default_alignment, n); + } + else if constexpr (::fast_io::details::has_reallocate_aligned_zero_at_least_impl) + { + return allocator_type::reallocate_aligned_zero_at_least(p, default_alignment, n).ptr; + } + else + { + ::fast_io::fast_terminate(); + } } - else if constexpr (::fast_io::details::has_reallocate_aligned_zero_impl) + } + +#if __has_cpp_attribute(__gnu__::__returns_nonnull__) + [[__gnu__::__returns_nonnull__]] +#endif + static inline void *reallocate(void *p, ::std::size_t n) noexcept + requires(!has_status && has_reallocate) + { + if constexpr (::fast_io::details::has_reallocate_impl) { - return allocator_type::reallocate_aligned_zero(p, default_alignment, n); + return allocator_type::reallocate(p, n); } - else if constexpr (::fast_io::details::has_reallocate_aligned_zero_at_least_impl) + else if constexpr (::fast_io::details::has_reallocate_at_least_impl) + { + return allocator_type::reallocate_at_least(p, n).ptr; + } + else { - return allocator_type::reallocate_aligned_zero_at_least(p, default_alignment, n).ptr; + return generic_allocator_adapter::reallocate_conditional_zero(p, n, false); } } @@ -251,13 +432,141 @@ class generic_allocator_adapter { return allocator_type::reallocate_zero_at_least(p, n).ptr; } - else if constexpr (::fast_io::details::has_reallocate_aligned_zero_impl) + else { - return allocator_type::reallocate_aligned_zero(p, default_alignment, n); + return generic_allocator_adapter::reallocate_conditional_zero(p, n, true); } - else if constexpr (::fast_io::details::has_reallocate_aligned_zero_at_least_impl) + } + +#if __has_cpp_attribute(__gnu__::__returns_nonnull__) + [[__gnu__::__returns_nonnull__]] +#endif + static inline void *reallocate_n_conditional_zero(void *p, ::std::size_t oldn, ::std::size_t n, bool zero) noexcept + requires(!has_status) + { + if (p != nullptr && oldn == n) + { + return p; + } +#if __cpp_if_consteval >= 202106L + if consteval +#elif __cpp_lib_is_constant_evaluated >= 201811L && __cpp_constexpr_dynamic_alloc >= 201907L + if (__builtin_is_constant_evaluated()) +#else + if (false) +#endif { - return allocator_type::reallocate_aligned_zero_at_least(p, default_alignment, n).ptr; + auto newptr{::operator new(n)}; + if (p != nullptr) + { + if (n) + { + ::std::size_t copyn{oldn < n ? oldn : n}; + ::fast_io::freestanding::nonoverlapped_bytes_copy_n(reinterpret_cast<::std::byte const *>(p), copyn, reinterpret_cast<::std::byte *>(newptr)); + } + ::operator delete(p); + } + if (zero && oldn < n) + { + ::fast_io::freestanding::bytes_clear_n(reinterpret_cast<::std::byte *>(newptr) + oldn, n - oldn); + } + return newptr; + } + else + { + if constexpr (::fast_io::details::has_reallocate_n_conditional_zero_impl) + { + return allocator_type::reallocate_n_conditional_zero(p, oldn, n, zero); + } + else if constexpr (::fast_io::details::has_reallocate_n_conditional_zero_at_least_impl) + { + return allocator_type::reallocate_n_conditional_zero_at_least(p, oldn, n, zero).ptr; + } + else if constexpr (::fast_io::details::has_reallocate_aligned_n_conditional_zero_impl) + { + return allocator_type::reallocate_aligned_n_conditional_zero(p, oldn, default_alignment, n, zero); + } + else if constexpr (::fast_io::details::has_reallocate_aligned_n_conditional_zero_at_least_impl) + { + return allocator_type::reallocate_aligned_n_conditional_zero_at_least(p, oldn, default_alignment, n, zero).ptr; + } + else if (zero) + { + if constexpr (::fast_io::details::has_reallocate_zero_n_impl) + { + return allocator_type::reallocate_zero_n(p, oldn, n); + } + else if constexpr (::fast_io::details::has_reallocate_zero_n_at_least_impl) + { + return allocator_type::reallocate_zero_n_at_least(p, oldn, n).ptr; + } + else if constexpr (::fast_io::details::has_reallocate_aligned_zero_n_impl) + { + return allocator_type::reallocate_aligned_zero_n(p, oldn, default_alignment, n); + } + else if constexpr (::fast_io::details::has_reallocate_aligned_zero_n_at_least_impl) + { + return allocator_type::reallocate_aligned_zero_n_at_least(p, oldn, default_alignment, n).ptr; + } + else + { + auto newptr{generic_allocator_adapter::reallocate_n(p, oldn, n)}; + if (oldn < n) + { + ::fast_io::freestanding::bytes_clear_n(reinterpret_cast<::std::byte *>(newptr) + oldn, n - oldn); + } + return newptr; + } + } + else + { + if constexpr (::fast_io::details::has_reallocate_n_impl) + { + return allocator_type::reallocate_n(p, oldn, n); + } + else if constexpr (::fast_io::details::has_reallocate_n_at_least_impl) + { + return allocator_type::reallocate_n_at_least(p, oldn, n).ptr; + } + else if constexpr (::fast_io::details::has_reallocate_aligned_n_impl) + { + return allocator_type::reallocate_aligned_n(p, oldn, default_alignment, n); + } + else if constexpr (::fast_io::details::has_reallocate_aligned_n_at_least_impl) + { + return allocator_type::reallocate_aligned_n_at_least(p, oldn, default_alignment, n).ptr; + } + else if constexpr (::fast_io::details::has_reallocate_aligned_zero_n_impl) + { + return allocator_type::reallocate_aligned_zero_n(p, oldn, default_alignment, n); + } + else if constexpr (::fast_io::details::has_reallocate_aligned_zero_n_at_least_impl) + { + return allocator_type::reallocate_aligned_zero_n_at_least(p, oldn, default_alignment, n).ptr; + } + else if constexpr (::fast_io::details::has_reallocate_zero_n_impl) + { + return allocator_type::reallocate_zero_n(p, oldn, n); + } + else if constexpr (::fast_io::details::has_reallocate_zero_n_at_least_impl) + { + return allocator_type::reallocate_zero_n_at_least(p, oldn, n).ptr; + } + else + { + auto newptr{generic_allocator_adapter::allocate(n)}; + if (p != nullptr) + { + if (n) + { + ::std::size_t copyn{oldn < n ? oldn : n}; + ::fast_io::freestanding::nonoverlapped_bytes_copy_n(reinterpret_cast<::std::byte const *>(p), copyn, reinterpret_cast<::std::byte *>(newptr)); + } + generic_allocator_adapter::deallocate_n(p, oldn); + } + return newptr; + } + } } } @@ -279,15 +588,23 @@ class generic_allocator_adapter { return allocator_type::reallocate_n_at_least(p, oldn, n).ptr; } - else if constexpr (::fast_io::details::has_reallocate_aligned_n_impl) + else { - return allocator_type::reallocate_aligned_n(p, oldn, default_alignment, n); + return generic_allocator_adapter::reallocate_n_conditional_zero(p, oldn, n, false); } - else if constexpr (::fast_io::details::has_reallocate_aligned_n_at_least_impl) + } + +#if __has_cpp_attribute(__gnu__::__returns_nonnull__) + [[__gnu__::__returns_nonnull__]] +#endif + static inline void *reallocate_zero_n(void *p, ::std::size_t oldn, ::std::size_t n) noexcept + requires(!has_status) + { + if (p != nullptr && oldn == n) { - return allocator_type::reallocate_aligned_n_at_least(p, oldn, default_alignment, n).ptr; + return p; } - else if constexpr (::fast_io::details::has_reallocate_zero_n_impl) + if constexpr (::fast_io::details::has_reallocate_zero_n_impl) { return allocator_type::reallocate_zero_n(p, oldn, n); } @@ -295,131 +612,24 @@ class generic_allocator_adapter { return allocator_type::reallocate_zero_n_at_least(p, oldn, n).ptr; } - else if constexpr (::fast_io::details::has_reallocate_aligned_zero_n_impl) - { - return allocator_type::reallocate_aligned_zero_n(p, oldn, default_alignment, n); - } - else if constexpr (::fast_io::details::has_reallocate_aligned_zero_n_at_least_impl) + else { - return allocator_type::reallocate_aligned_zero_n_at_least(p, oldn, default_alignment, n).ptr; + return generic_allocator_adapter::reallocate_n_conditional_zero(p, oldn, n, true); } - else if constexpr (::fast_io::details::has_reallocate_impl) + } + + static inline constexpr bool has_deallocate = (::fast_io::details::has_deallocate_impl || + ::fast_io::details::has_deallocate_aligned_impl); + static inline constexpr void deallocate(void *p) noexcept + requires(!has_status && has_deallocate) + { +#if __cpp_constexpr_dynamic_alloc >= 201907L + if (__builtin_is_constant_evaluated()) { - return allocator_type::reallocate(p, n); + ::operator delete(p); } - else if constexpr (::fast_io::details::has_reallocate_at_least_impl) - { - return allocator_type::reallocate_at_least(p, n).ptr; - } - else if constexpr (::fast_io::details::has_reallocate_aligned_impl) - { - return allocator_type::reallocate_aligned(p, default_alignment, n); - } - else if constexpr (::fast_io::details::has_reallocate_aligned_at_least_impl) - { - return allocator_type::reallocate_aligned_at_least(p, default_alignment, n).ptr; - } - else if constexpr (::fast_io::details::has_reallocate_zero_impl) - { - return allocator_type::reallocate_zero(p, n); - } - else if constexpr (::fast_io::details::has_reallocate_zero_at_least_impl) - { - return allocator_type::reallocate_zero_at_least(p, n).ptr; - } - else if constexpr (::fast_io::details::has_reallocate_aligned_zero_impl) - { - return allocator_type::reallocate_aligned_zero(p, default_alignment, n); - } - else if constexpr (::fast_io::details::has_reallocate_aligned_zero_at_least_impl) - { - return allocator_type::reallocate_aligned_zero_at_least(p, default_alignment, n).ptr; - } - else - { - auto newptr{generic_allocator_adapter::allocate(n)}; - if (p != nullptr) - { - if (n) - { - if (oldn < n) - { - n = oldn; - } - ::fast_io::freestanding::nonoverlapped_bytes_copy_n(reinterpret_cast<::std::byte const *>(p), n, reinterpret_cast<::std::byte *>(newptr)); - } - generic_allocator_adapter::deallocate_n(p, oldn); - } - return newptr; - } - } - -#if __has_cpp_attribute(__gnu__::__returns_nonnull__) - [[__gnu__::__returns_nonnull__]] -#endif - static inline void *reallocate_zero_n(void *p, ::std::size_t oldn, ::std::size_t n) noexcept - requires(!has_status) - { - if (p != nullptr && oldn == n) - { - return p; - } - if constexpr (::fast_io::details::has_reallocate_zero_n_impl) - { - return allocator_type::reallocate_zero_n(p, oldn, n); - } - else if constexpr (::fast_io::details::has_reallocate_zero_n_at_least_impl) - { - return allocator_type::reallocate_zero_n_at_least(p, oldn, n).ptr; - } - else if constexpr (::fast_io::details::has_reallocate_aligned_zero_n_impl) - { - return allocator_type::reallocate_aligned_zero_n(p, oldn, default_alignment, n); - } - else if constexpr (::fast_io::details::has_reallocate_aligned_zero_n_at_least_impl) - { - return allocator_type::reallocate_aligned_zero_n_at_least(p, oldn, default_alignment, n).ptr; - } - else if constexpr (::fast_io::details::has_reallocate_zero_impl) - { - return allocator_type::reallocate_zero(p, n); - } - else if constexpr (::fast_io::details::has_reallocate_zero_at_least_impl) - { - return allocator_type::reallocate_zero_at_least(p, n).ptr; - } - else if constexpr (::fast_io::details::has_reallocate_aligned_zero_impl) - { - return allocator_type::reallocate_aligned_zero(p, default_alignment, n); - } - else if constexpr (::fast_io::details::has_reallocate_aligned_zero_at_least_impl) - { - return allocator_type::reallocate_aligned_zero_at_least(p, default_alignment, n).ptr; - } - else - { - auto newptr{generic_allocator_adapter::reallocate_n(p, oldn, n)}; - if (oldn < n) - { - ::std::size_t const to_zero_bytes{static_cast<::std::size_t>(n - oldn)}; - ::fast_io::freestanding::bytes_clear_n(reinterpret_cast<::std::byte *>(newptr) + oldn, to_zero_bytes); - } - return newptr; - } - } - - static inline constexpr bool has_deallocate = (::fast_io::details::has_deallocate_impl || - ::fast_io::details::has_deallocate_aligned_impl); - static inline constexpr void deallocate(void *p) noexcept - requires(!has_status && has_deallocate) - { -#if __cpp_constexpr_dynamic_alloc >= 201907L - if (__builtin_is_constant_evaluated()) - { - ::operator delete(p); - } - else -#endif + else +#endif { if constexpr (::fast_io::details::has_deallocate_impl) { @@ -466,6 +676,35 @@ class generic_allocator_adapter } } +#if __has_cpp_attribute(__gnu__::__returns_nonnull__) + [[__gnu__::__returns_nonnull__]] +#endif + static inline constexpr + void * + allocate_aligned_conditional_zero(::std::size_t alignment, ::std::size_t n, bool zero) noexcept + requires(!has_status) + { +#if __cpp_if_consteval >= 202106L + if consteval +#elif __cpp_lib_is_constant_evaluated >= 201811L && __cpp_constexpr_dynamic_alloc >= 201907L + if (__builtin_is_constant_evaluated()) +#else + if (false) +#endif + { + auto p{::operator new(n)}; + if (zero) + { + ::fast_io::freestanding::bytes_clear_n(reinterpret_cast<::std::byte *>(p), n); + } + return p; + } + else + { + return ::fast_io::details::allocator_pointer_aligned_impl(alignment, n, zero); + } + } + #if __has_cpp_attribute(__gnu__::__returns_nonnull__) [[__gnu__::__returns_nonnull__]] #endif @@ -475,15 +714,19 @@ class generic_allocator_adapter allocate_aligned(::std::size_t alignment, ::std::size_t n) noexcept requires(!has_status) { -#if __cpp_constexpr_dynamic_alloc >= 201907L +#if __cpp_if_consteval >= 202106L + if consteval +#elif __cpp_lib_is_constant_evaluated >= 201811L && __cpp_constexpr_dynamic_alloc >= 201907L if (__builtin_is_constant_evaluated()) +#else + if (false) +#endif { return ::operator new(n); } else -#endif { - return ::fast_io::details::allocator_pointer_aligned_impl(alignment, n); + return generic_allocator_adapter::allocate_aligned_conditional_zero(alignment, n, false); } } @@ -495,15 +738,19 @@ class generic_allocator_adapter allocate_aligned_zero(::std::size_t alignment, ::std::size_t n) noexcept requires(!has_status) { -#if __cpp_constexpr_dynamic_alloc >= 201907L +#if __cpp_if_consteval >= 202106L + if consteval +#elif __cpp_lib_is_constant_evaluated >= 201811L && __cpp_constexpr_dynamic_alloc >= 201907L if (__builtin_is_constant_evaluated()) +#else + if (false) +#endif { - return ::operator new(n); // this is problematic. No way to clean it up at compile time. + return ::operator new(n); } else -#endif { - return ::fast_io::details::allocator_pointer_aligned_impl(alignment, n); + return generic_allocator_adapter::allocate_aligned_conditional_zero(alignment, n, true); } } @@ -653,13 +900,71 @@ class generic_allocator_adapter static inline constexpr bool has_reallocate_aligned = (::fast_io::details::has_reallocate_aligned_impl || ::fast_io::details::has_reallocate_aligned_at_least_impl || ::fast_io::details::has_reallocate_aligned_zero_impl || - ::fast_io::details::has_reallocate_aligned_zero_at_least_impl); + ::fast_io::details::has_reallocate_aligned_zero_at_least_impl || + ::fast_io::details::has_reallocate_aligned_conditional_zero_impl || + ::fast_io::details::has_reallocate_aligned_conditional_zero_at_least_impl); #if __has_cpp_attribute(__gnu__::__returns_nonnull__) [[__gnu__::__returns_nonnull__]] #endif static inline - void * + void * + reallocate_aligned_conditional_zero(void *p, ::std::size_t alignment, ::std::size_t n, bool zero) noexcept + requires(!has_status && has_reallocate_aligned) + { + if constexpr (::fast_io::details::has_reallocate_aligned_conditional_zero_impl) + { + return allocator_type::reallocate_aligned_conditional_zero(p, alignment, n, zero); + } + else if constexpr (::fast_io::details::has_reallocate_aligned_conditional_zero_at_least_impl) + { + return allocator_type::reallocate_aligned_conditional_zero_at_least(p, alignment, n, zero).ptr; + } + else if (zero) + { + if constexpr (::fast_io::details::has_reallocate_aligned_zero_impl) + { + return allocator_type::reallocate_aligned_zero(p, alignment, n); + } + else if constexpr (::fast_io::details::has_reallocate_aligned_zero_at_least_impl) + { + return allocator_type::reallocate_aligned_zero_at_least(p, alignment, n).ptr; + } + else + { + ::fast_io::fast_terminate(); + } + } + else + { + if constexpr (::fast_io::details::has_reallocate_aligned_impl) + { + return allocator_type::reallocate_aligned(p, alignment, n); + } + else if constexpr (::fast_io::details::has_reallocate_aligned_at_least_impl) + { + return allocator_type::reallocate_aligned_at_least(p, alignment, n).ptr; + } + else if constexpr (::fast_io::details::has_reallocate_aligned_zero_impl) + { + return allocator_type::reallocate_aligned_zero(p, alignment, n); + } + else if constexpr (::fast_io::details::has_reallocate_aligned_zero_at_least_impl) + { + return allocator_type::reallocate_aligned_zero_at_least(p, alignment, n).ptr; + } + else + { + ::fast_io::fast_terminate(); + } + } + } + +#if __has_cpp_attribute(__gnu__::__returns_nonnull__) + [[__gnu__::__returns_nonnull__]] +#endif + static inline + void * reallocate_aligned(void *p, ::std::size_t alignment, ::std::size_t n) noexcept requires(!has_status && has_reallocate_aligned) { @@ -671,13 +976,9 @@ class generic_allocator_adapter { return allocator_type::reallocate_aligned_at_least(p, alignment, n).ptr; } - else if constexpr (::fast_io::details::has_reallocate_aligned_zero_impl) - { - return allocator_type::reallocate_aligned_zero(p, alignment, n); - } - else if constexpr (::fast_io::details::has_reallocate_aligned_zero_at_least_impl) + else { - return allocator_type::reallocate_aligned_zero_at_least(p, alignment, n).ptr; + return generic_allocator_adapter::reallocate_aligned_conditional_zero(p, alignment, n, false); } } @@ -687,7 +988,7 @@ class generic_allocator_adapter [[__gnu__::__returns_nonnull__]] #endif static inline - void * + void * reallocate_aligned_zero(void *p, ::std::size_t alignment, ::std::size_t n) noexcept requires(!has_status && has_reallocate_aligned_zero) { @@ -699,113 +1000,198 @@ class generic_allocator_adapter { return allocator_type::reallocate_aligned_zero_at_least(p, alignment, n).ptr; } + else + { + return generic_allocator_adapter::reallocate_aligned_conditional_zero(p, alignment, n, true); + } } #if __has_cpp_attribute(__gnu__::__returns_nonnull__) [[__gnu__::__returns_nonnull__]] #endif static inline - void * - reallocate_aligned_n(void *p, ::std::size_t oldn, ::std::size_t alignment, ::std::size_t n) noexcept + void * + reallocate_aligned_n_conditional_zero(void *p, ::std::size_t oldn, ::std::size_t alignment, ::std::size_t n, bool zero) noexcept requires(!has_status) { if (p != nullptr && oldn == n) { return p; } - if constexpr (::fast_io::details::has_reallocate_aligned_n_impl) - { - return allocator_type::reallocate_aligned_n(p, oldn, alignment, n); - } - else if constexpr (::fast_io::details::has_reallocate_aligned_n_at_least_impl) - { - return allocator_type::reallocate_aligned_n_at_least(p, oldn, alignment, n).ptr; - } - else if constexpr (::fast_io::details::has_reallocate_aligned_impl) - { - return allocator_type::reallocate_aligned(p, alignment, n); - } - else if constexpr (::fast_io::details::has_reallocate_aligned_at_least_impl) - { - return allocator_type::reallocate_aligned_at_least(p, alignment, n).ptr; - } - else if constexpr (::fast_io::details::has_reallocate_aligned_zero_n_impl) - { - return allocator_type::reallocate_aligned_zero_n(p, oldn, alignment, n); - } - else if constexpr (::fast_io::details::has_reallocate_aligned_zero_n_at_least_impl) - { - return allocator_type::reallocate_aligned_zero_n_at_least(p, oldn, alignment, n).ptr; - } - else if constexpr (::fast_io::details::has_reallocate_aligned_zero_impl) - { - return allocator_type::reallocate_aligned_zero(p, alignment, n); - } - else if constexpr (::fast_io::details::has_reallocate_aligned_zero_at_least_impl) - { - return allocator_type::reallocate_aligned_zero_at_least(p, alignment, n).ptr; - } - else +#if __cpp_if_consteval >= 202106L + if consteval +#elif __cpp_lib_is_constant_evaluated >= 201811L && __cpp_constexpr_dynamic_alloc >= 201907L + if (__builtin_is_constant_evaluated()) +#else + if (false) +#endif { - if constexpr (::fast_io::details::has_reallocate_n_impl || - ::fast_io::details::has_reallocate_zero_n_impl || - ::fast_io::details::has_reallocate_impl || - ::fast_io::details::has_reallocate_zero_impl) - { - if (alignment <= default_alignment) - { - return generic_allocator_adapter::reallocate_n(p, oldn, n); - } - } - auto newptr{::fast_io::details::allocator_pointer_aligned_impl(alignment, n)}; + auto newptr{::operator new(n)}; if (p != nullptr) { if (n) { - if (oldn < n) - { - n = oldn; - } - ::fast_io::freestanding::nonoverlapped_bytes_copy_n(reinterpret_cast<::std::byte const *>(p), n, reinterpret_cast<::std::byte *>(newptr)); + ::std::size_t copyn{oldn < n ? oldn : n}; + ::fast_io::freestanding::nonoverlapped_bytes_copy_n(reinterpret_cast<::std::byte const *>(p), copyn, reinterpret_cast<::std::byte *>(newptr)); } - generic_allocator_adapter::deallocate_aligned_n(p, alignment, oldn); + ::operator delete(p); + } + if (zero && oldn < n) + { + ::fast_io::freestanding::bytes_clear_n(reinterpret_cast<::std::byte *>(newptr) + oldn, n - oldn); } return newptr; } - } - -#if __has_cpp_attribute(__gnu__::__returns_nonnull__) - [[__gnu__::__returns_nonnull__]] -#endif - static inline - void * - reallocate_aligned_zero_n(void *p, ::std::size_t oldn, ::std::size_t alignment, ::std::size_t n) noexcept - requires(!has_status) - { - if (p != nullptr && oldn == n) - { - return p; - } - if constexpr (::fast_io::details::has_reallocate_aligned_zero_n_impl) - { - return allocator_type::reallocate_aligned_zero_n(p, oldn, alignment, n); - } - else if constexpr (::fast_io::details::has_reallocate_aligned_zero_n_at_least_impl) - { - return allocator_type::reallocate_aligned_zero_n_at_least(p, oldn, alignment, n).ptr; - } else { - auto newptr{generic_allocator_adapter::reallocate_aligned_n(p, oldn, alignment, n)}; - if (oldn < n) + if constexpr (::fast_io::details::has_reallocate_aligned_n_conditional_zero_impl) { - ::std::size_t const to_zero_bytes{static_cast<::std::size_t>(n - oldn)}; - ::fast_io::freestanding::bytes_clear_n(reinterpret_cast<::std::byte *>(newptr) + oldn, to_zero_bytes); + return allocator_type::reallocate_aligned_n_conditional_zero(p, oldn, alignment, n, zero); } - return newptr; - } - } - + else if constexpr (::fast_io::details::has_reallocate_aligned_n_conditional_zero_at_least_impl) + { + return allocator_type::reallocate_aligned_n_conditional_zero_at_least(p, oldn, alignment, n, zero).ptr; + } + else if (zero) + { + if constexpr (::fast_io::details::has_reallocate_aligned_zero_n_impl) + { + return allocator_type::reallocate_aligned_zero_n(p, oldn, alignment, n); + } + else if constexpr (::fast_io::details::has_reallocate_aligned_zero_n_at_least_impl) + { + return allocator_type::reallocate_aligned_zero_n_at_least(p, oldn, alignment, n).ptr; + } + else + { + auto newptr{generic_allocator_adapter::reallocate_aligned_n(p, oldn, alignment, n)}; + if (oldn < n) + { + ::fast_io::freestanding::bytes_clear_n(reinterpret_cast<::std::byte *>(newptr) + oldn, n - oldn); + } + return newptr; + } + } + else + { + if constexpr (::fast_io::details::has_reallocate_aligned_n_impl) + { + return allocator_type::reallocate_aligned_n(p, oldn, alignment, n); + } + else if constexpr (::fast_io::details::has_reallocate_aligned_n_at_least_impl) + { + return allocator_type::reallocate_aligned_n_at_least(p, oldn, alignment, n).ptr; + } + else if constexpr (::fast_io::details::has_reallocate_aligned_impl) + { + return allocator_type::reallocate_aligned(p, alignment, n); + } + else if constexpr (::fast_io::details::has_reallocate_aligned_at_least_impl) + { + return allocator_type::reallocate_aligned_at_least(p, alignment, n).ptr; + } + else if constexpr (::fast_io::details::has_reallocate_aligned_zero_n_impl) + { + return allocator_type::reallocate_aligned_zero_n(p, oldn, alignment, n); + } + else if constexpr (::fast_io::details::has_reallocate_aligned_zero_n_at_least_impl) + { + return allocator_type::reallocate_aligned_zero_n_at_least(p, oldn, alignment, n).ptr; + } + else if constexpr (::fast_io::details::has_reallocate_aligned_zero_impl) + { + return allocator_type::reallocate_aligned_zero(p, alignment, n); + } + else if constexpr (::fast_io::details::has_reallocate_aligned_zero_at_least_impl) + { + return allocator_type::reallocate_aligned_zero_at_least(p, alignment, n).ptr; + } + else + { + if constexpr (::fast_io::details::has_reallocate_n_impl || + ::fast_io::details::has_reallocate_zero_n_impl || + ::fast_io::details::has_reallocate_impl || + ::fast_io::details::has_reallocate_zero_impl) + { + if (alignment <= default_alignment) + { + return generic_allocator_adapter::reallocate_n(p, oldn, n); + } + } + auto newptr{::fast_io::details::allocator_pointer_aligned_impl(alignment, n, false)}; + if (p != nullptr) + { + if (n) + { + ::std::size_t copyn{oldn < n ? oldn : n}; + ::fast_io::freestanding::nonoverlapped_bytes_copy_n(reinterpret_cast<::std::byte const *>(p), copyn, reinterpret_cast<::std::byte *>(newptr)); + } + generic_allocator_adapter::deallocate_aligned_n(p, alignment, oldn); + } + return newptr; + } + } + } + } + +#if __has_cpp_attribute(__gnu__::__returns_nonnull__) + [[__gnu__::__returns_nonnull__]] +#endif + static inline + void * + reallocate_aligned_n(void *p, ::std::size_t oldn, ::std::size_t alignment, ::std::size_t n) noexcept + requires(!has_status) + { + if (p != nullptr && oldn == n) + { + return p; + } + if constexpr (::fast_io::details::has_reallocate_aligned_n_impl) + { + return allocator_type::reallocate_aligned_n(p, oldn, alignment, n); + } + else if constexpr (::fast_io::details::has_reallocate_aligned_n_at_least_impl) + { + return allocator_type::reallocate_aligned_n_at_least(p, oldn, alignment, n).ptr; + } + else + { + return generic_allocator_adapter::reallocate_aligned_n_conditional_zero(p, oldn, alignment, n, false); + } + } + +#if __has_cpp_attribute(__gnu__::__returns_nonnull__) + [[__gnu__::__returns_nonnull__]] +#endif + static inline + void * + reallocate_aligned_zero_n(void *p, ::std::size_t oldn, ::std::size_t alignment, ::std::size_t n) noexcept + requires(!has_status) + { + if (p != nullptr && oldn == n) + { + return p; + } + if constexpr (::fast_io::details::has_reallocate_aligned_zero_n_impl) + { + return allocator_type::reallocate_aligned_zero_n(p, oldn, alignment, n); + } + else if constexpr (::fast_io::details::has_reallocate_aligned_zero_n_at_least_impl) + { + return allocator_type::reallocate_aligned_zero_n_at_least(p, oldn, alignment, n).ptr; + } + else + { + auto newptr{generic_allocator_adapter::reallocate_aligned_n(p, oldn, alignment, n)}; + if (oldn < n) + { + ::std::size_t const to_zero_bytes{static_cast<::std::size_t>(n - oldn)}; + ::fast_io::freestanding::bytes_clear_n(reinterpret_cast<::std::byte *>(newptr) + oldn, to_zero_bytes); + } + return newptr; + } + } + static inline constexpr bool has_native_reallocate_at_least = (has_reallocate && (::fast_io::details::has_reallocate_aligned_at_least_impl || ::fast_io::details::has_reallocate_aligned_zero_at_least_impl)); @@ -987,212 +1373,772 @@ class generic_allocator_adapter } else { - auto newres{generic_allocator_adapter::reallocate_n_at_least(p, oldn, n)}; - auto newptr{newres.ptr}; - n = newres.count; - if (oldn < n) + auto newres{generic_allocator_adapter::reallocate_n_at_least(p, oldn, n)}; + auto newptr{newres.ptr}; + n = newres.count; + if (oldn < n) + { + ::std::size_t const to_zero_bytes{static_cast<::std::size_t>(n - oldn)}; + ::fast_io::freestanding::bytes_clear_n(reinterpret_cast<::std::byte *>(newptr) + oldn, to_zero_bytes); + } + return newres; + } + } + + static inline constexpr bool has_native_reallocate_aligned_at_least = (has_reallocate_aligned && + (::fast_io::details::has_reallocate_aligned_zero_at_least_impl || + ::fast_io::details::has_reallocate_aligned_at_least_impl)); + + static inline ::fast_io::allocation_least_result + reallocate_aligned_at_least(void *p, ::std::size_t alignment, ::std::size_t n) noexcept + requires(!has_status && has_reallocate_aligned_zero) + { + if constexpr (::fast_io::details::has_reallocate_aligned_at_least_impl) + { + return allocator_type::reallocate_aligned_at_least(p, alignment, n); + } + else if constexpr (::fast_io::details::has_reallocate_aligned_zero_at_least_impl) + { + return allocator_type::reallocate_aligned_zero_at_least(p, alignment, n); + } + else if constexpr (::fast_io::details::has_reallocate_aligned_impl) + { + return {allocator_type::reallocate_aligned(p, alignment, n), n}; + } + else if constexpr (::fast_io::details::has_reallocate_aligned_zero_impl) + { + return {allocator_type::reallocate_aligned_zero(p, alignment, n), n}; + } + } + + static inline constexpr bool has_native_reallocate_aligned_zero_at_least = (has_reallocate_aligned_zero && + ::fast_io::details::has_reallocate_aligned_zero_at_least_impl); + + static inline ::fast_io::allocation_least_result + reallocate_aligned_zero_at_least(void *p, ::std::size_t alignment, ::std::size_t n) noexcept + requires(!has_status && has_reallocate_aligned_zero) + { + if constexpr (::fast_io::details::has_reallocate_aligned_zero_at_least_impl) + { + return allocator_type::reallocate_aligned_zero_at_least(p, alignment, n); + } + else if constexpr (::fast_io::details::has_reallocate_aligned_zero_impl) + { + return {allocator_type::reallocate_aligned_zero(p, alignment, n), n}; + } + } + + static inline constexpr bool has_native_reallocate_aligned_n_at_least = (has_reallocate_aligned && + (::fast_io::details::has_reallocate_aligned_n_at_least_impl || + ::fast_io::details::has_reallocate_aligned_zero_n_at_least_impl)); + static inline ::fast_io::allocation_least_result + reallocate_aligned_n_at_least(void *p, ::std::size_t oldn, ::std::size_t alignment, ::std::size_t n) noexcept + requires(!has_status) + { + if constexpr (::fast_io::details::has_reallocate_aligned_n_at_least_impl) + { + return allocator_type::reallocate_aligned_n_at_least(p, oldn, alignment, n); + } + else if constexpr (::fast_io::details::has_reallocate_aligned_at_least_impl) + { + return allocator_type::reallocate_aligned_at_least(p, alignment, n); + } + else if constexpr (::fast_io::details::has_reallocate_aligned_zero_n_at_least_impl) + { + return allocator_type::reallocate_aligned_zero_n_at_least(p, oldn, alignment, n); + } + else if constexpr (::fast_io::details::has_reallocate_aligned_zero_at_least_impl) + { + return allocator_type::reallocate_aligned_zero_at_least(p, alignment, n); + } + else if constexpr (::fast_io::details::has_reallocate_aligned_impl) + { + return {allocator_type::reallocate_aligned_n(p, oldn, alignment, n), n}; + } + else if constexpr (::fast_io::details::has_reallocate_aligned_impl) + { + return {allocator_type::reallocate_aligned(p, alignment, n), n}; + } + else if constexpr (::fast_io::details::has_reallocate_aligned_zero_n_impl) + { + return {allocator_type::reallocate_aligned_zero_n(p, oldn, alignment, n), n}; + } + else if constexpr (::fast_io::details::has_reallocate_aligned_zero_impl) + { + return {allocator_type::reallocate_aligned_zero(p, alignment, n), n}; + } + else + { + if constexpr ( + ::fast_io::details::has_reallocate_at_least_impl || + ::fast_io::details::has_reallocate_zero_at_least_impl || + ::fast_io::details::has_reallocate_n_at_least_impl || + ::fast_io::details::has_reallocate_zero_n_at_least_impl) + { + if (alignment <= default_alignment) + { + return generic_allocator_adapter::reallocate_n_at_least(p, oldn, n); + } + } + auto newres{::fast_io::details::allocator_pointer_aligned_at_least_impl(alignment, n)}; + auto newptr{newres.ptr}; + if (p != nullptr) + { + if (n) + { + if (oldn < n) + { + n = oldn; + } + ::fast_io::freestanding::nonoverlapped_bytes_copy_n(reinterpret_cast<::std::byte const *>(p), n, reinterpret_cast<::std::byte *>(newptr)); + } + generic_allocator_adapter::deallocate_aligned_n(p, alignment, oldn); + } + return newres; + } + } + + static inline constexpr bool has_native_reallocate_aligned_zero_n_at_least = (has_reallocate_aligned_zero && ::fast_io::details::has_reallocate_aligned_zero_at_least_impl); + + static inline ::fast_io::allocation_least_result reallocate_aligned_zero_n_at_least(void *p, ::std::size_t oldn, ::std::size_t alignment, ::std::size_t n) noexcept + requires(!has_status) + { + if constexpr (::fast_io::details::has_reallocate_aligned_zero_n_at_least_impl) + { + return allocator_type::reallocate_aligned_zero_n_at_least(p, oldn, alignment, n); + } + else if constexpr (::fast_io::details::has_reallocate_aligned_zero_n_impl) + { + return {allocator_type::reallocate_aligned_zero_n(p, oldn, alignment, n), n}; + } + else + { + auto newres = generic_allocator_adapter::reallocate_aligned_n_at_least(p, oldn, alignment, n); + auto newptr{newres.ptr}; + n = newres.count; + if (oldn < n) + { + ::std::size_t const to_zero_bytes{static_cast<::std::size_t>(n - oldn)}; + ::fast_io::freestanding::bytes_clear_n(reinterpret_cast<::std::byte *>(newptr) + oldn, to_zero_bytes); + } + return newres; + } + } + + static inline constexpr bool has_deallocate_aligned = (::fast_io::details::has_deallocate_aligned_impl || + ::fast_io::details::has_deallocate_impl); + static inline void deallocate_aligned(void *p, ::std::size_t alignment) noexcept + requires(!has_status && has_deallocate_aligned) + { + if constexpr (::fast_io::details::has_deallocate_aligned_impl) + { + allocator_type::deallocate_aligned(p, alignment); + } + else + { + if (p == nullptr) + { + return; + } + if (default_alignment < alignment) + { + p = reinterpret_cast(p)[-1]; + } + allocator_type::deallocate(p); + } + } + + static inline void deallocate_aligned_n(void *p, ::std::size_t alignment, ::std::size_t n) noexcept + requires(!has_status) + { + if constexpr (::fast_io::details::has_deallocate_aligned_n_impl) + { + allocator_type::deallocate_aligned_n(p, alignment, n); + } + else if constexpr (::fast_io::details::has_deallocate_aligned_impl) + { + allocator_type::deallocate_aligned(p, alignment); + } + else + { + if (p == nullptr) + { + return; + } + if (default_alignment < alignment) + { + auto start{reinterpret_cast(p)[-1]}; + n += static_cast<::std::size_t>(reinterpret_cast(p) - reinterpret_cast(start)); + p = start; + } + if constexpr (::fast_io::details::has_deallocate_impl) + { + allocator_type::deallocate(p); + } + else + { + allocator_type::deallocate_n(p, n); + } + } + } + + // Handle-based allocation functions (for allocators with non-empty handle_type) + static inline constexpr bool has_native_handle_allocate{ + has_status && (::fast_io::details::has_handle_allocate_impl || + ::fast_io::details::has_handle_allocate_aligned_impl || + ::fast_io::details::has_handle_allocate_zero_impl || + ::fast_io::details::has_handle_allocate_aligned_zero_impl || + ::fast_io::details::has_handle_allocate_at_least_impl || + ::fast_io::details::has_handle_allocate_aligned_at_least_impl || + ::fast_io::details::has_handle_allocate_zero_at_least_impl || + ::fast_io::details::has_handle_allocate_aligned_zero_at_least_impl || + ::fast_io::details::has_handle_allocate_conditional_zero_impl || + ::fast_io::details::has_handle_allocate_aligned_conditional_zero_impl || + ::fast_io::details::has_handle_allocate_conditional_zero_at_least_impl || + ::fast_io::details::has_handle_allocate_aligned_conditional_zero_at_least_impl)}; + +#if __has_cpp_attribute(__gnu__::__returns_nonnull__) + [[__gnu__::__returns_nonnull__]] +#endif + static inline void *handle_allocate_conditional_zero(handle_type handle, ::std::size_t n, bool zero) noexcept + requires(has_status && has_native_handle_allocate) + { +#if __cpp_if_consteval >= 202106L + if consteval +#elif __cpp_lib_is_constant_evaluated >= 201811L && __cpp_constexpr_dynamic_alloc >= 201907L + if (__builtin_is_constant_evaluated()) +#else + if (false) +#endif + { + auto p{::operator new(n)}; + if (zero) + { + ::fast_io::freestanding::bytes_clear_n(reinterpret_cast<::std::byte *>(p), n); + } + return p; + } + else + { + if constexpr (::fast_io::details::has_handle_allocate_conditional_zero_impl) + { + return allocator_type::handle_allocate_conditional_zero(handle, n, zero); + } + else if constexpr (::fast_io::details::has_handle_allocate_conditional_zero_at_least_impl) + { + return allocator_type::handle_allocate_conditional_zero_at_least(handle, n, zero).ptr; + } + else if constexpr (::fast_io::details::has_handle_allocate_aligned_conditional_zero_impl) + { + return allocator_type::handle_allocate_aligned_conditional_zero(handle, default_alignment, n, zero); + } + else if constexpr (::fast_io::details::has_handle_allocate_aligned_conditional_zero_at_least_impl) + { + return allocator_type::handle_allocate_aligned_conditional_zero_at_least(handle, default_alignment, n, zero).ptr; + } + else if constexpr (::fast_io::details::has_handle_allocate_impl || + ::fast_io::details::has_handle_allocate_at_least_impl || + ::fast_io::details::has_handle_allocate_aligned_impl || + ::fast_io::details::has_handle_allocate_aligned_at_least_impl) + { + if (zero) + { + if constexpr (::fast_io::details::has_handle_allocate_zero_impl) + { + return allocator_type::handle_allocate_zero(handle, n); + } + else if constexpr (::fast_io::details::has_handle_allocate_zero_at_least_impl) + { + return allocator_type::handle_allocate_zero_at_least(handle, n).ptr; + } + else if constexpr (::fast_io::details::has_handle_allocate_aligned_zero_impl) + { + return allocator_type::handle_allocate_aligned_zero(handle, default_alignment, n); + } + else if constexpr (::fast_io::details::has_handle_allocate_aligned_zero_at_least_impl) + { + return allocator_type::handle_allocate_aligned_zero_at_least(handle, default_alignment, n).ptr; + } + else + { + auto p{generic_allocator_adapter::handle_allocate(handle, n)}; + ::fast_io::freestanding::bytes_clear_n(reinterpret_cast<::std::byte *>(p), n); + return p; + } + } + else + { + if constexpr (::fast_io::details::has_handle_allocate_impl) + { + return allocator_type::handle_allocate(handle, n); + } + else if constexpr (::fast_io::details::has_handle_allocate_at_least_impl) + { + return allocator_type::handle_allocate_at_least(handle, n).ptr; + } + else if constexpr (::fast_io::details::has_handle_allocate_aligned_impl) + { + return allocator_type::handle_allocate_aligned(handle, default_alignment, n); + } + else + { + return allocator_type::handle_allocate_aligned_at_least(handle, default_alignment, n).ptr; + } + } + } + else + { + if constexpr (::fast_io::details::has_handle_allocate_zero_impl) + { + return allocator_type::handle_allocate_zero(handle, n); + } + else if constexpr (::fast_io::details::has_handle_allocate_zero_at_least_impl) + { + return allocator_type::handle_allocate_zero_at_least(handle, n).ptr; + } + else if constexpr (::fast_io::details::has_handle_allocate_aligned_zero_impl) + { + return allocator_type::handle_allocate_aligned_zero(handle, default_alignment, n); + } + else if constexpr (::fast_io::details::has_handle_allocate_aligned_zero_at_least_impl) + { + return allocator_type::handle_allocate_aligned_zero_at_least(handle, default_alignment, n).ptr; + } + else + { + ::fast_io::fast_terminate(); + } + } + } + } + +#if __has_cpp_attribute(__gnu__::__returns_nonnull__) + [[__gnu__::__returns_nonnull__]] +#endif + static inline void *handle_allocate(handle_type handle, ::std::size_t n) noexcept + requires(has_status && has_native_handle_allocate) + { +#if __cpp_if_consteval >= 202106L + if consteval +#elif __cpp_lib_is_constant_evaluated >= 201811L && __cpp_constexpr_dynamic_alloc >= 201907L + if (__builtin_is_constant_evaluated()) +#else + if (false) +#endif + { + return ::operator new(n); + } + else + { + if constexpr (::fast_io::details::has_handle_allocate_impl) + { + return allocator_type::handle_allocate(handle, n); + } + else if constexpr (::fast_io::details::has_handle_allocate_at_least_impl) + { + return allocator_type::handle_allocate_at_least(handle, n).ptr; + } + else + { + return generic_allocator_adapter::handle_allocate_conditional_zero(handle, n, false); + } + } + } + +#if __has_cpp_attribute(__gnu__::__returns_nonnull__) + [[__gnu__::__returns_nonnull__]] +#endif + static inline void *handle_allocate_zero(handle_type handle, ::std::size_t n) noexcept + requires(has_status && has_native_handle_allocate) + { + if constexpr (::fast_io::details::has_handle_allocate_zero_impl) + { + return allocator_type::handle_allocate_zero(handle, n); + } + else if constexpr (::fast_io::details::has_handle_allocate_zero_at_least_impl) + { + return allocator_type::handle_allocate_zero_at_least(handle, n).ptr; + } + else + { + return generic_allocator_adapter::handle_allocate_conditional_zero(handle, n, true); + } + } + + static inline constexpr bool has_handle_reallocate{ + has_status && (::fast_io::details::has_handle_reallocate_impl || + ::fast_io::details::has_handle_reallocate_aligned_impl || + ::fast_io::details::has_handle_reallocate_zero_impl || + ::fast_io::details::has_handle_reallocate_aligned_zero_impl || + ::fast_io::details::has_handle_reallocate_at_least_impl || + ::fast_io::details::has_handle_reallocate_aligned_at_least_impl || + ::fast_io::details::has_handle_reallocate_zero_at_least_impl || + ::fast_io::details::has_handle_reallocate_aligned_zero_at_least_impl || + ::fast_io::details::has_handle_reallocate_conditional_zero_impl || + ::fast_io::details::has_handle_reallocate_aligned_conditional_zero_impl || + ::fast_io::details::has_handle_reallocate_conditional_zero_at_least_impl || + ::fast_io::details::has_handle_reallocate_aligned_conditional_zero_at_least_impl)}; + +#if __has_cpp_attribute(__gnu__::__returns_nonnull__) + [[__gnu__::__returns_nonnull__]] +#endif + static inline void *handle_reallocate_conditional_zero(handle_type handle, void *p, ::std::size_t n, bool zero) noexcept + requires(has_status && has_handle_reallocate) + { + if constexpr (::fast_io::details::has_handle_reallocate_conditional_zero_impl) + { + return allocator_type::handle_reallocate_conditional_zero(handle, p, n, zero); + } + else if constexpr (::fast_io::details::has_handle_reallocate_conditional_zero_at_least_impl) + { + return allocator_type::handle_reallocate_conditional_zero_at_least(handle, p, n, zero).ptr; + } + else if constexpr (::fast_io::details::has_handle_reallocate_aligned_conditional_zero_impl) + { + return allocator_type::handle_reallocate_aligned_conditional_zero(handle, p, default_alignment, n, zero); + } + else if constexpr (::fast_io::details::has_handle_reallocate_aligned_conditional_zero_at_least_impl) + { + return allocator_type::handle_reallocate_aligned_conditional_zero_at_least(handle, p, default_alignment, n, zero).ptr; + } + else if constexpr (::fast_io::details::has_handle_reallocate_impl || + ::fast_io::details::has_handle_reallocate_at_least_impl || + ::fast_io::details::has_handle_reallocate_aligned_impl || + ::fast_io::details::has_handle_reallocate_aligned_at_least_impl) + { + if (zero) + { + if constexpr (::fast_io::details::has_handle_reallocate_zero_impl) + { + return allocator_type::handle_reallocate_zero(handle, p, n); + } + else if constexpr (::fast_io::details::has_handle_reallocate_zero_at_least_impl) + { + return allocator_type::handle_reallocate_zero_at_least(handle, p, n).ptr; + } + else if constexpr (::fast_io::details::has_handle_reallocate_aligned_zero_impl) + { + return allocator_type::handle_reallocate_aligned_zero(handle, p, default_alignment, n); + } + else if constexpr (::fast_io::details::has_handle_reallocate_aligned_zero_at_least_impl) + { + return allocator_type::handle_reallocate_aligned_zero_at_least(handle, p, default_alignment, n).ptr; + } + else + { + ::fast_io::fast_terminate(); + } + } + else + { + if constexpr (::fast_io::details::has_handle_reallocate_impl) + { + return allocator_type::handle_reallocate(handle, p, n); + } + else if constexpr (::fast_io::details::has_handle_reallocate_at_least_impl) + { + return allocator_type::handle_reallocate_at_least(handle, p, n).ptr; + } + else if constexpr (::fast_io::details::has_handle_reallocate_aligned_impl) + { + return allocator_type::handle_reallocate_aligned(handle, p, default_alignment, n); + } + else + { + return allocator_type::handle_reallocate_aligned_at_least(handle, p, default_alignment, n).ptr; + } + } + } + else + { + if constexpr (::fast_io::details::has_handle_reallocate_zero_impl) { - ::std::size_t const to_zero_bytes{static_cast<::std::size_t>(n - oldn)}; - ::fast_io::freestanding::bytes_clear_n(reinterpret_cast<::std::byte *>(newptr) + oldn, to_zero_bytes); + return allocator_type::handle_reallocate_zero(handle, p, n); + } + else if constexpr (::fast_io::details::has_handle_reallocate_zero_at_least_impl) + { + return allocator_type::handle_reallocate_zero_at_least(handle, p, n).ptr; + } + else if constexpr (::fast_io::details::has_handle_reallocate_aligned_zero_impl) + { + return allocator_type::handle_reallocate_aligned_zero(handle, p, default_alignment, n); + } + else if constexpr (::fast_io::details::has_handle_reallocate_aligned_zero_at_least_impl) + { + return allocator_type::handle_reallocate_aligned_zero_at_least(handle, p, default_alignment, n).ptr; + } + else + { + ::fast_io::fast_terminate(); } - return newres; } } - static inline constexpr bool has_native_reallocate_aligned_at_least = (has_reallocate_aligned && - (::fast_io::details::has_reallocate_aligned_zero_at_least_impl || - ::fast_io::details::has_reallocate_aligned_at_least_impl)); - - static inline ::fast_io::allocation_least_result - reallocate_aligned_at_least(void *p, ::std::size_t alignment, ::std::size_t n) noexcept - requires(!has_status && has_reallocate_aligned_zero) +#if __has_cpp_attribute(__gnu__::__returns_nonnull__) + [[__gnu__::__returns_nonnull__]] +#endif + static inline void *handle_reallocate(handle_type handle, void *p, ::std::size_t n) noexcept + requires(has_status && has_handle_reallocate) { - if constexpr (::fast_io::details::has_reallocate_aligned_at_least_impl) - { - return allocator_type::reallocate_aligned_at_least(p, alignment, n); - } - else if constexpr (::fast_io::details::has_reallocate_aligned_zero_at_least_impl) + if constexpr (::fast_io::details::has_handle_reallocate_impl) { - return allocator_type::reallocate_aligned_zero_at_least(p, alignment, n); + return allocator_type::handle_reallocate(handle, p, n); } - else if constexpr (::fast_io::details::has_reallocate_aligned_impl) + else if constexpr (::fast_io::details::has_handle_reallocate_at_least_impl) { - return {allocator_type::reallocate_aligned(p, alignment, n), n}; + return allocator_type::handle_reallocate_at_least(handle, p, n).ptr; } - else if constexpr (::fast_io::details::has_reallocate_aligned_zero_impl) + else { - return {allocator_type::reallocate_aligned_zero(p, alignment, n), n}; + return generic_allocator_adapter::handle_reallocate_conditional_zero(handle, p, n, false); } } - static inline constexpr bool has_native_reallocate_aligned_zero_at_least = (has_reallocate_aligned_zero && - ::fast_io::details::has_reallocate_aligned_zero_at_least_impl); - - static inline ::fast_io::allocation_least_result - reallocate_aligned_zero_at_least(void *p, ::std::size_t alignment, ::std::size_t n) noexcept - requires(!has_status && has_reallocate_aligned_zero) +#if __has_cpp_attribute(__gnu__::__returns_nonnull__) + [[__gnu__::__returns_nonnull__]] +#endif + static inline void *handle_reallocate_zero(handle_type handle, void *p, ::std::size_t n) noexcept + requires(has_status && has_handle_reallocate) { - if constexpr (::fast_io::details::has_reallocate_aligned_zero_at_least_impl) + if constexpr (::fast_io::details::has_handle_reallocate_zero_impl) { - return allocator_type::reallocate_aligned_zero_at_least(p, alignment, n); + return allocator_type::handle_reallocate_zero(handle, p, n); } - else if constexpr (::fast_io::details::has_reallocate_aligned_zero_impl) + else if constexpr (::fast_io::details::has_handle_reallocate_zero_at_least_impl) { - return {allocator_type::reallocate_aligned_zero(p, alignment, n), n}; + return allocator_type::handle_reallocate_zero_at_least(handle, p, n).ptr; + } + else + { + return generic_allocator_adapter::handle_reallocate_conditional_zero(handle, p, n, true); } } - static inline constexpr bool has_native_reallocate_aligned_n_at_least = (has_reallocate_aligned && - (::fast_io::details::has_reallocate_aligned_n_at_least_impl || - ::fast_io::details::has_reallocate_aligned_zero_n_at_least_impl)); - static inline ::fast_io::allocation_least_result - reallocate_aligned_n_at_least(void *p, ::std::size_t oldn, ::std::size_t alignment, ::std::size_t n) noexcept - requires(!has_status) + static inline constexpr bool has_handle_reallocate_n{ + has_status && (::fast_io::details::has_handle_reallocate_n_impl || + ::fast_io::details::has_handle_reallocate_aligned_n_impl || + ::fast_io::details::has_handle_reallocate_zero_n_impl || + ::fast_io::details::has_handle_reallocate_aligned_zero_n_impl || + ::fast_io::details::has_handle_reallocate_n_at_least_impl || + ::fast_io::details::has_handle_reallocate_aligned_n_at_least_impl || + ::fast_io::details::has_handle_reallocate_zero_n_at_least_impl || + ::fast_io::details::has_handle_reallocate_aligned_zero_n_at_least_impl || + ::fast_io::details::has_handle_reallocate_n_conditional_zero_impl || + ::fast_io::details::has_handle_reallocate_aligned_n_conditional_zero_impl || + ::fast_io::details::has_handle_reallocate_n_conditional_zero_at_least_impl || + ::fast_io::details::has_handle_reallocate_aligned_n_conditional_zero_at_least_impl)}; + +#if __has_cpp_attribute(__gnu__::__returns_nonnull__) + [[__gnu__::__returns_nonnull__]] +#endif + static inline void *handle_reallocate_n_conditional_zero(handle_type handle, void *p, ::std::size_t oldn, ::std::size_t n, bool zero) noexcept + requires(has_status && has_handle_reallocate_n) { - if constexpr (::fast_io::details::has_reallocate_aligned_n_at_least_impl) - { - return allocator_type::reallocate_aligned_n_at_least(p, oldn, alignment, n); - } - else if constexpr (::fast_io::details::has_reallocate_aligned_at_least_impl) - { - return allocator_type::reallocate_aligned_at_least(p, alignment, n); - } - else if constexpr (::fast_io::details::has_reallocate_aligned_zero_n_at_least_impl) + if (p != nullptr && oldn == n) { - return allocator_type::reallocate_aligned_zero_n_at_least(p, oldn, alignment, n); + return p; } - else if constexpr (::fast_io::details::has_reallocate_aligned_zero_at_least_impl) + if constexpr (::fast_io::details::has_handle_reallocate_n_conditional_zero_impl) { - return allocator_type::reallocate_aligned_zero_at_least(p, alignment, n); + return allocator_type::handle_reallocate_n_conditional_zero(handle, p, oldn, n, zero); } - else if constexpr (::fast_io::details::has_reallocate_aligned_impl) + else if constexpr (::fast_io::details::has_handle_reallocate_n_conditional_zero_at_least_impl) { - return {allocator_type::reallocate_aligned_n(p, oldn, alignment, n), n}; + return allocator_type::handle_reallocate_n_conditional_zero_at_least(handle, p, oldn, n, zero).ptr; } - else if constexpr (::fast_io::details::has_reallocate_aligned_impl) + else if constexpr (::fast_io::details::has_handle_reallocate_aligned_n_conditional_zero_impl) { - return {allocator_type::reallocate_aligned(p, alignment, n), n}; + return allocator_type::handle_reallocate_aligned_n_conditional_zero(handle, p, oldn, default_alignment, n, zero); } - else if constexpr (::fast_io::details::has_reallocate_aligned_zero_n_impl) + else if constexpr (::fast_io::details::has_handle_reallocate_aligned_n_conditional_zero_at_least_impl) { - return {allocator_type::reallocate_aligned_zero_n(p, oldn, alignment, n), n}; + return allocator_type::handle_reallocate_aligned_n_conditional_zero_at_least(handle, p, oldn, default_alignment, n, zero).ptr; } - else if constexpr (::fast_io::details::has_reallocate_aligned_zero_impl) + else if constexpr (::fast_io::details::has_handle_reallocate_n_impl || + ::fast_io::details::has_handle_reallocate_n_at_least_impl || + ::fast_io::details::has_handle_reallocate_aligned_n_impl || + ::fast_io::details::has_handle_reallocate_aligned_n_at_least_impl) { - return {allocator_type::reallocate_aligned_zero(p, alignment, n), n}; + if (zero) + { + if constexpr (::fast_io::details::has_handle_reallocate_zero_n_impl) + { + return allocator_type::handle_reallocate_zero_n(handle, p, oldn, n); + } + else if constexpr (::fast_io::details::has_handle_reallocate_zero_n_at_least_impl) + { + return allocator_type::handle_reallocate_zero_n_at_least(handle, p, oldn, n).ptr; + } + else if constexpr (::fast_io::details::has_handle_reallocate_aligned_zero_n_impl) + { + return allocator_type::handle_reallocate_aligned_zero_n(handle, p, oldn, default_alignment, n); + } + else if constexpr (::fast_io::details::has_handle_reallocate_aligned_zero_n_at_least_impl) + { + return allocator_type::handle_reallocate_aligned_zero_n_at_least(handle, p, oldn, default_alignment, n).ptr; + } + else + { + auto newptr{generic_allocator_adapter::handle_reallocate_n(handle, p, oldn, n)}; + if (oldn < n) + { + ::fast_io::freestanding::bytes_clear_n(reinterpret_cast<::std::byte *>(newptr) + oldn, n - oldn); + } + return newptr; + } + } + else + { + if constexpr (::fast_io::details::has_handle_reallocate_n_impl) + { + return allocator_type::handle_reallocate_n(handle, p, oldn, n); + } + else if constexpr (::fast_io::details::has_handle_reallocate_n_at_least_impl) + { + return allocator_type::handle_reallocate_n_at_least(handle, p, oldn, n).ptr; + } + else if constexpr (::fast_io::details::has_handle_reallocate_aligned_n_impl) + { + return allocator_type::handle_reallocate_aligned_n(handle, p, oldn, default_alignment, n); + } + else + { + return allocator_type::handle_reallocate_aligned_n_at_least(handle, p, oldn, default_alignment, n).ptr; + } + } } else { - if constexpr ( - ::fast_io::details::has_reallocate_at_least_impl || - ::fast_io::details::has_reallocate_zero_at_least_impl || - ::fast_io::details::has_reallocate_n_at_least_impl || - ::fast_io::details::has_reallocate_zero_n_at_least_impl) + if constexpr (::fast_io::details::has_handle_reallocate_zero_n_impl) { - if (alignment <= default_alignment) - { - return generic_allocator_adapter::reallocate_n_at_least(p, oldn, n); - } + return allocator_type::handle_reallocate_zero_n(handle, p, oldn, n); } - auto newres{::fast_io::details::allocator_pointer_aligned_at_least_impl(alignment, n)}; - auto newptr{newres.ptr}; - if (p != nullptr) + else if constexpr (::fast_io::details::has_handle_reallocate_zero_n_at_least_impl) { - if (n) + return allocator_type::handle_reallocate_zero_n_at_least(handle, p, oldn, n).ptr; + } + else if constexpr (::fast_io::details::has_handle_reallocate_aligned_zero_n_impl) + { + return allocator_type::handle_reallocate_aligned_zero_n(handle, p, oldn, default_alignment, n); + } + else if constexpr (::fast_io::details::has_handle_reallocate_aligned_zero_n_at_least_impl) + { + return allocator_type::handle_reallocate_aligned_zero_n_at_least(handle, p, oldn, default_alignment, n).ptr; + } + else + { + auto newptr{generic_allocator_adapter::handle_allocate(handle, n)}; + if (p != nullptr) { - if (oldn < n) + if (n) { - n = oldn; + ::std::size_t copyn{oldn < n ? oldn : n}; + ::fast_io::freestanding::nonoverlapped_bytes_copy_n(reinterpret_cast<::std::byte const *>(p), copyn, reinterpret_cast<::std::byte *>(newptr)); } - ::fast_io::freestanding::nonoverlapped_bytes_copy_n(reinterpret_cast<::std::byte const *>(p), n, reinterpret_cast<::std::byte *>(newptr)); + generic_allocator_adapter::handle_deallocate_n(handle, p, oldn); } - generic_allocator_adapter::deallocate_aligned_n(p, alignment, oldn); + if (zero && oldn < n) + { + ::fast_io::freestanding::bytes_clear_n(reinterpret_cast<::std::byte *>(newptr) + oldn, n - oldn); + } + return newptr; } - return newres; } } - static inline constexpr bool has_native_reallocate_aligned_zero_n_at_least = (has_reallocate_aligned_zero && ::fast_io::details::has_reallocate_aligned_zero_at_least_impl); +#if __has_cpp_attribute(__gnu__::__returns_nonnull__) + [[__gnu__::__returns_nonnull__]] +#endif + static inline void *handle_reallocate_n(handle_type handle, void *p, ::std::size_t oldn, ::std::size_t n) noexcept + requires(has_status && has_handle_reallocate_n) + { + if (p != nullptr && oldn == n) + { + return p; + } + if constexpr (::fast_io::details::has_handle_reallocate_n_impl) + { + return allocator_type::handle_reallocate_n(handle, p, oldn, n); + } + else if constexpr (::fast_io::details::has_handle_reallocate_n_at_least_impl) + { + return allocator_type::handle_reallocate_n_at_least(handle, p, oldn, n).ptr; + } + else + { + return generic_allocator_adapter::handle_reallocate_n_conditional_zero(handle, p, oldn, n, false); + } + } - static inline ::fast_io::allocation_least_result reallocate_aligned_zero_n_at_least(void *p, ::std::size_t oldn, ::std::size_t alignment, ::std::size_t n) noexcept - requires(!has_status) +#if __has_cpp_attribute(__gnu__::__returns_nonnull__) + [[__gnu__::__returns_nonnull__]] +#endif + static inline void *handle_reallocate_zero_n(handle_type handle, void *p, ::std::size_t oldn, ::std::size_t n) noexcept + requires(has_status && has_handle_reallocate_n) { - if constexpr (::fast_io::details::has_reallocate_aligned_zero_n_at_least_impl) + if (p != nullptr && oldn == n) { - return allocator_type::reallocate_aligned_zero_n_at_least(p, oldn, alignment, n); + return p; } - else if constexpr (::fast_io::details::has_reallocate_aligned_zero_n_impl) + if constexpr (::fast_io::details::has_handle_reallocate_zero_n_impl) { - return {allocator_type::reallocate_aligned_zero_n(p, oldn, alignment, n), n}; + return allocator_type::handle_reallocate_zero_n(handle, p, oldn, n); + } + else if constexpr (::fast_io::details::has_handle_reallocate_zero_n_at_least_impl) + { + return allocator_type::handle_reallocate_zero_n_at_least(handle, p, oldn, n).ptr; } else { - auto newres = generic_allocator_adapter::reallocate_aligned_n_at_least(p, oldn, alignment, n); - auto newptr{newres.ptr}; - n = newres.count; - if (oldn < n) - { - ::std::size_t const to_zero_bytes{static_cast<::std::size_t>(n - oldn)}; - ::fast_io::freestanding::bytes_clear_n(reinterpret_cast<::std::byte *>(newptr) + oldn, to_zero_bytes); - } - return newres; + return generic_allocator_adapter::handle_reallocate_n_conditional_zero(handle, p, oldn, n, true); } } - static inline constexpr bool has_deallocate_aligned = (::fast_io::details::has_deallocate_aligned_impl || - ::fast_io::details::has_deallocate_impl); - static inline void deallocate_aligned(void *p, ::std::size_t alignment) noexcept - requires(!has_status && has_deallocate_aligned) + static inline constexpr bool has_handle_deallocate{ + has_status && (::fast_io::details::has_handle_deallocate_impl || + ::fast_io::details::has_handle_deallocate_aligned_impl || + ::fast_io::details::has_handle_deallocate_n_impl || + ::fast_io::details::has_handle_deallocate_aligned_n_impl)}; + + static inline void handle_deallocate(handle_type handle, void *p) noexcept + requires(has_status && has_handle_deallocate) { - if constexpr (::fast_io::details::has_deallocate_aligned_impl) + if constexpr (::fast_io::details::has_handle_deallocate_impl) { - allocator_type::deallocate_aligned(p, alignment); + allocator_type::handle_deallocate(handle, p); + } + else if constexpr (::fast_io::details::has_handle_deallocate_aligned_impl) + { + allocator_type::handle_deallocate_aligned(handle, p, default_alignment); + } + else if constexpr (::fast_io::details::has_handle_deallocate_n_impl) + { + allocator_type::handle_deallocate_n(handle, p, 0); } else { - if (p == nullptr) - { - return; - } - if (default_alignment < alignment) - { - p = reinterpret_cast(p)[-1]; - } - allocator_type::deallocate(p); + allocator_type::handle_deallocate_aligned_n(handle, p, default_alignment, 0); } } - static inline void deallocate_aligned_n(void *p, ::std::size_t alignment, ::std::size_t n) noexcept - requires(!has_status) + static inline void handle_deallocate_n(handle_type handle, void *p, ::std::size_t n) noexcept + requires(has_status && has_handle_deallocate) { - if constexpr (::fast_io::details::has_deallocate_aligned_n_impl) + if constexpr (::fast_io::details::has_handle_deallocate_n_impl) { - allocator_type::deallocate_aligned_n(p, alignment, n); + allocator_type::handle_deallocate_n(handle, p, n); } - else if constexpr (::fast_io::details::has_deallocate_aligned_impl) + else if constexpr (::fast_io::details::has_handle_deallocate_aligned_n_impl) { - allocator_type::deallocate_aligned(p, alignment); + allocator_type::handle_deallocate_aligned_n(handle, p, default_alignment, n); + } + else if constexpr (::fast_io::details::has_handle_deallocate_impl) + { + allocator_type::handle_deallocate(handle, p); } else { - if (p == nullptr) - { - return; - } - if (default_alignment < alignment) - { - auto start{reinterpret_cast(p)[-1]}; - n += static_cast<::std::size_t>(reinterpret_cast(p) - reinterpret_cast(start)); - p = start; - } - if constexpr (::fast_io::details::has_deallocate_impl) - { - allocator_type::deallocate(p); - } - else - { - allocator_type::deallocate_n(p, n); - } + allocator_type::handle_deallocate_aligned(handle, p, default_alignment); } } }; @@ -1835,8 +2781,8 @@ class typed_generic_allocator_adapter namespace details { -template -inline constexpr void *allocator_pointer_aligned_impl(::std::size_t alignment, ::std::size_t n) noexcept +template +inline constexpr void *allocator_pointer_aligned_impl(::std::size_t alignment, ::std::size_t n, bool zero) noexcept { static_assert(::fast_io::generic_allocator_adapter::has_native_allocate); @@ -1846,15 +2792,7 @@ inline constexpr void *allocator_pointer_aligned_impl(::std::size_t alignment, : { n = ::fast_io::details::allocator_compute_aligned_total_size_impl(alignment, n); } - void *p; - if constexpr (zero) - { - p = ::fast_io::generic_allocator_adapter::allocate_zero(n); - } - else - { - p = ::fast_io::generic_allocator_adapter::allocate(n); - } + void *p = ::fast_io::generic_allocator_adapter::allocate_conditional_zero(n, zero); if (alignedadjustment) { p = ::fast_io::details::allocator_adjust_ptr_to_aligned_impl(p, alignment); @@ -1862,8 +2800,8 @@ inline constexpr void *allocator_pointer_aligned_impl(::std::size_t alignment, : return p; } -template -inline constexpr ::fast_io::allocation_least_result allocator_pointer_aligned_at_least_impl(::std::size_t alignment, ::std::size_t n) noexcept +template +inline constexpr ::fast_io::allocation_least_result allocator_pointer_aligned_at_least_impl(::std::size_t alignment, ::std::size_t n, bool zero) noexcept { static_assert(::fast_io::generic_allocator_adapter::has_native_allocate); @@ -1873,15 +2811,7 @@ inline constexpr ::fast_io::allocation_least_result allocator_pointer_aligned_at { n = ::fast_io::details::allocator_compute_aligned_total_size_impl(alignment, n); } - ::fast_io::allocation_least_result res; - if constexpr (zero) - { - res = ::fast_io::generic_allocator_adapter::allocate_zero_at_least(n); - } - else - { - res = ::fast_io::generic_allocator_adapter::allocate_at_least(n); - } + ::fast_io::allocation_least_result res = ::fast_io::generic_allocator_adapter::allocate_conditional_zero_at_least(n, zero); if (alignedadjustment) { auto resptr{res.ptr}; diff --git a/include/fast_io_core_impl/allocation/has_methods_detect.h b/include/fast_io_core_impl/allocation/has_methods_detect.h index 9a97cd770..747df39df 100644 --- a/include/fast_io_core_impl/allocation/has_methods_detect.h +++ b/include/fast_io_core_impl/allocation/has_methods_detect.h @@ -20,6 +20,16 @@ concept has_allocate_aligned_zero_impl = requires(::std::size_t n) { { alloc::allocate_aligned_zero(n, n) } -> ::std::same_as; }; +template +concept has_allocate_conditional_zero_impl = requires(::std::size_t n, bool zero) { + { alloc::allocate_conditional_zero(n, zero) } -> ::std::same_as; +}; + +template +concept has_allocate_aligned_conditional_zero_impl = requires(::std::size_t n, bool zero) { + { alloc::allocate_aligned_conditional_zero(n, n, zero) } -> ::std::same_as; +}; + template concept has_reallocate_impl = requires(void *p, ::std::size_t n) { { alloc::reallocate(p, n) } -> ::std::same_as; @@ -40,6 +50,16 @@ concept has_reallocate_aligned_zero_impl = requires(void *p, ::std::size_t n) { { alloc::reallocate_aligned_zero(p, n, n) } -> ::std::same_as; }; +template +concept has_reallocate_conditional_zero_impl = requires(void *p, ::std::size_t n, bool zero) { + { alloc::reallocate_conditional_zero(p, n, zero) } -> ::std::same_as; +}; + +template +concept has_reallocate_aligned_conditional_zero_impl = requires(void *p, ::std::size_t n, bool zero) { + { alloc::reallocate_aligned_conditional_zero(p, n, n, zero) } -> ::std::same_as; +}; + template concept has_reallocate_n_impl = requires(void *p, ::std::size_t n) { { alloc::reallocate_n(p, n, n) } -> ::std::same_as; @@ -60,6 +80,16 @@ concept has_reallocate_aligned_zero_n_impl = requires(void *p, ::std::size_t n) { alloc::reallocate_aligned_zero_n(p, n, n, n) } -> ::std::same_as; }; +template +concept has_reallocate_n_conditional_zero_impl = requires(void *p, ::std::size_t n, bool zero) { + { alloc::reallocate_n_conditional_zero(p, n, n, zero) } -> ::std::same_as; +}; + +template +concept has_reallocate_aligned_n_conditional_zero_impl = requires(void *p, ::std::size_t n, bool zero) { + { alloc::reallocate_aligned_n_conditional_zero(p, n, n, n, zero) } -> ::std::same_as; +}; + template concept has_deallocate_impl = requires(void *p) { { alloc::deallocate(p) } -> ::std::same_as; @@ -100,6 +130,16 @@ concept has_allocate_aligned_zero_at_least_impl = requires(::std::size_t n) { { alloc::allocate_aligned_zero_at_least(n, n) } -> ::std::same_as<::fast_io::allocation_least_result>; }; +template +concept has_allocate_conditional_zero_at_least_impl = requires(::std::size_t n, bool zero) { + { alloc::allocate_conditional_zero_at_least(n, zero) } -> ::std::same_as<::fast_io::allocation_least_result>; +}; + +template +concept has_allocate_aligned_conditional_zero_at_least_impl = requires(::std::size_t n, bool zero) { + { alloc::allocate_aligned_conditional_zero_at_least(n, n, zero) } -> ::std::same_as<::fast_io::allocation_least_result>; +}; + template concept has_reallocate_at_least_impl = requires(void *p, ::std::size_t n) { { alloc::reallocate_at_least(p, n) } -> ::std::same_as<::fast_io::allocation_least_result>; @@ -120,6 +160,16 @@ concept has_reallocate_aligned_zero_at_least_impl = requires(void *p, ::std::siz { alloc::reallocate_aligned_zero_at_least(p, n, n) } -> ::std::same_as<::fast_io::allocation_least_result>; }; +template +concept has_reallocate_conditional_zero_at_least_impl = requires(void *p, ::std::size_t n, bool zero) { + { alloc::reallocate_conditional_zero_at_least(p, n, zero) } -> ::std::same_as<::fast_io::allocation_least_result>; +}; + +template +concept has_reallocate_aligned_conditional_zero_at_least_impl = requires(void *p, ::std::size_t n, bool zero) { + { alloc::reallocate_aligned_conditional_zero_at_least(p, n, n, zero) } -> ::std::same_as<::fast_io::allocation_least_result>; +}; + template concept has_reallocate_n_at_least_impl = requires(void *p, ::std::size_t n) { { alloc::reallocate_n_at_least(p, n, n) } -> ::std::same_as<::fast_io::allocation_least_result>; @@ -140,6 +190,16 @@ concept has_reallocate_aligned_zero_n_at_least_impl = requires(void *p, ::std::s { alloc::reallocate_aligned_zero_n_at_least(p, n, n, n) } -> ::std::same_as<::fast_io::allocation_least_result>; }; +template +concept has_reallocate_n_conditional_zero_at_least_impl = requires(void *p, ::std::size_t n, bool zero) { + { alloc::reallocate_n_conditional_zero_at_least(p, n, n, zero) } -> ::std::same_as<::fast_io::allocation_least_result>; +}; + +template +concept has_reallocate_aligned_n_conditional_zero_at_least_impl = requires(void *p, ::std::size_t n, bool zero) { + { alloc::reallocate_aligned_n_conditional_zero_at_least(p, n, n, n, zero) } -> ::std::same_as<::fast_io::allocation_least_result>; +}; + template concept has_non_empty_handle_type = requires { typename alloc::handle_type; @@ -166,6 +226,16 @@ concept has_handle_allocate_aligned_zero_impl = requires(typename alloc::handle_ { alloc::handle_allocate_aligned_zero(handle, n, n) } -> ::std::same_as; }; +template +concept has_handle_allocate_conditional_zero_impl = requires(typename alloc::handle_type handle, ::std::size_t n, bool zero) { + { alloc::handle_allocate_conditional_zero(handle, n, zero) } -> ::std::same_as; +}; + +template +concept has_handle_allocate_aligned_conditional_zero_impl = requires(typename alloc::handle_type handle, ::std::size_t n, bool zero) { + { alloc::handle_allocate_aligned_conditional_zero(handle, n, n, zero) } -> ::std::same_as; +}; + template concept has_handle_reallocate_impl = requires(typename alloc::handle_type handle, void *p, ::std::size_t n) { { alloc::handle_reallocate(handle, p, n) } -> ::std::same_as; @@ -186,6 +256,16 @@ concept has_handle_reallocate_aligned_zero_impl = requires(typename alloc::handl { alloc::handle_reallocate_aligned_zero(handle, p, n, n) } -> ::std::same_as; }; +template +concept has_handle_reallocate_conditional_zero_impl = requires(typename alloc::handle_type handle, void *p, ::std::size_t n, bool zero) { + { alloc::handle_reallocate_conditional_zero(handle, p, n, zero) } -> ::std::same_as; +}; + +template +concept has_handle_reallocate_aligned_conditional_zero_impl = requires(typename alloc::handle_type handle, void *p, ::std::size_t n, bool zero) { + { alloc::handle_reallocate_aligned_conditional_zero(handle, p, n, n, zero) } -> ::std::same_as; +}; + template concept has_handle_reallocate_n_impl = requires(typename alloc::handle_type handle, void *p, ::std::size_t n) { { alloc::handle_reallocate_n(handle, p, n, n) } -> ::std::same_as; @@ -206,6 +286,16 @@ concept has_handle_reallocate_aligned_zero_n_impl = requires(typename alloc::han { alloc::handle_reallocate_aligned_zero_n(handle, p, n, n, n) } -> ::std::same_as; }; +template +concept has_handle_reallocate_n_conditional_zero_impl = requires(typename alloc::handle_type handle, void *p, ::std::size_t n, bool zero) { + { alloc::handle_reallocate_n_conditional_zero(handle, p, n, n, zero) } -> ::std::same_as; +}; + +template +concept has_handle_reallocate_aligned_n_conditional_zero_impl = requires(typename alloc::handle_type handle, void *p, ::std::size_t n, bool zero) { + { alloc::handle_reallocate_aligned_n_conditional_zero(handle, p, n, n, n, zero) } -> ::std::same_as; +}; + template concept has_handle_allocate_at_least_impl = requires(typename alloc::handle_type handle, ::std::size_t n) { @@ -227,6 +317,16 @@ concept has_handle_allocate_aligned_zero_at_least_impl = requires(typename alloc { alloc::handle_allocate_aligned_zero_at_least(handle, n, n) } -> ::std::same_as<::fast_io::allocation_least_result>; }; +template +concept has_handle_allocate_conditional_zero_at_least_impl = requires(typename alloc::handle_type handle, ::std::size_t n, bool zero) { + { alloc::handle_allocate_conditional_zero_at_least(handle, n, zero) } -> ::std::same_as<::fast_io::allocation_least_result>; +}; + +template +concept has_handle_allocate_aligned_conditional_zero_at_least_impl = requires(typename alloc::handle_type handle, ::std::size_t n, bool zero) { + { alloc::handle_allocate_aligned_conditional_zero_at_least(handle, n, n, zero) } -> ::std::same_as<::fast_io::allocation_least_result>; +}; + template concept has_handle_reallocate_at_least_impl = requires(typename alloc::handle_type handle, void *p, ::std::size_t n) { { alloc::handle_reallocate_at_least(handle, p, n) } -> ::std::same_as<::fast_io::allocation_least_result>; @@ -247,6 +347,16 @@ concept has_handle_reallocate_aligned_zero_at_least_impl = requires(typename all { alloc::handle_reallocate_aligned_zero_at_least(handle, p, n, n) } -> ::std::same_as<::fast_io::allocation_least_result>; }; +template +concept has_handle_reallocate_conditional_zero_at_least_impl = requires(typename alloc::handle_type handle, void *p, ::std::size_t n, bool zero) { + { alloc::handle_reallocate_conditional_zero_at_least(handle, p, n, zero) } -> ::std::same_as<::fast_io::allocation_least_result>; +}; + +template +concept has_handle_reallocate_aligned_conditional_zero_at_least_impl = requires(typename alloc::handle_type handle, void *p, ::std::size_t n, bool zero) { + { alloc::handle_reallocate_aligned_conditional_zero_at_least(handle, p, n, n, zero) } -> ::std::same_as<::fast_io::allocation_least_result>; +}; + template concept has_handle_reallocate_n_at_least_impl = requires(typename alloc::handle_type handle, void *p, ::std::size_t n) { { alloc::handle_reallocate_n_at_least(handle, p, n, n) } -> ::std::same_as<::fast_io::allocation_least_result>; @@ -267,6 +377,16 @@ concept has_handle_reallocate_aligned_zero_n_at_least_impl = requires(typename a { alloc::handle_reallocate_aligned_zero_n_at_least(handle, p, n, n, n) } -> ::std::same_as<::fast_io::allocation_least_result>; }; +template +concept has_handle_reallocate_n_conditional_zero_at_least_impl = requires(typename alloc::handle_type handle, void *p, ::std::size_t n, bool zero) { + { alloc::handle_reallocate_n_conditional_zero_at_least(handle, p, n, n, zero) } -> ::std::same_as<::fast_io::allocation_least_result>; +}; + +template +concept has_handle_reallocate_aligned_n_conditional_zero_at_least_impl = requires(typename alloc::handle_type handle, void *p, ::std::size_t n, bool zero) { + { alloc::handle_reallocate_aligned_n_conditional_zero_at_least(handle, p, n, n, n, zero) } -> ::std::same_as<::fast_io::allocation_least_result>; +}; + template concept has_handle_deallocate_impl = requires(typename alloc::handle_type handle, void *p) { diff --git a/include/fast_io_core_impl/operations/readimpl/decay.h b/include/fast_io_core_impl/operations/readimpl/decay.h index 23eca1794..fff23e84b 100644 --- a/include/fast_io_core_impl/operations/readimpl/decay.h +++ b/include/fast_io_core_impl/operations/readimpl/decay.h @@ -1,9 +1,10 @@ -#pragma once +#pragma once namespace fast_io::operations::decay { template + requires(::fast_io::operations::decay::defines::readable) inline constexpr typename instmtype::input_char_type * read_some_decay(instmtype insm, typename instmtype::input_char_type *first, typename instmtype::input_char_type *last) { @@ -11,6 +12,7 @@ read_some_decay(instmtype insm, typename instmtype::input_char_type *first, type } template + requires(::fast_io::operations::decay::defines::readable) inline constexpr void read_all_decay(instmtype insm, typename instmtype::input_char_type *first, typename instmtype::input_char_type *last) { @@ -18,18 +20,21 @@ inline constexpr void read_all_decay(instmtype insm, typename instmtype::input_c } template + requires(::fast_io::operations::decay::defines::bytes_readable) inline constexpr ::std::byte *read_some_bytes_decay(instmtype insm, ::std::byte *first, ::std::byte *last) { return ::fast_io::details::read_some_bytes_impl(insm, first, last); } template + requires(::fast_io::operations::decay::defines::bytes_readable) inline constexpr void read_all_bytes_decay(instmtype insm, ::std::byte *first, ::std::byte *last) { ::fast_io::details::read_all_bytes_impl(insm, first, last); } template + requires(::fast_io::operations::decay::defines::readable) inline constexpr io_scatter_status_t scatter_read_some_decay(instmtype insm, basic_io_scatter_t const *pscatters, ::std::size_t n) @@ -38,6 +43,7 @@ scatter_read_some_decay(instmtype insm, basic_io_scatter_t + requires(::fast_io::operations::decay::defines::bytes_readable) inline constexpr io_scatter_status_t scatter_read_some_bytes_decay(instmtype insm, io_scatter_t const *pscatters, ::std::size_t n) { @@ -45,6 +51,7 @@ inline constexpr io_scatter_status_t scatter_read_some_bytes_decay(instmtype ins } template + requires(::fast_io::operations::decay::defines::readable) inline constexpr void scatter_read_all_decay(instmtype insm, basic_io_scatter_t const *pscatters, ::std::size_t n) @@ -53,12 +60,14 @@ inline constexpr void scatter_read_all_decay(instmtype insm, } template + requires(::fast_io::operations::decay::defines::bytes_readable) inline constexpr void scatter_read_all_bytes_decay(instmtype insm, io_scatter_t const *pscatters, ::std::size_t n) { ::fast_io::details::scatter_read_all_bytes_impl(insm, pscatters, n); } template + requires(::fast_io::operations::decay::defines::preadable) inline constexpr typename instmtype::input_char_type * pread_some_decay(instmtype insm, typename instmtype::input_char_type *first, typename instmtype::input_char_type *last, ::fast_io::intfpos_t off) @@ -67,6 +76,7 @@ pread_some_decay(instmtype insm, typename instmtype::input_char_type *first, typ } template + requires(::fast_io::operations::decay::defines::preadable) inline constexpr void pread_all_decay(instmtype insm, typename instmtype::input_char_type *first, typename instmtype::input_char_type *last, ::fast_io::intfpos_t off) { @@ -74,6 +84,7 @@ inline constexpr void pread_all_decay(instmtype insm, typename instmtype::input_ } template + requires(::fast_io::operations::decay::defines::bytes_preadable) inline constexpr ::std::byte *pread_some_bytes_decay(instmtype insm, ::std::byte *first, ::std::byte *last, ::fast_io::intfpos_t off) { @@ -81,13 +92,15 @@ inline constexpr ::std::byte *pread_some_bytes_decay(instmtype insm, ::std::byte } template + requires(::fast_io::operations::decay::defines::bytes_preadable) inline constexpr void pread_all_bytes_decay(instmtype insm, ::std::byte *first, ::std::byte *last, - ::fast_io::intfpos_t off) + ::fast_io::intfpos_t off) { ::fast_io::details::pread_all_bytes_impl(insm, first, last, off); } template + requires(::fast_io::operations::decay::defines::preadable) inline constexpr io_scatter_status_t scatter_pread_some_decay(instmtype insm, basic_io_scatter_t const *pscatters, ::std::size_t n, ::fast_io::intfpos_t off) @@ -96,13 +109,15 @@ scatter_pread_some_decay(instmtype insm, basic_io_scatter_t + requires(::fast_io::operations::decay::defines::bytes_preadable) inline constexpr io_scatter_status_t scatter_pread_some_bytes_decay(instmtype insm, io_scatter_t const *pscatters, - ::std::size_t n, ::fast_io::intfpos_t off) + ::std::size_t n, ::fast_io::intfpos_t off) { return ::fast_io::details::scatter_pread_some_bytes_impl(insm, pscatters, n, off); } template + requires(::fast_io::operations::decay::defines::preadable) inline constexpr void scatter_pread_all_decay(instmtype insm, basic_io_scatter_t const *pscatters, ::std::size_t n, ::fast_io::intfpos_t off) @@ -111,10 +126,11 @@ inline constexpr void scatter_pread_all_decay(instmtype insm, } template + requires(::fast_io::operations::decay::defines::bytes_preadable) inline constexpr void scatter_pread_all_bytes_decay(instmtype insm, io_scatter_t const *pscatters, ::std::size_t n, - ::fast_io::intfpos_t off) + ::fast_io::intfpos_t off) { ::fast_io::details::scatter_pread_all_bytes_impl(insm, pscatters, n, off); } -} // namespace fast_io::operations::decay +} // namespace fast_io::operations::decay \ No newline at end of file diff --git a/include/fast_io_core_impl/operations/writeimpl/decay.h b/include/fast_io_core_impl/operations/writeimpl/decay.h index 9d14e3336..6270af327 100644 --- a/include/fast_io_core_impl/operations/writeimpl/decay.h +++ b/include/fast_io_core_impl/operations/writeimpl/decay.h @@ -1,9 +1,10 @@ -#pragma once +#pragma once namespace fast_io::operations::decay { template + requires(::fast_io::operations::decay::defines::writable) inline constexpr typename outstmtype::output_char_type const * write_some_decay(outstmtype outsm, typename outstmtype::output_char_type const *first, typename outstmtype::output_char_type const *last) @@ -12,6 +13,7 @@ write_some_decay(outstmtype outsm, typename outstmtype::output_char_type const * } template + requires(::fast_io::operations::decay::defines::writable) inline constexpr void write_all_decay(outstmtype outsm, typename outstmtype::output_char_type const *first, typename outstmtype::output_char_type const *last) { @@ -19,6 +21,7 @@ inline constexpr void write_all_decay(outstmtype outsm, typename outstmtype::out } template + requires(::fast_io::operations::decay::defines::bytes_writable) inline constexpr ::std::byte const *write_some_bytes_decay(outstmtype outsm, ::std::byte const *first, ::std::byte const *last) { @@ -26,12 +29,14 @@ inline constexpr ::std::byte const *write_some_bytes_decay(outstmtype outsm, ::s } template + requires(::fast_io::operations::decay::defines::bytes_writable) inline constexpr void write_all_bytes_decay(outstmtype outsm, ::std::byte const *first, ::std::byte const *last) { ::fast_io::details::write_all_bytes_impl(outsm, first, last); } template + requires(::fast_io::operations::decay::defines::writable) inline constexpr io_scatter_status_t scatter_write_some_decay(outstmtype outsm, basic_io_scatter_t const *pscatters, ::std::size_t n) @@ -40,13 +45,15 @@ scatter_write_some_decay(outstmtype outsm, basic_io_scatter_t + requires(::fast_io::operations::decay::defines::bytes_writable) inline constexpr io_scatter_status_t scatter_write_some_bytes_decay(outstmtype outsm, io_scatter_t const *pscatters, - ::std::size_t n) + ::std::size_t n) { return ::fast_io::details::scatter_write_some_bytes_impl(outsm, pscatters, n); } template + requires(::fast_io::operations::decay::defines::writable) inline constexpr void scatter_write_all_decay(outstmtype outsm, basic_io_scatter_t const *pscatters, ::std::size_t n) @@ -55,12 +62,14 @@ scatter_write_all_decay(outstmtype outsm, basic_io_scatter_t + requires(::fast_io::operations::decay::defines::bytes_writable) inline constexpr void scatter_write_all_bytes_decay(outstmtype outsm, io_scatter_t const *pscatters, ::std::size_t n) { ::fast_io::details::scatter_write_all_bytes_impl(outsm, pscatters, n); } template + requires(::fast_io::operations::decay::defines::pwritable) inline constexpr typename outstmtype::output_char_type const * pwrite_some_decay(outstmtype outsm, typename outstmtype::output_char_type const *first, typename outstmtype::output_char_type const *last, ::fast_io::intfpos_t off) @@ -69,6 +78,7 @@ pwrite_some_decay(outstmtype outsm, typename outstmtype::output_char_type const } template + requires(::fast_io::operations::decay::defines::pwritable) inline constexpr void pwrite_all_decay(outstmtype outsm, typename outstmtype::output_char_type const *first, typename outstmtype::output_char_type const *last, ::fast_io::intfpos_t off) { @@ -76,6 +86,7 @@ inline constexpr void pwrite_all_decay(outstmtype outsm, typename outstmtype::ou } template + requires(::fast_io::operations::decay::defines::bytes_pwritable) inline constexpr ::std::byte const *pwrite_some_bytes_decay(outstmtype outsm, ::std::byte const *first, ::std::byte const *last, ::fast_io::intfpos_t off) { @@ -83,6 +94,7 @@ inline constexpr ::std::byte const *pwrite_some_bytes_decay(outstmtype outsm, :: } template + requires(::fast_io::operations::decay::defines::bytes_pwritable) inline constexpr void pwrite_all_bytes_decay(outstmtype outsm, ::std::byte const *first, ::std::byte const *last, ::fast_io::intfpos_t off) { @@ -90,6 +102,7 @@ inline constexpr void pwrite_all_bytes_decay(outstmtype outsm, ::std::byte const } template + requires(::fast_io::operations::decay::defines::pwritable) inline constexpr io_scatter_status_t scatter_pwrite_some_decay(outstmtype outsm, basic_io_scatter_t const *pscatters, ::std::size_t n, ::fast_io::intfpos_t off) @@ -98,13 +111,15 @@ scatter_pwrite_some_decay(outstmtype outsm, basic_io_scatter_t + requires(::fast_io::operations::decay::defines::bytes_pwritable) inline constexpr io_scatter_status_t scatter_pwrite_some_bytes_decay(outstmtype outsm, io_scatter_t const *pscatters, - ::std::size_t n, ::fast_io::intfpos_t off) + ::std::size_t n, ::fast_io::intfpos_t off) { return ::fast_io::details::scatter_pwrite_some_bytes_impl(outsm, pscatters, n, off); } template + requires(::fast_io::operations::decay::defines::pwritable) inline constexpr void scatter_pwrite_all_decay(outstmtype outsm, basic_io_scatter_t const *pscatters, ::std::size_t n, ::fast_io::intfpos_t off) @@ -113,6 +128,7 @@ scatter_pwrite_all_decay(outstmtype outsm, basic_io_scatter_t + requires(::fast_io::operations::decay::defines::bytes_pwritable) inline constexpr void scatter_pwrite_all_bytes_decay(outstmtype outsm, io_scatter_t const *pscatters, ::std::size_t n, ::fast_io::intfpos_t off) { @@ -120,6 +136,7 @@ inline constexpr void scatter_pwrite_all_bytes_decay(outstmtype outsm, io_scatte } template + requires(::fast_io::operations::decay::defines::writable) #if __has_cpp_attribute(__gnu__::__always_inline__) [[__gnu__::__always_inline__]] #elif __has_cpp_attribute(msvc::forceinline) @@ -130,4 +147,4 @@ inline constexpr void char_put_decay(outstmtype outstm, typename outstmtype::out ::fast_io::details::char_put_impl(outstm, ch); } -} // namespace fast_io::operations::decay +} // namespace fast_io::operations::decay \ No newline at end of file From 9c9b82c89697e8191ef936e517ccdd17ce40c41a Mon Sep 17 00:00:00 2001 From: trcrsired Date: Thu, 14 May 2026 15:29:01 +0800 Subject: [PATCH 53/82] [allocator] try to fix one issue for adpaters here --- include/fast_io_core_impl/allocation/adapters.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fast_io_core_impl/allocation/adapters.h b/include/fast_io_core_impl/allocation/adapters.h index 3a8efc523..f9cf2bd67 100644 --- a/include/fast_io_core_impl/allocation/adapters.h +++ b/include/fast_io_core_impl/allocation/adapters.h @@ -854,7 +854,7 @@ class generic_allocator_adapter else if constexpr (::fast_io::details::has_allocate_at_least_impl || ::fast_io::details::has_allocate_zero_at_least_impl) { - return ::fast_io::details::allocator_pointer_aligned_at_least_impl(alignment, n); + return ::fast_io::details::allocator_pointer_aligned_at_least_impl(alignment, n, false); } else { @@ -1480,7 +1480,7 @@ class generic_allocator_adapter return generic_allocator_adapter::reallocate_n_at_least(p, oldn, n); } } - auto newres{::fast_io::details::allocator_pointer_aligned_at_least_impl(alignment, n)}; + auto newres{::fast_io::details::allocator_pointer_aligned_at_least_impl(alignment, n, false)}; auto newptr{newres.ptr}; if (p != nullptr) { From b735ca4995d2cd50d2db07b04bb327e742dabcb7 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Thu, 14 May 2026 20:19:43 +0800 Subject: [PATCH 54/82] [allocator] try to implement conditional_zero --- .../fast_io_core_impl/allocation/adapters.h | 640 +++++++++++++----- 1 file changed, 488 insertions(+), 152 deletions(-) diff --git a/include/fast_io_core_impl/allocation/adapters.h b/include/fast_io_core_impl/allocation/adapters.h index f9cf2bd67..0fd59fcaf 100644 --- a/include/fast_io_core_impl/allocation/adapters.h +++ b/include/fast_io_core_impl/allocation/adapters.h @@ -70,6 +70,29 @@ inline constexpr void *status_allocator_pointer_aligned_impl(typename alloc::han template inline constexpr ::fast_io::allocation_least_result status_allocator_pointer_aligned_at_least_impl(typename alloc::handle_type, ::std::size_t, ::std::size_t, bool) noexcept; + +template +concept native_allocate_aligned_has_none_zero_ops = + ::fast_io::details::has_allocate_aligned_impl || + ::fast_io::details::has_allocate_aligned_at_least_impl; +template +concept native_allocate_aligned_has_zero_ops = + ::fast_io::details::has_allocate_aligned_zero_impl || + ::fast_io::details::has_allocate_aligned_zero_at_least_impl; + +template +concept native_allocate_aligned_has_ops = + ::fast_io::details::native_allocate_aligned_has_none_zero_ops || + ::fast_io::details::native_allocate_aligned_has_zero_ops; + +template +concept native_allocate_has_none_zero_ops = ::fast_io::details::has_allocate_impl || + ::fast_io::details::has_allocate_at_least_impl || + ::fast_io::details::native_allocate_aligned_has_none_zero_ops; +template +concept native_allocate_has_zero_ops = + ::fast_io::details::has_allocate_zero_impl || + ::fast_io::details::has_allocate_zero_at_least_impl || ::fast_io::details::native_allocate_aligned_has_zero_ops; } // namespace details #if 0 @@ -147,13 +170,18 @@ class generic_allocator_adapter { return allocator_type::allocate_aligned_conditional_zero_at_least(default_alignment, n, zero).ptr; } - else if constexpr (::fast_io::details::has_allocate_impl || - ::fast_io::details::has_allocate_at_least_impl || - ::fast_io::details::has_allocate_aligned_impl || - ::fast_io::details::has_allocate_aligned_at_least_impl) + else { - // Non-zero APIs exist - need runtime branch - if (zero) + constexpr bool has_none_zero_ops{::fast_io::details::native_allocate_has_none_zero_ops}; + constexpr bool has_zero_ops{::fast_io::details::native_allocate_has_zero_ops}; + if constexpr (!has_none_zero_ops && !has_zero_ops) + { + ::fast_io::fast_terminate(); +#if __has_cpp_attribute(unreachable) + [[unreachable]]; +#endif + } + else if constexpr (!has_none_zero_ops && has_zero_ops) { if constexpr (::fast_io::details::has_allocate_zero_impl) { @@ -165,84 +193,107 @@ class generic_allocator_adapter } else if constexpr (::fast_io::details::has_allocate_aligned_zero_impl) { - return allocator_type::allocate_aligned_zero(default_alignment, n); + return allocator_type::allocate_aligned_zero(n, default_alignment); } else if constexpr (::fast_io::details::has_allocate_aligned_zero_at_least_impl) { - return allocator_type::allocate_aligned_zero_at_least(default_alignment, n).ptr; - } - else - { - auto p{generic_allocator_adapter::allocate(n)}; - ::fast_io::freestanding::bytes_clear_n(reinterpret_cast<::std::byte *>(p), n); - return p; + return allocator_type::allocate_aligned_zero_at_least(n, default_alignment).ptr; } } - else + else if constexpr (has_none_zero_ops && !has_zero_ops) { + void *ptr; if constexpr (::fast_io::details::has_allocate_impl) { - return allocator_type::allocate(n); + ptr = allocator_type::allocate(n); } else if constexpr (::fast_io::details::has_allocate_at_least_impl) { - return allocator_type::allocate_at_least(n).ptr; + ptr = allocator_type::allocate_at_least(n).ptr; } else if constexpr (::fast_io::details::has_allocate_aligned_impl) { - return allocator_type::allocate_aligned(default_alignment, n); + ptr = allocator_type::allocate_aligned(n, default_alignment); } - else + else if constexpr (::fast_io::details::has_allocate_aligned_at_least_impl) { - return allocator_type::allocate_aligned_at_least(default_alignment, n).ptr; + ptr = allocator_type::allocate_aligned_at_least(n, default_alignment).ptr; } - } - } - else - { - // Only zero APIs exist (or nothing) - use zero API for both cases (harmless extra zeroing) - if constexpr (::fast_io::details::has_allocate_zero_impl) - { - return allocator_type::allocate_zero(n); - } - else if constexpr (::fast_io::details::has_allocate_zero_at_least_impl) - { - return allocator_type::allocate_zero_at_least(n).ptr; - } - else if constexpr (::fast_io::details::has_allocate_aligned_zero_impl) - { - return allocator_type::allocate_aligned_zero(default_alignment, n); - } - else if constexpr (::fast_io::details::has_allocate_aligned_zero_at_least_impl) - { - return allocator_type::allocate_aligned_zero_at_least(default_alignment, n).ptr; + if (zero) + { + ::fast_io::freestanding::bytes_clear_n(reinterpret_cast<::std::byte *>(ptr), n); + } + return ptr; } else { - auto p{::operator new(n)}; + void *ptr; if (zero) { - ::fast_io::freestanding::bytes_clear_n(reinterpret_cast<::std::byte *>(p), n); + if constexpr (::fast_io::details::has_allocate_zero_impl) + { + ptr = allocator_type::allocate_zero(n); + } + else if constexpr (::fast_io::details::has_allocate_zero_at_least_impl) + { + ptr = allocator_type::allocate_zero_at_least(n).ptr; + } + else if constexpr (::fast_io::details::has_allocate_aligned_zero_impl) + { + ptr = allocator_type::allocate_aligned_zero(n, default_alignment); + } + else if constexpr (::fast_io::details::has_allocate_aligned_zero_at_least_impl) + { + ptr = allocator_type::allocate_aligned_zero_at_least(n, default_alignment).ptr; + } + else + { + ::fast_io::fast_terminate(); + } } - return p; + else + { + if constexpr (::fast_io::details::has_allocate_impl) + { + ptr = allocator_type::allocate(n); + } + else if constexpr (::fast_io::details::has_allocate_at_least_impl) + { + ptr = allocator_type::allocate_at_least(n).ptr; + } + else if constexpr (::fast_io::details::has_allocate_aligned_impl) + { + ptr = allocator_type::allocate_aligned(n, default_alignment); + } + else if constexpr (::fast_io::details::has_allocate_aligned_at_least_impl) + { + ptr = allocator_type::allocate_aligned_at_least(n, default_alignment).ptr; + } + else + { + ::fast_io::fast_terminate(); + } + } + return ptr; } } } } - #if __has_cpp_attribute(__gnu__::__returns_nonnull__) [[__gnu__::__returns_nonnull__]] #endif - static inline - constexpr - void * + static inline constexpr void * allocate(::std::size_t n) noexcept requires(!has_status) { #if __cpp_constexpr_dynamic_alloc >= 201907L +#if __cpp_if_consteval >= 202106L + if consteval +#else if (__builtin_is_constant_evaluated()) +#endif { - return ::operator new(n); + return generic_allocator_adapter::allocate_conditional_zero(n, false); } else #endif @@ -251,10 +302,6 @@ class generic_allocator_adapter { return allocator_type::allocate(n); } - else if constexpr (::fast_io::details::has_allocate_at_least_impl) - { - return allocator_type::allocate_at_least(n).ptr; - } else { return generic_allocator_adapter::allocate_conditional_zero(n, false); @@ -268,17 +315,26 @@ class generic_allocator_adapter static inline void *allocate_zero(::std::size_t n) noexcept requires(!has_status) { - if constexpr (::fast_io::details::has_allocate_zero_impl) - { - return allocator_type::allocate_zero(n); - } - else if constexpr (::fast_io::details::has_allocate_zero_at_least_impl) +#if __cpp_constexpr_dynamic_alloc >= 201907L +#if __cpp_if_consteval >= 202106L + if consteval +#else + if (__builtin_is_constant_evaluated()) +#endif { - return allocator_type::allocate_zero_at_least(n).ptr; + return generic_allocator_adapter::allocate_conditional_zero(n, true); } else +#endif { - return generic_allocator_adapter::allocate_conditional_zero(n, true); + if constexpr (::fast_io::details::has_allocate_zero_impl) + { + return allocator_type::allocate_zero(n); + } + else + { + return generic_allocator_adapter::allocate_conditional_zero(n, true); + } } } @@ -679,9 +735,8 @@ class generic_allocator_adapter #if __has_cpp_attribute(__gnu__::__returns_nonnull__) [[__gnu__::__returns_nonnull__]] #endif - static inline constexpr - void * - allocate_aligned_conditional_zero(::std::size_t alignment, ::std::size_t n, bool zero) noexcept + static inline constexpr void * + allocate_aligned_conditional_zero(::std::size_t alignment, ::std::size_t n, bool zero) noexcept requires(!has_status) { #if __cpp_if_consteval >= 202106L @@ -699,6 +754,78 @@ class generic_allocator_adapter } return p; } + if constexpr (::fast_io::details::has_allocate_aligned_conditional_zero_impl) + { + return allocator_type::allocate_aligned_conditional_zero(alignment, n, zero); + } + else if constexpr (::fast_io::details::has_allocate_aligned_conditional_zero_at_least_impl) + { + return allocator_type::allocate_aligned_conditional_zero_at_least(alignment, n, zero).ptr; + } + else if constexpr (::fast_io::details::native_allocate_aligned_has_ops) + { + constexpr bool has_none_zero_ops{::fast_io::details::native_allocate_aligned_has_none_zero_ops}; + constexpr bool has_zero_ops{::fast_io::details::native_allocate_aligned_has_zero_ops}; + if constexpr (!has_none_zero_ops && has_zero_ops) + { + if constexpr (::fast_io::details::has_allocate_aligned_zero_impl) + { + return allocator_type::allocate_aligned_zero(alignment, n); + } + else + { + return allocator_type::allocate_aligned_zero_at_least(alignment, n).ptr; + } + } + else if constexpr (has_none_zero_ops && !has_zero_ops) + { + void *ptr; + if constexpr (::fast_io::details::has_allocate_aligned_impl) + { + ptr = allocator_type::allocate_aligned(alignment, n); + } + else + { + ptr = allocator_type::allocate_aligned_at_least(alignment, n).ptr; + } + if (zero) + { + ::fast_io::freestanding::bytes_clear_n(reinterpret_cast<::std::byte *>(ptr), n); + } + return ptr; + } + else if constexpr (has_none_zero_ops && has_zero_ops) + { + void *ptr; + if (zero) + { + if constexpr (::fast_io::details::has_allocate_aligned_zero_impl) + { + ptr = allocator_type::allocate_aligned_zero(alignment, n); + } + else + { + ptr = allocator_type::allocate_aligned_at_least(alignment, n).ptr; + } + } + else + { + if constexpr (::fast_io::details::has_allocate_aligned_impl) + { + ptr = allocator_type::allocate_aligned_zero(alignment, n); + } + else + { + ptr = allocator_type::allocate_aligned_at_least(alignment, n).ptr; + } + } + return ptr; + } + else + { + ::fast_io::fast_terminate(); + } + } else { return ::fast_io::details::allocator_pointer_aligned_impl(alignment, n, zero); @@ -708,10 +835,8 @@ class generic_allocator_adapter #if __has_cpp_attribute(__gnu__::__returns_nonnull__) [[__gnu__::__returns_nonnull__]] #endif - static inline - constexpr - void * - allocate_aligned(::std::size_t alignment, ::std::size_t n) noexcept + static inline constexpr void * + allocate_aligned(::std::size_t alignment, ::std::size_t n) noexcept requires(!has_status) { #if __cpp_if_consteval >= 202106L @@ -724,6 +849,10 @@ class generic_allocator_adapter { return ::operator new(n); } + if constexpr (::fast_io::details::has_allocate_aligned_impl) + { + return allocator_type::allocate_aligned(alignment, n); + } else { return generic_allocator_adapter::allocate_aligned_conditional_zero(alignment, n, false); @@ -733,9 +862,8 @@ class generic_allocator_adapter #if __has_cpp_attribute(__gnu__::__returns_nonnull__) [[__gnu__::__returns_nonnull__]] #endif - static inline constexpr - void * - allocate_aligned_zero(::std::size_t alignment, ::std::size_t n) noexcept + static inline constexpr void * + allocate_aligned_zero(::std::size_t alignment, ::std::size_t n) noexcept requires(!has_status) { #if __cpp_if_consteval >= 202106L @@ -748,6 +876,10 @@ class generic_allocator_adapter { return ::operator new(n); } + if constexpr (::fast_io::details::has_allocate_aligned_zero_impl) + { + return allocator_type::allocate_aligned_zero(alignment, n); + } else { return generic_allocator_adapter::allocate_aligned_conditional_zero(alignment, n, true); @@ -764,30 +896,22 @@ class generic_allocator_adapter allocate_at_least(::std::size_t n) noexcept requires(!has_status) { -#if __cpp_constexpr_dynamic_alloc >= 201907L +#if __cpp_if_consteval >= 202106L + if consteval +#elif __cpp_lib_is_constant_evaluated >= 201811L && __cpp_constexpr_dynamic_alloc >= 201907L if (__builtin_is_constant_evaluated()) +#else + if (false) +#endif { return {::operator new(n), n}; } else -#endif { if constexpr (::fast_io::details::has_allocate_at_least_impl) { return allocator_type::allocate_at_least(n); } - else if constexpr (::fast_io::details::has_allocate_aligned_at_least_impl) - { - return allocator_type::allocate_aligned_at_least(default_alignment, n); - } - else if constexpr (::fast_io::details::has_allocate_zero_at_least_impl) - { - return allocator_type::allocate_zero_at_least(n); - } - else if constexpr (::fast_io::details::has_allocate_aligned_zero_at_least_impl) - { - return allocator_type::allocate_aligned_zero_at_least(default_alignment, n); - } else { return {generic_allocator_adapter::allocate(n), n}; @@ -799,66 +923,198 @@ class generic_allocator_adapter allocate_zero_at_least(::std::size_t n) noexcept requires(!has_status) { -#if __cpp_constexpr_dynamic_alloc >= 201907L +#if __cpp_if_consteval >= 202106L + if consteval +#elif __cpp_lib_is_constant_evaluated >= 201811L && __cpp_constexpr_dynamic_alloc >= 201907L if (__builtin_is_constant_evaluated()) +#else + if (false) +#endif { return {::operator new(n), n}; } else -#endif { if constexpr (::fast_io::details::has_allocate_zero_at_least_impl) { return allocator_type::allocate_zero_at_least(n); } - else if constexpr (::fast_io::details::has_allocate_aligned_zero_at_least_impl) + else + { + return generic_allocator_adapter::allocate_conditional_zero_at_least(n, true); + } + } + } + + static inline constexpr allocation_least_result + allocate_conditional_zero_at_least(::std::size_t n, bool zero) noexcept + requires(!has_status) + { +#if __cpp_if_consteval >= 202106L + if consteval +#elif __cpp_lib_is_constant_evaluated >= 201811L && __cpp_constexpr_dynamic_alloc >= 201907L + if (__builtin_is_constant_evaluated()) +#else + if (false) +#endif + { + auto p{::operator new(n)}; + if (zero) + { + ::fast_io::freestanding::bytes_clear_n(reinterpret_cast<::std::byte *>(p), n); + } + return {p, n}; + } + else + { + if constexpr (::fast_io::details::has_allocate_conditional_zero_at_least_impl) + { + return allocator_type::allocate_conditional_zero_at_least(n, zero); + } + if constexpr (::fast_io::details::has_allocate_conditional_zero_impl) + { + return {allocator_type::allocate_conditional_zero(n, zero), n}; + } + else if constexpr (::fast_io::details::has_allocate_aligned_conditional_zero_at_least_impl) { - return allocator_type::allocate_aligned_zero_at_least(default_alignment, n); + return allocator_type::allocate_aligned_conditional_zero_at_least(default_alignment, n, zero); } - else if constexpr (::fast_io::details::has_allocate_at_least_impl || - ::fast_io::details::has_allocate_aligned_at_least_impl) + else if constexpr (::fast_io::details::has_allocate_aligned_conditional_zero_impl) { - auto temp{generic_allocator_adapter::allocate_at_least(n)}; - auto ptr{temp.ptr}; - auto sz{temp.count}; - ::fast_io::freestanding::bytes_clear_n(reinterpret_cast<::std::byte *>(ptr), sz); - return temp; + return {allocator_type::allocate_aligned_conditional_zero(default_alignment, n, zero), n}; } else { - return {generic_allocator_adapter::allocate_zero(n), n}; + constexpr bool has_none_zero_ops{::fast_io::details::native_allocate_has_none_zero_ops}; + constexpr bool has_zero_ops{::fast_io::details::native_allocate_has_zero_ops}; + if constexpr (!has_none_zero_ops && !has_zero_ops) + { + ::fast_io::fast_terminate(); +#if __has_cpp_attribute(unreachable) + [[unreachable]]; +#endif + } + else if constexpr (!has_none_zero_ops && has_zero_ops) + { + if constexpr (::fast_io::details::has_allocate_zero_at_least_impl) + { + return allocator_type::allocate_zero_at_least(n); + } + else if constexpr (::fast_io::details::has_allocate_zero_impl) + { + return {allocator_type::allocate_zero(n), n}; + } + else if constexpr (::fast_io::details::has_allocate_aligned_zero_at_least_impl) + { + return allocator_type::allocate_aligned_zero_at_least(n, default_alignment); + } + else if constexpr (::fast_io::details::has_allocate_aligned_zero_impl) + { + return {allocator_type::allocate_aligned_zero(n, default_alignment), n}; + } + } + else if constexpr (has_none_zero_ops && !has_zero_ops) + { + ::fast_io::allocation_least_result res; + if constexpr (::fast_io::details::has_allocate_at_least_impl) + { + res = allocator_type::allocate_at_least(n); + } + else if constexpr (::fast_io::details::has_allocate_impl) + { + res = {allocator_type::allocate(n), n}; + } + else if constexpr (::fast_io::details::has_allocate_aligned_at_least_impl) + { + res = allocator_type::allocate_aligned_at_least(n, default_alignment); + } + else if constexpr (::fast_io::details::has_allocate_aligned_impl) + { + res = {allocator_type::allocate_aligned(n, default_alignment), n}; + } + if (zero) + { + ::fast_io::freestanding::bytes_clear_n(reinterpret_cast<::std::byte *>(res.ptr), res.count); + } + return res; + } + else + { + ::fast_io::allocation_least_result res; + if (zero) + { + if constexpr (::fast_io::details::has_allocate_at_least_impl) + { + res = allocator_type::allocate_at_least(n); + } + else if constexpr (::fast_io::details::has_allocate_impl) + { + res = {allocator_type::allocate(n), n}; + } + else if constexpr (::fast_io::details::has_allocate_aligned_at_least_impl) + { + res = allocator_type::allocate_aligned_at_least(n, default_alignment); + } + else if constexpr (::fast_io::details::has_allocate_aligned_impl) + { + res = {allocator_type::allocate_aligned(n, default_alignment), n}; + } + else + { + ::fast_io::fast_terminate(); + } + } + else + { + if constexpr (::fast_io::details::has_allocate_zero_at_least_impl) + { + res = allocator_type::allocate_zero_at_least(n); + } + else if constexpr (::fast_io::details::has_allocate_zero_impl) + { + res = {allocator_type::allocate_zero(n), n}; + } + else if constexpr (::fast_io::details::has_allocate_aligned_zero_at_least_impl) + { + res = allocator_type::allocate_aligned_zero_at_least(n, default_alignment); + } + else if constexpr (::fast_io::details::has_allocate_aligned_zero_impl) + { + res = {allocator_type::allocate_aligned_zero(n, default_alignment), n}; + } + else + { + ::fast_io::fast_terminate(); + } + } + return res; + } } } } - static inline constexpr allocation_least_result allocate_aligned_at_least(::std::size_t alignment, ::std::size_t n) noexcept requires(!has_status) { -#if __cpp_constexpr_dynamic_alloc >= 201907L +#if __cpp_if_consteval >= 202106L + if consteval +#elif __cpp_lib_is_constant_evaluated >= 201811L && __cpp_constexpr_dynamic_alloc >= 201907L if (__builtin_is_constant_evaluated()) +#else + if (false) +#endif { - return {::operator new(n), n}; + return generic_allocator_adapter::allocate_aligned_conditional_zero_at_least(alignment, n, false); } else -#endif { if constexpr (::fast_io::details::has_allocate_aligned_at_least_impl) { return allocator_type::allocate_aligned_at_least(alignment, n); } - else if constexpr (::fast_io::details::has_allocate_aligned_zero_at_least_impl) - { - return allocator_type::allocate_aligned_zero_at_least(alignment, n); - } - else if constexpr (::fast_io::details::has_allocate_at_least_impl || - ::fast_io::details::has_allocate_zero_at_least_impl) - { - return ::fast_io::details::allocator_pointer_aligned_at_least_impl(alignment, n, false); - } else { - return {generic_allocator_adapter::allocate_aligned(alignment, n), n}; + return generic_allocator_adapter::allocate_aligned_conditional_zero_at_least(alignment, n, false); } } } @@ -867,34 +1123,123 @@ class generic_allocator_adapter allocate_aligned_zero_at_least(::std::size_t alignment, ::std::size_t n) noexcept requires(!has_status) { -#if __cpp_constexpr_dynamic_alloc >= 201907L +#if __cpp_if_consteval >= 202106L + if consteval +#elif __cpp_lib_is_constant_evaluated >= 201811L && __cpp_constexpr_dynamic_alloc >= 201907L if (__builtin_is_constant_evaluated()) +#else + if (false) +#endif { - return {::operator new(n), n}; + return generic_allocator_adapter::allocate_aligned_conditional_zero_at_least(alignment, n, true); } else -#endif { if constexpr (::fast_io::details::has_allocate_aligned_zero_at_least_impl) { return allocator_type::allocate_aligned_zero_at_least(alignment, n); } - else if constexpr (::fast_io::details::has_allocate_aligned_at_least_impl) + else + { + return generic_allocator_adapter::allocate_aligned_conditional_zero_at_least(alignment, n, true); + } + } + } + static inline constexpr allocation_least_result + allocate_aligned_conditional_zero_at_least(::std::size_t alignment, ::std::size_t n, bool zero) noexcept + requires(!has_status) + { +#if __cpp_if_consteval >= 202106L + if consteval +#elif __cpp_lib_is_constant_evaluated >= 201811L && __cpp_constexpr_dynamic_alloc >= 201907L + if (__builtin_is_constant_evaluated()) +#else + if (false) +#endif + { + auto p{::operator new(n)}; + if (zero) + { + ::fast_io::freestanding::bytes_clear_n(reinterpret_cast<::std::byte *>(p), n); + } + return {p, n}; + } + if constexpr (::fast_io::details::has_allocate_aligned_conditional_zero_at_least_impl) + { + return allocator_type::allocate_aligned_conditional_zero_at_least(alignment, n, zero); + } + else if constexpr (::fast_io::details::has_allocate_aligned_conditional_zero_impl) + { + return {allocator_type::allocate_aligned_conditional_zero(alignment, n, zero), n}; + } + else if constexpr (::fast_io::details::native_allocate_aligned_has_ops) + { + constexpr bool has_none_zero_ops{::fast_io::details::native_allocate_aligned_has_none_zero_ops}; + constexpr bool has_zero_ops{::fast_io::details::native_allocate_aligned_has_zero_ops}; + if constexpr (!has_none_zero_ops && has_zero_ops) { - auto temp{allocator_type::allocate_aligned_at_least(alignment, n)}; - ::fast_io::freestanding::bytes_clear_n(reinterpret_cast<::std::byte *>(temp.ptr), temp.count); - return temp; + if constexpr (::fast_io::details::has_allocate_aligned_zero_at_least_impl) + { + return allocator_type::allocate_aligned_zero_at_least(alignment, n); + } + else + { + return {allocator_type::allocate_aligned_zero(alignment, n), n}; + } } - else if constexpr (::fast_io::details::has_allocate_at_least_impl || - ::fast_io::details::has_allocate_zero_at_least_impl) + else if constexpr (has_none_zero_ops && !has_zero_ops) { - return ::fast_io::details::allocator_pointer_aligned_at_least_impl(alignment, n); + ::fast_io::allocation_least_result res; + if constexpr (::fast_io::details::has_allocate_aligned_at_least_impl) + { + res = allocator_type::allocate_aligned_at_least(alignment, n); + } + else + { + res = {allocator_type::allocate_aligned(alignment, n), n}; + } + if (zero) + { + ::fast_io::freestanding::bytes_clear_n(reinterpret_cast<::std::byte *>(res.ptr), res.count); + } + return res; + } + else if constexpr (has_none_zero_ops && has_zero_ops) + { + ::fast_io::allocation_least_result res; + if (zero) + { + if constexpr (::fast_io::details::has_allocate_aligned_zero_at_least_impl) + { + res = allocator_type::allocate_aligned_zero_at_least(alignment, n); + } + else + { + res = {allocator_type::allocate_aligned_zero(alignment, n), n}; + } + } + else + { + if constexpr (::fast_io::details::has_allocate_aligned_at_least_impl) + { + res = allocator_type::allocate_aligned_at_least(alignment, n); + } + else + { + res = {allocator_type::allocate_aligned(alignment, n), n}; + } + } + return res; } else { - return {generic_allocator_adapter::allocate_aligned_zero(alignment, n), n}; + ::fast_io::fast_terminate(); } } + else + { + return ::fast_io::details::allocator_pointer_aligned_at_least_impl(default_alignment, n, zero); + } } static inline constexpr bool has_reallocate_aligned = (::fast_io::details::has_reallocate_aligned_impl || @@ -907,8 +1252,7 @@ class generic_allocator_adapter #if __has_cpp_attribute(__gnu__::__returns_nonnull__) [[__gnu__::__returns_nonnull__]] #endif - static inline - void * + static inline void * reallocate_aligned_conditional_zero(void *p, ::std::size_t alignment, ::std::size_t n, bool zero) noexcept requires(!has_status && has_reallocate_aligned) { @@ -963,8 +1307,7 @@ class generic_allocator_adapter #if __has_cpp_attribute(__gnu__::__returns_nonnull__) [[__gnu__::__returns_nonnull__]] #endif - static inline - void * + static inline void * reallocate_aligned(void *p, ::std::size_t alignment, ::std::size_t n) noexcept requires(!has_status && has_reallocate_aligned) { @@ -987,8 +1330,7 @@ class generic_allocator_adapter #if __has_cpp_attribute(__gnu__::__returns_nonnull__) [[__gnu__::__returns_nonnull__]] #endif - static inline - void * + static inline void * reallocate_aligned_zero(void *p, ::std::size_t alignment, ::std::size_t n) noexcept requires(!has_status && has_reallocate_aligned_zero) { @@ -1009,8 +1351,7 @@ class generic_allocator_adapter #if __has_cpp_attribute(__gnu__::__returns_nonnull__) [[__gnu__::__returns_nonnull__]] #endif - static inline - void * + static inline void * reallocate_aligned_n_conditional_zero(void *p, ::std::size_t oldn, ::std::size_t alignment, ::std::size_t n, bool zero) noexcept requires(!has_status) { @@ -1123,7 +1464,8 @@ class generic_allocator_adapter { if (n) { - ::std::size_t copyn{oldn < n ? oldn : n}; + bool moren{oldn < n}; + ::std::size_t copyn{moren ? oldn : n}; ::fast_io::freestanding::nonoverlapped_bytes_copy_n(reinterpret_cast<::std::byte const *>(p), copyn, reinterpret_cast<::std::byte *>(newptr)); } generic_allocator_adapter::deallocate_aligned_n(p, alignment, oldn); @@ -1137,8 +1479,7 @@ class generic_allocator_adapter #if __has_cpp_attribute(__gnu__::__returns_nonnull__) [[__gnu__::__returns_nonnull__]] #endif - static inline - void * + static inline void * reallocate_aligned_n(void *p, ::std::size_t oldn, ::std::size_t alignment, ::std::size_t n) noexcept requires(!has_status) { @@ -1163,8 +1504,7 @@ class generic_allocator_adapter #if __has_cpp_attribute(__gnu__::__returns_nonnull__) [[__gnu__::__returns_nonnull__]] #endif - static inline - void * + static inline void * reallocate_aligned_zero_n(void *p, ::std::size_t oldn, ::std::size_t alignment, ::std::size_t n) noexcept requires(!has_status) { @@ -1195,8 +1535,7 @@ class generic_allocator_adapter static inline constexpr bool has_native_reallocate_at_least = (has_reallocate && (::fast_io::details::has_reallocate_aligned_at_least_impl || ::fast_io::details::has_reallocate_aligned_zero_at_least_impl)); - static inline - ::fast_io::allocation_least_result + static inline ::fast_io::allocation_least_result reallocate_at_least(void *p, ::std::size_t n) noexcept requires(!has_status && has_reallocate) { @@ -1238,8 +1577,7 @@ class generic_allocator_adapter (::fast_io::details::has_reallocate_zero_at_least_impl || ::fast_io::details::has_reallocate_aligned_zero_at_least_impl)); - static inline - ::fast_io::allocation_least_result + static inline ::fast_io::allocation_least_result reallocate_zero_at_least(void *p, ::std::size_t n) noexcept requires(!has_status && has_reallocate) { @@ -1261,8 +1599,7 @@ class generic_allocator_adapter } } - static inline - ::fast_io::allocation_least_result + static inline ::fast_io::allocation_least_result reallocate_n_at_least(void *p, ::std::size_t oldn, ::std::size_t n) noexcept requires(!has_status) { @@ -1331,27 +1668,26 @@ class generic_allocator_adapter return {allocator_type::reallocate_aligned_zero(p, default_alignment, n), n}; } else + { + auto newres{generic_allocator_adapter::allocate_at_least(n)}; + auto newptr{newres.ptr}; + if (p != nullptr) { - auto newres{generic_allocator_adapter::allocate_at_least(n)}; - auto newptr{newres.ptr}; - if (p != nullptr) + if (n) { - if (n) + if (oldn < n) { - if (oldn < n) - { - n = oldn; - } - ::fast_io::freestanding::nonoverlapped_bytes_copy_n(reinterpret_cast<::std::byte const *>(p), n, reinterpret_cast<::std::byte *>(newptr)); + n = oldn; } - generic_allocator_adapter::deallocate_n(p, oldn); + ::fast_io::freestanding::nonoverlapped_bytes_copy_n(reinterpret_cast<::std::byte const *>(p), n, reinterpret_cast<::std::byte *>(newptr)); } - return newres; + generic_allocator_adapter::deallocate_n(p, oldn); } + return newres; + } } - static inline - ::fast_io::allocation_least_result + static inline ::fast_io::allocation_least_result reallocate_zero_n_at_least(void *p, ::std::size_t oldn, ::std::size_t n) noexcept requires(!has_status) { From 2f18f15e11fc5743f51907a23c68c90cda687e08 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Thu, 14 May 2026 20:30:07 +0800 Subject: [PATCH 55/82] [allocator] some puts alignments in the wrong order --- .../fast_io_core_impl/allocation/adapters.h | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/include/fast_io_core_impl/allocation/adapters.h b/include/fast_io_core_impl/allocation/adapters.h index 0fd59fcaf..38dad7e60 100644 --- a/include/fast_io_core_impl/allocation/adapters.h +++ b/include/fast_io_core_impl/allocation/adapters.h @@ -193,11 +193,11 @@ class generic_allocator_adapter } else if constexpr (::fast_io::details::has_allocate_aligned_zero_impl) { - return allocator_type::allocate_aligned_zero(n, default_alignment); + return allocator_type::allocate_aligned_zero(default_alignment, n); } else if constexpr (::fast_io::details::has_allocate_aligned_zero_at_least_impl) { - return allocator_type::allocate_aligned_zero_at_least(n, default_alignment).ptr; + return allocator_type::allocate_aligned_zero_at_least(default_alignment, n).ptr; } } else if constexpr (has_none_zero_ops && !has_zero_ops) @@ -213,11 +213,11 @@ class generic_allocator_adapter } else if constexpr (::fast_io::details::has_allocate_aligned_impl) { - ptr = allocator_type::allocate_aligned(n, default_alignment); + ptr = allocator_type::allocate_aligned(default_alignment, n); } else if constexpr (::fast_io::details::has_allocate_aligned_at_least_impl) { - ptr = allocator_type::allocate_aligned_at_least(n, default_alignment).ptr; + ptr = allocator_type::allocate_aligned_at_least(default_alignment, n).ptr; } if (zero) { @@ -240,11 +240,11 @@ class generic_allocator_adapter } else if constexpr (::fast_io::details::has_allocate_aligned_zero_impl) { - ptr = allocator_type::allocate_aligned_zero(n, default_alignment); + ptr = allocator_type::allocate_aligned_zero(default_alignment, n); } else if constexpr (::fast_io::details::has_allocate_aligned_zero_at_least_impl) { - ptr = allocator_type::allocate_aligned_zero_at_least(n, default_alignment).ptr; + ptr = allocator_type::allocate_aligned_zero_at_least(default_alignment, n).ptr; } else { @@ -263,11 +263,11 @@ class generic_allocator_adapter } else if constexpr (::fast_io::details::has_allocate_aligned_impl) { - ptr = allocator_type::allocate_aligned(n, default_alignment); + ptr = allocator_type::allocate_aligned(default_alignment, n); } else if constexpr (::fast_io::details::has_allocate_aligned_at_least_impl) { - ptr = allocator_type::allocate_aligned_at_least(n, default_alignment).ptr; + ptr = allocator_type::allocate_aligned_at_least(default_alignment, n).ptr; } else { @@ -1006,11 +1006,11 @@ class generic_allocator_adapter } else if constexpr (::fast_io::details::has_allocate_aligned_zero_at_least_impl) { - return allocator_type::allocate_aligned_zero_at_least(n, default_alignment); + return allocator_type::allocate_aligned_zero_at_least(default_alignment, n); } else if constexpr (::fast_io::details::has_allocate_aligned_zero_impl) { - return {allocator_type::allocate_aligned_zero(n, default_alignment), n}; + return {allocator_type::allocate_aligned_zero(default_alignment, n), n}; } } else if constexpr (has_none_zero_ops && !has_zero_ops) @@ -1026,11 +1026,11 @@ class generic_allocator_adapter } else if constexpr (::fast_io::details::has_allocate_aligned_at_least_impl) { - res = allocator_type::allocate_aligned_at_least(n, default_alignment); + res = allocator_type::allocate_aligned_at_least(default_alignment, n); } else if constexpr (::fast_io::details::has_allocate_aligned_impl) { - res = {allocator_type::allocate_aligned(n, default_alignment), n}; + res = {allocator_type::allocate_aligned(default_alignment, n), n}; } if (zero) { @@ -1053,11 +1053,11 @@ class generic_allocator_adapter } else if constexpr (::fast_io::details::has_allocate_aligned_at_least_impl) { - res = allocator_type::allocate_aligned_at_least(n, default_alignment); + res = allocator_type::allocate_aligned_at_least(default_alignment, n); } else if constexpr (::fast_io::details::has_allocate_aligned_impl) { - res = {allocator_type::allocate_aligned(n, default_alignment), n}; + res = {allocator_type::allocate_aligned(default_alignment, n), n}; } else { @@ -1076,11 +1076,11 @@ class generic_allocator_adapter } else if constexpr (::fast_io::details::has_allocate_aligned_zero_at_least_impl) { - res = allocator_type::allocate_aligned_zero_at_least(n, default_alignment); + res = allocator_type::allocate_aligned_zero_at_least(default_alignment, n); } else if constexpr (::fast_io::details::has_allocate_aligned_zero_impl) { - res = {allocator_type::allocate_aligned_zero(n, default_alignment), n}; + res = {allocator_type::allocate_aligned_zero(default_alignment, n), n}; } else { From 71bc68770f4914bbab7552a78203e92f590892b3 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Thu, 14 May 2026 21:35:41 +0800 Subject: [PATCH 56/82] add claude.md --- CLAUDE.md | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..813cc978c --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,90 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +**fast_io** is a header-only C++20 I/O library designed to replace `` and `` with dramatically better performance. It makes direct system calls, bypassing intermediary layers, and uses C++20 concepts extensively for type abstraction. + +## Build & Development + +### Prerequisites +- C++20 compiler: GCC >= 15, Clang >= 21, or MSVC +- CMake >= 3.15 + +### Build Tests, Benchmarks, and Examples + +```bash +# Prebuild: generate test files (only needed once) +cmake -B fast_io_prebuild -S . -DCMAKE_BUILD_TYPE=Release -DENABLE_TESTS=On -DTESTS_PREBUILD=On +cmake --build fast_io_prebuild +./fast_io_prebuild/tests_prebuild linux # or "windows msvc" + +# Build tests/examples/benchmarks +cmake -B fast_io_build -S . -DCMAKE_BUILD_TYPE=Release -DENABLE_TESTS=On +cmake --build fast_io_build + +# Run tests +cmake --build fast_io_build --target test +``` + +### Run a Single Test + +Tests are located under `tests/`. After building, individual test binaries are in the `fast_io_build/tests/` subdirectories. Run them directly. + +### CI + +GitHub Actions (`.github/workflows/c-cpp.yml`) runs: +- **Linux**: GCC with `-fsanitize=address,undefined -Wall -Wextra -Wpedantic -Wshadow -Wconversion -Werror` +- **Windows**: MSVC with `/EHsc /W3 /WX /sdl` +- Uses Ninja generator on both platforms + +## Architecture + +The library uses a layered architecture: + +| Layer | Header | Description | +|-------|--------|-------------| +| Concepts | `fast_io_concept.h` | C++20 concepts for I/O device abstraction | +| Core | `fast_io_core.h` | Freestanding-capable: bit ops, integer formatting, codecvt, SIMD | +| Freestanding | `fast_io_freestanding.h` | Adds buffered I/O, decorators, serializers, transcoders | +| Hosted | `fast_io_hosted.h` | Full features: platform abstractions, filesystem, threads, process/IPC | +| Main | `fast_io.h` | Entry point: combines hosted + legacy stream interop | + +### Key Directories + +- `include/fast_io_core_impl/` — Core implementation internals (operations: `printimpl`, `readimpl`, `writeimpl`, `transmitimpl`, `transcodeimpl`) +- `include/fast_io_hosted/` — Hosted platform implementations (console, filesystem, mmap, threads, process) +- `include/fast_io_freestanding_impl/` — Buffered I/O, decorators, scanners, serialization +- `include/fast_io_legacy_impl/` — FILE*/streambuf hacks for glibc, MSVCRT, UCRT, MUSL, BSD libc, libstdc++, libc++, MSVC STL +- `include/fast_io_dsal/` — Data Structure Abstraction Layer (vector, string, deque, list, etc.) +- `include/fast_io_driver/` — Third-party integrations (Boost.Asio, OpenSSL, Qt, MFC, LLVM, Python, zlib) +- `include/fast_io_crypto/` — SHA-1, SHA-256, SHA-512, HMAC, ciphers +- `share/fast_io/` — C++20 module files + +### Header Organization + +- `fast_io.h` — Primary entry point (most common include) +- `fast_io_device.h` — Device types (files, pipes, sockets) +- `fast_io_crypto.h` — Cryptographic hash functions +- `fast_io_i18n.h` — Internationalization/locale +- `fast_io_legacy.h` — Legacy C/C++ stream compatibility + +## Testing + +- Tests are organized into numbered categories under `tests/` +- `.test_prop.toml` controls which tests run per platform/compiler +- Test files are generated by `tests/0000.tests_prebuild/gentests.cc` +- Some tests are ignored for incomplete features or platform requirements + +## Benchmarking + +Benchmarks live under `benchmark/` with numbered categories (integer I/O, floating-point, file I/O, concat, containers, codecvt, syscalls, etc.). Many have standalone `Makefile`s using `clang++ -Ofast -march=native -std=c++20` with precompiled headers. + +## Style & Conventions + +- `.clang-format` and `.editorconfig` are present — format code before committing +- This is a header-only library — no `.cpp` source files in `include/` +- The library targets both freestanding (no OS) and hosted environments +- Consistent error handling via exceptions only (no `std::error_code` or `std::system_error`) +- License: Anti-Tivo License (ATL) v1.0 From caf1b1fc6f5de01a42192bdc12f6de642f8fee67 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Thu, 14 May 2026 21:39:54 +0800 Subject: [PATCH 57/82] claude --- CLAUDE.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index 813cc978c..7bbb44f7b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -70,6 +70,18 @@ The library uses a layered architecture: - `fast_io_i18n.h` — Internationalization/locale - `fast_io_legacy.h` — Legacy C/C++ stream compatibility +### fast_io's 6 layers of files from bottom to top +- wine_file +- nt_file +- win32_file +- posix_file +- c_file +- filebuf_file + +From bottom to top we do a move. +From top to bottom we do a static cast to the +lower level of io_observer. + ## Testing - Tests are organized into numbered categories under `tests/` From 1509ffb2f71b0e73279e4fd2255ddb2941bf622d Mon Sep 17 00:00:00 2001 From: trcrsired Date: Thu, 14 May 2026 23:15:40 +0800 Subject: [PATCH 58/82] [deque] try to seperate the code from the common one --- .../allocation/nt_rtlheapalloc.h | 11 +- .../allocation/win32_heapalloc.h | 15 - include/fast_io_dsal/impl/deque.h | 287 ++++++++++-------- 3 files changed, 161 insertions(+), 152 deletions(-) diff --git a/include/fast_io_core_impl/allocation/nt_rtlheapalloc.h b/include/fast_io_core_impl/allocation/nt_rtlheapalloc.h index 80ca4a833..05c242e48 100644 --- a/include/fast_io_core_impl/allocation/nt_rtlheapalloc.h +++ b/include/fast_io_core_impl/allocation/nt_rtlheapalloc.h @@ -90,16 +90,9 @@ class nt_rtlallocateheap_allocator #if __has_cpp_attribute(__gnu__::__malloc__) [[__gnu__::__malloc__]] #endif - static inline void *allocate(::std::size_t n) noexcept + static inline void *allocate_conditional_zero(::std::size_t n, bool zero) noexcept { - return ::fast_io::details::nt_rtlallocate_heap_common_impl(n, 0u); - } -#if __has_cpp_attribute(__gnu__::__malloc__) - [[__gnu__::__malloc__]] -#endif - static inline void *allocate_zero(::std::size_t n) noexcept - { - return ::fast_io::details::nt_rtlallocate_heap_common_impl(n, 0x00000008u); + return ::fast_io::details::nt_rtlallocate_heap_common_impl(n, zero ? 0x00000008u : 0u); } static inline void *reallocate(void *addr, ::std::size_t n) noexcept { diff --git a/include/fast_io_core_impl/allocation/win32_heapalloc.h b/include/fast_io_core_impl/allocation/win32_heapalloc.h index ea8fa37b0..303a818a1 100644 --- a/include/fast_io_core_impl/allocation/win32_heapalloc.h +++ b/include/fast_io_core_impl/allocation/win32_heapalloc.h @@ -139,21 +139,6 @@ inline ::fast_io::allocation_least_result win32_heaprealloc_least_common_impl(vo class win32_heapalloc_allocator { public: -#if __has_cpp_attribute(__gnu__::__malloc__) - [[__gnu__::__malloc__]] -#endif - static inline void *allocate(::std::size_t n) noexcept - { - return ::fast_io::details::win32_heapalloc_common_impl(n, 0u); - } - -#if __has_cpp_attribute(__gnu__::__malloc__) - [[__gnu__::__malloc__]] -#endif - static inline void *allocate_zero(::std::size_t n) noexcept - { - return ::fast_io::details::win32_heapalloc_common_impl(n, 0x00000008u); - } #if __has_cpp_attribute(__gnu__::__malloc__) [[__gnu__::__malloc__]] #endif diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index 12ef4ac98..68234b49b 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -598,27 +598,13 @@ inline constexpr void deque_rebalance_or_grow_2x_after_blocks_impl(dequecontrolt } } } - template -inline constexpr void deque_allocate_on_empty_common_with_n_impl(dequecontroltype &controller, ::std::size_t initial_allocated_block_counts, ::std::size_t align, ::std::size_t bytes, - int position) noexcept +inline constexpr void deque_allocate_on_empty_common_with_n_impl(dequecontroltype &controller, ::std::size_t initial_allocated_block_counts, ::std::size_t align, ::std::size_t bytes) noexcept { - constexpr bool rightaddone{false}; ::std::size_t initial_allocated_block_counts_with_sentinel; #if (defined(__GNUC__) || defined(__clang__)) if constexpr (true) { - if constexpr (rightaddone) - { - if (0 < position) - { - if (__builtin_add_overflow(initial_allocated_block_counts, 1u, - __builtin_addressof(initial_allocated_block_counts))) - { - ::fast_io::fast_terminate(); - } - } - } if (__builtin_add_overflow(initial_allocated_block_counts, 1u, __builtin_addressof(initial_allocated_block_counts_with_sentinel))) { @@ -629,17 +615,6 @@ inline constexpr void deque_allocate_on_empty_common_with_n_impl(dequecontroltyp #endif { constexpr ::std::size_t maxval{::std::numeric_limits<::std::size_t>::max()}; - if constexpr (rightaddone) - { - if (0 < position) - { - if (initial_allocated_block_counts == maxval) - { - ::fast_io::fast_terminate(); - } - ++initial_allocated_block_counts; - } - } if (initial_allocated_block_counts == maxval) [[unlikely]] { ::fast_io::fast_terminate(); @@ -652,14 +627,11 @@ inline constexpr void deque_allocate_on_empty_common_with_n_impl(dequecontroltyp // we need a null terminator as sentinel like c style string does --allocated_blocks_count; auto &controller_block{controller.controller_block}; - auto &front_block{controller.front_block}; - auto &back_block{controller.back_block}; using begin_ptrtype = typename dequecontroltype::replacetype *; controller_block.controller_after_ptr = (controller_block.controller_start_ptr = allocated_blocks_ptr) + allocated_blocks_count; - ::std::size_t const allocated_blocks_count_half{allocated_blocks_count >> 1u}; ::std::size_t const initial_allocated_block_counts_half{initial_allocated_block_counts >> 1u}; @@ -675,72 +647,21 @@ inline constexpr void deque_allocate_on_empty_common_with_n_impl(dequecontroltyp *end_block_ptr = nullptr; controller_block.controller_start_reserved_ptr = start_block_ptr; controller_block.controller_after_reserved_ptr = end_block_ptr; +} - begin_ptrtype begin_ptr; - if constexpr (rightaddone) - { - if (position == 0) - { - // place logical cursor in the middle block, middle of that block - auto mid_block_ptr{allocated_mid_block}; - begin_ptr = *mid_block_ptr; - auto mid_ptr{begin_ptr + (bytes >> 1u)}; - - front_block.controller_ptr = mid_block_ptr; - back_block.controller_ptr = mid_block_ptr; - - front_block.curr_ptr = back_block.curr_ptr = mid_ptr; - } - else - { - // place logical cursor at the first reserved block (front side) - auto first_block_ptr{start_block_ptr}; - begin_ptr = *first_block_ptr; - - front_block.controller_ptr = first_block_ptr; - back_block.controller_ptr = first_block_ptr; - - front_block.curr_ptr = back_block.curr_ptr = begin_ptr; - } - } - else - { - if (position < 0) - { - // place logical cursor at the first reserved block (front side) - auto first_block_ptr{start_block_ptr}; - begin_ptr = *first_block_ptr; - - front_block.controller_ptr = first_block_ptr; - back_block.controller_ptr = first_block_ptr; - front_block.curr_ptr = back_block.curr_ptr = begin_ptr; - } - else if (position == 0) - { - // place logical cursor in the middle block, middle of that block - auto mid_block_ptr{allocated_mid_block}; - begin_ptr = *mid_block_ptr; - auto mid_ptr{begin_ptr + (bytes >> 1u)}; - - front_block.controller_ptr = mid_block_ptr; - back_block.controller_ptr = mid_block_ptr; +template +inline constexpr void deque_allocate_empty_single_block_impl(dequecontroltype &controller, ::std::size_t align, ::std::size_t bytes) noexcept +{ + ::fast_io::containers::details::deque_allocate_on_empty_common_with_n_impl(controller, 1u, align, bytes); - front_block.curr_ptr = back_block.curr_ptr = mid_ptr; - } - else - { - // place logical cursor at the last reserved block (back side) - auto last_block_ptr{end_block_ptr - 1}; - begin_ptr = *last_block_ptr; + auto controllerptr{controller.controller_block.controller_start_reserved_ptr}; + auto begin_ptr{*controllerptr}; + auto mid_ptr{begin_ptr + (bytes >> 1u)}; - front_block.controller_ptr = last_block_ptr; - back_block.controller_ptr = last_block_ptr; - front_block.curr_ptr = back_block.curr_ptr = begin_ptr + bytes; - } - } - front_block.begin_ptr = back_block.begin_ptr = begin_ptr; - controller.front_end_ptr = controller.back_end_ptr = begin_ptr + bytes; + controller.front_block = + controller.back_block = {begin_ptr, mid_ptr, controllerptr}; + controller.front_end_ptr = controller.back_end_ptr = (begin_ptr + bytes); } template @@ -798,14 +719,7 @@ inline constexpr void deque_allocate_init_blocks_dezeroing_impl(dequecontroltype using begin_ptrtype = typename dequecontroltype::replacetype *; for (auto it{reserve_start}, ed{reserve_after}; it != ed; ++it) { - if (zeroing) - { - ::std::construct_at(it, static_cast(allocator::allocate_aligned_zero(align, blockbytes))); - } - else - { - ::std::construct_at(it, static_cast(allocator::allocate_aligned(align, blockbytes))); - } + ::std::construct_at(it, static_cast(allocator::allocate_aligned_conditional_zero(align, blockbytes, zeroing))); } ::std::construct_at(reserve_after, nullptr); using replacetype = typename dequecontroltype::replacetype; @@ -819,21 +733,16 @@ inline constexpr void deque_allocate_init_blocks_dezeroing_impl(dequecontroltype controller.controller_block = { start_ptr, reserve_start, reserve_after, start_ptr + blocks_count}; } -template -inline constexpr void deque_allocate_init_blocks_impl(dequecontroltype &controller, ::std::size_t align, ::std::size_t blockbytes, ::std::size_t blocks_count_least) noexcept -{ - ::fast_io::containers::details::deque_allocate_init_blocks_dezeroing_impl(controller, align, blockbytes, blocks_count_least, zeroing); -} -template -inline constexpr void deque_init_space_common(dequecontroltype &controller, ::std::size_t n) noexcept +template +inline constexpr void deque_init_space_common(dequecontroltype &controller, ::std::size_t n, bool zeroing) noexcept { constexpr ::std::size_t blockbytes{sz * block_size}; ::std::size_t const ndivsz{n / block_size}; ::std::size_t const nmodsz{n % block_size}; ::std::size_t const counts{ndivsz + static_cast<::std::size_t>(nmodsz != 0u)}; - ::fast_io::containers::details::deque_allocate_init_blocks_impl(controller, align, blockbytes, counts); + ::fast_io::containers::details::deque_allocate_init_blocks_dezeroing_impl(controller, align, blockbytes, counts, zeroing); if (!n) { return; @@ -1344,7 +1253,81 @@ deque_erase_common_trivial_impl(::fast_io::containers::details::deque_controller controller.back_end_ptr = back_block.begin_ptr + blockbytes; return first; } +#if 0 +template +inline constexpr void deque_rebalance_or_grow_insertation_impl(dequecontroltype &controller, ::std::size_t extrablocks) noexcept +{ + auto const used_blocks_count{ + static_cast<::std::size_t>(controller.back_block.controller_ptr - controller.front_block.controller_ptr) + 1zu}; + + // total_slots_count is the distance (after - start). + // If start=0 and after=47, total_slots_count is 47, but there are 48 physical slots (0-47). + auto const total_slots_count{ + static_cast<::std::size_t>(controller.controller_block.controller_after_ptr - controller.controller_block.controller_start_ptr)}; + + // We MUST leave one slot for the nullptr sentinel. + // Usable capacity for pointers is exactly total_slots_count. + auto const usable_ptr_capacity{total_slots_count}; + + ::std::size_t new_used_blocks_count; +#if (defined(__GNUC__) || defined(__clang__)) + if (__builtin_add_overflow(used_blocks_count, extrablocks, __builtin_addressof(new_used_blocks_count))) [[unlikely]] + { + ::fast_io::fast_terminate(); + } +#else + if (::std::numeric_limits<::std::size_t>::max() - extrablocks < used_blocks_count) + { + ::fast_io::fast_terminate(); + } + new_used_blocks_count = used_blocks_count + extrablocks; +#endif + // Heuristic: If we are using more than half the map, grow it. + // This ensures we aren't rebalancing too frequently. + if ((total_slots_count >> 1u) < new_used_blocks_count) + { + ::std::size_t doubleslotsextra; + // ... (Keep your existing overflow-safe doubling logic here) ... + ::fast_io::containers::details::deque_grow_to_new_blocks_count_impl(controller, doubleslotsextra); + } + else + { + // BALANCE BLOCKS: The single-shift strategy + auto const cb_start{controller.controller_block.controller_start_ptr}; + auto const old_front{controller.front_block.controller_ptr}; + auto const old_back_plus_one{controller.back_block.controller_ptr + 1}; + + /* To center the used blocks: + Target Offset = (Total Usable Slots - Blocks to fit) / 2 + We use (usable_ptr_capacity - used_blocks_count) because index total_slots_count + is reserved for the nullptr sentinel. + */ + ::std::size_t const target_offset{(usable_ptr_capacity - used_blocks_count) >> 1u}; + auto const new_front{cb_start + target_offset}; + + if (new_front != old_front) + { + // 1. Move only the actual block pointers to the new centered location + ::fast_io::freestanding::overlapped_copy(old_front, old_back_plus_one, new_front); + + // 2. Calculate the pointer diff to update the controller state + ::std::ptrdiff_t const diff{new_front - old_front}; + + controller.front_block.controller_ptr += diff; + controller.back_block.controller_ptr += diff; + + // 3. Update the reserved range tracking + controller.controller_block.controller_start_reserved_ptr = new_front; + controller.controller_block.controller_after_reserved_ptr = new_front + used_blocks_count; + + // 4. THE FIX: Safely write the sentinel. + // Because of target_offset math, this is guaranteed to be <= controller_after_ptr. + *(controller.controller_block.controller_after_reserved_ptr) = nullptr; + } + } +} +#else template inline constexpr void deque_rebalance_or_grow_insertation_impl(dequecontroltype &controller, ::std::size_t extrablocks) noexcept { @@ -1432,6 +1415,7 @@ inline constexpr void deque_rebalance_or_grow_insertation_impl(dequecontroltype controller.front_block.controller_ptr += diff; controller.back_block.controller_ptr += diff; } +#if 0 auto const half_slotsextra_count{static_cast<::std::size_t>((total_slots_count + extrablocks) >> 1u)}; auto slots_pivot{controller.controller_block.controller_start_ptr + half_slotsextra_count}; if (slots_pivot != reserved_pivot) @@ -1444,8 +1428,10 @@ inline constexpr void deque_rebalance_or_grow_insertation_impl(dequecontroltype controller.controller_block.controller_start_reserved_ptr += diff; *(controller.controller_block.controller_after_reserved_ptr += diff) = nullptr; } +#endif } } +#endif template inline constexpr void deque_reserve_back_blocks_impl_none_empty(dequecontroltype &controller, ::std::size_t nb, ::std::size_t align, ::std::size_t blockbytes) noexcept @@ -1519,12 +1505,19 @@ inline constexpr void deque_reserve_back_blocks_impl_none_empty(dequecontroltype } template -inline constexpr bool deque_reserve_back_blocks_impl(dequecontroltype &controller, ::std::size_t nb, ::std::size_t align, ::std::size_t blockbytes) noexcept +inline constexpr bool deque_reserve_back_blocks_impl(dequecontroltype &controller, ::std::size_t nb, ::std::size_t align, ::std::size_t blockbytes, ::std::size_t startoffset) noexcept { if (controller.controller_block.controller_start_ptr == nullptr) { ::fast_io::containers::details::deque_allocate_on_empty_common_with_n_impl( - controller, nb, align, blockbytes, -1); + controller, nb, align, blockbytes); + auto controllerptr{controller.controller_block.controller_start_reserved_ptr}; + controller.front_block.controller_ptr = controller.back_block.controller_ptr = controllerptr; + auto begin_ptr{*controllerptr}; + controller.front_block.begin_ptr = controller.back_block.begin_ptr = begin_ptr; + controller.front_block.curr_ptr = controller.back_block.curr_ptr = begin_ptr + startoffset; + controller.front_end_ptr = controller.back_end_ptr = begin_ptr + blockbytes; + return false; } ::fast_io::containers::details::deque_reserve_back_blocks_impl_none_empty(controller, nb, align, blockbytes); @@ -1539,7 +1532,7 @@ inline constexpr void deque_grow_back_common_impl( { if (controller.controller_block.controller_start_ptr == nullptr) { - ::fast_io::containers::details::deque_allocate_on_empty_common_with_n_impl(controller, 1u, align, bytes, 0); + ::fast_io::containers::details::deque_allocate_empty_single_block_impl(controller, align, bytes); return; } ::fast_io::containers::details::deque_reserve_back_blocks_impl_none_empty(controller, 1u, align, bytes); @@ -1586,14 +1579,16 @@ inline constexpr void deque_reserve_back_spaces_impl(dequecontroltype &controlle if consteval { ::fast_io::containers::details::deque_reserve_back_blocks_impl(controller, - toallocate, align, block_size); + toallocate, align, block_size, 1); } else { ::std::size_t const block_bytes{block_size * sz}; +#if 1 ::fast_io::containers::details::deque_reserve_back_blocks_impl(*reinterpret_cast<::fast_io::containers::details::deque_controller_common *>( __builtin_addressof(controller)), - toallocate, align, block_bytes); + toallocate, align, block_bytes, sz); +#endif } } @@ -1673,12 +1668,18 @@ inline constexpr void deque_reserve_front_blocks_none_empty_impl(dequecontroltyp } template -inline constexpr void deque_reserve_front_blocks_impl(dequecontroltype &controller, ::std::size_t nb, ::std::size_t align, ::std::size_t blockbytes) noexcept +inline constexpr void deque_reserve_front_blocks_impl(dequecontroltype &controller, ::std::size_t nb, ::std::size_t align, ::std::size_t blockbytes, ::std::size_t startoffset) noexcept { if (controller.controller_block.controller_start_ptr == nullptr) { ::fast_io::containers::details::deque_allocate_on_empty_common_with_n_impl( - controller, nb, align, blockbytes, 1); + controller, nb, align, blockbytes); + auto controllerptr{controller.controller_block.after_reserved_ptr - 1}; + controller.front_block.controller_ptr = controller.back_block.controller_ptr = controllerptr; + auto begin_ptr{*controllerptr}; + controller.front_block.begin_ptr = controller.back_block.begin_ptr = begin_ptr; + controller.front_block.curr_ptr = controller.back_block.curr_ptr = begin_ptr + (blockbytes - startoffset); + controller.front_end_ptr = controller.back_end_ptr = begin_ptr + blockbytes; return; } ::fast_io::containers::details::deque_reserve_front_blocks_none_empty_impl(controller, nb, align, blockbytes); @@ -1709,15 +1710,14 @@ inline constexpr void deque_reserve_front_spaces_impl(dequecontroltype &controll } if consteval { - ::fast_io::containers::details::deque_reserve_front_blocks_impl(controller, - toallocate, align, block_size); + ::fast_io::containers::details::deque_reserve_front_blocks_impl(controller, toallocate, align, block_size, 1u); } else { ::std::size_t const block_bytes{block_size * sz}; ::fast_io::containers::details::deque_reserve_front_blocks_impl(*reinterpret_cast<::fast_io::containers::details::deque_controller_common *>( __builtin_addressof(controller)), - toallocate, align, block_bytes); + toallocate, align, block_bytes, sz); } } @@ -1735,7 +1735,7 @@ inline constexpr void deque_grow_front_common_impl( { if (controller.controller_block.controller_start_ptr == nullptr) { - ::fast_io::containers::details::deque_allocate_on_empty_common_with_n_impl(controller, 1u, align, bytes, 0); + ::fast_io::containers::details::deque_allocate_empty_single_block_impl(controller, align, bytes); return; } ::fast_io::containers::details::deque_reserve_front_blocks_none_empty_impl(controller, 1zu, align, bytes); @@ -2297,7 +2297,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE ::std::is_nothrow_default_constructible_v) { constexpr bool iszeroconstr{::fast_io::freestanding::is_zero_default_constructible_v}; - this->init_blocks_common(n); + this->init_blocks_common(n, iszeroconstr); if constexpr (!iszeroconstr) { this->default_construct_impl(); @@ -2309,15 +2309,15 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { if constexpr (::std::is_trivially_default_constructible_v) { - this->init_blocks_common(n); + this->init_blocks_common(n, false); } else if constexpr (::fast_io::freestanding::is_zero_default_constructible_v) { - this->init_blocks_common(n); + this->init_blocks_common(n, true); } else { - this->init_blocks_common(n); + this->init_blocks_common(n, false); this->default_construct_impl(); } } @@ -2347,7 +2347,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { auto const dist{::std::ranges::distance(first, last)}; - this->init_blocks_common(static_cast<::std::size_t>(dist)); + this->init_blocks_common(static_cast<::std::size_t>(dist), false); auto front_controller_ptr{controller.front_block.controller_ptr}; auto back_controller_ptr{controller.back_block.controller_ptr}; auto dq_back_backup{this->controller.back_block}; @@ -2390,16 +2390,15 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE des.thiscontroller = nullptr; } - template - inline constexpr void init_blocks_common(::std::size_t n) noexcept + inline constexpr void init_blocks_common(::std::size_t n, bool iszeroconstr) noexcept { if (__builtin_is_constant_evaluated()) { - ::fast_io::containers::details::deque_init_space_common(controller, n); + ::fast_io::containers::details::deque_init_space_common(controller, n, iszeroconstr); } else { - ::fast_io::containers::details::deque_init_space_common(*reinterpret_cast<::fast_io::containers::details::deque_controller_common *>(__builtin_addressof(controller)), n); + ::fast_io::containers::details::deque_init_space_common(*reinterpret_cast<::fast_io::containers::details::deque_controller_common *>(__builtin_addressof(controller)), n, iszeroconstr); } } inline static constexpr void destroy_elements_range( @@ -2802,7 +2801,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE } else { - return ::fast_io::containers::details::deque_get_back_capacity<1u, block_size * sizeof(value_type)>( + return ::fast_io::containers::details::deque_get_back_capacity( *reinterpret_cast<::fast_io::containers::details::deque_controller_common const *>(this->controller)); } } @@ -3564,6 +3563,11 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE this->controller))); } } + +public: + /* + "The reserve_back and reserve_front APIs are fundamentally problematic for a deque. Because our logic redistributes and borrows blocks from both ends to maintain balance, direction-specific reservation is semantically unstable. A unified reserve(n) is likely more appropriate. Boost's approach appears to share this design flaw; for deques, resize for_overwrite provides clear utility, whereas direction-based reserve is often a misnomer." + */ inline constexpr void reserve_back(size_type backcap) noexcept { if consteval @@ -3586,6 +3590,8 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE ::fast_io::containers::details::deque_reserve_front_common(*reinterpret_cast<::fast_io::containers::details::deque_controller_common *>(__builtin_addressof(this->controller)), frontcap); } } + +public: #if 0 inline constexpr void assign(size_type count, const_reference val) noexcept(::std::is_nothrow_copy_constructible_v) { @@ -3623,9 +3629,25 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE } else { +#if 0 + ::fast_io::io::debug_println(::std::source_location::current()," count=",count," back_capacity=",this->back_capacity(), + " oldsz=",oldsz,"\n", + ::fast_io::mnp::debug_view(*this)); +#endif this->reserve_back(count); +#if 0 + ::fast_io::io::debug_println(::std::source_location::current()," count=",count," back_capacity=",this->back_capacity(), + " oldsz=",oldsz); +#endif auto ed{this->end()}; newed = ed + static_cast(count - oldsz); +#if 0 + ::fast_io::io::debug_println(::std::source_location::current()," count=",count," back_capacity=",this->back_capacity(), + " oldsz=",oldsz, + " ed.itercontent.curr_ptr=", ::fast_io::mnp::pointervw(ed.itercontent.curr_ptr), + " newed.itercontent.curr_ptr=", ::fast_io::mnp::pointervw(newed.itercontent.curr_ptr),"\n", + ::fast_io::mnp::debug_view(*this)); +#endif if (pval) { ::fast_io::freestanding::uninitialized_fill(ed, newed, *pval); @@ -3634,15 +3656,24 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { ::fast_io::freestanding::uninitialized_default_construct(ed, newed); } +#if 0 + ::fast_io::io::debug_println(::std::source_location::current()," count=",count," back_capacity=",this->back_capacity()); +#endif } if (newed.itercontent.curr_ptr == newed.itercontent.begin_ptr && newed.itercontent.controller_ptr != this->controller.front_block.controller_ptr) { +#if 0 + ::fast_io::io::debug_println(::std::source_location::current()," count=",count," back_capacity=",this->back_capacity()); +#endif newed.itercontent.curr_ptr = (newed.itercontent.begin_ptr = *--newed.itercontent.controller_ptr) + block_size; } this->controller.back_block.controller_ptr = newed.itercontent.controller_ptr; this->controller.back_end_ptr = (this->controller.back_block.begin_ptr = newed.itercontent.begin_ptr) + block_size; this->controller.back_block.curr_ptr = newed.itercontent.curr_ptr; +#if 0 + ::fast_io::io::debug_println(::std::source_location::current()," ", ::fast_io::mnp::debug_view(*this)); +#endif } inline constexpr void resize_for_overwrite_impl(size_type count) noexcept(::std::is_nothrow_move_constructible_v) { From b7917010c120ea6ef8614e898c10c13a9df1f683 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Fri, 15 May 2026 02:14:19 +0800 Subject: [PATCH 59/82] [deque] correctly implement fuzz_deque_resize --- .../deque/fuzz_deque_resize.cc | 49 +++------------ include/fast_io_dsal/impl/deque.h | 60 ++++++++++++++----- 2 files changed, 53 insertions(+), 56 deletions(-) diff --git a/fuzzing/0007.containers/deque/fuzz_deque_resize.cc b/fuzzing/0007.containers/deque/fuzz_deque_resize.cc index 1ccad3e6d..aeed8cd16 100644 --- a/fuzzing/0007.containers/deque/fuzz_deque_resize.cc +++ b/fuzzing/0007.containers/deque/fuzz_deque_resize.cc @@ -21,8 +21,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const *data, size_t size) while (i < size) { uint8_t op = read_u8(i); - - switch (op % 8) + switch (op % 6) { case 0: { // push_back @@ -39,36 +38,13 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const *data, size_t size) break; } case 2: - { // reserve_back - size_t n = static_cast(read_u8(i)) * 256; - fq.reserve_back(n); - - // capacity checks - if (fq.back_capacity() < n) - { - __builtin_trap(); - } - break; - } - case 3: - { // reserve_front - size_t n = static_cast(read_u8(i)) * 256; - fq.reserve_front(n); - - if (fq.front_capacity() < n) - { - __builtin_trap(); - } - break; - } - case 4: { // resize size_t n = read_u8(i); fq.resize(n); sq.resize(n); break; } - case 5: + case 3: { // resize overwrite size_t n = read_u8(i); int v = read_u8(i); @@ -76,7 +52,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const *data, size_t size) sq.resize(n, v); break; } - case 6: + case 4: { // assign_range size_t n = read_u8(i); std::vector tmp(n); @@ -89,14 +65,14 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const *data, size_t size) sq.assign(tmp.begin(), tmp.end()); break; } - case 7: + case 5: { // pop ops - if (!fq.empty()) + if (!sq.empty()) { fq.pop_back(); sq.pop_back(); } - if (!fq.empty()) + if (!sq.empty()) { fq.pop_front(); sq.pop_front(); @@ -104,26 +80,19 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const *data, size_t size) break; } } - // Validate element correctness - if (fq.size() != sq.size()) + ::std::size_t fqsize{fq.size()}; + if (fqsize != sq.size()) { __builtin_trap(); } - - for (size_t k = 0; k < fq.size(); ++k) + for (size_t k = 0; k != fqsize; ++k) { if (fq[k] != sq[k]) { __builtin_trap(); } } - - // capacity must always be >= size - if (fq.capacity() < fq.size()) - { - __builtin_trap(); - } } return 0; diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index 68234b49b..7ba863f62 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -1244,7 +1244,11 @@ deque_erase_common_trivial_impl(::fast_io::containers::details::deque_controller } if (back_block.begin_ptr == back_block.curr_ptr) { - if (controller.front_block.controller_ptr != back_block.controller_ptr) + if (controller.front_block.controller_ptr == back_block.controller_ptr) + { + controller.front_block.curr_ptr = back_block.curr_ptr = (back_block.begin_ptr) + (blockbytes >> 1u); + } + else { back_block.curr_ptr = ((back_block.begin_ptr = (*--back_block.controller_ptr)) + blockbytes); } @@ -1584,11 +1588,9 @@ inline constexpr void deque_reserve_back_spaces_impl(dequecontroltype &controlle else { ::std::size_t const block_bytes{block_size * sz}; -#if 1 ::fast_io::containers::details::deque_reserve_back_blocks_impl(*reinterpret_cast<::fast_io::containers::details::deque_controller_common *>( __builtin_addressof(controller)), toallocate, align, block_bytes, sz); -#endif } } @@ -2569,6 +2571,10 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { ::std::destroy_at(controller.back_block.curr_ptr - 1); } +#if 0 + ::fast_io::io::debug_println(::std::source_location::current(), "\n", + ::fast_io::mnp::debug_view(*this)); +#endif if (--controller.back_block.curr_ptr == controller.back_block.begin_ptr) [[unlikely]] { this->back_backspace(); @@ -3610,21 +3616,29 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE private: inline constexpr void resize_impl(size_type count, T const *pval) noexcept(::std::is_nothrow_move_constructible_v) { +#if 0 + ::fast_io::io::debug_print(::std::source_location::current(), " debugresize\n"); +#endif size_type oldsz{this->size()}; if (count == oldsz) { return; } iterator newed; +#if 0 + ::fast_io::io::debug_println(::std::source_location::current(), " debugresize\tcount=",count, " oldsz=",oldsz); +#endif if (count < oldsz) { auto ed{this->end()}; newed = ed; newed -= static_cast(oldsz - count); +#if 0 + ::fast_io::io::debug_println(::std::source_location::current(), " debugresize\tcount=",count, " oldsz=",oldsz, " newed.itercontent.curr_ptr=", ::fast_io::mnp::pointervw(newed.itercontent.curr_ptr)); +#endif if constexpr (!::std::is_trivially_destructible_v) { - this->erase(newed, ed); - return; + this->destroy_elements_range(newed, ed); } } else @@ -3637,7 +3651,8 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE this->reserve_back(count); #if 0 ::fast_io::io::debug_println(::std::source_location::current()," count=",count," back_capacity=",this->back_capacity(), - " oldsz=",oldsz); + " oldsz=",oldsz,"\n", + ::fast_io::mnp::debug_view(*this)); #endif auto ed{this->end()}; newed = ed + static_cast(count - oldsz); @@ -3660,13 +3675,16 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE ::fast_io::io::debug_println(::std::source_location::current()," count=",count," back_capacity=",this->back_capacity()); #endif } - if (newed.itercontent.curr_ptr == newed.itercontent.begin_ptr && - newed.itercontent.controller_ptr != this->controller.front_block.controller_ptr) + if (newed.itercontent.curr_ptr == newed.itercontent.begin_ptr) { -#if 0 - ::fast_io::io::debug_println(::std::source_location::current()," count=",count," back_capacity=",this->back_capacity()); -#endif - newed.itercontent.curr_ptr = (newed.itercontent.begin_ptr = *--newed.itercontent.controller_ptr) + block_size; + if (newed.itercontent.controller_ptr == this->controller.front_block.controller_ptr) + { + this->controller.front_block.curr_ptr = newed.itercontent.curr_ptr = newed.itercontent.begin_ptr + (block_size >> 1u); + } + else + { + newed.itercontent.curr_ptr = (newed.itercontent.begin_ptr = *--newed.itercontent.controller_ptr) + block_size; + } } this->controller.back_block.controller_ptr = newed.itercontent.controller_ptr; this->controller.back_end_ptr = (this->controller.back_block.begin_ptr = newed.itercontent.begin_ptr) + block_size; @@ -3700,10 +3718,16 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE auto ed{this->end()}; newed = ed + static_cast(count - oldsz); } - if (newed.itercontent.curr_ptr == newed.itercontent.begin_ptr && - newed.itercontent.controller_ptr != this->controller.front_block.controller_ptr) + if (newed.itercontent.curr_ptr == newed.itercontent.begin_ptr) { - newed.itercontent.curr_ptr = (newed.itercontent.begin_ptr = *--newed.itercontent.controller_ptr) + block_size; + if (newed.itercontent.controller_ptr == this->controller.front_block.controller_ptr) + { + this->controller.front_block.curr_ptr = newed.itercontent.curr_ptr = newed.itercontent.begin_ptr + (block_size >> 1u); + } + else + { + newed.itercontent.curr_ptr = (newed.itercontent.begin_ptr = *--newed.itercontent.controller_ptr) + block_size; + } } this->controller.back_block.controller_ptr = newed.itercontent.controller_ptr; this->controller.back_end_ptr = (this->controller.back_block.begin_ptr = newed.itercontent.begin_ptr) + block_size; @@ -3758,7 +3782,11 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE } if (back_block.begin_ptr == back_block.curr_ptr) { - if (this->controller.front_block.controller_ptr != back_block.controller_ptr) + if (this->controller.front_block.controller_ptr == back_block.controller_ptr) + { + this->controller.front_block.curr_ptr = back_block.curr_ptr_ptr = back_block.begin_ptr + (block_size >> 1u); + } + else { back_block.curr_ptr = ((back_block.begin_ptr = (*--back_block.controller_ptr)) + block_size); } From b63267cc47b006319ad2885ea7a5615f8c653212 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Fri, 15 May 2026 02:21:51 +0800 Subject: [PATCH 60/82] [deque] benchmark add std_vec as a reference --- benchmark/0011.containers/deque/0001.push_back/std.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/benchmark/0011.containers/deque/0001.push_back/std.cc b/benchmark/0011.containers/deque/0001.push_back/std.cc index b2744c2a4..b7a34242f 100644 --- a/benchmark/0011.containers/deque/0001.push_back/std.cc +++ b/benchmark/0011.containers/deque/0001.push_back/std.cc @@ -20,7 +20,7 @@ int main() for (auto const e : deq) { sum += e; - } + } } - ::fast_io::io::perrln("sum=",sum); + ::fast_io::io::perrln("sum=", sum); } From e0bfd41d0b5f4f7309b78da039d495ed2534a4c9 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Fri, 15 May 2026 02:45:18 +0800 Subject: [PATCH 61/82] [decay] remove claude slop code --- .../operations/readimpl/decay.h | 16 ---------------- .../operations/writeimpl/decay.h | 17 ----------------- 2 files changed, 33 deletions(-) diff --git a/include/fast_io_core_impl/operations/readimpl/decay.h b/include/fast_io_core_impl/operations/readimpl/decay.h index fff23e84b..014f90877 100644 --- a/include/fast_io_core_impl/operations/readimpl/decay.h +++ b/include/fast_io_core_impl/operations/readimpl/decay.h @@ -4,7 +4,6 @@ namespace fast_io::operations::decay { template - requires(::fast_io::operations::decay::defines::readable) inline constexpr typename instmtype::input_char_type * read_some_decay(instmtype insm, typename instmtype::input_char_type *first, typename instmtype::input_char_type *last) { @@ -12,7 +11,6 @@ read_some_decay(instmtype insm, typename instmtype::input_char_type *first, type } template - requires(::fast_io::operations::decay::defines::readable) inline constexpr void read_all_decay(instmtype insm, typename instmtype::input_char_type *first, typename instmtype::input_char_type *last) { @@ -20,21 +18,18 @@ inline constexpr void read_all_decay(instmtype insm, typename instmtype::input_c } template - requires(::fast_io::operations::decay::defines::bytes_readable) inline constexpr ::std::byte *read_some_bytes_decay(instmtype insm, ::std::byte *first, ::std::byte *last) { return ::fast_io::details::read_some_bytes_impl(insm, first, last); } template - requires(::fast_io::operations::decay::defines::bytes_readable) inline constexpr void read_all_bytes_decay(instmtype insm, ::std::byte *first, ::std::byte *last) { ::fast_io::details::read_all_bytes_impl(insm, first, last); } template - requires(::fast_io::operations::decay::defines::readable) inline constexpr io_scatter_status_t scatter_read_some_decay(instmtype insm, basic_io_scatter_t const *pscatters, ::std::size_t n) @@ -43,7 +38,6 @@ scatter_read_some_decay(instmtype insm, basic_io_scatter_t - requires(::fast_io::operations::decay::defines::bytes_readable) inline constexpr io_scatter_status_t scatter_read_some_bytes_decay(instmtype insm, io_scatter_t const *pscatters, ::std::size_t n) { @@ -51,7 +45,6 @@ inline constexpr io_scatter_status_t scatter_read_some_bytes_decay(instmtype ins } template - requires(::fast_io::operations::decay::defines::readable) inline constexpr void scatter_read_all_decay(instmtype insm, basic_io_scatter_t const *pscatters, ::std::size_t n) @@ -60,14 +53,12 @@ inline constexpr void scatter_read_all_decay(instmtype insm, } template - requires(::fast_io::operations::decay::defines::bytes_readable) inline constexpr void scatter_read_all_bytes_decay(instmtype insm, io_scatter_t const *pscatters, ::std::size_t n) { ::fast_io::details::scatter_read_all_bytes_impl(insm, pscatters, n); } template - requires(::fast_io::operations::decay::defines::preadable) inline constexpr typename instmtype::input_char_type * pread_some_decay(instmtype insm, typename instmtype::input_char_type *first, typename instmtype::input_char_type *last, ::fast_io::intfpos_t off) @@ -76,7 +67,6 @@ pread_some_decay(instmtype insm, typename instmtype::input_char_type *first, typ } template - requires(::fast_io::operations::decay::defines::preadable) inline constexpr void pread_all_decay(instmtype insm, typename instmtype::input_char_type *first, typename instmtype::input_char_type *last, ::fast_io::intfpos_t off) { @@ -84,7 +74,6 @@ inline constexpr void pread_all_decay(instmtype insm, typename instmtype::input_ } template - requires(::fast_io::operations::decay::defines::bytes_preadable) inline constexpr ::std::byte *pread_some_bytes_decay(instmtype insm, ::std::byte *first, ::std::byte *last, ::fast_io::intfpos_t off) { @@ -92,7 +81,6 @@ inline constexpr ::std::byte *pread_some_bytes_decay(instmtype insm, ::std::byte } template - requires(::fast_io::operations::decay::defines::bytes_preadable) inline constexpr void pread_all_bytes_decay(instmtype insm, ::std::byte *first, ::std::byte *last, ::fast_io::intfpos_t off) { @@ -100,7 +88,6 @@ inline constexpr void pread_all_bytes_decay(instmtype insm, ::std::byte *first, } template - requires(::fast_io::operations::decay::defines::preadable) inline constexpr io_scatter_status_t scatter_pread_some_decay(instmtype insm, basic_io_scatter_t const *pscatters, ::std::size_t n, ::fast_io::intfpos_t off) @@ -109,7 +96,6 @@ scatter_pread_some_decay(instmtype insm, basic_io_scatter_t - requires(::fast_io::operations::decay::defines::bytes_preadable) inline constexpr io_scatter_status_t scatter_pread_some_bytes_decay(instmtype insm, io_scatter_t const *pscatters, ::std::size_t n, ::fast_io::intfpos_t off) { @@ -117,7 +103,6 @@ inline constexpr io_scatter_status_t scatter_pread_some_bytes_decay(instmtype in } template - requires(::fast_io::operations::decay::defines::preadable) inline constexpr void scatter_pread_all_decay(instmtype insm, basic_io_scatter_t const *pscatters, ::std::size_t n, ::fast_io::intfpos_t off) @@ -126,7 +111,6 @@ inline constexpr void scatter_pread_all_decay(instmtype insm, } template - requires(::fast_io::operations::decay::defines::bytes_preadable) inline constexpr void scatter_pread_all_bytes_decay(instmtype insm, io_scatter_t const *pscatters, ::std::size_t n, ::fast_io::intfpos_t off) { diff --git a/include/fast_io_core_impl/operations/writeimpl/decay.h b/include/fast_io_core_impl/operations/writeimpl/decay.h index 6270af327..6c8ed5c13 100644 --- a/include/fast_io_core_impl/operations/writeimpl/decay.h +++ b/include/fast_io_core_impl/operations/writeimpl/decay.h @@ -4,7 +4,6 @@ namespace fast_io::operations::decay { template - requires(::fast_io::operations::decay::defines::writable) inline constexpr typename outstmtype::output_char_type const * write_some_decay(outstmtype outsm, typename outstmtype::output_char_type const *first, typename outstmtype::output_char_type const *last) @@ -13,7 +12,6 @@ write_some_decay(outstmtype outsm, typename outstmtype::output_char_type const * } template - requires(::fast_io::operations::decay::defines::writable) inline constexpr void write_all_decay(outstmtype outsm, typename outstmtype::output_char_type const *first, typename outstmtype::output_char_type const *last) { @@ -21,7 +19,6 @@ inline constexpr void write_all_decay(outstmtype outsm, typename outstmtype::out } template - requires(::fast_io::operations::decay::defines::bytes_writable) inline constexpr ::std::byte const *write_some_bytes_decay(outstmtype outsm, ::std::byte const *first, ::std::byte const *last) { @@ -29,14 +26,12 @@ inline constexpr ::std::byte const *write_some_bytes_decay(outstmtype outsm, ::s } template - requires(::fast_io::operations::decay::defines::bytes_writable) inline constexpr void write_all_bytes_decay(outstmtype outsm, ::std::byte const *first, ::std::byte const *last) { ::fast_io::details::write_all_bytes_impl(outsm, first, last); } template - requires(::fast_io::operations::decay::defines::writable) inline constexpr io_scatter_status_t scatter_write_some_decay(outstmtype outsm, basic_io_scatter_t const *pscatters, ::std::size_t n) @@ -45,7 +40,6 @@ scatter_write_some_decay(outstmtype outsm, basic_io_scatter_t - requires(::fast_io::operations::decay::defines::bytes_writable) inline constexpr io_scatter_status_t scatter_write_some_bytes_decay(outstmtype outsm, io_scatter_t const *pscatters, ::std::size_t n) { @@ -53,7 +47,6 @@ inline constexpr io_scatter_status_t scatter_write_some_bytes_decay(outstmtype o } template - requires(::fast_io::operations::decay::defines::writable) inline constexpr void scatter_write_all_decay(outstmtype outsm, basic_io_scatter_t const *pscatters, ::std::size_t n) @@ -62,14 +55,12 @@ scatter_write_all_decay(outstmtype outsm, basic_io_scatter_t - requires(::fast_io::operations::decay::defines::bytes_writable) inline constexpr void scatter_write_all_bytes_decay(outstmtype outsm, io_scatter_t const *pscatters, ::std::size_t n) { ::fast_io::details::scatter_write_all_bytes_impl(outsm, pscatters, n); } template - requires(::fast_io::operations::decay::defines::pwritable) inline constexpr typename outstmtype::output_char_type const * pwrite_some_decay(outstmtype outsm, typename outstmtype::output_char_type const *first, typename outstmtype::output_char_type const *last, ::fast_io::intfpos_t off) @@ -78,7 +69,6 @@ pwrite_some_decay(outstmtype outsm, typename outstmtype::output_char_type const } template - requires(::fast_io::operations::decay::defines::pwritable) inline constexpr void pwrite_all_decay(outstmtype outsm, typename outstmtype::output_char_type const *first, typename outstmtype::output_char_type const *last, ::fast_io::intfpos_t off) { @@ -86,7 +76,6 @@ inline constexpr void pwrite_all_decay(outstmtype outsm, typename outstmtype::ou } template - requires(::fast_io::operations::decay::defines::bytes_pwritable) inline constexpr ::std::byte const *pwrite_some_bytes_decay(outstmtype outsm, ::std::byte const *first, ::std::byte const *last, ::fast_io::intfpos_t off) { @@ -94,7 +83,6 @@ inline constexpr ::std::byte const *pwrite_some_bytes_decay(outstmtype outsm, :: } template - requires(::fast_io::operations::decay::defines::bytes_pwritable) inline constexpr void pwrite_all_bytes_decay(outstmtype outsm, ::std::byte const *first, ::std::byte const *last, ::fast_io::intfpos_t off) { @@ -102,7 +90,6 @@ inline constexpr void pwrite_all_bytes_decay(outstmtype outsm, ::std::byte const } template - requires(::fast_io::operations::decay::defines::pwritable) inline constexpr io_scatter_status_t scatter_pwrite_some_decay(outstmtype outsm, basic_io_scatter_t const *pscatters, ::std::size_t n, ::fast_io::intfpos_t off) @@ -111,7 +98,6 @@ scatter_pwrite_some_decay(outstmtype outsm, basic_io_scatter_t - requires(::fast_io::operations::decay::defines::bytes_pwritable) inline constexpr io_scatter_status_t scatter_pwrite_some_bytes_decay(outstmtype outsm, io_scatter_t const *pscatters, ::std::size_t n, ::fast_io::intfpos_t off) { @@ -119,7 +105,6 @@ inline constexpr io_scatter_status_t scatter_pwrite_some_bytes_decay(outstmtype } template - requires(::fast_io::operations::decay::defines::pwritable) inline constexpr void scatter_pwrite_all_decay(outstmtype outsm, basic_io_scatter_t const *pscatters, ::std::size_t n, ::fast_io::intfpos_t off) @@ -128,7 +113,6 @@ scatter_pwrite_all_decay(outstmtype outsm, basic_io_scatter_t - requires(::fast_io::operations::decay::defines::bytes_pwritable) inline constexpr void scatter_pwrite_all_bytes_decay(outstmtype outsm, io_scatter_t const *pscatters, ::std::size_t n, ::fast_io::intfpos_t off) { @@ -136,7 +120,6 @@ inline constexpr void scatter_pwrite_all_bytes_decay(outstmtype outsm, io_scatte } template - requires(::fast_io::operations::decay::defines::writable) #if __has_cpp_attribute(__gnu__::__always_inline__) [[__gnu__::__always_inline__]] #elif __has_cpp_attribute(msvc::forceinline) From 0ec67c26f327fb06e82c5f8303960074132cb7a8 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Fri, 15 May 2026 02:48:38 +0800 Subject: [PATCH 62/82] [deque] controller_ is missing for a variable --- include/fast_io_dsal/impl/deque.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index 7ba863f62..c000071ef 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -1676,7 +1676,7 @@ inline constexpr void deque_reserve_front_blocks_impl(dequecontroltype &controll { ::fast_io::containers::details::deque_allocate_on_empty_common_with_n_impl( controller, nb, align, blockbytes); - auto controllerptr{controller.controller_block.after_reserved_ptr - 1}; + auto controllerptr{controller.controller_block.controller_after_reserved_ptr - 1}; controller.front_block.controller_ptr = controller.back_block.controller_ptr = controllerptr; auto begin_ptr{*controllerptr}; controller.front_block.begin_ptr = controller.back_block.begin_ptr = begin_ptr; From db3810ed0ad8059971787c05e68c486d049562bd Mon Sep 17 00:00:00 2001 From: trcrsired Date: Fri, 15 May 2026 02:53:46 +0800 Subject: [PATCH 63/82] =?UTF-8?q?[deque]=20has=20no=20member=20named=20?= =?UTF-8?q?=E2=80=98curr=5Fptr=5Fptr=E2=80=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/fast_io_dsal/impl/deque.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index c000071ef..3b1fddbbe 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -3784,7 +3784,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { if (this->controller.front_block.controller_ptr == back_block.controller_ptr) { - this->controller.front_block.curr_ptr = back_block.curr_ptr_ptr = back_block.begin_ptr + (block_size >> 1u); + this->controller.front_block.curr_ptr = back_block.curr_ptr = back_block.begin_ptr + (block_size >> 1u); } else { From a7e3b2858b615fb06ef858f901ef60bfd42673eb Mon Sep 17 00:00:00 2001 From: trcrsired Date: Fri, 15 May 2026 02:55:32 +0800 Subject: [PATCH 64/82] [skip ci][deque] benchmark needs std_vec one --- .../deque/0001.push_back/std_vec.cc | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 benchmark/0011.containers/deque/0001.push_back/std_vec.cc diff --git a/benchmark/0011.containers/deque/0001.push_back/std_vec.cc b/benchmark/0011.containers/deque/0001.push_back/std_vec.cc new file mode 100644 index 000000000..8b3407e89 --- /dev/null +++ b/benchmark/0011.containers/deque/0001.push_back/std_vec.cc @@ -0,0 +1,26 @@ +#include +#include +#include + +int main() +{ + fast_io::timer tm(u8"std::vector"); + std::vector vec; + constexpr std::size_t n{100000000}; + { + fast_io::timer tm1(u8"push_back"); + for (std::size_t i{}; i != n; ++i) + { + vec.push_back(i); + } + } + ::std::size_t sum{}; + { + fast_io::timer tm1(u8"loop"); + for (auto const e : vec) + { + sum += e; + } + } + ::fast_io::io::perrln("sum=", sum); +} From a5c38ed19f4abcd0c8c119200b8e4b36dcd67be3 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Fri, 15 May 2026 02:58:45 +0800 Subject: [PATCH 65/82] [skip ci][deque]benchmark should be overwrite. the i misesed --- ..._io_resize_for_overwite.cc => fast_io_resize_for_overwrite.cc} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename benchmark/0011.containers/deque/0001.push_back/{fast_io_resize_for_overwite.cc => fast_io_resize_for_overwrite.cc} (100%) diff --git a/benchmark/0011.containers/deque/0001.push_back/fast_io_resize_for_overwite.cc b/benchmark/0011.containers/deque/0001.push_back/fast_io_resize_for_overwrite.cc similarity index 100% rename from benchmark/0011.containers/deque/0001.push_back/fast_io_resize_for_overwite.cc rename to benchmark/0011.containers/deque/0001.push_back/fast_io_resize_for_overwrite.cc From ea31ea1676b1779b17b7e8a57277a5bc717beeb3 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Fri, 15 May 2026 06:15:02 +0800 Subject: [PATCH 66/82] [deque] deque assign --- include/fast_io_dsal/impl/deque.h | 148 ++++++++++----------- tests/0026.container/0003.deque/assign.cc | 151 +--------------------- 2 files changed, 74 insertions(+), 225 deletions(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index 3b1fddbbe..3a58b62ee 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -2335,6 +2335,29 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE this->construct_deque_common_impl(ilist.begin(), ilist.end()); } + inline explicit constexpr deque(size_type n, const_reference val) noexcept(::std::is_nothrow_copy_constructible_v) + { + if constexpr (::std::is_nothrow_copy_constructible_v) + { + this->reserve_back(n); + auto bg{this->begin()}; + auto ed{bg + n}; + ::fast_io::freestanding::uninitialized_fill(bg, ed, val); + this->set_newed_common(ed.itercontent); + } + else + { + deque d; + d.reserve_back(n); + auto bg{d.begin()}; + auto ed{bg + n}; + ::fast_io::freestanding::uninitialized_fill(bg, ed, val); + d.set_newed_common(ed.itercontent); + this->controller = d.controller; + d.controller = {}; + } + } + private: template inline constexpr void construct_deque_common_impl(Iter first, Sentinel last) @@ -3597,14 +3620,50 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE } } + inline constexpr void set_newed_common(::fast_io::containers::details::deque_control_block newed) noexcept + { + if (newed.curr_ptr == newed.begin_ptr) + { + if (newed.controller_ptr == this->controller.front_block.controller_ptr) + { + this->controller.front_block.curr_ptr = newed.curr_ptr = newed.begin_ptr + (block_size >> 1u); + } + else + { + newed.curr_ptr = (newed.begin_ptr = *--newed.controller_ptr) + block_size; + } + } + this->controller.back_block.controller_ptr = newed.controller_ptr; + this->controller.back_end_ptr = (this->controller.back_block.begin_ptr = newed.begin_ptr) + block_size; + this->controller.back_block.curr_ptr = newed.curr_ptr; + } + public: -#if 0 - inline constexpr void assign(size_type count, const_reference val) noexcept(::std::is_nothrow_copy_constructible_v) + inline constexpr void assign(size_type count, const_reference val) noexcept(::std::is_nothrow_copy_constructible_v) { - deque temp(count,val); - this->swap(temp); + if constexpr (::std::is_nothrow_copy_constructible_v) + { + if constexpr (!::std::is_trivially_destructible_v) + { + this->clear(); + } + if (!count) + { + return; + } + this->reserve_back(count); + auto bg{this->begin()}; + auto newed{bg + count}; + ::fast_io::freestanding::uninitialized_fill(bg, newed, val); + this->set_newed_common(newed.itercontent); + } + else + { + deque d(count, val); + this->controller = d.controller; + d.controller = {}; + } } -#endif template <::std::ranges::range R> requires ::std::constructible_from> inline constexpr void assign_range(R &&rg) noexcept(::std::is_nothrow_constructible_v>) @@ -3616,26 +3675,17 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE private: inline constexpr void resize_impl(size_type count, T const *pval) noexcept(::std::is_nothrow_move_constructible_v) { -#if 0 - ::fast_io::io::debug_print(::std::source_location::current(), " debugresize\n"); -#endif size_type oldsz{this->size()}; if (count == oldsz) { return; } iterator newed; -#if 0 - ::fast_io::io::debug_println(::std::source_location::current(), " debugresize\tcount=",count, " oldsz=",oldsz); -#endif if (count < oldsz) { auto ed{this->end()}; newed = ed; newed -= static_cast(oldsz - count); -#if 0 - ::fast_io::io::debug_println(::std::source_location::current(), " debugresize\tcount=",count, " oldsz=",oldsz, " newed.itercontent.curr_ptr=", ::fast_io::mnp::pointervw(newed.itercontent.curr_ptr)); -#endif if constexpr (!::std::is_trivially_destructible_v) { this->destroy_elements_range(newed, ed); @@ -3643,26 +3693,11 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE } else { -#if 0 - ::fast_io::io::debug_println(::std::source_location::current()," count=",count," back_capacity=",this->back_capacity(), - " oldsz=",oldsz,"\n", - ::fast_io::mnp::debug_view(*this)); -#endif + this->reserve_back(count); -#if 0 - ::fast_io::io::debug_println(::std::source_location::current()," count=",count," back_capacity=",this->back_capacity(), - " oldsz=",oldsz,"\n", - ::fast_io::mnp::debug_view(*this)); -#endif + auto ed{this->end()}; newed = ed + static_cast(count - oldsz); -#if 0 - ::fast_io::io::debug_println(::std::source_location::current()," count=",count," back_capacity=",this->back_capacity(), - " oldsz=",oldsz, - " ed.itercontent.curr_ptr=", ::fast_io::mnp::pointervw(ed.itercontent.curr_ptr), - " newed.itercontent.curr_ptr=", ::fast_io::mnp::pointervw(newed.itercontent.curr_ptr),"\n", - ::fast_io::mnp::debug_view(*this)); -#endif if (pval) { ::fast_io::freestanding::uninitialized_fill(ed, newed, *pval); @@ -3671,27 +3706,8 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { ::fast_io::freestanding::uninitialized_default_construct(ed, newed); } -#if 0 - ::fast_io::io::debug_println(::std::source_location::current()," count=",count," back_capacity=",this->back_capacity()); -#endif } - if (newed.itercontent.curr_ptr == newed.itercontent.begin_ptr) - { - if (newed.itercontent.controller_ptr == this->controller.front_block.controller_ptr) - { - this->controller.front_block.curr_ptr = newed.itercontent.curr_ptr = newed.itercontent.begin_ptr + (block_size >> 1u); - } - else - { - newed.itercontent.curr_ptr = (newed.itercontent.begin_ptr = *--newed.itercontent.controller_ptr) + block_size; - } - } - this->controller.back_block.controller_ptr = newed.itercontent.controller_ptr; - this->controller.back_end_ptr = (this->controller.back_block.begin_ptr = newed.itercontent.begin_ptr) + block_size; - this->controller.back_block.curr_ptr = newed.itercontent.curr_ptr; -#if 0 - ::fast_io::io::debug_println(::std::source_location::current()," ", ::fast_io::mnp::debug_view(*this)); -#endif + this->set_newed_common(newed.itercontent); } inline constexpr void resize_for_overwrite_impl(size_type count) noexcept(::std::is_nothrow_move_constructible_v) { @@ -3718,20 +3734,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE auto ed{this->end()}; newed = ed + static_cast(count - oldsz); } - if (newed.itercontent.curr_ptr == newed.itercontent.begin_ptr) - { - if (newed.itercontent.controller_ptr == this->controller.front_block.controller_ptr) - { - this->controller.front_block.curr_ptr = newed.itercontent.curr_ptr = newed.itercontent.begin_ptr + (block_size >> 1u); - } - else - { - newed.itercontent.curr_ptr = (newed.itercontent.begin_ptr = *--newed.itercontent.controller_ptr) + block_size; - } - } - this->controller.back_block.controller_ptr = newed.itercontent.controller_ptr; - this->controller.back_end_ptr = (this->controller.back_block.begin_ptr = newed.itercontent.begin_ptr) + block_size; - this->controller.back_block.curr_ptr = newed.itercontent.curr_ptr; + this->set_newed_common(newed.itercontent); } public: @@ -3780,19 +3783,8 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { back_block = ::fast_io::freestanding::uninitialized_relocate(last, this->end(), first).itercontent; } - if (back_block.begin_ptr == back_block.curr_ptr) - { - if (this->controller.front_block.controller_ptr == back_block.controller_ptr) - { - this->controller.front_block.curr_ptr = back_block.curr_ptr = back_block.begin_ptr + (block_size >> 1u); - } - else - { - back_block.curr_ptr = ((back_block.begin_ptr = (*--back_block.controller_ptr)) + block_size); - } - } - this->controller.back_block = back_block; - this->controller.back_end_ptr = back_block.begin_ptr + block_size; + + this->set_newed_common(back_block); return first; } diff --git a/tests/0026.container/0003.deque/assign.cc b/tests/0026.container/0003.deque/assign.cc index 1bc266549..b23f1373c 100644 --- a/tests/0026.container/0003.deque/assign.cc +++ b/tests/0026.container/0003.deque/assign.cc @@ -1,153 +1,10 @@ #include #include -#include -#include -#include - -using fast_io::deque; - -// A type that throws on copy after N copies -struct ThrowOnCopy -{ - static inline int counter = 0; - int value; - - ThrowOnCopy(int v = 0) : value(v) - {} - - ThrowOnCopy(ThrowOnCopy const &other) : value(other.value) - { - if (++counter > 3) - { - throw std::runtime_error("copy fail"); - } - } - ThrowOnCopy &operator=(ThrowOnCopy const &) = default; -}; -#if 0 -inline void test_assign_basic() { - deque d; - d.push_back(1); - d.push_back(2); - d.push_back(3); - - d.assign(5, 42); - - assert(d.size() == 5); - for (auto& x : d) assert(x == 42); -} -#endif -inline void test_assign_range_basic() -{ - deque d; - std::vector v = {10, 20, 30, 40}; - - d.assign_range(v); - - assert(d.size() == 4); - for (int i = 0; i < 4; ++i) - { - assert(d[i] == v[i]); - } -} -#if 0 -inline void test_assign_strong_exception_guarantee() { - deque d; - d.push_back({1}); - d.push_back({2}); - d.push_back({3}); - - auto old = d; // snapshot - - ThrowOnCopy::counter = 0; - - try { - d.assign(10, ThrowOnCopy{7}); // will throw after 3 copies - assert(false); // should not reach - } catch (...) { - // strong exception guarantee: unchanged - assert(d.size() == old.size()); - for (size_t i = 0; i < d.size(); ++i) - assert(d[i].value == old[i].value); - } -} -#endif -inline void test_assign_range_exception_guarantee() -{ - deque d; - d.push_back({1}); - d.push_back({2}); - d.push_back({3}); - - auto old = d; - - std::vector v(10, ThrowOnCopy{9}); - ThrowOnCopy::counter = 0; - - try - { - d.assign_range(v); // throws - assert(false); - } - catch (...) - { - assert(d.size() == old.size()); - for (size_t i = 0; i < d.size(); ++i) - { - assert(d[i].value == old[i].value); - } - } -} - -inline void test_self_assign() -{ - deque d; - for (int i = 0; i < 10; ++i) - { - d.push_back(i); - } - - d.assign_range(d); // safe because you use temp - - assert(d.size() == 10); - for (int i = 0; i < 10; ++i) - { - assert(d[i] == i); - } -} - -inline void test_assign_from_subrange() -{ - deque d; - for (int i = 0; i < 10; ++i) - { - d.push_back(i); - } - - auto first = d.begin() + 2; - auto last = d.begin() + 7; - - d.assign_range(std::ranges::subrange(first, last)); - - assert(d.size() == 5); - for (int i = 0; i < 5; ++i) - { - assert(d[i] == i + 2); - } -} int main() { -#if 0 - test_assign_basic(); -#endif - test_assign_range_basic(); -#if 0 - test_assign_strong_exception_guarantee(); - test_assign_range_exception_guarantee(); -#endif - test_self_assign(); - test_assign_from_subrange(); - - ::fast_io::io::print("All tests passed.\n"); + ::fast_io::deque<::std::size_t> b(1000); + ::fast_io::io::println("before assign size()=", b.size()); + b.assign(100000, 10); + ::fast_io::io::println("after assign size()", b.size()); } From e53ec8e8f0e5bbfe43592ef8226259904f885658 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Fri, 15 May 2026 06:34:45 +0800 Subject: [PATCH 67/82] [deque] add fuzzings --- .../deque/fuzz_deque_assign.cc | 161 +++++++ .../deque/fuzz_deque_nontrivial.cc | 449 ++++++++++++++++++ .../deque/fuzz_deque_trivial.cc | 327 +++++++++++++ include/fast_io_dsal/impl/deque.h | 6 +- 4 files changed, 940 insertions(+), 3 deletions(-) create mode 100644 fuzzing/0007.containers/deque/fuzz_deque_assign.cc create mode 100644 fuzzing/0007.containers/deque/fuzz_deque_nontrivial.cc create mode 100644 fuzzing/0007.containers/deque/fuzz_deque_trivial.cc diff --git a/fuzzing/0007.containers/deque/fuzz_deque_assign.cc b/fuzzing/0007.containers/deque/fuzz_deque_assign.cc new file mode 100644 index 000000000..d7fe3e5de --- /dev/null +++ b/fuzzing/0007.containers/deque/fuzz_deque_assign.cc @@ -0,0 +1,161 @@ +#include +#include +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(uint8_t const *data, size_t size) +{ + fast_io::deque dq; + std::deque ref; + + auto read_u8 = [&](size_t &i) -> uint8_t { + if (i >= size) + { + return 0; + } + return data[i++]; + }; + + auto read_u64 = [&](size_t &i) -> std::size_t { + if (i + 7 >= size) + { + return 0; + } + std::size_t v{}; + for (int k = 0; k < 8; ++k) + { + v |= static_cast(data[i++]) << (k * 8); + } + return v; + }; + + size_t i = 0; + while (i < size) + { + uint8_t op = read_u8(i); + + switch (op % 8u) + { + case 0: + { // assign(count, val) + std::size_t n = read_u64(i); + std::size_t v = read_u64(i); + // Cap n to avoid OOM + if (n > 1000000) + { + n = n % 1000001; + } + dq.assign(n, v); + ref.assign(n, v); + break; + } + + case 1: + { // assign_range from vector + std::size_t n = read_u8(i); + std::vector tmp(n); + for (std::size_t k = 0; k != n; ++k) + { + tmp[k] = read_u64(i); + } + dq.assign_range(tmp); + ref.assign(tmp.begin(), tmp.end()); + break; + } + + case 2: + { // assign after growth: push_back then assign + std::size_t pushes = read_u8(i); + for (std::size_t k = 0; k != pushes; ++k) + { + dq.push_back(k); + ref.push_back(k); + } + std::size_t n = read_u64(i); + std::size_t v = read_u64(i); + if (n > 1000000) + { + n = n % 1000001; + } + dq.assign(n, v); + ref.assign(n, v); + break; + } + + case 3: + { // assign(0, val) — clear via assign + std::size_t v = read_u64(i); + dq.assign(0, v); + ref.assign(0, v); + break; + } + + case 4: + { // assign_range from empty range + std::vector tmp; + dq.assign_range(tmp); + ref.assign(tmp.begin(), tmp.end()); + break; + } + + case 5: + { // assign after push_front (tests front block) + std::size_t pushes = read_u8(i); + for (std::size_t k = 0; k != pushes; ++k) + { + dq.push_front(k * 7); + ref.push_front(k * 7); + } + std::size_t n = read_u64(i); + std::size_t v = read_u64(i); + if (n > 1000000) + { + n = n % 1000001; + } + dq.assign(n, v); + ref.assign(n, v); + break; + } + + case 6: + { // assign_range from std::deque + std::size_t n = read_u8(i); + std::deque src(n); + for (std::size_t k = 0; k != n; ++k) + { + src[k] = read_u64(i); + } + dq.assign_range(src); + ref.assign(src.begin(), src.end()); + break; + } + + case 7: + { // repeated small assigns (stress re-allocation) + std::size_t rounds = read_u8(i); + for (std::size_t r = 0; r != rounds; ++r) + { + std::size_t n = read_u8(i); + std::size_t v = read_u64(i); + dq.assign(n, v); + ref.assign(n, v); + } + break; + } + } + + // Validate + if (dq.size() != ref.size()) + { + __builtin_trap(); + } + + if (!std::ranges::equal(dq, ref)) + { + __builtin_trap(); + } + } + + return 0; +} diff --git a/fuzzing/0007.containers/deque/fuzz_deque_nontrivial.cc b/fuzzing/0007.containers/deque/fuzz_deque_nontrivial.cc new file mode 100644 index 000000000..1ff1224c2 --- /dev/null +++ b/fuzzing/0007.containers/deque/fuzz_deque_nontrivial.cc @@ -0,0 +1,449 @@ +#include +#include +#include +#include +#include +#include + +// Non-trivial type: has destructor, copy constructor, copy assignment operator +struct tracked_object +{ + int value{}; + bool *destroyed{}; + + tracked_object() = default; + explicit tracked_object(int v, bool *flag) : value{v}, destroyed{flag} + {} + tracked_object(tracked_object const &other) : value{other.value}, destroyed{other.destroyed} + { + if (destroyed && *destroyed) + { + __builtin_trap(); // double-destroy / use after destroy + } + } + tracked_object &operator=(tracked_object const &other) + { + if (destroyed && *destroyed) + { + __builtin_trap(); + } + if (this != &other) + { + value = other.value; + destroyed = other.destroyed; + } + return *this; + } + tracked_object(tracked_object &&other) noexcept : value{other.value}, destroyed{other.destroyed} + { + other.value = 0; + other.destroyed = nullptr; + } + tracked_object &operator=(tracked_object &&other) noexcept + { + if (this != &other) + { + value = other.value; + destroyed = other.destroyed; + other.value = 0; + other.destroyed = nullptr; + } + return *this; + } + ~tracked_object() + { + if (destroyed && *destroyed) + { + __builtin_trap(); // double destroy + } + if (destroyed) + { + *destroyed = true; + } + } + bool operator==(tracked_object const &other) const noexcept + { + return value == other.value; + } +}; + +// Same struct for std::deque reference +struct ref_tracked_object +{ + int value{}; + bool *destroyed{}; + + ref_tracked_object() = default; + explicit ref_tracked_object(int v, bool *flag) : value{v}, destroyed{flag} + {} + ref_tracked_object(ref_tracked_object const &other) : value{other.value}, destroyed{other.destroyed} + { + if (destroyed && *destroyed) + { + __builtin_trap(); + } + } + ref_tracked_object &operator=(ref_tracked_object const &other) + { + if (destroyed && *destroyed) + { + __builtin_trap(); + } + if (this != &other) + { + value = other.value; + destroyed = other.destroyed; + } + return *this; + } + ref_tracked_object(ref_tracked_object &&other) noexcept : value{other.value}, destroyed{other.destroyed} + { + other.value = 0; + other.destroyed = nullptr; + } + ref_tracked_object &operator=(ref_tracked_object &&other) noexcept + { + if (this != &other) + { + value = other.value; + destroyed = other.destroyed; + other.value = 0; + other.destroyed = nullptr; + } + return *this; + } + ~ref_tracked_object() + { + if (destroyed && *destroyed) + { + __builtin_trap(); + } + if (destroyed) + { + *destroyed = true; + } + } + bool operator==(ref_tracked_object const &other) const noexcept + { + return value == other.value; + } +}; + +// Storage for destruction flags so we can verify no double-frees / leaks +static constexpr std::size_t max_tracked = 4096; +static bool destroy_flags_fast[max_tracked]; +static bool destroy_flags_ref[max_tracked]; + +extern "C" int LLVMFuzzerTestOneInput(uint8_t const *data, size_t size) +{ + // Reset destruction flags + for (std::size_t i = 0; i != max_tracked; ++i) + { + destroy_flags_fast[i] = false; + destroy_flags_ref[i] = false; + } + + fast_io::deque dq; + std::deque ref; + + auto read_u8 = [&](std::size_t &i) -> uint8_t { + if (i >= size) + { + return 0; + } + return data[i++]; + }; + + auto read_u64 = [&](std::size_t &i) -> std::size_t { + if (i + 7 >= size) + { + return 0; + } + std::size_t v{}; + for (int k = 0; k < 8; ++k) + { + v |= static_cast(data[i++]) << (k * 8); + } + return v; + }; + + auto make_fast = [&](int v) -> tracked_object { + std::size_t idx = static_cast(v) % max_tracked; + return tracked_object{v, &destroy_flags_fast[idx]}; + }; + + auto make_ref = [&](int v) -> ref_tracked_object { + std::size_t idx = static_cast(v) % max_tracked; + return ref_tracked_object{v, &destroy_flags_ref[idx]}; + }; + + auto validate = [&]() { + if (dq.size() != ref.size()) + { + __builtin_trap(); + } + if (dq.empty() != ref.empty()) + { + __builtin_trap(); + } + auto it1 = dq.begin(); + auto it2 = ref.begin(); + for (std::size_t k = 0, sz = dq.size(); k != sz; ++k, ++it1, ++it2) + { + if (it1->value != it2->value) + { + __builtin_trap(); + } + } + if (!ref.empty()) + { + if (dq.front().value != ref.front().value) + { + __builtin_trap(); + } + if (dq.back().value != ref.back().value) + { + __builtin_trap(); + } + } + }; + + std::size_t i = 0; + while (i < size) + { + uint8_t op = read_u8(i); + + switch (op % 18u) + { + case 0: + { // push_back + int v = static_cast(read_u8(i)); + dq.push_back(make_fast(v)); + ref.push_back(make_ref(v)); + break; + } + + case 1: + { // push_front + int v = static_cast(read_u8(i)); + dq.push_front(make_fast(v)); + ref.push_front(make_ref(v)); + break; + } + + case 2: + { // pop_back + if (!ref.empty()) + { + dq.pop_back(); + ref.pop_back(); + } + break; + } + + case 3: + { // pop_front + if (!ref.empty()) + { + dq.pop_front(); + ref.pop_front(); + } + break; + } + + case 4: + { // emplace_back + int v = static_cast(read_u8(i)); + dq.emplace_back(make_fast(v)); + ref.emplace_back(make_ref(v)); + break; + } + + case 5: + { // emplace_front + int v = static_cast(read_u8(i)); + dq.emplace_front(make_fast(v)); + ref.emplace_front(make_ref(v)); + break; + } + + case 6: + { // insert (iterator) + int v = static_cast(read_u8(i)); + if (ref.empty()) + { + dq.insert(dq.cbegin(), make_fast(v)); + ref.insert(ref.begin(), make_ref(v)); + } + else + { + std::size_t pos = static_cast(v) % (ref.size() + 1); + dq.insert(dq.cbegin() + pos, make_fast(v)); + ref.insert(ref.begin() + pos, make_ref(v)); + } + break; + } + + case 7: + { // insert_index + int v = static_cast(read_u8(i)); + if (ref.empty()) + { + dq.insert_index(0, make_fast(v)); + ref.insert(ref.begin(), make_ref(v)); + } + else + { + std::size_t pos = static_cast(v) % (ref.size() + 1); + dq.insert_index(pos, make_fast(v)); + ref.insert(ref.begin() + pos, make_ref(v)); + } + break; + } + + case 8: + { // erase single + if (!ref.empty()) + { + std::size_t seed = read_u8(i); + std::size_t pos = seed % ref.size(); + dq.erase_index(pos); + ref.erase(ref.begin() + pos); + } + break; + } + + case 9: + { // erase range + if (ref.size() >= 2) + { + std::size_t a = read_u8(i); + std::size_t b = read_u8(i); + std::size_t lo = a % ref.size(); + std::size_t hi = b % (ref.size() - lo) + lo + 1; + if (hi > ref.size()) + { + hi = ref.size(); + } + dq.erase_index(lo, hi); + ref.erase(ref.begin() + lo, ref.begin() + hi); + } + break; + } + + case 10: + { // resize default + std::size_t n = read_u64(i); + if (n > 100000) + { + n = n % 100001; + } + dq.resize(n); + ref.resize(n); + break; + } + + case 11: + { // resize with value + std::size_t n = read_u64(i); + int v = static_cast(read_u8(i)); + if (n > 100000) + { + n = n % 100001; + } + dq.resize(n, make_fast(v)); + ref.resize(n, make_ref(v)); + break; + } + + case 12: + { // assign(count, val) + std::size_t n = read_u64(i); + int v = static_cast(read_u8(i)); + if (n > 100000) + { + n = n % 100001; + } + dq.assign(n, make_fast(v)); + ref.assign(n, make_ref(v)); + break; + } + + case 13: + { // assign_range + std::size_t n = read_u8(i); + std::vector tmp; + std::vector ref_tmp; + tmp.reserve(n); + ref_tmp.reserve(n); + for (std::size_t k = 0; k != n; ++k) + { + int v = static_cast(read_u8(i)); + tmp.emplace_back(make_fast(v)); + ref_tmp.emplace_back(make_ref(v)); + } + dq.assign_range(tmp); + ref.assign(ref_tmp.begin(), ref_tmp.end()); + break; + } + + case 14: + { // clear + dq.clear(); + ref.clear(); + break; + } + + case 15: + { // clear_destroy + dq.clear_destroy(); + ref.clear(); + break; + } + + case 16: + { // append_range + std::size_t n = read_u8(i); + std::vector tmp; + std::vector ref_tmp; + tmp.reserve(n); + ref_tmp.reserve(n); + for (std::size_t k = 0; k != n; ++k) + { + int v = static_cast(read_u8(i)); + tmp.emplace_back(make_fast(v)); + ref_tmp.emplace_back(make_ref(v)); + } + dq.append_range(tmp); + ref.insert(ref.end(), ref_tmp.begin(), ref_tmp.end()); + break; + } + + case 17: + { // prepend_range + std::size_t n = read_u8(i); + std::vector tmp; + std::vector ref_tmp; + tmp.reserve(n); + ref_tmp.reserve(n); + for (std::size_t k = 0; k != n; ++k) + { + int v = static_cast(read_u8(i)); + tmp.emplace_back(make_fast(v)); + ref_tmp.emplace_back(make_ref(v)); + } + dq.prepend_range(tmp); + ref.insert(ref.begin(), ref_tmp.begin(), ref_tmp.end()); + break; + } + } + + validate(); + } + + // Both deques go out of scope here — destructors fire. + // The tracked_object destructors already trap on double-destroy above. + // If we reach return 0, no double-free / use-after-free occurred. + + return 0; +} diff --git a/fuzzing/0007.containers/deque/fuzz_deque_trivial.cc b/fuzzing/0007.containers/deque/fuzz_deque_trivial.cc new file mode 100644 index 000000000..71be1373b --- /dev/null +++ b/fuzzing/0007.containers/deque/fuzz_deque_trivial.cc @@ -0,0 +1,327 @@ +#include +#include +#include +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(uint8_t const *data, size_t size) +{ + fast_io::deque dq; + std::deque ref; + + auto read_u8 = [&](size_t &i) -> uint8_t { + if (i >= size) + { + return 0; + } + return data[i++]; + }; + + auto read_u64 = [&](size_t &i) -> std::size_t { + if (i + 7 >= size) + { + return 0; + } + std::size_t v{}; + for (int k = 0; k < 8; ++k) + { + v |= static_cast(data[i++]) << (k * 8); + } + return v; + }; + + auto validate = [&]() { + if (dq.size() != ref.size()) + { + __builtin_trap(); + } + if (dq.empty() != ref.empty()) + { + __builtin_trap(); + } + for (std::size_t k = 0, sz = dq.size(); k != sz; ++k) + { + if (dq[k] != ref[k]) + { + __builtin_trap(); + } + } + if (!ref.empty()) + { + if (dq.front() != ref.front()) + { + __builtin_trap(); + } + if (dq.back() != ref.back()) + { + __builtin_trap(); + } + } + }; + + size_t i = 0; + while (i < size) + { + uint8_t op = read_u8(i); + + switch (op % 20u) + { + case 0: + { // push_back + std::size_t v = read_u64(i); + dq.push_back(v); + ref.push_back(v); + break; + } + + case 1: + { // push_front + std::size_t v = read_u64(i); + dq.push_front(v); + ref.push_front(v); + break; + } + + case 2: + { // pop_back + if (!ref.empty()) + { + dq.pop_back(); + ref.pop_back(); + } + break; + } + + case 3: + { // pop_front + if (!ref.empty()) + { + dq.pop_front(); + ref.pop_front(); + } + break; + } + + case 4: + { // emplace_back + std::size_t v = read_u64(i); + dq.emplace_back(v); + ref.emplace_back(v); + break; + } + + case 5: + { // emplace_front + std::size_t v = read_u64(i); + dq.emplace_front(v); + ref.emplace_front(v); + break; + } + + case 6: + { // insert (iterator) + std::size_t v = read_u64(i); + if (ref.empty()) + { + auto it = dq.insert(dq.cbegin(), v); + (void)it; + ref.insert(ref.begin(), v); + } + else + { + std::size_t pos = (v * 37) % (ref.size() + 1); + dq.insert(dq.cbegin() + pos, v); + ref.insert(ref.begin() + pos, v); + } + break; + } + + case 7: + { // insert_index + std::size_t v = read_u64(i); + if (ref.empty()) + { + dq.insert_index(0, v); + ref.insert(ref.begin(), v); + } + else + { + std::size_t pos = (v * 37) % (ref.size() + 1); + dq.insert_index(pos, v); + ref.insert(ref.begin() + pos, v); + } + break; + } + + case 8: + { // erase single index + if (!ref.empty()) + { + std::size_t seed = read_u8(i); + std::size_t pos = seed % ref.size(); + dq.erase_index(pos); + ref.erase(ref.begin() + pos); + } + break; + } + + case 9: + { // erase range index + if (ref.size() >= 2) + { + std::size_t a = read_u8(i); + std::size_t b = read_u8(i); + std::size_t lo = a % ref.size(); + std::size_t hi = b % (ref.size() - lo) + lo + 1; + if (hi > ref.size()) + { + hi = ref.size(); + } + dq.erase_index(lo, hi); + ref.erase(ref.begin() + lo, ref.begin() + hi); + } + break; + } + + case 10: + { // resize default + std::size_t n = read_u64(i); + if (n > 100000) + { + n = n % 100001; + } + dq.resize(n); + ref.resize(n); + break; + } + + case 11: + { // resize with value + std::size_t n = read_u64(i); + std::size_t v = read_u64(i); + if (n > 100000) + { + n = n % 100001; + } + dq.resize(n, v); + ref.resize(n, v); + break; + } + + case 12: + { // assign(count, val) + std::size_t n = read_u64(i); + std::size_t v = read_u64(i); + if (n > 100000) + { + n = n % 100001; + } + dq.assign(n, v); + ref.assign(n, v); + break; + } + + case 13: + { // assign_range + std::size_t n = read_u8(i); + std::vector tmp(n); + for (std::size_t k = 0; k != n; ++k) + { + tmp[k] = read_u64(i); + } + dq.assign_range(tmp); + ref.assign(tmp.begin(), tmp.end()); + break; + } + + case 14: + { // clear + dq.clear(); + ref.clear(); + break; + } + + case 15: + { // clear_destroy + dq.clear_destroy(); + ref.clear(); + break; + } + + case 16: + { // swap with another deque + std::size_t n = read_u8(i); + fast_io::deque other(n); + std::deque other_ref(n); + for (std::size_t k = 0; k != n; ++k) + { + other[k] = read_u64(i); + other_ref[k] = other[k]; + } + dq.swap(other); + std::swap(ref, other_ref); + break; + } + + case 17: + { // append_range + std::size_t n = read_u8(i); + std::vector tmp(n); + for (std::size_t k = 0; k != n; ++k) + { + tmp[k] = read_u64(i); + } + dq.append_range(tmp); + ref.insert(ref.end(), tmp.begin(), tmp.end()); + break; + } + + case 18: + { // prepend_range + std::size_t n = read_u8(i); + std::vector tmp(n); + for (std::size_t k = 0; k != n; ++k) + { + tmp[k] = read_u64(i); + } + dq.prepend_range(tmp); + ref.insert(ref.begin(), tmp.begin(), tmp.end()); + break; + } + + case 19: + { // emplace_index + if (ref.empty()) + { + std::size_t v = read_u64(i); + dq.emplace_index(0, v); + ref.emplace(ref.begin(), v); + } + else + { + std::size_t seed = read_u8(i); + std::size_t v = read_u64(i); + std::size_t pos = seed % ref.size(); + dq.emplace_index(pos, v); + ref.emplace(ref.begin() + pos, v); + } + break; + } + } + + validate(); + } + + // Final iterator validation + for (auto it1 = dq.begin(), it2 = ref.begin(), e1 = dq.end(), e2 = ref.end(); + it1 != e1 && it2 != e2; ++it1, ++it2) + { + if (*it1 != *it2) + { + __builtin_trap(); + } + } + + return 0; +} diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index 3a58b62ee..de3512ec2 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -3688,7 +3688,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE newed -= static_cast(oldsz - count); if constexpr (!::std::is_trivially_destructible_v) { - this->destroy_elements_range(newed, ed); + this->destroy_elements_range(newed.itercontent, ed.itercontent); } } else @@ -3829,7 +3829,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE } if constexpr (!::std::is_trivially_destructible_v) { - this->destroy_elements_range(first, last); + this->destroy_elements_range(first.itercontent, last.itercontent); } return this->erase_unchecked_nodestroy_impl(first, last, moveleft); } @@ -3864,7 +3864,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { if constexpr (!::std::is_trivially_destructible_v) { - ::std::destroy(pos.itercontent.curr_ptr); + ::std::destroy_at(pos.itercontent.curr_ptr); } return this->erase_unchecked_single_nodestroy_impl(pos, moveleft); } From 627e4d7ca8976916e38630e243f3a3a718cd0af4 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Fri, 15 May 2026 06:37:02 +0800 Subject: [PATCH 68/82] [deque] fuzz deque trivial --- .../0007.containers/deque/fuzz_deque_trivial.cc | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/fuzzing/0007.containers/deque/fuzz_deque_trivial.cc b/fuzzing/0007.containers/deque/fuzz_deque_trivial.cc index 71be1373b..595f47951 100644 --- a/fuzzing/0007.containers/deque/fuzz_deque_trivial.cc +++ b/fuzzing/0007.containers/deque/fuzz_deque_trivial.cc @@ -314,12 +314,18 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const *data, size_t size) } // Final iterator validation - for (auto it1 = dq.begin(), it2 = ref.begin(), e1 = dq.end(), e2 = ref.end(); - it1 != e1 && it2 != e2; ++it1, ++it2) { - if (*it1 != *it2) + auto it1 = dq.begin(); + auto it2 = ref.begin(); + auto e1 = dq.end(); + auto e2 = ref.end(); + for (; + it1 != e1 && it2 != e2; ++it1, ++it2) { - __builtin_trap(); + if (*it1 != *it2) + { + __builtin_trap(); + } } } From e4080dd5b413a7aae3b9e9ef1ebded8ac66dcfc5 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Fri, 15 May 2026 13:31:40 +0800 Subject: [PATCH 69/82] [deque] the rotation logic was correct but i forgot to remove the --- include/fast_io_dsal/impl/deque.h | 86 ++----------------------------- 1 file changed, 4 insertions(+), 82 deletions(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index de3512ec2..c34e3c07a 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -594,7 +594,7 @@ inline constexpr void deque_rebalance_or_grow_2x_after_blocks_impl(dequecontrolt controller.front_block.controller_ptr += diff; controller.back_block.controller_ptr += diff; controller.controller_block.controller_start_reserved_ptr += diff; - *(controller.controller_block.controller_after_reserved_ptr += diff) = nullptr; + ::std::construct_at(controller.controller_block.controller_after_reserved_ptr += diff, nullptr); } } } @@ -1257,81 +1257,7 @@ deque_erase_common_trivial_impl(::fast_io::containers::details::deque_controller controller.back_end_ptr = back_block.begin_ptr + blockbytes; return first; } -#if 0 -template -inline constexpr void deque_rebalance_or_grow_insertation_impl(dequecontroltype &controller, ::std::size_t extrablocks) noexcept -{ - auto const used_blocks_count{ - static_cast<::std::size_t>(controller.back_block.controller_ptr - controller.front_block.controller_ptr) + 1zu}; - - // total_slots_count is the distance (after - start). - // If start=0 and after=47, total_slots_count is 47, but there are 48 physical slots (0-47). - auto const total_slots_count{ - static_cast<::std::size_t>(controller.controller_block.controller_after_ptr - controller.controller_block.controller_start_ptr)}; - - // We MUST leave one slot for the nullptr sentinel. - // Usable capacity for pointers is exactly total_slots_count. - auto const usable_ptr_capacity{total_slots_count}; - - ::std::size_t new_used_blocks_count; -#if (defined(__GNUC__) || defined(__clang__)) - if (__builtin_add_overflow(used_blocks_count, extrablocks, __builtin_addressof(new_used_blocks_count))) [[unlikely]] - { - ::fast_io::fast_terminate(); - } -#else - if (::std::numeric_limits<::std::size_t>::max() - extrablocks < used_blocks_count) - { - ::fast_io::fast_terminate(); - } - new_used_blocks_count = used_blocks_count + extrablocks; -#endif - // Heuristic: If we are using more than half the map, grow it. - // This ensures we aren't rebalancing too frequently. - if ((total_slots_count >> 1u) < new_used_blocks_count) - { - ::std::size_t doubleslotsextra; - // ... (Keep your existing overflow-safe doubling logic here) ... - ::fast_io::containers::details::deque_grow_to_new_blocks_count_impl(controller, doubleslotsextra); - } - else - { - // BALANCE BLOCKS: The single-shift strategy - auto const cb_start{controller.controller_block.controller_start_ptr}; - auto const old_front{controller.front_block.controller_ptr}; - auto const old_back_plus_one{controller.back_block.controller_ptr + 1}; - - /* To center the used blocks: - Target Offset = (Total Usable Slots - Blocks to fit) / 2 - We use (usable_ptr_capacity - used_blocks_count) because index total_slots_count - is reserved for the nullptr sentinel. - */ - ::std::size_t const target_offset{(usable_ptr_capacity - used_blocks_count) >> 1u}; - auto const new_front{cb_start + target_offset}; - - if (new_front != old_front) - { - // 1. Move only the actual block pointers to the new centered location - ::fast_io::freestanding::overlapped_copy(old_front, old_back_plus_one, new_front); - - // 2. Calculate the pointer diff to update the controller state - ::std::ptrdiff_t const diff{new_front - old_front}; - - controller.front_block.controller_ptr += diff; - controller.back_block.controller_ptr += diff; - - // 3. Update the reserved range tracking - controller.controller_block.controller_start_reserved_ptr = new_front; - controller.controller_block.controller_after_reserved_ptr = new_front + used_blocks_count; - - // 4. THE FIX: Safely write the sentinel. - // Because of target_offset math, this is guaranteed to be <= controller_after_ptr. - *(controller.controller_block.controller_after_reserved_ptr) = nullptr; - } - } -} -#else template inline constexpr void deque_rebalance_or_grow_insertation_impl(dequecontroltype &controller, ::std::size_t extrablocks) noexcept { @@ -1419,7 +1345,6 @@ inline constexpr void deque_rebalance_or_grow_insertation_impl(dequecontroltype controller.front_block.controller_ptr += diff; controller.back_block.controller_ptr += diff; } -#if 0 auto const half_slotsextra_count{static_cast<::std::size_t>((total_slots_count + extrablocks) >> 1u)}; auto slots_pivot{controller.controller_block.controller_start_ptr + half_slotsextra_count}; if (slots_pivot != reserved_pivot) @@ -1430,12 +1355,10 @@ inline constexpr void deque_rebalance_or_grow_insertation_impl(dequecontroltype controller.front_block.controller_ptr += diff; controller.back_block.controller_ptr += diff; controller.controller_block.controller_start_reserved_ptr += diff; - *(controller.controller_block.controller_after_reserved_ptr += diff) = nullptr; + ::std::construct_at(controller.controller_block.controller_after_reserved_ptr += diff, nullptr); } -#endif } } -#endif template inline constexpr void deque_reserve_back_blocks_impl_none_empty(dequecontroltype &controller, ::std::size_t nb, ::std::size_t align, ::std::size_t blockbytes) noexcept @@ -1493,11 +1416,10 @@ inline constexpr void deque_reserve_back_blocks_impl_none_empty(dequecontroltype { ::std::construct_at(pos, static_cast(allocator::allocate_aligned(align, blockbytes))); } - *pos = nullptr; + ::std::construct_at(pos, nullptr); controller.controller_block.controller_after_reserved_ptr = pos; } } - if (controller.back_block.controller_ptr == controller.front_block.controller_ptr && controller.front_block.curr_ptr == controller.front_end_ptr) { auto front_block_controller_ptr{controller.front_block.controller_ptr + 1}; @@ -1655,7 +1577,7 @@ inline constexpr void deque_reserve_front_blocks_none_empty_impl(dequecontroltyp ::fast_io::freestanding::non_overlapped_copy_n(new_controller_after_reserved_ptr, back_borrowed_blocks_count, new_controller_start_reserved_ptr); - *(controller.controller_block.controller_after_reserved_ptr = new_controller_after_reserved_ptr) = nullptr; + ::std::construct_at(controller.controller_block.controller_after_reserved_ptr = new_controller_after_reserved_ptr, nullptr); // after this line Todo auto ed{new_controller_start_reserved_ptr}; From 034b8931e10d016f6941651728cc45bea88576d6 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Fri, 15 May 2026 16:39:24 +0800 Subject: [PATCH 70/82] [deque] clear() should be executed for assign too. --- include/fast_io_dsal/impl/deque.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index c34e3c07a..cf376720f 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -3565,10 +3565,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { if constexpr (::std::is_nothrow_copy_constructible_v) { - if constexpr (!::std::is_trivially_destructible_v) - { - this->clear(); - } + this->clear(); if (!count) { return; From e99fdfad8c2263d27a0f6a78bd47e2b8035ecd89 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Fri, 15 May 2026 20:09:41 +0800 Subject: [PATCH 71/82] [deque] allocate one more block for reserve even at front --- include/fast_io_dsal/impl/deque.h | 39 ++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index cf376720f..3ea316e79 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -1495,10 +1495,23 @@ inline constexpr void deque_reserve_back_spaces_impl(dequecontroltype &controlle } ::std::size_t nmblocksn{n - blocksn}; ::std::size_t back_more_blocks{nmblocksn / block_size}; - ::std::size_t const back_more_blocks_mod{nmblocksn % block_size}; ::std::size_t toallocate{back_more_blocks}; - if (back_more_blocks_mod) +#if defined(__GNUC__) || defined(__clang__) + if constexpr (true) + { + if (__builtin_add_overflow(toallocate, 1u, __builtin_addressof(toallocate))) + { + ::fast_io::fast_terminate(); + } + } + else +#endif { + constexpr ::std::size_t mxval{::std::numeric_limits<::std::size_t>::max()}; + if (toallocate == mxval) + { + ::fast_io::fast_terminate(); + } ++toallocate; } @@ -1628,8 +1641,22 @@ inline constexpr void deque_reserve_front_spaces_impl(dequecontroltype &controll ::std::size_t front_more_blocks{nmblocksn / block_size}; ::std::size_t const front_more_blocks_mod{nmblocksn % block_size}; ::std::size_t toallocate{front_more_blocks}; - if (front_more_blocks_mod) +#if defined(__GNUC__) || defined(__clang__) + if constexpr (true) { + if (__builtin_add_overflow(toallocate, 1u, __builtin_addressof(toallocate))) + { + ::fast_io::fast_terminate(); + } + } + else +#endif + { + constexpr ::std::size_t mxval{::std::numeric_limits<::std::size_t>::max()}; + if (toallocate == mxval) + { + ::fast_io::fast_terminate(); + } ++toallocate; } if consteval @@ -2516,10 +2543,6 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { ::std::destroy_at(controller.back_block.curr_ptr - 1); } -#if 0 - ::fast_io::io::debug_println(::std::source_location::current(), "\n", - ::fast_io::mnp::debug_view(*this)); -#endif if (--controller.back_block.curr_ptr == controller.back_block.begin_ptr) [[unlikely]] { this->back_backspace(); @@ -3600,6 +3623,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE return; } iterator newed; + if (count < oldsz) { auto ed{this->end()}; @@ -3612,7 +3636,6 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE } else { - this->reserve_back(count); auto ed{this->end()}; From 41b89bbd10fafaa3db988eeb6af92a01cf078709 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Sun, 24 May 2026 01:56:32 +0800 Subject: [PATCH 72/82] [skip ci] add some random shit implementation of deque --- .../deque/fuzz_deque_trivial.cc | 2 +- include/fast_io_dsal/impl/deque.h | 268 +++++++++++++----- 2 files changed, 194 insertions(+), 76 deletions(-) diff --git a/fuzzing/0007.containers/deque/fuzz_deque_trivial.cc b/fuzzing/0007.containers/deque/fuzz_deque_trivial.cc index 595f47951..96499739d 100644 --- a/fuzzing/0007.containers/deque/fuzz_deque_trivial.cc +++ b/fuzzing/0007.containers/deque/fuzz_deque_trivial.cc @@ -1,3 +1,4 @@ +#include #include #include #include @@ -64,7 +65,6 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const *data, size_t size) while (i < size) { uint8_t op = read_u8(i); - switch (op % 20u) { case 0: diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index 3ea316e79..b1c3fd5e2 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -543,61 +543,6 @@ inline constexpr void deque_grow_to_new_blocks_count_impl(dequecontroltype &cont controller.back_block.controller_ptr = new_start_ptr + (new_blocks_offset + (old_back_block_ptr_pos - old_start_reserved_ptr_pos)) + pivot_diff; } -template -inline constexpr void deque_rebalance_or_grow_2x_after_blocks_impl(dequecontroltype &controller) noexcept -{ - auto const used_blocks_count{ - static_cast<::std::size_t>(controller.back_block.controller_ptr - controller.front_block.controller_ptr) + 1zu}; - auto const total_slots_count{ - static_cast<::std::size_t>(controller.controller_block.controller_after_ptr - controller.controller_block.controller_start_ptr)}; - auto const half_slots_count{static_cast<::std::size_t>(total_slots_count >> 1u)}; - if (half_slots_count < used_blocks_count) // grow blocks - { - constexpr ::std::size_t mx{::std::numeric_limits<::std::size_t>::max()}; - constexpr ::std::size_t mxdv2m1{(mx >> 1u) - 1u}; - if (mxdv2m1 < total_slots_count) - { - ::fast_io::fast_terminate(); - } - ::fast_io::containers::details::deque_grow_to_new_blocks_count_impl(controller, - static_cast<::std::size_t>((total_slots_count << 1u) + 1u)); - } - else - { - // balance blocks - auto start_reserved_ptr{controller.controller_block.controller_start_reserved_ptr}; - auto after_reserved_ptr{controller.controller_block.controller_after_reserved_ptr}; - auto const reserved_blocks_count{ - static_cast<::std::size_t>(after_reserved_ptr - start_reserved_ptr)}; - auto const half_reserved_blocks_count{ - static_cast<::std::size_t>(reserved_blocks_count >> 1u)}; - auto reserved_pivot{start_reserved_ptr + half_reserved_blocks_count}; - auto const half_used_blocks_count{ - static_cast<::std::size_t>(used_blocks_count >> 1u)}; - auto used_blocks_pivot{controller.front_block.controller_ptr + half_used_blocks_count}; - if (used_blocks_pivot != reserved_pivot) - { - ::std::ptrdiff_t diff{reserved_pivot - used_blocks_pivot}; - auto rotate_pivot{diff < 0 ? start_reserved_ptr : after_reserved_ptr}; - rotate_pivot -= diff; - ::std::rotate(start_reserved_ptr, rotate_pivot, after_reserved_ptr); - controller.front_block.controller_ptr += diff; - controller.back_block.controller_ptr += diff; - } - - auto slots_pivot{controller.controller_block.controller_start_ptr + half_slots_count}; - if (slots_pivot != reserved_pivot) - { - ::std::ptrdiff_t diff{slots_pivot - reserved_pivot}; - ::fast_io::freestanding::overlapped_copy(start_reserved_ptr, - after_reserved_ptr, start_reserved_ptr + diff); - controller.front_block.controller_ptr += diff; - controller.back_block.controller_ptr += diff; - controller.controller_block.controller_start_reserved_ptr += diff; - ::std::construct_at(controller.controller_block.controller_after_reserved_ptr += diff, nullptr); - } - } -} template inline constexpr void deque_allocate_on_empty_common_with_n_impl(dequecontroltype &controller, ::std::size_t initial_allocated_block_counts, ::std::size_t align, ::std::size_t bytes) noexcept { @@ -1258,14 +1203,175 @@ deque_erase_common_trivial_impl(::fast_io::containers::details::deque_controller return first; } +template +inline constexpr void deque_grow_to_new_blocks_count_direction_impl(dequecontroltype &controller, ::std::size_t new_blocks_count_least, bool toleft) noexcept +{ + auto old_start_ptr{controller.controller_block.controller_start_ptr}; +#if __has_cpp_attribute(assume) + [[assume(old_start_ptr!=nullptr)]]; +#endif + auto old_start_reserved_ptr{controller.controller_block.controller_start_reserved_ptr}; + auto old_after_reserved_ptr{controller.controller_block.controller_after_reserved_ptr}; + + ::std::size_t const old_start_reserved_ptr_pos{static_cast<::std::size_t>(old_start_reserved_ptr - old_start_ptr)}; + ::std::size_t const old_after_ptr_pos{static_cast<::std::size_t>(controller.controller_block.controller_after_ptr - old_start_ptr)}; + auto old_front_block_controller_ptr{controller.front_block.controller_ptr}; + ::std::size_t const old_front_block_ptr_pos{static_cast<::std::size_t>(old_front_block_controller_ptr - old_start_ptr)}; + auto old_back_block_controller_ptr{controller.back_block.controller_ptr}; + ::std::size_t const old_back_block_ptr_pos{static_cast<::std::size_t>(old_back_block_controller_ptr - old_start_ptr)}; + + using block_typed_allocator = ::fast_io::typed_generic_allocator_adapter; + + ::std::size_t new_blocks_count_least_p1; +#if (defined(__GNUC__) || defined(__clang__)) + if constexpr (true) + { + if (__builtin_add_overflow(new_blocks_count_least, 1zu, __builtin_addressof(new_blocks_count_least_p1))) [[unlikely]] + { + ::fast_io::fast_terminate(); + } + } + else +#endif + { + constexpr ::std::size_t mx{::std::numeric_limits<::std::size_t>::max()}; + if (mx == new_blocks_count_least) + { + ::fast_io::fast_terminate(); + } + new_blocks_count_least_p1 = new_blocks_count_least + 1u; + } + + auto [new_start_ptr, new_blocks_count_p1] = block_typed_allocator::allocate_at_least(new_blocks_count_least_p1); + ::std::size_t new_blocks_count{static_cast<::std::size_t>(new_blocks_count_p1-1zu)}; + auto new_end_ptr{new_start_ptr + new_blocks_count}; + + decltype(new_end_ptr) destit; + decltype(destit) new_start_reserved_ptr; + decltype(destit) new_end_reserved_ptr; + decltype(destit) new_front_controller_ptr; + decltype(destit) new_back_controller_ptr; + if (toleft) + { + ::std::size_t diff{static_cast<::std::size_t>(old_after_reserved_ptr - old_start_reserved_ptr)}; + auto start_from_ptr{old_back_block_ptr_pos-diff}; + new_start_reserved_ptr = start_from_ptr; + new_end_reserved_ptr = new_end_ptr; + new_back_controller_ptr = new_end_ptr - 1; + new_front_controller_ptr = new_back_controller_ptr - static_cast<::std::size_t>(old_back_block_ptr_pos - old_front_block_ptr_pos); + start_from_ptr = ::fast_io::freestanding::non_overlapped_copy(old_back_block_controller_ptr + 1, + old_after_reserved_ptr, start_from_ptr); + destit = ::fast_io::freestanding::non_overlapped_copy(old_start_reserved_ptr, old_back_block_controller_ptr + 1, start_from_ptr); + } + else + { + destit = new_start_ptr; + destit = ::fast_io::freestanding::non_overlapped_copy(old_front_block_controller_ptr, + old_after_reserved_ptr, destit); + destit = ::fast_io::freestanding::non_overlapped_copy(old_start_reserved_ptr, + old_front_block_controller_ptr, destit); + new_start_reserved_ptr = new_start_ptr; + new_front_controller_ptr = new_start_ptr; + new_back_controller_ptr = new_start_ptr + static_cast<::std::size_t>(old_back_block_ptr_pos - old_front_block_ptr_pos); + new_end_reserved_ptr = destit; + } + ::std::construct_at(destit, nullptr); + controller.controller_block.controller_start_ptr = new_start_ptr; + controller.controller_block.controller_end_ptr = new_start_ptr + new_blocks_count; + controller.controller_block.controller_start_reserved_ptr = new_start_reserved_ptr; + controller.controller_block.controller_end_reserved_ptr = new_end_reserved_ptr; + controller.front_block.controller_ptr = new_front_controller_ptr; + controller.back_block.controller_ptr = new_back_controller_ptr; +} + +template +inline constexpr void deque_rebalance_or_grow_insertation_direction_impl(dequecontroltype &controller, ::std::size_t extrablocks, bool toleft) noexcept +{ + auto old_front_controller_ptr{controller.front_block.controller_ptr}; + auto old_back_controller_ptr{controller.back_block.controller_ptr}; + auto old_back_after_controller_ptr{old_back_controller_ptr + 1zu}; + ::std::size_t const old_elements_blocks_count{static_cast<::std::size_t>(old_back_after_controller_ptr - old_front_controller_ptr)}; + ::std::size_t new_elements_blocks_count; + +#if (defined(__GNUC__) || defined(__clang__)) + if constexpr (true) + { + if (__builtin_add_overflow(old_elements_blocks_count, extrablocks, __builtin_addressof(new_elements_blocks_count))) [[unlikely]] + { + ::fast_io::fast_terminate(); + } + } + else +#endif + { + constexpr ::std::size_t mx{::std::numeric_limits<::std::size_t>::max()}; + ::std::size_t const mx_sub_extrablocks{mx - extrablocks}; + if (mx_sub_extrablocks < old_elements_blocks_count) + { + ::fast_io::fast_terminate(); + } + new_elements_blocks_count = old_elements_blocks_count + extrablocks; + } + auto start_ptr{controller.controller_block.controller_start_ptr}; + auto after_ptr{controller.controller_block.controller_after_ptr}; + ::std::size_t const capacity_blocks_count_direction{ + toleft? static_cast<::std::size_t>(old_back_after_controller_ptr - start_ptr): + static_cast<::std::size_t>(after_ptr - old_front_controller_ptr)}; + if (capacity_blocks_count < new_elements_blocks_count) + { + ::std::size_t double_capacity_blocks_count{capacity_blocks_count}; + if ((new_elements_blocks_count>>1u) < double_capacity_blocks_count) + { +#if (defined(__GNUC__) || defined(__clang__)) + if constexpr (true) + { + if (__builtin_add_overflow(double_capacity_blocks_count, double_capacity_blocks_count, __builtin_addressof(double_capacity_blocks_count))) [[unlikely]] + { + ::fast_io::fast_terminate(); + } + } + else +#endif + { + constexpr ::std::size_t mx{::std::numeric_limits<::std::size_t>::max()}; + ::std::size_t const mx_sub_extrablocks{mx - double_capacity_blocks_count}; + if (mx_sub_extrablocks < double_capacity_blocks_count) + { + ::fast_io::fast_terminate(); + } + double_capacity_blocks_count<<=1u; + } + new_elements_blocks_count = double_capacity_blocks_count; + } + ::fast_io::containers::details::deque_grow_to_new_blocks_count_direction_impl(controller, new_elements_blocks_count, toleft); + return; + } + else + { + auto start_reserved_ptr{controller.controller_block.controller_start_reserved_ptr}; + auto after_reserved_ptr{controller.controller_block.controller_after_reserved_ptr}; + auto rotate_pivot{toleft? old_front_controller_ptr : old_back_controller_ptr + 1}; + ::std::size_t reservedcount{static_cast<::std::size_t>(after_reserved_ptr-start_reserved_ptr)}; + auto copy_pivot{toleft? start_ptr : after_ptr-reservedcount}; + auto new_front_ptr{::std::rotate(start_reserved_ptr, rotate_pivot, after_reserved_ptr)}; + ::std::construct_at(::fast_io::freestanding::overlapped_copy(start_reserved_ptr,after_reserved_ptr,copy_pivot), nullptr); + + controller.controller_block.controller_start_reserved_ptr = copy_pivot; + controller.controller_block.controller_after_reserved_ptr = copy_pivot + reservedcount; + controller.front_block.controller_ptr = new_front_ptr; + controller.back_block.controller_ptr = new_front_ptr + old_elements_blocks_count; + } +} + template inline constexpr void deque_rebalance_or_grow_insertation_impl(dequecontroltype &controller, ::std::size_t extrablocks) noexcept { // ignore overchecked first auto const used_blocks_count{ static_cast<::std::size_t>(controller.back_block.controller_ptr - controller.front_block.controller_ptr) + 1zu}; + auto start_ptr{controller.controller_block.controller_start_ptr}; auto const total_slots_count{ - static_cast<::std::size_t>(controller.controller_block.controller_after_ptr - controller.controller_block.controller_start_ptr)}; + static_cast<::std::size_t>(controller.controller_block.controller_after_ptr - start_ptr)}; auto const half_slots_count{static_cast<::std::size_t>(total_slots_count >> 1u)}; ::std::size_t new_used_blocks_count; @@ -1288,17 +1394,20 @@ inline constexpr void deque_rebalance_or_grow_insertation_impl(dequecontroltype } new_used_blocks_count = used_blocks_count + extrablocks; } - + auto start_reserved_ptr{controller.controller_block.controller_start_reserved_ptr}; + auto after_reserved_ptr{controller.controller_block.controller_after_reserved_ptr}; + auto const reserved_count{ + static_cast<::std::size_t>(after_reserved_ptr - start_reserved_ptr)}; + if (new_used_blocks_count < reserved_count) + { + new_used_blocks_count = reserved_count; + } if (half_slots_count < new_used_blocks_count) // grow blocks { - ::std::size_t doubleslotsextra; + ::std::size_t doubleslotsextra{new_used_blocks_count}; #if (defined(__GNUC__) || defined(__clang__)) if constexpr (true) { - if (__builtin_add_overflow(total_slots_count, extrablocks, __builtin_addressof(doubleslotsextra))) - { - ::fast_io::fast_terminate(); - } if (__builtin_add_overflow(doubleslotsextra, doubleslotsextra, __builtin_addressof(doubleslotsextra))) { ::fast_io::fast_terminate(); @@ -1308,12 +1417,6 @@ inline constexpr void deque_rebalance_or_grow_insertation_impl(dequecontroltype #endif { constexpr ::std::size_t mx{::std::numeric_limits<::std::size_t>::max()}; - ::std::size_t mx_total_slots{mx - extrablocks}; - if (mx_total_slots < total_slots_count) - { - ::fast_io::fast_terminate(); - } - doubleslotsextra = extrablocks + total_slots_count; constexpr ::std::size_t mxdv2m1{(mx >> 1u)}; if (mxdv2m1 < doubleslotsextra) { @@ -1325,11 +1428,8 @@ inline constexpr void deque_rebalance_or_grow_insertation_impl(dequecontroltype } else { +#if 1 // balance blocks - auto start_reserved_ptr{controller.controller_block.controller_start_reserved_ptr}; - auto after_reserved_ptr{controller.controller_block.controller_after_reserved_ptr}; - auto const reserved_blocks_count{ - static_cast<::std::size_t>(after_reserved_ptr - start_reserved_ptr)}; auto const half_reserved_blocks_count{ static_cast<::std::size_t>(reserved_blocks_count >> 1u)}; auto reserved_pivot{start_reserved_ptr + half_reserved_blocks_count}; @@ -1357,6 +1457,24 @@ inline constexpr void deque_rebalance_or_grow_insertation_impl(dequecontroltype controller.controller_block.controller_start_reserved_ptr += diff; ::std::construct_at(controller.controller_block.controller_after_reserved_ptr += diff, nullptr); } +#else + ::std::size_t extra_reserved_count{reserved_count}; + ::std::size_t half_extra_reserved_count{extra_reserved_count>>1u}; + ::std::size_t start_reserved_pos{static_cast<::std::size_t>(start_reserved_ptr-start_ptr)}; + ::std::ptrdiff_t reserved_pivot{static_cast<::std::ptrdiff_t>(start_reserved_pos+half_extra_reserved_count)}; + ::std::ptrdiff_t pivot{static_cast<::std::ptrdiff_t>(half_slots_count)}; + ::std::ptrdiff_t diff{pivot - reserved_pivot}; + if(diff) + { + ::fast_io::freestanding::overlapped_copy(start_reserved_ptr, + after_reserved_ptr, start_reserved_ptr + diff); + controller.front_block.controller_ptr += diff; + controller.back_block.controller_ptr += diff; + controller.controller_block.controller_start_reserved_ptr += diff; + ::std::construct_at(controller.controller_block.controller_after_reserved_ptr += diff, nullptr); + } + +#endif } } @@ -1411,7 +1529,7 @@ inline constexpr void deque_reserve_back_blocks_impl_none_empty(dequecontroltype front_borrowed_blocks_count, pos); controller.controller_block.controller_start_reserved_ptr = - controller_start_reserved_ptr + front_borrowed_blocks_count; + controller_start_reserved_ptr + front_borrowed_blocks_count; g for (auto e{pos + to_allocate_blocks}; pos != e; ++pos) { ::std::construct_at(pos, static_cast(allocator::allocate_aligned(align, blockbytes))); @@ -2987,8 +3105,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE auto thisbg{this->begin()}; auto posit{thisbg + pos}; auto thisbgrgsize{thisbg - rgsize}; - auto thisbgrgsizenew{::fast_io::freestanding::uninitialized_relocate(thisbg, - posit, thisbgrgsize)}; + auto thisbgrgsizenew{::fast_io::freestanding::uninitialized_relocate(thisbg, posit, thisbgrgsize)}; this->controller.front_block = thisbgrgsize.itercontent; this->controller.front_end_ptr = thisbgrgsize.itercontent.begin_ptr + block_size; return {pos, thisbgrgsizenew}; @@ -3192,6 +3309,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { return; } + ::fast_io::io::debug_println(::std::source_location::current(), " rgsize=",rgsize); this->insert_range_front_impl(0, ::std::forward(rg), rgsize); } else From f6e852b804c4d4e9feb448bf9582c9f0eb97324d Mon Sep 17 00:00:00 2001 From: trcrsired Date: Mon, 25 May 2026 07:03:45 +0800 Subject: [PATCH 73/82] [deque] try a new strategy for grow --- include/fast_io_dsal/impl/deque.h | 300 ++++++++++-------------------- 1 file changed, 97 insertions(+), 203 deletions(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index b1c3fd5e2..fdfb20413 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -1203,89 +1203,116 @@ deque_erase_common_trivial_impl(::fast_io::containers::details::deque_controller return first; } -template -inline constexpr void deque_grow_to_new_blocks_count_direction_impl(dequecontroltype &controller, ::std::size_t new_blocks_count_least, bool toleft) noexcept +inline constexpr ::std::size_t deque_new_blocks_count_compute_impl(::std::size_t new_blocks_count_least, ::std::size_t blocks, ::std::size_t reserved_space_at_opposite_direction) noexcept { - auto old_start_ptr{controller.controller_block.controller_start_ptr}; -#if __has_cpp_attribute(assume) - [[assume(old_start_ptr!=nullptr)]]; -#endif - auto old_start_reserved_ptr{controller.controller_block.controller_start_reserved_ptr}; - auto old_after_reserved_ptr{controller.controller_block.controller_after_reserved_ptr}; - - ::std::size_t const old_start_reserved_ptr_pos{static_cast<::std::size_t>(old_start_reserved_ptr - old_start_ptr)}; - ::std::size_t const old_after_ptr_pos{static_cast<::std::size_t>(controller.controller_block.controller_after_ptr - old_start_ptr)}; - auto old_front_block_controller_ptr{controller.front_block.controller_ptr}; - ::std::size_t const old_front_block_ptr_pos{static_cast<::std::size_t>(old_front_block_controller_ptr - old_start_ptr)}; - auto old_back_block_controller_ptr{controller.back_block.controller_ptr}; - ::std::size_t const old_back_block_ptr_pos{static_cast<::std::size_t>(old_back_block_controller_ptr - old_start_ptr)}; - - using block_typed_allocator = ::fast_io::typed_generic_allocator_adapter; - - ::std::size_t new_blocks_count_least_p1; #if (defined(__GNUC__) || defined(__clang__)) if constexpr (true) { - if (__builtin_add_overflow(new_blocks_count_least, 1zu, __builtin_addressof(new_blocks_count_least_p1))) [[unlikely]] + ::std::size_t blocksx2; + if (__builtin_add_overflow(blocks, blocks, __builtin_addressof(blocksx2))) + { + ::fast_io::fast_terminate(); + } + if (reserved_space_at_opposite_direction < blocksx2) + { + reserved_space_at_opposite_direction = blocksx2; + } + if (__builtin_add_overflow(new_blocks_count_least, reserved_space_at_opposite_direction, __builtin_addressof(reserved_space_at_opposite_direction))) + { + ::fast_io::fast_terminate(); + } + if (__builtin_add_overflow(reserved_space_at_opposite_direction, 1u, __builtin_addressof(reserved_space_at_opposite_direction))) { ::fast_io::fast_terminate(); } + return reserved_space_at_opposite_direction; } else #endif { + ::std::size_t blocksx2{blocks + blocks}; + if (blocksx2 < blocks) + { + ::fast_io::fast_terminate(); + } + if (reserved_space_at_opposite_direction < blocksx2) + { + reserved_space_at_opposite_direction = blocksx2; + } constexpr ::std::size_t mx{::std::numeric_limits<::std::size_t>::max()}; - if (mx == new_blocks_count_least) + ::std::size_t const mxm{mx - new_blocks_count_least}; + if (mxm < reserved_space_at_opposite_direction) + { + ::fast_io::fast_terminate(); + } + reserved_space_at_opposite_direction += new_blocks_count_least; + if (mx == reserved_space_at_opposite_direction) { ::fast_io::fast_terminate(); } - new_blocks_count_least_p1 = new_blocks_count_least + 1u; + ++reserved_space_at_opposite_direction; + return reserved_space_at_opposite_direction; } +} + +template +inline constexpr void deque_grow_to_new_blocks_count_direction_impl(dequecontroltype &controller, ::std::size_t new_blocks_count_least, bool no_space_at_back) noexcept +{ + auto old_start_ptr{controller.controller_block.controller_start_ptr}; +#if __has_cpp_attribute(assume) + [[assume(old_start_ptr != nullptr)]]; +#endif + auto old_after_ptr{controller.controller_block.controller_after_ptr}; + auto old_start_reserved_ptr{controller.controller_block.controller_start_reserved_ptr}; + auto old_after_reserved_ptr{controller.controller_block.controller_after_reserved_ptr}; + auto old_front_block_controller_ptr{controller.front_block.controller_ptr}; + auto old_back_block_controller_ptr{controller.back_block.controller_ptr}; + auto old_back_block_controller_ptr_p1{old_back_block_controller_ptr + 1}; + + ::std::size_t old_start_reserved_pos{ + static_cast<::std::size_t>(old_start_reserved_ptr - old_start_ptr)}; + ::std::size_t old_after_reserved_pos{ + static_cast<::std::size_t>(old_after_reserved_ptr - old_start_ptr)}; + + ::std::size_t old_front_block_controller_pos{ + static_cast<::std::size_t>(old_front_block_controller_ptr - old_start_ptr)}; + ::std::size_t old_back_block_controller_pos{ + static_cast<::std::size_t>(old_back_block_controller_ptr - old_start_ptr)}; - auto [new_start_ptr, new_blocks_count_p1] = block_typed_allocator::allocate_at_least(new_blocks_count_least_p1); - ::std::size_t new_blocks_count{static_cast<::std::size_t>(new_blocks_count_p1-1zu)}; - auto new_end_ptr{new_start_ptr + new_blocks_count}; + ::std::size_t old_blocks_count{static_cast<::std::size_t>(old_back_block_controller_ptr_p1 - old_front_block_controller_ptr)}; + ::std::size_t to_allocated_blocks_least_p1{::fast_io::containers::details::deque_new_blocks_count_compute_impl(new_blocks_count_least, + old_blocks_count, (no_space_at_back ? static_cast<::std::size_t>(old_back_block_controller_ptr_p1 - old_start_reserved_ptr) : static_cast<::std::size_t>(old_after_reserved_ptr - old_front_block_controller_ptr)))}; + using block_typed_allocator = ::fast_io::typed_generic_allocator_adapter; + auto [new_start_ptr, allocated_blocks_p1] = block_typed_allocator::allocate_at_least(to_allocated_blocks_least_p1); - decltype(new_end_ptr) destit; - decltype(destit) new_start_reserved_ptr; - decltype(destit) new_end_reserved_ptr; - decltype(destit) new_front_controller_ptr; - decltype(destit) new_back_controller_ptr; - if (toleft) + ::std::size_t allocated_blocks{allocated_blocks_p1}; + --allocated_blocks; + ::std::size_t new_start_reserved_ptr_pos; + if (no_space_at_back) { - ::std::size_t diff{static_cast<::std::size_t>(old_after_reserved_ptr - old_start_reserved_ptr)}; - auto start_from_ptr{old_back_block_ptr_pos-diff}; - new_start_reserved_ptr = start_from_ptr; - new_end_reserved_ptr = new_end_ptr; - new_back_controller_ptr = new_end_ptr - 1; - new_front_controller_ptr = new_back_controller_ptr - static_cast<::std::size_t>(old_back_block_ptr_pos - old_front_block_ptr_pos); - start_from_ptr = ::fast_io::freestanding::non_overlapped_copy(old_back_block_controller_ptr + 1, - old_after_reserved_ptr, start_from_ptr); - destit = ::fast_io::freestanding::non_overlapped_copy(old_start_reserved_ptr, old_back_block_controller_ptr + 1, start_from_ptr); + new_start_reserved_ptr_pos = allocated_blocks - new_blocks_count_least - static_cast<::std::size_t>(old_front_block_controller_pos - old_start_reserved_pos); } else { - destit = new_start_ptr; - destit = ::fast_io::freestanding::non_overlapped_copy(old_front_block_controller_ptr, - old_after_reserved_ptr, destit); - destit = ::fast_io::freestanding::non_overlapped_copy(old_start_reserved_ptr, - old_front_block_controller_ptr, destit); - new_start_reserved_ptr = new_start_ptr; - new_front_controller_ptr = new_start_ptr; - new_back_controller_ptr = new_start_ptr + static_cast<::std::size_t>(old_back_block_ptr_pos - old_front_block_ptr_pos); - new_end_reserved_ptr = destit; - } - ::std::construct_at(destit, nullptr); + new_start_reserved_ptr_pos = new_blocks_count_least - static_cast<::std::size_t>(old_back_block_controller_pos - old_start_reserved_pos); + } + auto new_start_reserved_ptr{new_start_ptr + new_start_reserved_ptr_pos}; + auto ed{::fast_io::freestanding::non_overlapped_copy(old_start_ptr + old_start_reserved_pos, old_start_ptr + old_after_reserved_pos, new_start_reserved_ptr)}; + ::std::construct_at(ed, nullptr); + controller.controller_block.controller_start_ptr = new_start_ptr; - controller.controller_block.controller_end_ptr = new_start_ptr + new_blocks_count; + controller.controller_block.controller_after_ptr = new_start_ptr + allocated_blocks; controller.controller_block.controller_start_reserved_ptr = new_start_reserved_ptr; - controller.controller_block.controller_end_reserved_ptr = new_end_reserved_ptr; - controller.front_block.controller_ptr = new_front_controller_ptr; - controller.back_block.controller_ptr = new_back_controller_ptr; + controller.controller_block.controller_after_reserved_ptr = ed; + controller.front_block.controller_ptr = new_start_reserved_ptr + static_cast<::std::size_t>(old_front_block_controller_pos - old_start_reserved_pos); + controller.back_block.controller_ptr = new_start_reserved_ptr + static_cast<::std::size_t>(old_back_block_controller_pos - old_start_reserved_pos); + + block_typed_allocator::deallocate_n(old_start_ptr, + static_cast<::std::size_t>(static_cast<::std::size_t>(old_after_ptr - old_start_ptr) + 1zu)); } template -inline constexpr void deque_rebalance_or_grow_insertation_direction_impl(dequecontroltype &controller, ::std::size_t extrablocks, bool toleft) noexcept +inline constexpr void deque_rebalance_or_grow_insertation_direction_impl(dequecontroltype &controller, ::std::size_t extrablocks, bool no_space_at_back) noexcept { auto old_front_controller_ptr{controller.front_block.controller_ptr}; auto old_back_controller_ptr{controller.back_block.controller_ptr}; @@ -1314,71 +1341,14 @@ inline constexpr void deque_rebalance_or_grow_insertation_direction_impl(dequeco } auto start_ptr{controller.controller_block.controller_start_ptr}; auto after_ptr{controller.controller_block.controller_after_ptr}; - ::std::size_t const capacity_blocks_count_direction{ - toleft? static_cast<::std::size_t>(old_back_after_controller_ptr - start_ptr): - static_cast<::std::size_t>(after_ptr - old_front_controller_ptr)}; - if (capacity_blocks_count < new_elements_blocks_count) - { - ::std::size_t double_capacity_blocks_count{capacity_blocks_count}; - if ((new_elements_blocks_count>>1u) < double_capacity_blocks_count) - { -#if (defined(__GNUC__) || defined(__clang__)) - if constexpr (true) - { - if (__builtin_add_overflow(double_capacity_blocks_count, double_capacity_blocks_count, __builtin_addressof(double_capacity_blocks_count))) [[unlikely]] - { - ::fast_io::fast_terminate(); - } - } - else -#endif - { - constexpr ::std::size_t mx{::std::numeric_limits<::std::size_t>::max()}; - ::std::size_t const mx_sub_extrablocks{mx - double_capacity_blocks_count}; - if (mx_sub_extrablocks < double_capacity_blocks_count) - { - ::fast_io::fast_terminate(); - } - double_capacity_blocks_count<<=1u; - } - new_elements_blocks_count = double_capacity_blocks_count; - } - ::fast_io::containers::details::deque_grow_to_new_blocks_count_direction_impl(controller, new_elements_blocks_count, toleft); - return; - } - else - { - auto start_reserved_ptr{controller.controller_block.controller_start_reserved_ptr}; - auto after_reserved_ptr{controller.controller_block.controller_after_reserved_ptr}; - auto rotate_pivot{toleft? old_front_controller_ptr : old_back_controller_ptr + 1}; - ::std::size_t reservedcount{static_cast<::std::size_t>(after_reserved_ptr-start_reserved_ptr)}; - auto copy_pivot{toleft? start_ptr : after_ptr-reservedcount}; - auto new_front_ptr{::std::rotate(start_reserved_ptr, rotate_pivot, after_reserved_ptr)}; - ::std::construct_at(::fast_io::freestanding::overlapped_copy(start_reserved_ptr,after_reserved_ptr,copy_pivot), nullptr); - - controller.controller_block.controller_start_reserved_ptr = copy_pivot; - controller.controller_block.controller_after_reserved_ptr = copy_pivot + reservedcount; - controller.front_block.controller_ptr = new_front_ptr; - controller.back_block.controller_ptr = new_front_ptr + old_elements_blocks_count; - } -} - -template -inline constexpr void deque_rebalance_or_grow_insertation_impl(dequecontroltype &controller, ::std::size_t extrablocks) noexcept -{ - // ignore overchecked first - auto const used_blocks_count{ - static_cast<::std::size_t>(controller.back_block.controller_ptr - controller.front_block.controller_ptr) + 1zu}; - auto start_ptr{controller.controller_block.controller_start_ptr}; - auto const total_slots_count{ - static_cast<::std::size_t>(controller.controller_block.controller_after_ptr - start_ptr)}; - auto const half_slots_count{static_cast<::std::size_t>(total_slots_count >> 1u)}; - ::std::size_t new_used_blocks_count; + ::std::size_t capacity_blocks_count_direction{ + no_space_at_back ? static_cast<::std::size_t>(after_ptr - old_front_controller_ptr) : static_cast<::std::size_t>(old_back_after_controller_ptr - start_ptr)}; + ::std::size_t doubleslotsextra{capacity_blocks_count_direction}; #if (defined(__GNUC__) || defined(__clang__)) if constexpr (true) { - if (__builtin_add_overflow(used_blocks_count, extrablocks, __builtin_addressof(new_used_blocks_count))) [[unlikely]] + if (__builtin_add_overflow(capacity_blocks_count_direction, capacity_blocks_count_direction, __builtin_addressof(capacity_blocks_count_direction))) { ::fast_io::fast_terminate(); } @@ -1387,95 +1357,19 @@ inline constexpr void deque_rebalance_or_grow_insertation_impl(dequecontroltype #endif { constexpr ::std::size_t mx{::std::numeric_limits<::std::size_t>::max()}; - ::std::size_t const mx_sub_extrablocks{mx - extrablocks}; - if (mx_sub_extrablocks < used_blocks_count) + constexpr ::std::size_t mxdv2m1{(mx >> 1u)}; + if (mxdv2m1 < capacity_blocks_count_direction) { ::fast_io::fast_terminate(); } - new_used_blocks_count = used_blocks_count + extrablocks; - } - auto start_reserved_ptr{controller.controller_block.controller_start_reserved_ptr}; - auto after_reserved_ptr{controller.controller_block.controller_after_reserved_ptr}; - auto const reserved_count{ - static_cast<::std::size_t>(after_reserved_ptr - start_reserved_ptr)}; - if (new_used_blocks_count < reserved_count) - { - new_used_blocks_count = reserved_count; + capacity_blocks_count_direction <<= 1u; } - if (half_slots_count < new_used_blocks_count) // grow blocks + if (capacity_blocks_count_direction < new_elements_blocks_count) { - ::std::size_t doubleslotsextra{new_used_blocks_count}; -#if (defined(__GNUC__) || defined(__clang__)) - if constexpr (true) - { - if (__builtin_add_overflow(doubleslotsextra, doubleslotsextra, __builtin_addressof(doubleslotsextra))) - { - ::fast_io::fast_terminate(); - } - } - else -#endif - { - constexpr ::std::size_t mx{::std::numeric_limits<::std::size_t>::max()}; - constexpr ::std::size_t mxdv2m1{(mx >> 1u)}; - if (mxdv2m1 < doubleslotsextra) - { - ::fast_io::fast_terminate(); - } - doubleslotsextra <<= 1u; - } - ::fast_io::containers::details::deque_grow_to_new_blocks_count_impl(controller, doubleslotsextra); + capacity_blocks_count_direction = new_elements_blocks_count; } - else - { -#if 1 - // balance blocks - auto const half_reserved_blocks_count{ - static_cast<::std::size_t>(reserved_blocks_count >> 1u)}; - auto reserved_pivot{start_reserved_ptr + half_reserved_blocks_count}; - auto const half_used_blocks_count{ - static_cast<::std::size_t>(used_blocks_count >> 1u)}; // this place needs to deal with extra block - auto used_blocks_pivot{controller.front_block.controller_ptr + half_used_blocks_count}; - if (used_blocks_pivot != reserved_pivot) - { - ::std::ptrdiff_t diff{reserved_pivot - used_blocks_pivot}; - auto rotate_pivot{diff < 0 ? start_reserved_ptr : after_reserved_ptr}; - rotate_pivot -= diff; - ::std::rotate(start_reserved_ptr, rotate_pivot, after_reserved_ptr); - controller.front_block.controller_ptr += diff; - controller.back_block.controller_ptr += diff; - } - auto const half_slotsextra_count{static_cast<::std::size_t>((total_slots_count + extrablocks) >> 1u)}; - auto slots_pivot{controller.controller_block.controller_start_ptr + half_slotsextra_count}; - if (slots_pivot != reserved_pivot) - { - ::std::ptrdiff_t diff{slots_pivot - reserved_pivot}; - ::fast_io::freestanding::overlapped_copy(start_reserved_ptr, - after_reserved_ptr, start_reserved_ptr + diff); - controller.front_block.controller_ptr += diff; - controller.back_block.controller_ptr += diff; - controller.controller_block.controller_start_reserved_ptr += diff; - ::std::construct_at(controller.controller_block.controller_after_reserved_ptr += diff, nullptr); - } -#else - ::std::size_t extra_reserved_count{reserved_count}; - ::std::size_t half_extra_reserved_count{extra_reserved_count>>1u}; - ::std::size_t start_reserved_pos{static_cast<::std::size_t>(start_reserved_ptr-start_ptr)}; - ::std::ptrdiff_t reserved_pivot{static_cast<::std::ptrdiff_t>(start_reserved_pos+half_extra_reserved_count)}; - ::std::ptrdiff_t pivot{static_cast<::std::ptrdiff_t>(half_slots_count)}; - ::std::ptrdiff_t diff{pivot - reserved_pivot}; - if(diff) - { - ::fast_io::freestanding::overlapped_copy(start_reserved_ptr, - after_reserved_ptr, start_reserved_ptr + diff); - controller.front_block.controller_ptr += diff; - controller.back_block.controller_ptr += diff; - controller.controller_block.controller_start_reserved_ptr += diff; - ::std::construct_at(controller.controller_block.controller_after_reserved_ptr += diff, nullptr); - } -#endif - } + return ::fast_io::containers::details::deque_grow_to_new_blocks_count_direction_impl(controller, capacity_blocks_count_direction, no_space_at_back); } template @@ -1499,7 +1393,7 @@ inline constexpr void deque_reserve_back_blocks_impl_none_empty(dequecontroltype controller.back_block.controller_ptr)}; if (distance_back_to_after <= nb) { - ::fast_io::containers::details::deque_rebalance_or_grow_insertation_impl(controller, nb); + ::fast_io::containers::details::deque_rebalance_or_grow_insertation_direction_impl(controller, nb, true); } ::std::size_t diff_to_after_ptr2 = static_cast<::std::size_t>( @@ -1529,7 +1423,7 @@ inline constexpr void deque_reserve_back_blocks_impl_none_empty(dequecontroltype front_borrowed_blocks_count, pos); controller.controller_block.controller_start_reserved_ptr = - controller_start_reserved_ptr + front_borrowed_blocks_count; g + controller_start_reserved_ptr + front_borrowed_blocks_count; for (auto e{pos + to_allocate_blocks}; pos != e; ++pos) { ::std::construct_at(pos, static_cast(allocator::allocate_aligned(align, blockbytes))); @@ -1671,7 +1565,7 @@ inline constexpr void deque_reserve_front_blocks_none_empty_impl(dequecontroltyp controller.controller_block.controller_start_ptr)}; if (distance_front_to_start < nb) { - ::fast_io::containers::details::deque_rebalance_or_grow_insertation_impl(controller, nb); + ::fast_io::containers::details::deque_rebalance_or_grow_insertation_direction_impl(controller, nb, false); } ::std::size_t diff_to_start_ptr2 = static_cast<::std::size_t>( @@ -3309,7 +3203,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { return; } - ::fast_io::io::debug_println(::std::source_location::current(), " rgsize=",rgsize); + ::fast_io::io::debug_println(::std::source_location::current(), " rgsize=", rgsize); this->insert_range_front_impl(0, ::std::forward(rg), rgsize); } else From 68520dceda924d7a17794b33ef10136795e0545a Mon Sep 17 00:00:00 2001 From: trcrsired Date: Mon, 25 May 2026 07:14:43 +0800 Subject: [PATCH 74/82] [deque] try to implement new logic by just detecting the size and merge logic --- include/fast_io_dsal/impl/deque.h | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index fdfb20413..cbfd0a005 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -1283,10 +1283,24 @@ inline constexpr void deque_grow_to_new_blocks_count_direction_impl(dequecontrol ::std::size_t to_allocated_blocks_least_p1{::fast_io::containers::details::deque_new_blocks_count_compute_impl(new_blocks_count_least, old_blocks_count, (no_space_at_back ? static_cast<::std::size_t>(old_back_block_controller_ptr_p1 - old_start_reserved_ptr) : static_cast<::std::size_t>(old_after_reserved_ptr - old_front_block_controller_ptr)))}; using block_typed_allocator = ::fast_io::typed_generic_allocator_adapter; - auto [new_start_ptr, allocated_blocks_p1] = block_typed_allocator::allocate_at_least(to_allocated_blocks_least_p1); + decltype(old_start_ptr) new_start_ptr; + ::std::size_t allocated_blocks; - ::std::size_t allocated_blocks{allocated_blocks_p1}; - --allocated_blocks; + ::std::size_t old_allocated_sz{static_cast<::std::size_t>(old_after_ptr - old_start_ptr)}; + ::std::size_t old_allocated_sz_p1{old_allocated_sz + 1zu}; + bool is_allocating_new_block{old_allocated_sz_p1 < to_allocated_blocks_least_p1}; + if (is_allocating_new_block) + { + auto allocate_result = block_typed_allocator::allocate_at_least(to_allocated_blocks_least_p1); + new_start_ptr = allocate_result.ptr; + allocated_blocks = allocate_result.count; + --allocated_blocks; + } + else + { + new_start_ptr = old_start_ptr; + allocated_blocks = old_allocated_sz; + } ::std::size_t new_start_reserved_ptr_pos; if (no_space_at_back) { @@ -1297,7 +1311,7 @@ inline constexpr void deque_grow_to_new_blocks_count_direction_impl(dequecontrol new_start_reserved_ptr_pos = new_blocks_count_least - static_cast<::std::size_t>(old_back_block_controller_pos - old_start_reserved_pos); } auto new_start_reserved_ptr{new_start_ptr + new_start_reserved_ptr_pos}; - auto ed{::fast_io::freestanding::non_overlapped_copy(old_start_ptr + old_start_reserved_pos, old_start_ptr + old_after_reserved_pos, new_start_reserved_ptr)}; + auto ed{::fast_io::freestanding::overlapped_copy(old_start_ptr + old_start_reserved_pos, old_start_ptr + old_after_reserved_pos, new_start_reserved_ptr)}; ::std::construct_at(ed, nullptr); controller.controller_block.controller_start_ptr = new_start_ptr; @@ -1306,9 +1320,10 @@ inline constexpr void deque_grow_to_new_blocks_count_direction_impl(dequecontrol controller.controller_block.controller_after_reserved_ptr = ed; controller.front_block.controller_ptr = new_start_reserved_ptr + static_cast<::std::size_t>(old_front_block_controller_pos - old_start_reserved_pos); controller.back_block.controller_ptr = new_start_reserved_ptr + static_cast<::std::size_t>(old_back_block_controller_pos - old_start_reserved_pos); - - block_typed_allocator::deallocate_n(old_start_ptr, - static_cast<::std::size_t>(static_cast<::std::size_t>(old_after_ptr - old_start_ptr) + 1zu)); + if (is_allocating_new_block) + { + block_typed_allocator::deallocate_n(old_start_ptr, old_allocated_sz_p1); + } } template From 5fc101389d66d9206f82e670c459e46816b7e19e Mon Sep 17 00:00:00 2001 From: trcrsired Date: Mon, 25 May 2026 07:19:24 +0800 Subject: [PATCH 75/82] [deque] remove debug_print in resize --- include/fast_io_dsal/impl/deque.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index cbfd0a005..fbe992281 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -3218,7 +3218,6 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { return; } - ::fast_io::io::debug_println(::std::source_location::current(), " rgsize=", rgsize); this->insert_range_front_impl(0, ::std::forward(rg), rgsize); } else From 18bf91b221ab4b3a4ba501979b9276c05f0e1f00 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Mon, 25 May 2026 23:39:34 +0800 Subject: [PATCH 76/82] [skip ci][deque] try to implement more although still wrong --- include/fast_io_dsal/impl/deque.h | 11 ++++------- include/fast_io_legacy_impl/io.h | 2 +- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index fbe992281..56e09381f 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -1289,6 +1289,7 @@ inline constexpr void deque_grow_to_new_blocks_count_direction_impl(dequecontrol ::std::size_t old_allocated_sz{static_cast<::std::size_t>(old_after_ptr - old_start_ptr)}; ::std::size_t old_allocated_sz_p1{old_allocated_sz + 1zu}; bool is_allocating_new_block{old_allocated_sz_p1 < to_allocated_blocks_least_p1}; + if (is_allocating_new_block) { auto allocate_result = block_typed_allocator::allocate_at_least(to_allocated_blocks_least_p1); @@ -1399,10 +1400,6 @@ inline constexpr void deque_reserve_back_blocks_impl_none_empty(dequecontroltype controller.back_block.controller_ptr); if (diff_to_after_ptr <= nb) { - if (1u < diff_to_after_ptr) - { - nb -= static_cast<::std::size_t>(diff_to_after_ptr - 1u); - } ::std::size_t distance_back_to_after{ static_cast<::std::size_t>(controller.controller_block.controller_after_ptr - controller.back_block.controller_ptr)}; @@ -1420,7 +1417,8 @@ inline constexpr void deque_reserve_back_blocks_impl_none_empty(dequecontroltype static_cast<::std::size_t>(controller.front_block.controller_ptr - controller.controller_block.controller_start_reserved_ptr)}; ::std::size_t front_borrowed_blocks_count{front_reserved_blocks}; - ::std::size_t to_allocate_blocks{static_cast<::std::size_t>(nb)}; + ::std::size_t to_allocate_blocks{static_cast<::std::size_t>(nb - diff_to_after_ptr2 - 1zu)}; + if (to_allocate_blocks < front_reserved_blocks) { front_borrowed_blocks_count = nb; @@ -1574,7 +1572,6 @@ inline constexpr void deque_reserve_front_blocks_none_empty_impl(dequecontroltyp controller.controller_block.controller_start_reserved_ptr); if (diff_to_start_ptr < nb) { - nb -= diff_to_start_ptr; ::std::size_t distance_front_to_start{ static_cast<::std::size_t>(controller.front_block.controller_ptr - controller.controller_block.controller_start_ptr)}; @@ -1593,7 +1590,7 @@ inline constexpr void deque_reserve_front_blocks_none_empty_impl(dequecontroltyp controller.back_block.controller_ptr - 1)}; ::std::size_t back_borrowed_blocks_count{back_reserved_blocks}; - ::std::size_t to_allocate_blocks{static_cast<::std::size_t>(nb)}; + ::std::size_t to_allocate_blocks{static_cast<::std::size_t>(nb - diff_to_start_ptr2)}; if (to_allocate_blocks < back_reserved_blocks) { back_borrowed_blocks_count = nb; diff --git a/include/fast_io_legacy_impl/io.h b/include/fast_io_legacy_impl/io.h index 4c3cac0c8..c14bcaaf7 100644 --- a/include/fast_io_legacy_impl/io.h +++ b/include/fast_io_legacy_impl/io.h @@ -217,7 +217,7 @@ template } // Allow debug print -#ifndef FAST_IO_DISABLE_DEBUG_PRINT +#if FAST_IO_DISABLE_DEBUG_PRINT == 0 // With debugging. We output to POSIX fd or Win32 Handle directly instead of C's stdout. template inline constexpr void debug_print(T &&t, Args &&...args) From 5f93301ebbf6d7e9f722677ac3d6189f041f2d05 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Mon, 25 May 2026 23:42:52 +0800 Subject: [PATCH 77/82] [skip ci][deque] still false --- include/fast_io_dsal/impl/deque.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index 56e09381f..f1e84dbef 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -1421,7 +1421,7 @@ inline constexpr void deque_reserve_back_blocks_impl_none_empty(dequecontroltype if (to_allocate_blocks < front_reserved_blocks) { - front_borrowed_blocks_count = nb; + front_borrowed_blocks_count = to_allocate_blocks; to_allocate_blocks = 0u; } else From d4dfe83704d5a4c6635138c22f97cc61e4ed78d3 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Wed, 27 May 2026 17:49:40 +0800 Subject: [PATCH 78/82] [deque] incorrectly commented out code causing crash --- include/fast_io_dsal/impl/deque.h | 44 +++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index f1e84dbef..664b28cdf 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -1280,6 +1280,18 @@ inline constexpr void deque_grow_to_new_blocks_count_direction_impl(dequecontrol static_cast<::std::size_t>(old_back_block_controller_ptr - old_start_ptr)}; ::std::size_t old_blocks_count{static_cast<::std::size_t>(old_back_block_controller_ptr_p1 - old_front_block_controller_ptr)}; +#if 0 + ::fast_io::io::debug_perr(::std::source_location::current(), "\n" + "old_start_ptr=",::fast_io::mnp::pointervw(old_start_ptr),"\n" + "old_after_pos=",old_after_ptr-old_start_ptr,"\n" + "old_start_reserved_pos=",old_start_reserved_pos,"\n" + "old_after_reserved_pos=",old_after_reserved_pos,"\n" + "old_front_block_controller_pos=",old_front_block_controller_pos,"\n" + "old_back_block_controller_pos=",old_back_block_controller_pos,"\n" + "old_blocks_count=",old_blocks_count,"\n" + "new_blocks_count_least=",new_blocks_count_least,"\n\n" + ); +#endif ::std::size_t to_allocated_blocks_least_p1{::fast_io::containers::details::deque_new_blocks_count_compute_impl(new_blocks_count_least, old_blocks_count, (no_space_at_back ? static_cast<::std::size_t>(old_back_block_controller_ptr_p1 - old_start_reserved_ptr) : static_cast<::std::size_t>(old_after_reserved_ptr - old_front_block_controller_ptr)))}; using block_typed_allocator = ::fast_io::typed_generic_allocator_adapter; @@ -1289,7 +1301,10 @@ inline constexpr void deque_grow_to_new_blocks_count_direction_impl(dequecontrol ::std::size_t old_allocated_sz{static_cast<::std::size_t>(old_after_ptr - old_start_ptr)}; ::std::size_t old_allocated_sz_p1{old_allocated_sz + 1zu}; bool is_allocating_new_block{old_allocated_sz_p1 < to_allocated_blocks_least_p1}; - +#if 0 + ::fast_io::io::debug_perrln(::std::source_location::current(), "\tto_allocated_blocks_least_p1=", to_allocated_blocks_least_p1, + "\tnew_blocks_count_least=",new_blocks_count_least); +#endif if (is_allocating_new_block) { auto allocate_result = block_typed_allocator::allocate_at_least(to_allocated_blocks_least_p1); @@ -1384,7 +1399,6 @@ inline constexpr void deque_rebalance_or_grow_insertation_direction_impl(dequeco { capacity_blocks_count_direction = new_elements_blocks_count; } - return ::fast_io::containers::details::deque_grow_to_new_blocks_count_direction_impl(controller, capacity_blocks_count_direction, no_space_at_back); } @@ -1398,6 +1412,11 @@ inline constexpr void deque_reserve_back_blocks_impl_none_empty(dequecontroltype static_cast<::std::size_t>( controller.controller_block.controller_after_reserved_ptr - controller.back_block.controller_ptr); +#if 0 + ::fast_io::io::debug_perr(::std::source_location::current(), + "\ndiff_to_after_ptr=",diff_to_after_ptr, + "\nnb=",nb,"\n\n"); +#endif if (diff_to_after_ptr <= nb) { ::std::size_t distance_back_to_after{ @@ -1417,9 +1436,14 @@ inline constexpr void deque_reserve_back_blocks_impl_none_empty(dequecontroltype static_cast<::std::size_t>(controller.front_block.controller_ptr - controller.controller_block.controller_start_reserved_ptr)}; ::std::size_t front_borrowed_blocks_count{front_reserved_blocks}; - ::std::size_t to_allocate_blocks{static_cast<::std::size_t>(nb - diff_to_after_ptr2 - 1zu)}; - - if (to_allocate_blocks < front_reserved_blocks) + ::std::size_t to_allocate_blocks{static_cast<::std::size_t>(nb - (diff_to_after_ptr2 ? diff_to_after_ptr2 - 1zu : 0zu))}; +#if 0 + ::fast_io::io::debug_perrln(::std::source_location::current(), + "\nto_allocate_blocks=",to_allocate_blocks, + "\tnb=",nb, + "\tcontroller.front_block.controller_ptr-controller.controller_block.controller_start_ptr=",controller.front_block.controller_ptr-controller.controller_block.controller_start_ptr); +#endif + if (to_allocate_blocks < front_borrowed_blocks_count) { front_borrowed_blocks_count = to_allocate_blocks; to_allocate_blocks = 0u; @@ -1437,6 +1461,16 @@ inline constexpr void deque_reserve_back_blocks_impl_none_empty(dequecontroltype pos); controller.controller_block.controller_start_reserved_ptr = controller_start_reserved_ptr + front_borrowed_blocks_count; +#if 0 + ::fast_io::io::debug_perrln(::std::source_location::current(),"\n" + "pos-controller.controller_block.controller_start_ptr=", + pos-controller.controller_block.controller_start_ptr,"\n" + "pos + to_allocate_blocks - controller.controller_block.controller_start_ptr=", + pos + to_allocate_blocks - controller.controller_block.controller_start_ptr,"\n" + "controller.controller_block.controller_after_ptr-controller.controller_block.controller_start_ptr=", + controller.controller_block.controller_after_ptr-controller.controller_block.controller_start_ptr,"\n" + "to_allocate_blocks=",to_allocate_blocks); +#endif for (auto e{pos + to_allocate_blocks}; pos != e; ++pos) { ::std::construct_at(pos, static_cast(allocator::allocate_aligned(align, blockbytes))); From caa345bfd772ae1fbc4ab37f2affff381132491d Mon Sep 17 00:00:00 2001 From: trcrsired Date: Wed, 27 May 2026 19:54:08 +0800 Subject: [PATCH 79/82] [deque] erase should correctly reset front_end_ptr --- fuzzing/0007.containers/deque/fuzz_deque_trivial.cc | 13 ++++++++++++- include/fast_io_dsal/impl/deque.h | 4 +++- tests/0000.tests_prebuild/gentests.cc | 8 ++++---- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/fuzzing/0007.containers/deque/fuzz_deque_trivial.cc b/fuzzing/0007.containers/deque/fuzz_deque_trivial.cc index 96499739d..7a0a9f328 100644 --- a/fuzzing/0007.containers/deque/fuzz_deque_trivial.cc +++ b/fuzzing/0007.containers/deque/fuzz_deque_trivial.cc @@ -1,4 +1,7 @@ #include +#if FAST_IO_FUZZ_DEBUG != 0 +#include +#endif #include #include #include @@ -65,6 +68,9 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const *data, size_t size) while (i < size) { uint8_t op = read_u8(i); +#if FAST_IO_FUZZ_DEBUG != 0 + ::fast_io::io::debug_perrln(::std::source_location::current(), " op%20=", op % 20, " ", ::fast_io::mnp::debug_view(dq)); +#endif switch (op % 20u) { case 0: @@ -309,8 +315,13 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const *data, size_t size) break; } } - +#if FAST_IO_FUZZ_DEBUG != 0 + ::fast_io::io::debug_perrln(::std::source_location::current(), " op%20=", op % 20, " ", ::fast_io::mnp::debug_view(dq)); +#endif validate(); +#if FAST_IO_FUZZ_DEBUG != 0 + ::fast_io::io::debug_perrln(::std::source_location::current(), " op%20=", op % 20, " ", ::fast_io::mnp::debug_view(dq)); +#endif } // Final iterator validation diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index 664b28cdf..e4810bda1 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -1165,6 +1165,7 @@ deque_erase_common_trivial_impl(::fast_io::containers::details::deque_controller if (moveleft) { controller.front_block = ::fast_io::containers::details::deque_copy_backward_impl(controller.front_block, first, last, blockbytes); + controller.front_end_ptr = controller.front_block.begin_ptr + blockbytes; first = last; if (controller.front_block.curr_ptr == back_block.curr_ptr && back_block.curr_ptr == controller.back_end_ptr) [[unlikely]] { @@ -3775,6 +3776,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE if (moveleft) { this->controller.front_block = ::fast_io::freestanding::uninitialized_relocate_backward(this->begin(), first, last).itercontent; + this->controller.front_end_ptr = this->controller.front_block.begin_ptr + block_size; first = last; back_block = this->controller.back_block; } @@ -3789,7 +3791,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE inline constexpr iterator erase_unchecked_nodestroy_impl(iterator first, iterator last, bool moveleft) noexcept { - if constexpr (::fast_io::freestanding::is_trivially_copyable_or_relocatable_v) + if constexpr (::fast_io::freestanding::is_trivially_copyable_or_relocatable_v && 0) { if !consteval { diff --git a/tests/0000.tests_prebuild/gentests.cc b/tests/0000.tests_prebuild/gentests.cc index 76c435b8b..bb4928760 100644 --- a/tests/0000.tests_prebuild/gentests.cc +++ b/tests/0000.tests_prebuild/gentests.cc @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include #include @@ -77,17 +77,17 @@ inline constexpr file_entry_t operator|(file_entry_t const &lhs, file_entry_t co .will_fail = lhs.will_fail | rhs.will_fail, .platform = lhs.platform | rhs.platform}; } -using file_property_t = std::unordered_map; +using file_property_t = std::map; inline platform_t global_platform; inline bool msvc{}; inline void parse_prop_files(fast_io::native_file_loader &&file, file_property_t &file_properties) { - std::unordered_map> file_contents; + std::map> file_contents; fast_io::u8ibuffer_view u8fv{reinterpret_cast(file.begin()), reinterpret_cast(file.end())}; - std::unordered_map *curr_entry{}; + std::map *curr_entry{}; for (std::u8string line; scan(u8fv, fast_io::mnp::line_get(line));) { std::u8string_view linevw{line}; From b2b92a3d397b83b6b1ccf7903ecd07c337d10341 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Thu, 28 May 2026 05:02:00 +0800 Subject: [PATCH 80/82] [deque] Rewrite fuzz_deque_nontrivial by using ::std::shared_ptr as the type --- .../deque/fuzz_deque_nontrivial.cc | 381 +++++++----------- include/fast_io_dsal/impl/deque.h | 12 +- 2 files changed, 159 insertions(+), 234 deletions(-) diff --git a/fuzzing/0007.containers/deque/fuzz_deque_nontrivial.cc b/fuzzing/0007.containers/deque/fuzz_deque_nontrivial.cc index 1ff1224c2..8e363dc10 100644 --- a/fuzzing/0007.containers/deque/fuzz_deque_nontrivial.cc +++ b/fuzzing/0007.containers/deque/fuzz_deque_nontrivial.cc @@ -1,152 +1,23 @@ +#include +#if FAST_IO_FUZZ_DEBUG != 0 +#include +#endif #include #include #include #include #include -#include +#include +#include -// Non-trivial type: has destructor, copy constructor, copy assignment operator -struct tracked_object -{ - int value{}; - bool *destroyed{}; - - tracked_object() = default; - explicit tracked_object(int v, bool *flag) : value{v}, destroyed{flag} - {} - tracked_object(tracked_object const &other) : value{other.value}, destroyed{other.destroyed} - { - if (destroyed && *destroyed) - { - __builtin_trap(); // double-destroy / use after destroy - } - } - tracked_object &operator=(tracked_object const &other) - { - if (destroyed && *destroyed) - { - __builtin_trap(); - } - if (this != &other) - { - value = other.value; - destroyed = other.destroyed; - } - return *this; - } - tracked_object(tracked_object &&other) noexcept : value{other.value}, destroyed{other.destroyed} - { - other.value = 0; - other.destroyed = nullptr; - } - tracked_object &operator=(tracked_object &&other) noexcept - { - if (this != &other) - { - value = other.value; - destroyed = other.destroyed; - other.value = 0; - other.destroyed = nullptr; - } - return *this; - } - ~tracked_object() - { - if (destroyed && *destroyed) - { - __builtin_trap(); // double destroy - } - if (destroyed) - { - *destroyed = true; - } - } - bool operator==(tracked_object const &other) const noexcept - { - return value == other.value; - } -}; - -// Same struct for std::deque reference -struct ref_tracked_object -{ - int value{}; - bool *destroyed{}; - - ref_tracked_object() = default; - explicit ref_tracked_object(int v, bool *flag) : value{v}, destroyed{flag} - {} - ref_tracked_object(ref_tracked_object const &other) : value{other.value}, destroyed{other.destroyed} - { - if (destroyed && *destroyed) - { - __builtin_trap(); - } - } - ref_tracked_object &operator=(ref_tracked_object const &other) - { - if (destroyed && *destroyed) - { - __builtin_trap(); - } - if (this != &other) - { - value = other.value; - destroyed = other.destroyed; - } - return *this; - } - ref_tracked_object(ref_tracked_object &&other) noexcept : value{other.value}, destroyed{other.destroyed} - { - other.value = 0; - other.destroyed = nullptr; - } - ref_tracked_object &operator=(ref_tracked_object &&other) noexcept - { - if (this != &other) - { - value = other.value; - destroyed = other.destroyed; - other.value = 0; - other.destroyed = nullptr; - } - return *this; - } - ~ref_tracked_object() - { - if (destroyed && *destroyed) - { - __builtin_trap(); - } - if (destroyed) - { - *destroyed = true; - } - } - bool operator==(ref_tracked_object const &other) const noexcept - { - return value == other.value; - } -}; - -// Storage for destruction flags so we can verify no double-frees / leaks -static constexpr std::size_t max_tracked = 4096; -static bool destroy_flags_fast[max_tracked]; -static bool destroy_flags_ref[max_tracked]; +using TestType = ::std::shared_ptr; extern "C" int LLVMFuzzerTestOneInput(uint8_t const *data, size_t size) { - // Reset destruction flags - for (std::size_t i = 0; i != max_tracked; ++i) - { - destroy_flags_fast[i] = false; - destroy_flags_ref[i] = false; - } - - fast_io::deque dq; - std::deque ref; + fast_io::deque dq; + std::deque ref; - auto read_u8 = [&](std::size_t &i) -> uint8_t { + auto read_u8 = [&](size_t &i) -> uint8_t { if (i >= size) { return 0; @@ -154,7 +25,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const *data, size_t size) return data[i++]; }; - auto read_u64 = [&](std::size_t &i) -> std::size_t { + auto read_u64 = [&](size_t &i) -> std::size_t { if (i + 7 >= size) { return 0; @@ -167,16 +38,6 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const *data, size_t size) return v; }; - auto make_fast = [&](int v) -> tracked_object { - std::size_t idx = static_cast(v) % max_tracked; - return tracked_object{v, &destroy_flags_fast[idx]}; - }; - - auto make_ref = [&](int v) -> ref_tracked_object { - std::size_t idx = static_cast(v) % max_tracked; - return ref_tracked_object{v, &destroy_flags_ref[idx]}; - }; - auto validate = [&]() { if (dq.size() != ref.size()) { @@ -186,53 +47,67 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const *data, size_t size) { __builtin_trap(); } - auto it1 = dq.begin(); - auto it2 = ref.begin(); - for (std::size_t k = 0, sz = dq.size(); k != sz; ++k, ++it1, ++it2) + for (std::size_t k = 0, sz = dq.size(); k != sz; ++k) { - if (it1->value != it2->value) + if ((dq[k] == nullptr) != (ref[k] == nullptr)) + { + __builtin_trap(); + } + if (dq[k] && ref[k] && *dq[k] != *ref[k]) { __builtin_trap(); } } if (!ref.empty()) { - if (dq.front().value != ref.front().value) + if ((dq.front() == nullptr) != (ref.front() == nullptr)) + { + __builtin_trap(); + } + if (dq.front() && ref.front() && *dq.front() != *ref.front()) + { + __builtin_trap(); + } + if ((dq.back() == nullptr) != (ref.back() == nullptr)) { __builtin_trap(); } - if (dq.back().value != ref.back().value) + if (dq.back() && ref.back() && *dq.back() != *ref.back()) { __builtin_trap(); } } }; - std::size_t i = 0; + size_t i = 0; while (i < size) { uint8_t op = read_u8(i); - - switch (op % 18u) +#if FAST_IO_FUZZ_DEBUG != 0 + ::fast_io::io::debug_perrln(::std::source_location::current(), " op%20=", op % 20, " ", ::fast_io::mnp::debug_view(dq)); +#endif + switch (op % 20u) { case 0: - { // push_back - int v = static_cast(read_u8(i)); - dq.push_back(make_fast(v)); - ref.push_back(make_ref(v)); + { // push_back (Copy construction via shared_ptr) + std::size_t val = read_u64(i); + auto ptr = std::make_shared(val); + dq.push_back(ptr); // Tests copy + ref.push_back(ptr); break; } case 1: - { // push_front - int v = static_cast(read_u8(i)); - dq.push_front(make_fast(v)); - ref.push_front(make_ref(v)); + { // push_front (Copy construction) + std::size_t val = read_u64(i); + auto ptr = std::make_shared(val); + dq.push_front(ptr); + ref.push_front(ptr); break; } case 2: - { // pop_back + { // pop_back (Tests destruction / reference count decrement) if (!ref.empty()) { dq.pop_back(); @@ -242,7 +117,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const *data, size_t size) } case 3: - { // pop_front + { // pop_front (Tests destruction / reference count decrement) if (!ref.empty()) { dq.pop_front(); @@ -252,57 +127,59 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const *data, size_t size) } case 4: - { // emplace_back - int v = static_cast(read_u8(i)); - dq.emplace_back(make_fast(v)); - ref.emplace_back(make_ref(v)); + { // emplace_back (Tests forwarding / move mechanics) + std::size_t val = read_u64(i); + dq.emplace_back(std::make_shared(val)); + ref.emplace_back(std::make_shared(val)); break; } case 5: - { // emplace_front - int v = static_cast(read_u8(i)); - dq.emplace_front(make_fast(v)); - ref.emplace_front(make_ref(v)); + { // emplace_front (Tests forwarding / move mechanics) + std::size_t val = read_u64(i); + dq.emplace_front(std::make_shared(val)); + ref.emplace_front(std::make_shared(val)); break; } case 6: { // insert (iterator) - int v = static_cast(read_u8(i)); + std::size_t val = read_u64(i); + auto ptr = std::make_shared(val); if (ref.empty()) { - dq.insert(dq.cbegin(), make_fast(v)); - ref.insert(ref.begin(), make_ref(v)); + dq.insert(dq.cbegin(), ptr); + ref.insert(ref.begin(), ptr); } else { - std::size_t pos = static_cast(v) % (ref.size() + 1); - dq.insert(dq.cbegin() + pos, make_fast(v)); - ref.insert(ref.begin() + pos, make_ref(v)); + std::size_t pos = (val * 37) % (ref.size() + 1); + dq.insert(dq.cbegin() + pos, ptr); + ref.insert(ref.begin() + pos, ptr); } break; } case 7: { // insert_index - int v = static_cast(read_u8(i)); + std::size_t val = read_u64(i); + auto ptr = std::make_shared(val); if (ref.empty()) { - dq.insert_index(0, make_fast(v)); - ref.insert(ref.begin(), make_ref(v)); + dq.insert_index(0, ptr); + ref.insert(ref.begin(), ptr); } else { - std::size_t pos = static_cast(v) % (ref.size() + 1); - dq.insert_index(pos, make_fast(v)); - ref.insert(ref.begin() + pos, make_ref(v)); + std::size_t pos = (val * 37) % (ref.size() + 1); + dq.insert_index(pos, ptr); + ref.insert(ref.begin() + pos, ptr); } break; } case 8: - { // erase single + { // erase single index if (!ref.empty()) { std::size_t seed = read_u8(i); @@ -314,7 +191,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const *data, size_t size) } case 9: - { // erase range + { // erase range index if (ref.size() >= 2) { std::size_t a = read_u8(i); @@ -332,7 +209,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const *data, size_t size) } case 10: - { // resize default + { // resize default (creates null shared_ptrs) std::size_t n = read_u64(i); if (n > 100000) { @@ -344,46 +221,43 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const *data, size_t size) } case 11: - { // resize with value + { // resize with value (copies prototype value) std::size_t n = read_u64(i); - int v = static_cast(read_u8(i)); + std::size_t val = read_u64(i); if (n > 100000) { n = n % 100001; } - dq.resize(n, make_fast(v)); - ref.resize(n, make_ref(v)); + auto prototype = std::make_shared(val); + dq.resize(n, prototype); + ref.resize(n, prototype); break; } case 12: { // assign(count, val) std::size_t n = read_u64(i); - int v = static_cast(read_u8(i)); + std::size_t val = read_u64(i); if (n > 100000) { n = n % 100001; } - dq.assign(n, make_fast(v)); - ref.assign(n, make_ref(v)); + auto prototype = std::make_shared(val); + dq.assign(n, prototype); + ref.assign(n, prototype); break; } case 13: - { // assign_range + { // assign_range (Triggers true collection duplication copying) std::size_t n = read_u8(i); - std::vector tmp; - std::vector ref_tmp; - tmp.reserve(n); - ref_tmp.reserve(n); + std::vector tmp(n); for (std::size_t k = 0; k != n; ++k) { - int v = static_cast(read_u8(i)); - tmp.emplace_back(make_fast(v)); - ref_tmp.emplace_back(make_ref(v)); + tmp[k] = std::make_shared(read_u64(i)); } dq.assign_range(tmp); - ref.assign(ref_tmp.begin(), ref_tmp.end()); + ref.assign(tmp.begin(), tmp.end()); break; } @@ -402,48 +276,93 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const *data, size_t size) } case 16: - { // append_range + { // swap with another deque std::size_t n = read_u8(i); - std::vector tmp; - std::vector ref_tmp; - tmp.reserve(n); - ref_tmp.reserve(n); + fast_io::deque other; + std::deque other_ref; for (std::size_t k = 0; k != n; ++k) { - int v = static_cast(read_u8(i)); - tmp.emplace_back(make_fast(v)); - ref_tmp.emplace_back(make_ref(v)); + auto ptr = std::make_shared(read_u64(i)); + other.push_back(ptr); + other_ref.push_back(ptr); } - dq.append_range(tmp); - ref.insert(ref.end(), ref_tmp.begin(), ref_tmp.end()); + dq.swap(other); + std::swap(ref, other_ref); break; } case 17: - { // prepend_range + { // append_range (Triggers copies from input range) std::size_t n = read_u8(i); - std::vector tmp; - std::vector ref_tmp; - tmp.reserve(n); - ref_tmp.reserve(n); + std::vector tmp(n); for (std::size_t k = 0; k != n; ++k) { - int v = static_cast(read_u8(i)); - tmp.emplace_back(make_fast(v)); - ref_tmp.emplace_back(make_ref(v)); + tmp[k] = std::make_shared(read_u64(i)); } - dq.prepend_range(tmp); - ref.insert(ref.begin(), ref_tmp.begin(), ref_tmp.end()); + dq.append_range(tmp); + ref.insert(ref.end(), tmp.begin(), tmp.end()); break; } + + case 18: + { // prepend_range (Triggers copies from input range) + std::size_t n = read_u8(i); + std::vector tmp(n); + for (std::size_t k = 0; k != n; ++k) + { + tmp[k] = std::make_shared(read_u64(i)); + } + dq.prepend_range(tmp); + ref.insert(ref.begin(), tmp.begin(), tmp.end()); + break; } + case 19: + { // emplace_index + if (ref.empty()) + { + std::size_t val = read_u64(i); + dq.emplace_index(0, std::make_shared(val)); + ref.emplace(ref.begin(), std::make_shared(val)); + } + else + { + std::size_t seed = read_u8(i); + std::size_t val = read_u64(i); + std::size_t pos = seed % ref.size(); + dq.emplace_index(pos, std::make_shared(val)); + ref.emplace(ref.begin() + pos, std::make_shared(val)); + } + break; + } + } +#if FAST_IO_FUZZ_DEBUG != 0 + ::fast_io::io::debug_perrln(::std::source_location::current(), " op%20=", op % 20, " ", ::fast_io::mnp::debug_view(dq)); +#endif validate(); +#if FAST_IO_FUZZ_DEBUG != 0 + ::fast_io::io::debug_perrln(::std::source_location::current(), " op%20=", op % 20, " ", ::fast_io::mnp::debug_view(dq)); +#endif } - // Both deques go out of scope here — destructors fire. - // The tracked_object destructors already trap on double-destroy above. - // If we reach return 0, no double-free / use-after-free occurred. + // Final iterator validation + { + auto it1 = dq.begin(); + auto it2 = ref.begin(); + auto e1 = dq.end(); + auto e2 = ref.end(); + for (; it1 != e1 && it2 != e2; ++it1, ++it2) + { + if ((*it1 == nullptr) != (*it2 == nullptr)) + { + __builtin_trap(); + } + if (*it1 && *it2 && **it1 != **it2) + { + __builtin_trap(); + } + } + } return 0; } diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index e4810bda1..020d73f45 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -3775,10 +3775,16 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE ::fast_io::containers::details::deque_control_block back_block; if (moveleft) { - this->controller.front_block = ::fast_io::freestanding::uninitialized_relocate_backward(this->begin(), first, last).itercontent; - this->controller.front_end_ptr = this->controller.front_block.begin_ptr + block_size; - first = last; + auto ed{this->end()}; + auto front_block{::fast_io::freestanding::uninitialized_relocate_backward(this->begin(), first, last).itercontent}; back_block = this->controller.back_block; + if (last == ed) + { + front_block = back_block; + } + this->controller.front_block = front_block; + this->controller.front_end_ptr = front_block.begin_ptr + block_size; + first = last; } else { From 9c530032098af23fd171cca63a16a2296c916e20 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Thu, 28 May 2026 05:12:48 +0800 Subject: [PATCH 81/82] [deque] remove unused variable double extra --- include/fast_io_dsal/impl/deque.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index 020d73f45..57bcf8067 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -1376,7 +1376,6 @@ inline constexpr void deque_rebalance_or_grow_insertation_direction_impl(dequeco ::std::size_t capacity_blocks_count_direction{ no_space_at_back ? static_cast<::std::size_t>(after_ptr - old_front_controller_ptr) : static_cast<::std::size_t>(old_back_after_controller_ptr - start_ptr)}; - ::std::size_t doubleslotsextra{capacity_blocks_count_direction}; #if (defined(__GNUC__) || defined(__clang__)) if constexpr (true) { From 9bd5817f5ef9b64312ba66d3f091303b81e8c37d Mon Sep 17 00:00:00 2001 From: trcrsired Date: Thu, 28 May 2026 05:16:44 +0800 Subject: [PATCH 82/82] [deque] remove front_more_blocks_mod --- include/fast_io_dsal/impl/deque.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index 57bcf8067..c1f8607a6 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -1697,7 +1697,6 @@ inline constexpr void deque_reserve_front_spaces_impl(dequecontroltype &controll } ::std::size_t nmblocksn{n - blocksn}; ::std::size_t front_more_blocks{nmblocksn / block_size}; - ::std::size_t const front_more_blocks_mod{nmblocksn % block_size}; ::std::size_t toallocate{front_more_blocks}; #if defined(__GNUC__) || defined(__clang__) if constexpr (true)