From 265c343e5812a5b9679d28b5a9b71c38d49d92bb Mon Sep 17 00:00:00 2001 From: trcrsired Date: Thu, 8 Jan 2026 19:41:12 +0800 Subject: [PATCH 1/6] [skip ci] initial attempt for deque insert_range --- include/fast_io_dsal/impl/deque.h | 383 ++++++++++++++---- .../0026.container/0003.deque/insert_range.cc | 84 ++++ 2 files changed, 386 insertions(+), 81 deletions(-) create mode 100644 tests/0026.container/0003.deque/insert_range.cc diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index 06191ed6..8a4c1cdf 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -77,6 +77,136 @@ struct ::fast_io::containers::details::deque_controller_block_common controller_block; }; +template +#if __has_cpp_attribute(clang::no_sanitize) +[[clang::no_sanitize("undefined")]] +#endif +inline constexpr void deque_add_assign_signed_impl(::fast_io::containers::details::deque_control_block &itercontent, ::std::ptrdiff_t pos) noexcept +{ + using size_type = ::std::size_t; + constexpr size_type blocksize{::fast_io::containers::details::deque_block_size}; + constexpr size_type blocksizem1{blocksize - 1u}; + size_type unsignedpos{static_cast(pos)}; + auto curr_ptr{itercontent.curr_ptr}; + auto controllerptr{itercontent.controller_ptr}; + decltype(curr_ptr) beginptr; + if (pos < 0) + { + size_type diff{static_cast(itercontent.end_ptr - curr_ptr)}; + constexpr size_type zero{}; + size_type abspos{static_cast(zero - unsignedpos)}; + diff += abspos; + itercontent.curr_ptr = (beginptr = *(controllerptr -= diff / blocksize)) + (blocksizem1 - diff % blocksize); + } + else + { + size_type diff{static_cast(curr_ptr - itercontent.begin_ptr)}; + diff += unsignedpos; + itercontent.curr_ptr = (beginptr = *(controllerptr += diff / blocksize)) + diff % blocksize; + } + itercontent.controller_ptr = controllerptr; + itercontent.begin_ptr = beginptr; + itercontent.end_ptr = beginptr + blocksize; +} + +template +#if __has_cpp_attribute(clang::no_sanitize) +[[clang::no_sanitize("undefined")]] +#endif +inline constexpr void deque_add_assign_unsigned_impl(::fast_io::containers::details::deque_control_block &itercontent, ::std::size_t unsignedpos) noexcept +{ + using size_type = ::std::size_t; + constexpr size_type blocksize{::fast_io::containers::details::deque_block_size}; + + size_type diff{static_cast(itercontent.end_ptr - itercontent.curr_ptr) + unsignedpos}; + auto beginptr{*(itercontent.controller_ptr += diff / blocksize)}; + itercontent.begin_ptr = beginptr; + itercontent.curr_ptr = beginptr + diff % blocksize; + itercontent.end_ptr = beginptr + blocksize; +} + +template +#if __has_cpp_attribute(clang::no_sanitize) +[[clang::no_sanitize("undefined")]] +#endif +inline constexpr void deque_sub_assign_signed_impl(::fast_io::containers::details::deque_control_block &itercontent, ::std::ptrdiff_t pos) noexcept +{ + using size_type = ::std::size_t; + constexpr size_type blocksize{::fast_io::containers::details::deque_block_size}; + constexpr size_type blocksizem1{blocksize - 1u}; + size_type unsignedpos{static_cast(pos)}; + auto curr_ptr{itercontent.curr_ptr}; + auto controllerptr{itercontent.controller_ptr}; + decltype(curr_ptr) beginptr; + if (pos < 0) + { + size_type diff{static_cast(curr_ptr - itercontent.begin_ptr)}; + constexpr size_type zero{}; + size_type abspos{static_cast(zero - unsignedpos)}; + diff += abspos; + itercontent.curr_ptr = (beginptr = *(controllerptr += diff / blocksize)) + diff % blocksize; + } + else + { + size_type diff{static_cast(itercontent.end_ptr - curr_ptr)}; + diff += unsignedpos; + itercontent.curr_ptr = (beginptr = *(controllerptr -= diff / blocksize)) + (blocksizem1 - diff % blocksize); + } + itercontent.controller_ptr = controllerptr; + itercontent.begin_ptr = beginptr; + itercontent.end_ptr = beginptr + blocksize; +} + +template +#if __has_cpp_attribute(clang::no_sanitize) +[[clang::no_sanitize("undefined")]] +#endif +inline constexpr void deque_sub_assign_unsigned_impl(::fast_io::containers::details::deque_control_block &itercontent, ::std::size_t unsignedpos) noexcept +{ + using size_type = ::std::size_t; + constexpr size_type blocksize{::fast_io::containers::details::deque_block_size}; + constexpr size_type blocksizem1{blocksize - 1u}; + size_type diff{static_cast(itercontent.end_ptr - itercontent.curr_ptr) + unsignedpos}; + auto beginptr{*(itercontent.controller_ptr -= diff / blocksize)}; + itercontent.begin_ptr = beginptr; + itercontent.curr_ptr = beginptr + (blocksizem1 - diff % blocksize); + itercontent.end_ptr = beginptr + blocksize; +} + +template +inline constexpr T &deque_index_signed(::fast_io::containers::details::deque_control_block &itercontent, ::std::ptrdiff_t pos) noexcept +{ + using size_type = ::std::size_t; + constexpr size_type blocksize{::fast_io::containers::details::deque_block_size}; + constexpr size_type blocksizem1{blocksize - 1u}; + size_type unsignedpos{static_cast(pos)}; + auto curr_ptr{itercontent.curr_ptr}; + auto controllerptr{itercontent.controller_ptr}; + if (pos < 0) + { + size_type diff{static_cast(itercontent.end_ptr - curr_ptr) - 1u}; + constexpr size_type zero{}; + size_type abspos{static_cast(zero - unsignedpos)}; + diff += abspos; + return (*(controllerptr - diff / blocksize))[blocksizem1 - diff % blocksize]; + } + else + { + size_type diff{static_cast(curr_ptr - itercontent.begin_ptr)}; + diff += unsignedpos; + return controllerptr[diff / blocksize][diff % blocksize]; + } +} + +template +inline constexpr T &deque_index_unsigned(::fast_io::containers::details::deque_control_block &itercontent, ::std::size_t unsignedpos) noexcept +{ + using size_type = ::std::size_t; + constexpr size_type blocksize{::fast_io::containers::details::deque_block_size}; + size_type const diff{static_cast(itercontent.curr_ptr - itercontent.begin_ptr) + unsignedpos}; + return itercontent.controller_ptr[diff / blocksize][diff % blocksize]; +} + template struct deque_iterator { @@ -155,83 +285,48 @@ struct deque_iterator { return this->itercontent.curr_ptr; } - - inline constexpr deque_iterator &operator+=(difference_type pos) noexcept + template <::std::integral postype> + inline constexpr deque_iterator &operator+=(postype pos) noexcept { - constexpr size_type blocksize{::fast_io::containers::details::deque_block_size}; - constexpr size_type blocksizem1{blocksize - 1u}; - size_type unsignedpos{static_cast(pos)}; - auto curr_ptr{this->itercontent.curr_ptr}; - auto controllerptr{this->itercontent.controller_ptr}; - decltype(curr_ptr) beginptr; - if (pos < 0) + if constexpr (::std::signed_integral) { - size_type diff{static_cast(this->itercontent.end_ptr - curr_ptr)}; - constexpr size_type zero{}; - size_type abspos{static_cast(zero - unsignedpos)}; - diff += abspos; - this->itercontent.curr_ptr = (beginptr = *(controllerptr -= diff / blocksize)) + (blocksizem1 - diff % blocksize); + ::fast_io::containers::details::deque_add_assign_signed_impl( + this->itercontent, static_cast(pos)); } else { - size_type diff{static_cast(curr_ptr - this->itercontent.begin_ptr)}; - diff += unsignedpos; - this->itercontent.curr_ptr = (beginptr = *(controllerptr += diff / blocksize)) + diff % blocksize; + ::fast_io::containers::details::deque_add_assign_unsigned_impl( + this->itercontent, static_cast(pos)); } - this->itercontent.controller_ptr = controllerptr; - this->itercontent.begin_ptr = beginptr; - this->itercontent.end_ptr = beginptr + blocksize; return *this; } - - inline constexpr deque_iterator &operator-=(difference_type pos) noexcept + template <::std::integral postype> + inline constexpr deque_iterator &operator-=(postype pos) noexcept { - constexpr size_type blocksize{::fast_io::containers::details::deque_block_size}; - constexpr size_type blocksizem1{blocksize - 1u}; - size_type unsignedpos{static_cast(pos)}; - auto curr_ptr{this->itercontent.curr_ptr}; - auto controllerptr{this->itercontent.controller_ptr}; - decltype(curr_ptr) beginptr; - if (pos < 0) + if constexpr (::std::signed_integral) { - size_type diff{static_cast(curr_ptr - this->itercontent.begin_ptr)}; - constexpr size_type zero{}; - size_type abspos{static_cast(zero - unsignedpos)}; - diff += abspos; - this->itercontent.curr_ptr = (beginptr = *(controllerptr += diff / blocksize)) + diff % blocksize; + ::fast_io::containers::details::deque_sub_assign_signed_impl( + this->itercontent, static_cast(pos)); } else { - size_type diff{static_cast(this->itercontent.end_ptr - curr_ptr)}; - diff += unsignedpos; - this->itercontent.curr_ptr = (beginptr = *(controllerptr -= diff / blocksize)) + (blocksizem1 - diff % blocksize); + ::fast_io::containers::details::deque_sub_assign_unsigned_impl( + this->itercontent, static_cast(pos)); } - this->itercontent.controller_ptr = controllerptr; - this->itercontent.begin_ptr = beginptr; - this->itercontent.end_ptr = beginptr + blocksize; return *this; } - - inline constexpr reference operator[](difference_type pos) const noexcept + template <::std::integral postype> + inline constexpr reference operator[](postype pos) const noexcept { - constexpr size_type blocksize{::fast_io::containers::details::deque_block_size}; - constexpr size_type blocksizem1{blocksize - 1u}; - size_type unsignedpos{static_cast(pos)}; - auto curr_ptr{this->itercontent.curr_ptr}; - auto controllerptr{this->itercontent.controller_ptr}; - if (pos < 0) + if constexpr (::std::signed_integral) { - size_type diff{static_cast(this->itercontent.end_ptr - curr_ptr) - 1u}; - constexpr size_type zero{}; - size_type abspos{static_cast(zero - unsignedpos)}; - diff += abspos; - return (*(controllerptr - diff / blocksize))[blocksizem1 - diff % blocksize]; + return ::fast_io::containers::details::deque_index_signed(this->itercontent, + static_cast(pos)); } else { - size_type diff{static_cast(curr_ptr - this->itercontent.begin_ptr)}; - diff += unsignedpos; - return controllerptr[diff / blocksize][diff % blocksize]; + return ::fast_io::containers::details::deque_index_unsigned(this->itercontent, + static_cast(pos)); } } @@ -242,22 +337,52 @@ struct deque_iterator } }; -template -inline constexpr ::fast_io::containers::details::deque_iterator operator+(::fast_io::containers::details::deque_iterator a, ::std::ptrdiff_t pos) noexcept +template +inline constexpr ::fast_io::containers::details::deque_iterator operator+(::fast_io::containers::details::deque_iterator a, postype pos) noexcept { - return (a += pos); + if constexpr (::std::signed_integral) + { + ::fast_io::containers::details::deque_add_assign_signed_impl( + a.itercontent, static_cast<::std::ptrdiff_t>(pos)); + } + else + { + ::fast_io::containers::details::deque_add_assign_unsigned_impl( + a.itercontent, static_cast<::std::size_t>(pos)); + } + return a; } -template -inline constexpr ::fast_io::containers::details::deque_iterator operator+(::std::ptrdiff_t pos, ::fast_io::containers::details::deque_iterator a) noexcept +template +inline constexpr ::fast_io::containers::details::deque_iterator operator+(postype pos, ::fast_io::containers::details::deque_iterator a) noexcept { - return (a += pos); + if constexpr (::std::signed_integral) + { + ::fast_io::containers::details::deque_add_assign_signed_impl( + a.itercontent, static_cast<::std::ptrdiff_t>(pos)); + } + else + { + ::fast_io::containers::details::deque_add_assign_unsigned_impl( + a.itercontent, static_cast<::std::size_t>(pos)); + } + return a; } -template -inline constexpr ::fast_io::containers::details::deque_iterator operator-(::fast_io::containers::details::deque_iterator a, ::std::ptrdiff_t pos) noexcept +template +inline constexpr ::fast_io::containers::details::deque_iterator operator-(::fast_io::containers::details::deque_iterator a, postype pos) noexcept { - return (a -= pos); + if constexpr (::std::signed_integral) + { + ::fast_io::containers::details::deque_sub_assign_signed_impl( + a.itercontent, static_cast<::std::ptrdiff_t>(pos)); + } + else + { + ::fast_io::containers::details::deque_sub_assign_unsigned_impl( + a.itercontent, static_cast<::std::size_t>(pos)); + } + return a; } template @@ -268,6 +393,14 @@ inline constexpr ::std::ptrdiff_t deque_iter_difference_common(::fast_io::contai return controllerdiff * blocksizedf + (a.curr_ptr - b.begin_ptr) + (b.begin_ptr - b.curr_ptr); } +template +inline constexpr ::std::size_t deque_iter_difference_unsigned_common(::fast_io::containers::details::deque_control_block const &a, ::fast_io::containers::details::deque_control_block const &b) noexcept +{ + ::std::size_t controllerdiff{a.controller_ptr - b.controller_ptr}; + constexpr ::std::size_t blocksizedf{::fast_io::containers::details::deque_block_size}; + return controllerdiff * blocksizedf + static_cast<::std::size_t>((a.curr_ptr - b.begin_ptr) + (b.begin_ptr - b.curr_ptr)); +} + template inline constexpr ::std::ptrdiff_t operator-(::fast_io::containers::details::deque_iterator const &a, ::fast_io::containers::details::deque_iterator const &b) noexcept { @@ -929,6 +1062,12 @@ inline constexpr void deque_clone_trivial_common(dequecontroltype &controller, d } // namespace details +template <::std::forward_iterator ForwardIt> +inline constexpr ForwardIt rotate_for_fast_io_deque(ForwardIt first, ForwardIt middle, ForwardIt last) noexcept +{ + return ::std::rotate(first, middle, last); +} + template class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { @@ -1497,10 +1636,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { ::fast_io::fast_terminate(); } - - size_type real_index{static_cast(controller.front_block.curr_ptr - controller.front_block.begin_ptr) + index}; - - return controller.front_block.controller_ptr[real_index / block_size][real_index % block_size]; + return ::fast_io::containers::details::deque_index_unsigned(controller.front_block, index); } inline constexpr const_reference operator[](size_type index) const noexcept @@ -1509,35 +1645,28 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { ::fast_io::fast_terminate(); } - - size_type real_index{static_cast(controller.front_block.curr_ptr - controller.front_block.begin_ptr) + index}; - - return controller.front_block.controller_ptr[real_index / block_size][real_index % block_size]; + return ::fast_io::containers::details::deque_index_unsigned(controller.front_block, index); } inline constexpr reference index_unchecked(size_type index) noexcept { - size_type real_index{static_cast(controller.front_block.curr_ptr - controller.front_block.begin_ptr) + index}; - - return controller.front_block.controller_ptr[real_index / block_size][real_index % block_size]; + return ::fast_io::containers::details::deque_index_unsigned(controller.front_block, index); } inline constexpr const_reference index_unchecked(size_type index) const noexcept { - size_type real_index{static_cast(controller.front_block.curr_ptr - controller.front_block.begin_ptr) + index}; - - return controller.front_block.controller_ptr[real_index / block_size][real_index % block_size]; + return ::fast_io::containers::details::deque_index_unsigned(controller.front_block, index); } static inline constexpr size_type max_size() noexcept { - constexpr size_type mxval{SIZE_MAX / sizeof(value_type)}; + constexpr size_type mxval{::std::numeric_limits<::std::size_t>::max() / sizeof(value_type)}; return mxval; } static inline constexpr size_type max_size_bytes() noexcept { - constexpr size_type mxval{SIZE_MAX / sizeof(value_type) * sizeof(value_type)}; + constexpr size_type mxval{::std::numeric_limits<::std::size_t>::max() / sizeof(value_type) * sizeof(value_type)}; return mxval; } @@ -1660,6 +1789,98 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE this->controller = {{}, {}, {}}; } +private: + struct insert_range_result + { + size_type pos; + iterator it; + }; + template <::std::ranges::range R> + requires ::std::constructible_from> + inline constexpr insert_range_result insert_range_impl(size_type pos, R &&rg, size_type old_size) noexcept(::std::is_nothrow_constructible_v>) + { + size_type const halfold_size{old_size >> 1u}; +#if 0 + if constexpr(::std::ranges::sized_range) + { + size_type const rgsize{::std::ranges::size(rg)}; + } + else +#endif + { + size_type retpos; + iterator retit, rotfirst, rotmid, rotlast; + if (pos < halfold_size) + { + this->prepend_range(rg); + size_type const new_size{this->size()}; + size_type const inserted{new_size - old_size}; + auto bg{this->begin()}; + size_type newpos{pos + inserted}; + rotfirst = bg; + rotmid = bg + inserted; + retpos = newpos; + retit = rotlast = bg + newpos; + } + else + { + this->append_range(rg); + auto bg{this->begin()}; + rotfirst = retit = bg + pos; + rotmid = bg + old_size; + rotlast = this->end(); + retpos = pos; + } + ::fast_io::containers::rotate_for_fast_io_deque(rotfirst, rotmid, rotlast); + return {retpos, retit}; + } + } + +public: + template <::std::ranges::range R> + requires ::std::constructible_from> + inline constexpr iterator insert_range(const_iterator pos, R &&rg) noexcept(::std::is_nothrow_constructible_v>) + { + return this->insert_range_impl( + ::fast_io::containers::details::deque_iter_difference_unsigned_common(pos, this->cbegin()), rg, this->size()) + .it; + } + + template <::std::ranges::range R> + requires ::std::constructible_from> + inline constexpr size_type insert_range_index(size_type pos, R &&rg) noexcept(::std::is_nothrow_constructible_v>) + { + size_type const n{this->size()}; + if (n < pos) [[unlikely]] + { + ::fast_io::fast_terminate(); + } + return this->insert_range_impl(pos, rg, n).pos; + } + + template <::std::ranges::range R> + requires ::std::constructible_from> + inline constexpr void append_range(R &&rg) noexcept(::std::is_nothrow_constructible_v>) + { + // To do: cleanup code + for (auto &e : rg) + { + this->push_back(e); + } + } + + template <::std::ranges::range R> + requires ::std::constructible_from> + inline constexpr void prepend_range(R &&rg) noexcept(::std::is_nothrow_constructible_v>) + { + // To do: cleanup code + for (auto &e : rg) + { + this->push_front(e); + } + } + + inline constexpr ~deque() { destroy_deque_controller(this->controller); diff --git a/tests/0026.container/0003.deque/insert_range.cc b/tests/0026.container/0003.deque/insert_range.cc new file mode 100644 index 00000000..23ea687f --- /dev/null +++ b/tests/0026.container/0003.deque/insert_range.cc @@ -0,0 +1,84 @@ +#include +#include +#include +#include +namespace +{ +inline void test_insert_range_index() +{ + ::fast_io::io::perr("=== deque insert_range_index 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); + } + + // Helper to compare dq and ref + auto check_equal = [&](auto const &msg) { + if (dq.size() != ref.size()) + { + ::fast_io::io::panicln("ERROR: size mismatch: ", msg); + } + for (::std::size_t i{}; i != dq.size(); ++i) + { + if (dq[i] != ref[i]) + { + ::fast_io::io::panicln("ERROR: value mismatch at index ", i, " : ", msg); + } + } + }; + + // Test ranges + ::std::vector rg1{1000, 1001, 1002, 1003, 1004}; + ::std::vector rg2{2000, 2001, 2002}; + ::std::vector rg3{3000}; + + // Insert at front + { + dq.insert_range_index(0, rg1); + ref.insert(ref.begin(), rg1.begin(), rg1.end()); + check_equal("insert at front"); + } + + // Insert at middle + { + ::std::size_t pos{dq.size() / 2}; + dq.insert_range_index(pos, rg2); + ref.insert(ref.begin() + pos, rg2.begin(), rg2.end()); + check_equal("insert at middle"); + } + + // Insert at back + { + ::std::size_t pos{dq.size()}; + dq.insert_range_index(pos, rg3); + ref.insert(ref.end(), rg3.begin(), rg3.end()); + check_equal("insert at back"); + } + + // Randomized insertions + for (::std::size_t iter{}; iter != 200u; ++iter) + { + ::std::size_t pos = iter % (dq.size() + 1); + ::std::vector rg{iter + 5000, iter + 5001}; + + dq.insert_range_index(pos, rg); + ref.insert(ref.begin() + pos, rg.begin(), rg.end()); + + check_equal("randomized insert"); + } + + ::fast_io::io::print("deque insert_range_index test finished\n"); +} +} // namespace + +int main() +{ + test_insert_range_index(); +} \ No newline at end of file From 99e64db2e4d9ea1131dd497283910659ea2ecb43 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Fri, 9 Jan 2026 00:45:38 +0800 Subject: [PATCH 2/6] [skip ci] remove end_ptr in the iterator itself, only keep it in container This should resolve undefined behaviors due to nullptr+blocksize for end_ptr plus performance impact should be minimum for iterators due to compiler optimizations and probably even faster since iterators now have fewer fields --- include/fast_io_dsal/impl/deque.h | 184 ++++++++++++------------------ 1 file changed, 74 insertions(+), 110 deletions(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index 8a4c1cdf..65d675bd 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -13,15 +13,15 @@ struct #endif deque_control_block_common { + ::std::byte *begin_ptr, *curr_ptr; ::std::byte **controller_ptr; - ::std::byte *begin_ptr, *curr_ptr, *end_ptr; }; template struct deque_control_block { + T *begin_ptr, *curr_ptr; T **controller_ptr; - T *begin_ptr, *curr_ptr, *end_ptr; }; inline constexpr ::std::size_t deque_block_size_shift{12}; @@ -29,7 +29,7 @@ inline constexpr ::std::size_t deque_block_size_shift{12}; inline constexpr ::std::size_t deque_block_size_common{static_cast<::std::size_t>(1) << deque_block_size_shift}; template <::std::size_t sz> -inline constexpr ::std::size_t deque_block_size{sz <= (deque_block_size_common / 16u) ? (deque_block_size_common / sz) : 16u}; +inline constexpr ::std::size_t deque_block_size{sz <= (deque_block_size_common / 16u) ? ::std::bit_ceil(static_cast<::std::size_t>(deque_block_size_common / sz)) : static_cast<::std::size_t>(16u)}; struct #if __has_cpp_attribute(__gnu__::__may_alias__) @@ -60,7 +60,9 @@ struct deque_controller using replacetype = T; using controlreplacetype = T *; ::fast_io::containers::details::deque_control_block front_block; + controlreplacetype front_end_ptr; ::fast_io::containers::details::deque_control_block back_block; + controlreplacetype back_end_ptr; ::fast_io::containers::details::deque_controller_block controller_block; }; @@ -73,104 +75,92 @@ struct using replacetype = ::std::byte; using controlreplacetype = ::std::byte *; ::fast_io::containers::details::deque_control_block_common front_block; + controlreplacetype front_end_ptr; ::fast_io::containers::details::deque_control_block_common back_block; + controlreplacetype back_end_ptr; ::fast_io::containers::details::deque_controller_block_common controller_block; }; template -#if __has_cpp_attribute(clang::no_sanitize) -[[clang::no_sanitize("undefined")]] -#endif inline constexpr void deque_add_assign_signed_impl(::fast_io::containers::details::deque_control_block &itercontent, ::std::ptrdiff_t pos) noexcept { using size_type = ::std::size_t; constexpr size_type blocksize{::fast_io::containers::details::deque_block_size}; constexpr size_type blocksizem1{blocksize - 1u}; size_type unsignedpos{static_cast(pos)}; + auto begin_ptr{itercontent.begin_ptr}; auto curr_ptr{itercontent.curr_ptr}; auto controllerptr{itercontent.controller_ptr}; - decltype(curr_ptr) beginptr; + size_type diff{static_cast(curr_ptr - begin_ptr)}; if (pos < 0) { - size_type diff{static_cast(itercontent.end_ptr - curr_ptr)}; + diff = blocksizem1 - diff; constexpr size_type zero{}; size_type abspos{static_cast(zero - unsignedpos)}; diff += abspos; - itercontent.curr_ptr = (beginptr = *(controllerptr -= diff / blocksize)) + (blocksizem1 - diff % blocksize); + curr_ptr = (begin_ptr = *(controllerptr -= diff / blocksize)) + (blocksizem1 - diff % blocksize); } else { - size_type diff{static_cast(curr_ptr - itercontent.begin_ptr)}; diff += unsignedpos; - itercontent.curr_ptr = (beginptr = *(controllerptr += diff / blocksize)) + diff % blocksize; + curr_ptr = (begin_ptr = *(controllerptr += diff / blocksize)) + diff % blocksize; } + itercontent.begin_ptr = begin_ptr; + itercontent.curr_ptr = curr_ptr; itercontent.controller_ptr = controllerptr; - itercontent.begin_ptr = beginptr; - itercontent.end_ptr = beginptr + blocksize; } template -#if __has_cpp_attribute(clang::no_sanitize) -[[clang::no_sanitize("undefined")]] -#endif inline constexpr void deque_add_assign_unsigned_impl(::fast_io::containers::details::deque_control_block &itercontent, ::std::size_t unsignedpos) noexcept { using size_type = ::std::size_t; constexpr size_type blocksize{::fast_io::containers::details::deque_block_size}; - size_type diff{static_cast(itercontent.end_ptr - itercontent.curr_ptr) + unsignedpos}; - auto beginptr{*(itercontent.controller_ptr += diff / blocksize)}; - itercontent.begin_ptr = beginptr; - itercontent.curr_ptr = beginptr + diff % blocksize; - itercontent.end_ptr = beginptr + blocksize; + size_type diff{static_cast(itercontent.curr_ptr - itercontent.begin_ptr) + unsignedpos}; + auto begin_ptr{*(itercontent.controller_ptr += diff / blocksize)}; + itercontent.begin_ptr = begin_ptr; + itercontent.curr_ptr = begin_ptr + diff % blocksize; } template -#if __has_cpp_attribute(clang::no_sanitize) -[[clang::no_sanitize("undefined")]] -#endif inline constexpr void deque_sub_assign_signed_impl(::fast_io::containers::details::deque_control_block &itercontent, ::std::ptrdiff_t pos) noexcept { using size_type = ::std::size_t; constexpr size_type blocksize{::fast_io::containers::details::deque_block_size}; constexpr size_type blocksizem1{blocksize - 1u}; size_type unsignedpos{static_cast(pos)}; + auto begin_ptr{itercontent.begin_ptr}; auto curr_ptr{itercontent.curr_ptr}; auto controllerptr{itercontent.controller_ptr}; - decltype(curr_ptr) beginptr; + size_type diff{static_cast(curr_ptr - begin_ptr)}; if (pos < 0) { - size_type diff{static_cast(curr_ptr - itercontent.begin_ptr)}; constexpr size_type zero{}; size_type abspos{static_cast(zero - unsignedpos)}; diff += abspos; - itercontent.curr_ptr = (beginptr = *(controllerptr += diff / blocksize)) + diff % blocksize; + curr_ptr = (begin_ptr = *(controllerptr += diff / blocksize)) + diff % blocksize; } else { - size_type diff{static_cast(itercontent.end_ptr - curr_ptr)}; - diff += unsignedpos; - itercontent.curr_ptr = (beginptr = *(controllerptr -= diff / blocksize)) + (blocksizem1 - diff % blocksize); + diff = blocksize + unsignedpos - diff; + curr_ptr = (begin_ptr = *(controllerptr -= diff / blocksize)) + (blocksizem1 - diff % blocksize); } + itercontent.begin_ptr = begin_ptr; + itercontent.curr_ptr = curr_ptr; itercontent.controller_ptr = controllerptr; - itercontent.begin_ptr = beginptr; - itercontent.end_ptr = beginptr + blocksize; } template -#if __has_cpp_attribute(clang::no_sanitize) -[[clang::no_sanitize("undefined")]] -#endif inline constexpr void deque_sub_assign_unsigned_impl(::fast_io::containers::details::deque_control_block &itercontent, ::std::size_t unsignedpos) noexcept { using size_type = ::std::size_t; constexpr size_type blocksize{::fast_io::containers::details::deque_block_size}; constexpr size_type blocksizem1{blocksize - 1u}; - size_type diff{static_cast(itercontent.end_ptr - itercontent.curr_ptr) + unsignedpos}; - auto beginptr{*(itercontent.controller_ptr -= diff / blocksize)}; - itercontent.begin_ptr = beginptr; - itercontent.curr_ptr = beginptr + (blocksizem1 - diff % blocksize); - itercontent.end_ptr = beginptr + blocksize; + size_type diff{blocksize + unsignedpos - + static_cast(itercontent.curr_ptr - itercontent.begin_ptr)}; + auto begin_ptr{*(itercontent.controller_ptr -= diff / blocksize)}; + itercontent.begin_ptr = begin_ptr; + itercontent.curr_ptr = begin_ptr + (blocksizem1 - diff % blocksize); } template @@ -180,19 +170,19 @@ inline constexpr T &deque_index_signed(::fast_io::containers::details::deque_con constexpr size_type blocksize{::fast_io::containers::details::deque_block_size}; constexpr size_type blocksizem1{blocksize - 1u}; size_type unsignedpos{static_cast(pos)}; + auto begin_ptr{itercontent.begin_ptr}; auto curr_ptr{itercontent.curr_ptr}; auto controllerptr{itercontent.controller_ptr}; + size_type diff{static_cast(curr_ptr - begin_ptr)}; if (pos < 0) { - size_type diff{static_cast(itercontent.end_ptr - curr_ptr) - 1u}; constexpr size_type zero{}; size_type abspos{static_cast(zero - unsignedpos)}; - diff += abspos; + diff = blocksizem1 + abspos - diff; return (*(controllerptr - diff / blocksize))[blocksizem1 - diff % blocksize]; } else { - size_type diff{static_cast(curr_ptr - itercontent.begin_ptr)}; diff += unsignedpos; return controllerptr[diff / blocksize][diff % blocksize]; } @@ -221,32 +211,12 @@ struct deque_iterator using difference_type = ::std::ptrdiff_t; deque_control_block itercontent; -#if __has_cpp_attribute(clang::no_sanitize) - [[clang::no_sanitize("undefined")]] -#endif + inline constexpr deque_iterator &operator++() noexcept { - if (++itercontent.curr_ptr == itercontent.end_ptr) [[unlikely]] + if ((itercontent.begin_ptr + ::fast_io::containers::details::deque_block_size) == ++itercontent.curr_ptr) [[unlikely]] { - constexpr size_type blocksize{::fast_io::containers::details::deque_block_size}; - auto tmp{(itercontent.curr_ptr = itercontent.begin_ptr = (*++itercontent.controller_ptr))}; - constexpr bool ubsandisabled{ -#if __has_cpp_attribute(clang::no_sanitize) - true -#endif - }; - if constexpr (ubsandisabled) - { - tmp += blocksize; - } - else - { - if (tmp) [[likely]] // this makes no sense for sentinel - { - tmp += blocksize; - } - } - itercontent.end_ptr = tmp; + itercontent.curr_ptr = itercontent.begin_ptr = (*++itercontent.controller_ptr); } return *this; } @@ -255,8 +225,7 @@ struct deque_iterator { if (itercontent.curr_ptr == itercontent.begin_ptr) [[unlikely]] { - constexpr size_type blocksize{::fast_io::containers::details::deque_block_size}; - itercontent.end_ptr = itercontent.curr_ptr = ((itercontent.begin_ptr = (*--itercontent.controller_ptr)) + blocksize); + itercontent.curr_ptr = (itercontent.begin_ptr = (*--itercontent.controller_ptr)) + ::fast_io::containers::details::deque_block_size; } --itercontent.curr_ptr; return *this; @@ -622,7 +591,7 @@ inline constexpr void deque_allocate_on_empty_common_impl(dequecontroltype &cont ::std::size_t halfsize{bytes >> 1u}; back_block.begin_ptr = front_block.begin_ptr = begin_ptr; - back_block.end_ptr = front_block.end_ptr = (begin_ptr + bytes); + 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; @@ -724,13 +693,13 @@ inline constexpr void deque_grow_back_common_impl( } } - if (controller.back_block.controller_ptr == controller.front_block.controller_ptr && controller.front_block.curr_ptr == controller.front_block.end_ptr) + 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}; controller.front_block.controller_ptr = front_block_controller_ptr; auto front_begin_ptr = static_cast(*front_block_controller_ptr); controller.front_block.curr_ptr = controller.front_block.begin_ptr = front_begin_ptr; - controller.front_block.end_ptr = front_begin_ptr + bytes; + controller.front_end_ptr = front_begin_ptr + bytes; } /** @@ -747,7 +716,7 @@ inline constexpr void deque_grow_back_common_impl( controller.back_block.begin_ptr = begin_ptr; controller.back_block.curr_ptr = begin_ptr; - controller.back_block.end_ptr = begin_ptr + bytes; + controller.back_end_ptr = begin_ptr + bytes; #if 0 ::fast_io::iomnp::debug_println(::std::source_location::current()); @@ -835,7 +804,7 @@ inline constexpr void deque_grow_front_common_impl( "\n\tstart_ptr:", ::fast_io::iomnp::pointervw(controller.controller_block.controller_start_ptr)); #endif controller.front_block.begin_ptr = begin_ptr; - controller.front_block.end_ptr = (controller.front_block.curr_ptr = (begin_ptr + bytes)); + controller.front_end_ptr = (controller.front_block.curr_ptr = (begin_ptr + bytes)); } template @@ -875,7 +844,7 @@ inline constexpr void deque_clear_common_impl(dequecontroltype &controller, ::st controller.back_block.controller_ptr = controller.front_block.controller_ptr = reserved_pivot; controller.back_block.begin_ptr = controller.front_block.begin_ptr = begin_ptr; controller.back_block.curr_ptr = controller.front_block.curr_ptr = mid_ptr; - controller.back_block.end_ptr = controller.front_block.end_ptr = end_ptr; + controller.back_end_ptr = controller.front_end_ptr = end_ptr; } template @@ -890,7 +859,7 @@ inline constexpr void deque_allocate_init_blocks_dezeroing_impl(dequecontroltype { if (!blocks_count_least) { - controller = {{}, {}, {}}; + controller = {}; return; } constexpr ::std::size_t mx{::std::numeric_limits<::std::size_t>::max()}; @@ -921,11 +890,11 @@ inline constexpr void deque_allocate_init_blocks_dezeroing_impl(dequecontroltype using replacetype = typename dequecontroltype::replacetype; using begin_ptrtype = replacetype *; begin_ptrtype reserve_start_block{static_cast(*reserve_start)}; - controller.front_block = { - reserve_start, reserve_start_block, reserve_start_block, reserve_start_block + blockbytes}; + controller.front_block = {reserve_start_block, reserve_start_block, reserve_start}; + controller.front_end_ptr = reserve_start_block + blockbytes; begin_ptrtype reserve_back_block{static_cast(reserve_after[-1])}; - controller.back_block = { - reserve_after - 1, reserve_back_block, reserve_back_block, reserve_back_block + blockbytes}; + controller.back_block = {reserve_back_block, reserve_back_block, reserve_after - 1}; + controller.back_end_ptr = reserve_back_block + blockbytes; controller.controller_block = { start_ptr, reserve_start, reserve_after, start_ptr + blocks_count}; } @@ -1013,7 +982,7 @@ inline constexpr void deque_clone_trivial_impl(dequecontroltype &controller, deq { if (fromcontroller.front_block.curr_ptr == fromcontroller.back_block.curr_ptr) { - controller = {{}, {}, {}}; + controller = {}; return; } auto front_controller_ptr{fromcontroller.front_block.controller_ptr}; @@ -1034,9 +1003,9 @@ inline constexpr void deque_clone_trivial_impl(dequecontroltype &controller, deq { auto destit{controller.front_block.controller_ptr}; auto pos{fromcontroller.front_block.curr_ptr - fromcontroller.front_block.begin_ptr}; - controller.front_block.end_ptr = + controller.front_end_ptr = ::fast_io::freestanding::non_overlapped_copy(fromcontroller.front_block.curr_ptr, - fromcontroller.front_block.end_ptr, + fromcontroller.front_end_ptr, (controller.front_block.curr_ptr = pos + controller.front_block.begin_ptr)); ++destit; @@ -1090,7 +1059,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE controller_type controller; static inline constexpr size_type block_size{::fast_io::containers::details::deque_block_size}; inline constexpr deque() noexcept - : controller{{}, {}, {}} + : controller{} {} inline constexpr deque(deque const &other) noexcept(::std::is_nothrow_copy_constructible_v) @@ -1106,13 +1075,13 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE deque temp(other); destroy_deque_controller(this->controller); this->controller = temp.controller; - temp.controller = {{}, {}, {}}; + temp.controller = {}; return *this; } inline constexpr deque(deque &&other) noexcept : controller(other.controller) { - other.controller = {{}, {}, {}}; + other.controller = {}; } inline constexpr deque &operator=(deque &&other) noexcept { @@ -1122,7 +1091,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE } destroy_deque_controller(this->controller); this->controller = other.controller; - other.controller = {{}, {}, {}}; + other.controller = {}; return *this; } @@ -1163,7 +1132,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { if (fromcontroller.front_block.curr_ptr == fromcontroller.back_block.curr_ptr) { - this->controller = {{}, {}, {}}; + this->controller = {}; return; } @@ -1188,10 +1157,10 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE auto pos{fromcontroller.front_block.curr_ptr - fromcontroller.front_block.begin_ptr}; ::fast_io::freestanding::uninitialized_copy( fromcontroller.front_block.curr_ptr, - fromcontroller.front_block.end_ptr, + fromcontroller.front_end_ptr, (controller.front_block.curr_ptr = pos + controller.front_block.begin_ptr)); - this->controller.back_block.curr_ptr = controller.front_block.end_ptr = + this->controller.back_block.curr_ptr = controller.front_end_ptr = controller.front_block.begin_ptr + block_size; ++destit; for (pointer *it{front_controller_ptr + 1}, *ed{back_controller_ptr}; it != ed; ++it) @@ -1229,8 +1198,8 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE } else { - ::fast_io::freestanding::uninitialized_default_construct(controller.front_block.curr_ptr, controller.front_block.end_ptr); - this->controller.back_block.curr_ptr = this->controller.back_block.end_ptr; + ::fast_io::freestanding::uninitialized_default_construct(controller.front_block.curr_ptr, controller.front_end_ptr); + this->controller.back_block.curr_ptr = this->controller.back_end_ptr; for (T **it{front_controller_ptr + 1}, **ed{back_controller_ptr}; it != ed; ++it) { T *blockptr{*it}; @@ -1291,7 +1260,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { if (first == last) { - controller = {{}, {}, {}}; + controller = {}; return; } run_destroy des(__builtin_addressof(this->controller)); @@ -1329,7 +1298,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE } else { - controller = {{}, {}, {}}; + controller = {}; for (; first != last; ++first) { this->push_back(*first); @@ -1361,7 +1330,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE } else { - ::std::destroy(controller.front_block.curr_ptr, controller.front_block.end_ptr); + ::std::destroy(controller.front_block.curr_ptr, controller.front_end_ptr); for (T **it{front_controller_ptr + 1}, **ed{back_controller_ptr}; it != ed; ++it) { T *blockptr{*it}; @@ -1418,12 +1387,12 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { return; } - controller.front_block.end_ptr = (controller.front_block.curr_ptr = controller.front_block.begin_ptr = *(controller.front_block.controller_ptr = front_controller_ptr + 1)) + block_size; + controller.front_end_ptr = (controller.front_block.curr_ptr = controller.front_block.begin_ptr = *(controller.front_block.controller_ptr = front_controller_ptr + 1)) + block_size; } inline constexpr void back_backspace() noexcept { - controller.back_block.curr_ptr = (controller.back_block.end_ptr = ((controller.back_block.begin_ptr = *--controller.back_block.controller_ptr) + block_size)); + controller.back_block.curr_ptr = (controller.back_end_ptr = ((controller.back_block.begin_ptr = *--controller.back_block.controller_ptr) + block_size)); } public: @@ -1446,7 +1415,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE requires ::std::constructible_from inline constexpr reference emplace_back(Args &&...args) noexcept(::std::is_nothrow_constructible_v) { - if (controller.back_block.curr_ptr == controller.back_block.end_ptr) [[unlikely]] + if (controller.back_block.curr_ptr == controller.back_end_ptr) [[unlikely]] { grow_back(); } @@ -1534,11 +1503,11 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { auto &frontblock{this->thisdeq->front_block}; if (frontblock.curr_ptr == - frontblock.end_ptr && + this->thisdeq->front_end_ptr && frontblock.controller_ptr != this->thisdeq->back_block.controller_ptr) { - frontblock.end_ptr = ((frontblock.curr_ptr = frontblock.begin_ptr = *(++frontblock.controller_ptr)) + block_size); + this->thisdeq->front_end_ptr = ((frontblock.curr_ptr = frontblock.begin_ptr = *(++frontblock.controller_ptr)) + block_size); } } } @@ -1594,7 +1563,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE ::std::destroy_at(controller.front_block.curr_ptr); } - if (++controller.front_block.curr_ptr == controller.front_block.end_ptr) [[unlikely]] + if (++controller.front_block.curr_ptr == controller.front_end_ptr) [[unlikely]] { this->front_backspace(); } @@ -1714,16 +1683,11 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE inline constexpr ::fast_io::containers::details::deque_control_block end_common() noexcept { ::fast_io::containers::details::deque_control_block backblock{this->controller.back_block}; - if (backblock.curr_ptr == backblock.end_ptr) [[unlikely]] + if (backblock.curr_ptr == this->controller.back_end_ptr) [[unlikely]] { if (backblock.controller_ptr) [[likely]] { - auto tmp{backblock.curr_ptr = backblock.begin_ptr = (*++backblock.controller_ptr)}; - if (tmp) [[likely]] - { - tmp += block_size; - } - backblock.end_ptr = tmp; + backblock.curr_ptr = backblock.begin_ptr = (*++backblock.controller_ptr); } } return {backblock}; @@ -1732,11 +1696,11 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE inline constexpr ::fast_io::containers::details::deque_control_block end_common() const noexcept { ::fast_io::containers::details::deque_control_block backblock{this->controller.back_block}; - if (backblock.curr_ptr == backblock.end_ptr) [[unlikely]] + if (backblock.curr_ptr == this->controller.back_end_ptr) [[unlikely]] { if (backblock.controller_ptr) [[likely]] { - backblock.end_ptr = ((backblock.curr_ptr = backblock.begin_ptr = (*++backblock.controller_ptr)) + block_size); + backblock.curr_ptr = backblock.begin_ptr = (*++backblock.controller_ptr); } } return {backblock}; @@ -1786,7 +1750,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE inline constexpr void clear_destroy() noexcept { destroy_deque_controller(this->controller); - this->controller = {{}, {}, {}}; + this->controller = {}; } private: From 9defa04f1e94fe8a2db47aecb34aaf013b62662c Mon Sep 17 00:00:00 2001 From: trcrsired Date: Fri, 9 Jan 2026 01:29:12 +0800 Subject: [PATCH 3/6] add deque iterator test and fix -= --- include/fast_io_dsal/impl/deque.h | 13 +- .../0026.container/0003.deque/insert_range.cc | 181 +++++++++++++++++- 2 files changed, 186 insertions(+), 8 deletions(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index 65d675bd..0ea4bd9e 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -94,10 +94,9 @@ inline constexpr void deque_add_assign_signed_impl(::fast_io::containers::detail size_type diff{static_cast(curr_ptr - begin_ptr)}; if (pos < 0) { - diff = blocksizem1 - diff; constexpr size_type zero{}; size_type abspos{static_cast(zero - unsignedpos)}; - diff += abspos; + diff = (blocksizem1 + abspos) - diff; curr_ptr = (begin_ptr = *(controllerptr -= diff / blocksize)) + (blocksizem1 - diff % blocksize); } else @@ -142,7 +141,7 @@ inline constexpr void deque_sub_assign_signed_impl(::fast_io::containers::detail } else { - diff = blocksize + unsignedpos - diff; + diff = blocksizem1 + unsignedpos - diff; curr_ptr = (begin_ptr = *(controllerptr -= diff / blocksize)) + (blocksizem1 - diff % blocksize); } itercontent.begin_ptr = begin_ptr; @@ -156,7 +155,7 @@ inline constexpr void deque_sub_assign_unsigned_impl(::fast_io::containers::deta using size_type = ::std::size_t; constexpr size_type blocksize{::fast_io::containers::details::deque_block_size}; constexpr size_type blocksizem1{blocksize - 1u}; - size_type diff{blocksize + unsignedpos - + size_type diff{blocksizem1 + unsignedpos - static_cast(itercontent.curr_ptr - itercontent.begin_ptr)}; auto begin_ptr{*(itercontent.controller_ptr -= diff / blocksize)}; itercontent.begin_ptr = begin_ptr; @@ -164,7 +163,7 @@ inline constexpr void deque_sub_assign_unsigned_impl(::fast_io::containers::deta } template -inline constexpr T &deque_index_signed(::fast_io::containers::details::deque_control_block &itercontent, ::std::ptrdiff_t pos) noexcept +inline constexpr T &deque_index_signed(::fast_io::containers::details::deque_control_block const &itercontent, ::std::ptrdiff_t pos) noexcept { using size_type = ::std::size_t; constexpr size_type blocksize{::fast_io::containers::details::deque_block_size}; @@ -189,7 +188,7 @@ inline constexpr T &deque_index_signed(::fast_io::containers::details::deque_con } template -inline constexpr T &deque_index_unsigned(::fast_io::containers::details::deque_control_block &itercontent, ::std::size_t unsignedpos) noexcept +inline constexpr T &deque_index_unsigned(::fast_io::containers::details::deque_control_block const &itercontent, ::std::size_t unsignedpos) noexcept { using size_type = ::std::size_t; constexpr size_type blocksize{::fast_io::containers::details::deque_block_size}; @@ -1298,7 +1297,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE } else { - controller = {}; + this->controller = {}; for (; first != last; ++first) { this->push_back(*first); diff --git a/tests/0026.container/0003.deque/insert_range.cc b/tests/0026.container/0003.deque/insert_range.cc index 23ea687f..ee3569f4 100644 --- a/tests/0026.container/0003.deque/insert_range.cc +++ b/tests/0026.container/0003.deque/insert_range.cc @@ -2,8 +2,184 @@ #include #include #include + namespace { + +inline void test_iterator_ops() +{ + ::fast_io::io::perr("=== deque iterator test ===\n"); + + using T = std::size_t; + ::fast_io::deque dq; + std::deque ref; + + // Fill with known values + for (std::size_t i{}; i != 300u; ++i) + { + dq.push_back(i * 10); + ref.push_back(i * 10); + } + + auto check_equal = [&](auto const &msg, ::std::source_location src = ::std::source_location::current()) { + if (dq.size() != ref.size()) + { + ::fast_io::io::panicln(src, "\tsize mismatch: ", msg); + } + + for (std::size_t i{}; i != dq.size(); ++i) + { + if (*(dq.begin() + i) != ref[i]) + { + ::fast_io::io::panicln(src, "\tvalue mismatch at index ", i); + } + } + }; + + // 1. Forward iteration + { + auto it = dq.begin(); + for (std::size_t i{}; i != dq.size(); ++i, ++it) + { + if (*it != ref[i]) + { + ::fast_io::io::panicln("forward iteration mismatch at ", i); + } + } + } + + // 2. Backward iteration + { + auto it = dq.end(); + for (std::size_t i{dq.size()}; i != 0;) + { + --i; + --it; + if (*it != ref[i]) + { + ::fast_io::io::panicln("backward iteration mismatch at ", i); + } + } + } + + // 3. Random-access jumps + { + auto it = dq.begin(); + it += 100; + if (*it != ref[100]) + { + ::fast_io::io::panic("+= jump mismatch\n"); + } + + it -= 50; + if (*it != ref[50]) + { + ::fast_io::io::panic("-= jump mismatch\n"); + } + + auto it2 = it + 25; + if (*it2 != ref[75]) + { + ::fast_io::io::panic("it + n mismatch\n"); + } + + auto it3 = it2 - 30; + if (*it3 != ref[45]) + { + ::fast_io::io::panic("it - n mismatch\n"); + } + + std::ptrdiff_t diff = it2 - it3; + if (diff != 30) + { + ::fast_io::io::panic("iterator difference mismatch\n"); + } + } + + // 4. Comparison operators (<=> and == only) + { + auto a = dq.begin() + 10; + auto b = dq.begin() + 20; + + // Test <=> ordering + auto cmp = (a <=> b); + if (!(cmp < 0)) + { + ::fast_io::io::panic("a <=> b should be negative\n"); + } + + auto cmp2 = (b <=> a); + if (!(cmp2 > 0)) + { + ::fast_io::io::panic("b <=> a should be positive\n"); + } + + auto cmp3 = (a <=> a); + if (!(cmp3 == 0)) + { + ::fast_io::io::panic("a <=> a should be zero\n"); + } + + // Test equality + if (!(a == a)) + { + ::fast_io::io::panic("a == a failed\n"); + } + + if (a == b) + { + ::fast_io::io::panic("a == b incorrect\n"); + } + + if (!(a != b)) + { + ::fast_io::io::panic("a != b failed\n"); + } + } + + + // 5. Indexing operator it[n] + { + auto it = dq.begin() + 50; + for (std::size_t k{}; k != 20; ++k) + { + if (it[k] != ref[50 + k]) + { + ::fast_io::io::panicln("iterator indexing mismatch at offset ", k); + } + } + } + + // 6. const_iterator compatibility + { + auto const &cdq = dq; + auto cit = cdq.begin(); + auto it = dq.begin(); + + if (*cit != *it) + { + ::fast_io::io::panic("const_iterator deref mismatch\n"); + } + + cit += 123; + it += 123; + + if (*cit != *it) + { + ::fast_io::io::panic("const_iterator += mismatch\n"); + } + + if ((cit - cdq.begin()) != 123) + { + ::fast_io::io::panic("const_iterator difference mismatch\n"); + } + } + + check_equal("iterator ops"); + + ::fast_io::io::print("deque iterator test finished\n"); +} + inline void test_insert_range_index() { ::fast_io::io::perr("=== deque insert_range_index test ===\n"); @@ -80,5 +256,8 @@ inline void test_insert_range_index() int main() { - test_insert_range_index(); + test_iterator_ops(); +#if 0 + test_insert_range_index(); +#endif } \ No newline at end of file From 83813ec0bc693211778f9b0eb4b6e498a0806723 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Fri, 9 Jan 2026 02:04:27 +0800 Subject: [PATCH 4/6] deque fix some issues with missed back_block --- .../deque/0004.push_front/fast_io.cc | 26 +++++++++++++++++++ .../deque/0004.push_front/std.cc | 26 +++++++++++++++++++ include/fast_io_dsal/impl/deque.h | 26 +++++++++++++++---- 3 files changed, 73 insertions(+), 5 deletions(-) create mode 100644 benchmark/0011.containers/deque/0004.push_front/fast_io.cc create mode 100644 benchmark/0011.containers/deque/0004.push_front/std.cc diff --git a/benchmark/0011.containers/deque/0004.push_front/fast_io.cc b/benchmark/0011.containers/deque/0004.push_front/fast_io.cc new file mode 100644 index 00000000..444a76d3 --- /dev/null +++ b/benchmark/0011.containers/deque/0004.push_front/fast_io.cc @@ -0,0 +1,26 @@ +#include +#include +#include + +int main() +{ + fast_io::timer tm(u8"fast_io::deque"); + fast_io::deque deq; + constexpr std::size_t n{100000000}; + { + fast_io::timer tm1(u8"push_front"); + for (std::size_t i{}; i != n; ++i) + { + deq.push_front(i); + } + } + ::std::size_t sum{}; + { + fast_io::timer tm1(u8"loop"); + for (auto const e : deq) + { + sum += e; + } + } + ::fast_io::io::perrln("sum=",sum); +} diff --git a/benchmark/0011.containers/deque/0004.push_front/std.cc b/benchmark/0011.containers/deque/0004.push_front/std.cc new file mode 100644 index 00000000..707c8fc1 --- /dev/null +++ b/benchmark/0011.containers/deque/0004.push_front/std.cc @@ -0,0 +1,26 @@ +#include +#include +#include + +int main() +{ + fast_io::timer tm(u8"std::deque"); + std::deque deq; + constexpr std::size_t n{100000000}; + { + fast_io::timer tm1(u8"push_front"); + for (std::size_t i{}; i != n; ++i) + { + deq.push_front(i); + } + } + ::std::size_t sum{}; + { + fast_io::timer tm1(u8"loop"); + for (auto const e : deq) + { + 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 0ea4bd9e..266e906f 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -222,7 +222,7 @@ struct deque_iterator inline constexpr deque_iterator &operator--() noexcept { - if (itercontent.curr_ptr == itercontent.begin_ptr) [[unlikely]] + if (itercontent.begin_ptr == itercontent.curr_ptr) [[unlikely]] { itercontent.curr_ptr = (itercontent.begin_ptr = (*--itercontent.controller_ptr)) + ::fast_io::containers::details::deque_block_size; } @@ -1145,6 +1145,8 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE run_destroy destroyer(__builtin_addressof(this->controller)); auto dq_back_backup{this->controller.back_block}; this->controller.back_block = this->controller.front_block; + auto dq_back_end_ptr_backup{this->controller.back_end_ptr}; + this->controller.back_end_ptr = this->controller.front_end_ptr; pointer lastblockbegin; if (front_controller_ptr == back_controller_ptr) { @@ -1166,7 +1168,9 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { pointer blockptr{*it}; ::fast_io::freestanding::uninitialized_copy_n(blockptr, block_size, *destit); - this->controller.back_block = {destit, blockptr, blockptr, blockptr + block_size}; + auto new_curr_ptr{blockptr + block_size}; + this->controller.back_block = {blockptr, new_curr_ptr, destit}; + this->controller.back_end_ptr = new_curr_ptr; ++destit; } lastblockbegin = fromcontroller.back_block.begin_ptr; @@ -1177,6 +1181,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE fromcontroller.back_block.curr_ptr, dq_back_backup.begin_ptr); this->controller.back_block = dq_back_backup; + this->controller.back_end_ptr = dq_back_end_ptr_backup; destroyer.thiscontroller = nullptr; } } @@ -1186,6 +1191,8 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE auto dq_back_backup{controller.back_block}; controller.back_block = controller.front_block; + auto dq_back_end_ptr_backup{controller.back_end_ptr}; + controller.back_end_ptr = controller.back_begin_ptr; auto front_controller_ptr{controller.front_block.controller_ptr}; auto back_controller_ptr{controller.back_block.controller_ptr}; @@ -1203,12 +1210,15 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { T *blockptr{*it}; ::fast_io::freestanding::uninitialized_default_construct(blockptr, blockptr + block_size); - this->controller.back_block = {it, blockptr, blockptr + block_size, blockptr + block_size}; + auto new_curr_ptr{blockptr + block_size}; + this->controller.back_block = {blockptr, new_curr_ptr, it}; + this->controller.back_end_ptr = new_curr_ptr; } lastblockbegin = dq_back_backup.begin_ptr; } ::fast_io::freestanding::uninitialized_default_construct(lastblockbegin, dq_back_backup.curr_ptr); this->controller.back_block = dq_back_backup; + this->controller.back_end_ptr = dq_back_end_ptr_backup; des.thiscontroller = nullptr; } @@ -1270,9 +1280,12 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE this->init_blocks_common(static_cast<::std::size_t>(dist)); auto dq_back_backup{this->controller.back_block}; + this->controller.back_block = this->controller.front_block; + auto dq_back_end_ptr_backup{controller.back_end_ptr}; + controller.back_end_ptr = controller.back_begin_ptr; + auto front_controller_ptr{controller.front_block.controller_ptr}; auto back_controller_ptr{controller.back_block.controller_ptr}; - this->controller.back_block = this->controller.front_block; T *lastblockbegin; if (front_controller_ptr == back_controller_ptr) @@ -1285,7 +1298,9 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { T *blockptr{*it}; first = ::fast_io::containers::details::uninitialized_copy_n_for_deque(first, block_size, blockptr).from; - this->controller.back_block = {it, blockptr, blockptr + block_size, blockptr + block_size}; + auto new_curr_ptr{blockptr + block_size}; + this->controller.back_block = {blockptr, new_curr_ptr, it}; + this->controller.back_end_ptr = new_curr_ptr; } lastblockbegin = dq_back_backup.begin_ptr; } @@ -1294,6 +1309,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE static_cast<::std::size_t>(dq_back_backup.curr_ptr - lastblockbegin), lastblockbegin); this->controller.back_block = dq_back_backup; + this->controller.back_end_ptr = dq_back_end_ptr_backup; } else { From 06b056fc8b90f780e8419953088d3b5967985567 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Fri, 9 Jan 2026 02:24:14 +0800 Subject: [PATCH 5/6] controller.front_end_ptr misspelled --- 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 266e906f..d7df6aca 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -1282,7 +1282,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE auto dq_back_backup{this->controller.back_block}; this->controller.back_block = this->controller.front_block; auto dq_back_end_ptr_backup{controller.back_end_ptr}; - controller.back_end_ptr = controller.back_begin_ptr; + controller.back_end_ptr = controller.front_end_ptr; auto front_controller_ptr{controller.front_block.controller_ptr}; auto back_controller_ptr{controller.back_block.controller_ptr}; From 0661f8be1f2913ac371cd99dc31c50c4867b72a5 Mon Sep 17 00:00:00 2001 From: trcrsired Date: Fri, 9 Jan 2026 05:29:48 +0800 Subject: [PATCH 6/6] deque implementation the order was incorrectly changed, causing tests fail --- include/fast_io_dsal/impl/deque.h | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index d7df6aca..24a2ef43 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -1189,14 +1189,14 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { run_destroy des(__builtin_addressof(this->controller)); + auto front_controller_ptr{controller.front_block.controller_ptr}; + auto back_controller_ptr{controller.back_block.controller_ptr}; + auto dq_back_backup{controller.back_block}; controller.back_block = controller.front_block; auto dq_back_end_ptr_backup{controller.back_end_ptr}; controller.back_end_ptr = controller.back_begin_ptr; - auto front_controller_ptr{controller.front_block.controller_ptr}; - auto back_controller_ptr{controller.back_block.controller_ptr}; - T *lastblockbegin; if (front_controller_ptr == back_controller_ptr) { @@ -1278,15 +1278,13 @@ 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)); - + 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}; this->controller.back_block = this->controller.front_block; auto dq_back_end_ptr_backup{controller.back_end_ptr}; controller.back_end_ptr = controller.front_end_ptr; - auto front_controller_ptr{controller.front_block.controller_ptr}; - auto back_controller_ptr{controller.back_block.controller_ptr}; - T *lastblockbegin; if (front_controller_ptr == back_controller_ptr) {