diff --git a/.gitignore b/.gitignore index de6f16e4..060af3e2 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,6 @@ compile_commands.json # --- Exceptions --- # Allow documentation HTMLs !docs/**/*.html +# Claw Code local artifacts +.claude/settings.local.json +.claude/sessions/ diff --git a/benchmark/0011.containers/deque/0007.insert_single/fast_io.cc b/benchmark/0011.containers/deque/0007.insert_single/fast_io.cc new file mode 100644 index 00000000..fcdd5a9f --- /dev/null +++ b/benchmark/0011.containers/deque/0007.insert_single/fast_io.cc @@ -0,0 +1,32 @@ +#include +#include +#include +#include + +int main() +{ + fast_io::timer tm(u8"fast_io::deque insert single"); + fast_io::deque dq; + constexpr std::size_t n{50000}; + + { + fast_io::timer t(u8"insert_index"); + for (std::size_t i{}; i != n; ++i) + { + ::std::size_t dqsz{dq.size()}; + std::size_t pos = dqsz ? (i % dqsz) : 0; + dq.insert_index(pos, i); + } + } + + std::size_t sum{}; + { + fast_io::timer t(u8"loop"); + for (auto const e : dq) + { + sum += e; + } + } + + fast_io::io::perrln("sum=", sum); +} \ No newline at end of file diff --git a/benchmark/0011.containers/deque/0007.insert_single/fast_io_emplace.cc b/benchmark/0011.containers/deque/0007.insert_single/fast_io_emplace.cc new file mode 100644 index 00000000..a407062f --- /dev/null +++ b/benchmark/0011.containers/deque/0007.insert_single/fast_io_emplace.cc @@ -0,0 +1,32 @@ +#include +#include +#include +#include + +int main() +{ + fast_io::timer tm(u8"fast_io::deque emplace single"); + fast_io::deque dq; + constexpr std::size_t n{50000}; + + { + fast_io::timer t(u8"emplace_index"); + for (std::size_t i{}; i != n; ++i) + { + ::std::size_t dqsz{dq.size()}; + std::size_t pos = dqsz ? (i % dqsz) : 0; + dq.emplace_index(pos, i); + } + } + + std::size_t sum{}; + { + fast_io::timer t(u8"loop"); + for (auto const e : dq) + { + sum += e; + } + } + + fast_io::io::perrln("sum=", sum); +} \ No newline at end of file diff --git a/benchmark/0011.containers/deque/0007.insert_single/fast_io_iter.cc b/benchmark/0011.containers/deque/0007.insert_single/fast_io_iter.cc new file mode 100644 index 00000000..f7cdab6e --- /dev/null +++ b/benchmark/0011.containers/deque/0007.insert_single/fast_io_iter.cc @@ -0,0 +1,32 @@ +#include +#include +#include +#include + +int main() +{ + fast_io::timer tm(u8"fast_io::deque insert iterator"); + fast_io::deque dq; + constexpr std::size_t n{50000}; + + { + fast_io::timer t(u8"insert(iterator)"); + for (std::size_t i{}; i != n; ++i) + { + ::std::size_t dqsz{dq.size()}; + std::size_t pos = dqsz ? (i % dqsz) : 0; + dq.insert(dq.begin() + pos, i); + } + } + + std::size_t sum{}; + { + fast_io::timer t(u8"loop"); + for (auto const e : dq) + { + sum += e; + } + } + + fast_io::io::perrln("sum=", sum); +} \ No newline at end of file diff --git a/benchmark/0011.containers/deque/0007.insert_single/std.cc b/benchmark/0011.containers/deque/0007.insert_single/std.cc new file mode 100644 index 00000000..f3406cca --- /dev/null +++ b/benchmark/0011.containers/deque/0007.insert_single/std.cc @@ -0,0 +1,32 @@ +#include +#include +#include +#include + +int main() +{ + fast_io::timer tm(u8"std::deque insert single"); + ::std::deque dq; + constexpr std::size_t n{50000}; + + { + fast_io::timer t(u8"insert"); + for (std::size_t i{}; i != n; ++i) + { + ::std::size_t dqsz{dq.size()}; + std::size_t pos = dqsz ? (i % dqsz) : 0; + dq.insert(dq.begin() + pos, i); + } + } + + std::size_t sum{}; + { + fast_io::timer t(u8"loop"); + for (auto const e : dq) + { + sum += e; + } + } + + fast_io::io::perrln("sum=", sum); +} \ No newline at end of file diff --git a/fuzzing/0007.containers/deque/fuzz_deque_insert_single.cc b/fuzzing/0007.containers/deque/fuzz_deque_insert_single.cc new file mode 100644 index 00000000..664bf8b7 --- /dev/null +++ b/fuzzing/0007.containers/deque/fuzz_deque_insert_single.cc @@ -0,0 +1,75 @@ +#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 single at various positions + uint8_t op = b & 0x3u; + + // Position: [0, size] + std::size_t pos = dq.size() == 0 ? 0 : (static_cast(b) * 37u) % (dq.size() + 1); + + std::size_t value = i * 1315423911ull; + + switch (op) + { + case 0: // insert_index (single element) + { + dq.insert_index(pos, value); + ref.insert(ref.begin() + pos, value); + break; + } + + case 1: // insert using iterator (single element) + { + auto it = dq.insert(dq.cbegin() + pos, value); + (void)it; + ref.insert(ref.begin() + pos, value); + break; + } + + case 2: // erase single element (to keep sizes bounded) + { + if (!ref.empty()) + { + std::size_t p = pos % ref.size(); + dq.erase_index(p); + ref.erase(ref.begin() + p); + } + break; + } + + case 3: // emplace_index (single element) + { + dq.emplace_index(pos, value); + ref.emplace(ref.begin() + pos, value); + break; + } + } + + // Validate correctness + if (dq.size() != ref.size()) + { + __builtin_trap(); + } + + if (!std::ranges::equal(dq, ref)) + { + __builtin_trap(); + } + } + + return 0; +} \ No newline at end of file diff --git a/include/fast_io_dsal/impl/debug/common.h b/include/fast_io_dsal/impl/debug/common.h new file mode 100644 index 00000000..00af097b --- /dev/null +++ b/include/fast_io_dsal/impl/debug/common.h @@ -0,0 +1,24 @@ +#pragma once + +namespace fast_io +{ + +namespace manipulators +{ + +template +struct debug_view_t +{ + using manip_tag = manip_tag_t; + T reference; +}; + +template +inline constexpr debug_view_t debug_view(T const &v) noexcept +{ + return ::fast_io::manipulators::debug_view_t{v}; +} + +} // namespace manipulators + +} // namespace fast_io diff --git a/include/fast_io_dsal/impl/debug/deque.h b/include/fast_io_dsal/impl/debug/deque.h new file mode 100644 index 00000000..ddb0bcc4 --- /dev/null +++ b/include/fast_io_dsal/impl/debug/deque.h @@ -0,0 +1,213 @@ +#pragma once + +#include "common.h" + +namespace fast_io +{ + +namespace containers +{ +template +class deque; + +namespace details +{ +struct deque_controller_common; +} + +} // namespace containers + +namespace details +{ + +template <::std::integral char_type, typename T> +inline constexpr char_type *pr_rsv_define_deque_debug_impl(char_type *iter, T const &val) noexcept +{ + if constexpr (::std::same_as) + { + iter = ::fast_io::details::copy_string_literal("fast_io deque controller:\n\tfront_block.begin_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.front_block.begin_ptr)); + iter = ::fast_io::details::copy_string_literal("\n\tfront_block.curr_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.front_block.curr_ptr)); + iter = ::fast_io::details::copy_string_literal("\n\tfront_block.controller_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.front_block.controller_ptr)); + iter = ::fast_io::details::copy_string_literal("\n\tfront_end_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.front_end_ptr)); + iter = ::fast_io::details::copy_string_literal("\n\tback_block.begin_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.back_block.begin_ptr)); + iter = ::fast_io::details::copy_string_literal("\n\tback_block.curr_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.back_block.curr_ptr)); + iter = ::fast_io::details::copy_string_literal("\n\tback_block.controller_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.back_block.controller_ptr)); + iter = ::fast_io::details::copy_string_literal("\n\tback_end_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.back_end_ptr)); + iter = ::fast_io::details::copy_string_literal("\n\tcontroller_block.controller_start_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.controller_block.controller_start_ptr)); + iter = ::fast_io::details::copy_string_literal("\n\tcontroller_block.controller_start_reserved_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.controller_block.controller_start_reserved_ptr)); + iter = ::fast_io::details::copy_string_literal("\n\tcontroller_block.controller_after_reserved_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.controller_block.controller_after_reserved_ptr)); + iter = ::fast_io::details::copy_string_literal("\n\tcontroller_block.controller_after_ptr:", iter); + return ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.controller_block.controller_after_ptr)); + } + else if constexpr (::std::same_as) + { + iter = ::fast_io::details::copy_string_literal(L"fast_io deque controller:\n\tfront_block.begin_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.front_block.begin_ptr)); + iter = ::fast_io::details::copy_string_literal(L"\n\tfront_block.curr_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.front_block.curr_ptr)); + iter = ::fast_io::details::copy_string_literal(L"\n\tfront_block.controller_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.front_block.controller_ptr)); + iter = ::fast_io::details::copy_string_literal(L"\n\tfront_end_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.front_end_ptr)); + iter = ::fast_io::details::copy_string_literal(L"\n\tback_block.begin_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.back_block.begin_ptr)); + iter = ::fast_io::details::copy_string_literal(L"\n\tback_block.curr_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.back_block.curr_ptr)); + iter = ::fast_io::details::copy_string_literal(L"\n\tback_block.controller_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.back_block.controller_ptr)); + iter = ::fast_io::details::copy_string_literal(L"\n\tback_end_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.back_end_ptr)); + iter = ::fast_io::details::copy_string_literal(L"\n\tcontroller_block.controller_start_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.controller_block.controller_start_ptr)); + iter = ::fast_io::details::copy_string_literal(L"\n\tcontroller_block.controller_start_reserved_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.controller_block.controller_start_reserved_ptr)); + iter = ::fast_io::details::copy_string_literal(L"\n\tcontroller_block.controller_after_reserved_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.controller_block.controller_after_reserved_ptr)); + iter = ::fast_io::details::copy_string_literal(L"\n\tcontroller_block.controller_after_ptr:", iter); + return ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.controller_block.controller_after_ptr)); + } + else if constexpr (::std::same_as) + { + iter = ::fast_io::details::copy_string_literal(u"fast_io deque controller:\n\tfront_block.begin_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.front_block.begin_ptr)); + iter = ::fast_io::details::copy_string_literal(u"\n\tfront_block.curr_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.front_block.curr_ptr)); + iter = ::fast_io::details::copy_string_literal(u"\n\tfront_block.controller_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.front_block.controller_ptr)); + iter = ::fast_io::details::copy_string_literal(u"\n\tfront_end_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.front_end_ptr)); + iter = ::fast_io::details::copy_string_literal(u"\n\tback_block.begin_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.back_block.begin_ptr)); + iter = ::fast_io::details::copy_string_literal(u"\n\tback_block.curr_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.back_block.curr_ptr)); + iter = ::fast_io::details::copy_string_literal(u"\n\tback_block.controller_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.back_block.controller_ptr)); + iter = ::fast_io::details::copy_string_literal(u"\n\tback_end_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.back_end_ptr)); + iter = ::fast_io::details::copy_string_literal(u"\n\tcontroller_block.controller_start_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.controller_block.controller_start_ptr)); + iter = ::fast_io::details::copy_string_literal(u"\n\tcontroller_block.controller_start_reserved_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.controller_block.controller_start_reserved_ptr)); + iter = ::fast_io::details::copy_string_literal(u"\n\tcontroller_block.controller_after_reserved_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.controller_block.controller_after_reserved_ptr)); + iter = ::fast_io::details::copy_string_literal(u"\n\tcontroller_block.controller_after_ptr:", iter); + return ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.controller_block.controller_after_ptr)); + } + else if constexpr (::std::same_as) + { + iter = ::fast_io::details::copy_string_literal(U"fast_io deque controller:\n\tfront_block.begin_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.front_block.begin_ptr)); + iter = ::fast_io::details::copy_string_literal(U"\n\tfront_block.curr_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.front_block.curr_ptr)); + iter = ::fast_io::details::copy_string_literal(U"\n\tfront_block.controller_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.front_block.controller_ptr)); + iter = ::fast_io::details::copy_string_literal(U"\n\tfront_end_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.front_end_ptr)); + iter = ::fast_io::details::copy_string_literal(U"\n\tback_block.begin_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.back_block.begin_ptr)); + iter = ::fast_io::details::copy_string_literal(U"\n\tback_block.curr_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.back_block.curr_ptr)); + iter = ::fast_io::details::copy_string_literal(U"\n\tback_block.controller_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.back_block.controller_ptr)); + iter = ::fast_io::details::copy_string_literal(U"\n\tback_end_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.back_end_ptr)); + iter = ::fast_io::details::copy_string_literal(U"\n\tcontroller_block.controller_start_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.controller_block.controller_start_ptr)); + iter = ::fast_io::details::copy_string_literal(U"\n\tcontroller_block.controller_start_reserved_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.controller_block.controller_start_reserved_ptr)); + iter = ::fast_io::details::copy_string_literal(U"\n\tcontroller_block.controller_after_reserved_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.controller_block.controller_after_reserved_ptr)); + iter = ::fast_io::details::copy_string_literal(U"\n\tcontroller_block.controller_after_ptr:", iter); + return ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.controller_block.controller_after_ptr)); + } + else + { + iter = ::fast_io::details::copy_string_literal(u8"fast_io deque controller:\n\tfront_block.begin_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.front_block.begin_ptr)); + iter = ::fast_io::details::copy_string_literal(u8"\n\tfront_block.curr_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.front_block.curr_ptr)); + iter = ::fast_io::details::copy_string_literal(u8"\n\tfront_block.controller_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.front_block.controller_ptr)); + iter = ::fast_io::details::copy_string_literal(u8"\n\tfront_end_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.front_end_ptr)); + iter = ::fast_io::details::copy_string_literal(u8"\n\tback_block.begin_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.back_block.begin_ptr)); + iter = ::fast_io::details::copy_string_literal(u8"\n\tback_block.curr_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.back_block.curr_ptr)); + iter = ::fast_io::details::copy_string_literal(u8"\n\tback_block.controller_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.back_block.controller_ptr)); + iter = ::fast_io::details::copy_string_literal(u8"\n\tback_end_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.back_end_ptr)); + iter = ::fast_io::details::copy_string_literal(u8"\n\tcontroller_block.controller_start_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.controller_block.controller_start_ptr)); + iter = ::fast_io::details::copy_string_literal(u8"\n\tcontroller_block.controller_start_reserved_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.controller_block.controller_start_reserved_ptr)); + iter = ::fast_io::details::copy_string_literal(u8"\n\tcontroller_block.controller_after_reserved_ptr:", iter); + iter = ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.controller_block.controller_after_reserved_ptr)); + iter = ::fast_io::details::copy_string_literal(u8"\n\tcontroller_block.controller_after_ptr:", iter); + return ::fast_io::pr_rsv_to_iterator_unchecked(iter, ::fast_io::mnp::pointervw(val.controller_block.controller_after_ptr)); + } +} + +} // namespace details + +namespace manipulators +{ +template <::std::integral char_type, typename T, typename allocator> +inline constexpr ::std::size_t print_reserve_size(::fast_io::io_reserve_type_t const &>>) noexcept +{ + constexpr ::std::size_t ptrlen{::fast_io::pr_rsv_size()))>}; + constexpr ::std::size_t literal_counts{12u}; + constexpr std::size_t literal_total{ + sizeof( + u8"fast_io deque controller:\n\tfront_block.begin_ptr:" + u8"\n\tfront_block.curr_ptr:" + u8"\n\tfront_block.controller_ptr:" + u8"\n\tfront_end_ptr:" + u8"\n\tback_block.begin_ptr:" + u8"\n\tback_block.curr_ptr:" + u8"\n\tback_block.controller_ptr:" + u8"\n\tback_end_ptr:" + u8"\n\tcontroller_block.controller_start_ptr:" + u8"\n\tcontroller_block.controller_start_reserved_ptr:" + u8"\n\tcontroller_block.controller_after_reserved_ptr:" + u8"\n\tcontroller_block.controller_after_ptr:") - + 1u}; + return literal_total + literal_counts * ptrlen; +} + +template <::std::integral char_type, typename T, typename allocator> +inline constexpr char_type *print_reserve_define( + ::fast_io::io_reserve_type_t const &>>, + char_type *ptr, ::fast_io::manipulators::debug_view_t<::fast_io::containers::deque const &> val) noexcept +{ + if consteval + { + return ::fast_io::details::pr_rsv_define_deque_debug_impl(ptr, val.reference.controller); + } + else + { + return ::fast_io::details::pr_rsv_define_deque_debug_impl( + ptr, + *reinterpret_cast< + ::fast_io::containers::details::deque_controller_common const *>( + __builtin_addressof(val.reference.controller))); + } +} + +} // namespace manipulators + +} // namespace fast_io diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index ca6e41e2..ec46a2ce 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -458,9 +458,6 @@ inline constexpr void deque_destroy_trivial_common(controllerblocktype &controll template inline constexpr void deque_grow_to_new_blocks_count_impl(dequecontroltype &controller, ::std::size_t new_blocks_count_least) noexcept { -#if 0 - ::fast_io::iomnp::debug_println(::std::source_location::current()); -#endif auto old_start_ptr{controller.controller_block.controller_start_ptr}; auto old_start_reserved_ptr{controller.controller_block.controller_start_reserved_ptr}; @@ -505,13 +502,7 @@ inline constexpr void deque_grow_to_new_blocks_count_impl(dequecontroltype &cont ::std::size_t const new_blocks_offset{static_cast<::std::size_t>(new_blocks_count - old_reserved_blocks_count) >> 1u}; --new_blocks_count; -#if 0 - ::fast_io::iomnp::debug_println(::std::source_location::current(),"\n" - "\tnew_blocks_count=",new_blocks_count,"\n" - "\told_after_ptr_pos=",old_after_ptr_pos,"\n" - "\tnew_blocks_offset=",new_blocks_offset,"\n" - "\tpivot_diff=",pivot_diff); -#endif + auto new_start_reserved_ptr{new_start_ptr + new_blocks_offset}; auto new_after_reserved_ptr{new_start_reserved_ptr + old_reserved_blocks_count}; @@ -556,9 +547,6 @@ inline constexpr void deque_rebalance_or_grow_2x_after_blocks_impl(dequecontrolt auto const half_slots_count{static_cast<::std::size_t>(total_slots_count >> 1u)}; if (half_slots_count < used_blocks_count) // grow blocks { -#if 0 - ::fast_io::iomnp::debug_println(::std::source_location::current()); -#endif 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) @@ -570,9 +558,6 @@ inline constexpr void deque_rebalance_or_grow_2x_after_blocks_impl(dequecontrolt } else { -#if 0 - ::fast_io::iomnp::debug_println(::std::source_location::current()); -#endif // balance blocks auto start_reserved_ptr{controller.controller_block.controller_start_reserved_ptr}; auto after_reserved_ptr{controller.controller_block.controller_after_reserved_ptr}; @@ -587,10 +572,6 @@ inline constexpr void deque_rebalance_or_grow_2x_after_blocks_impl(dequecontrolt if (used_blocks_pivot != reserved_pivot) { ::std::ptrdiff_t diff{reserved_pivot - used_blocks_pivot}; -#if 0 - ::fast_io::iomnp::debug_println(::std::source_location::current(), - "\tdiff=",diff); -#endif auto rotate_pivot{diff < 0 ? start_reserved_ptr : after_reserved_ptr}; rotate_pivot -= diff; ::std::rotate(start_reserved_ptr, rotate_pivot, after_reserved_ptr); @@ -601,9 +582,6 @@ inline constexpr void deque_rebalance_or_grow_2x_after_blocks_impl(dequecontrolt auto slots_pivot{controller.controller_block.controller_start_ptr + half_slots_count}; if (slots_pivot != reserved_pivot) { -#if 0 - ::fast_io::iomnp::debug_println(::std::source_location::current()); -#endif ::std::ptrdiff_t diff{slots_pivot - reserved_pivot}; ::fast_io::freestanding::overlapped_copy(start_reserved_ptr, after_reserved_ptr, start_reserved_ptr + diff); @@ -1143,6 +1121,15 @@ deque_erase_common_trivial_impl(::fast_io::containers::details::deque_controller { controller.front_block = ::fast_io::containers::details::deque_copy_backward_impl(controller.front_block, first, last, blockbytes); first = last; + if (controller.front_block.curr_ptr == back_block.curr_ptr && back_block.curr_ptr == controller.back_end_ptr) [[unlikely]] + { + auto back_begin_ptr{back_block.begin_ptr}; + if (back_begin_ptr) [[likely]] + { + // erase after empty we should reset to middle + controller.front_block.curr_ptr = back_block.curr_ptr = back_begin_ptr + (blockbytes >> 1u); + } + } } else { @@ -1624,7 +1611,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE public: controller_type controller; static inline constexpr size_type block_size{::fast_io::containers::details::deque_block_size}; - inline constexpr deque() noexcept + inline explicit constexpr deque() noexcept : controller{} {} @@ -2043,7 +2030,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE return *currptr; } - inline constexpr void push_back(value_type const &value) + inline constexpr void push_back(value_type const &value) noexcept(::std::is_nothrow_copy_constructible_v) { this->emplace_back(value); } @@ -2052,7 +2039,6 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { this->emplace_back(::std::move(value)); } - inline constexpr void pop_back() noexcept { if (controller.front_block.curr_ptr == controller.back_block.curr_ptr) [[unlikely]] @@ -2107,7 +2093,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE private: struct emplace_front_guard { - using handletype = ::fast_io::containers::details::deque_controller_block; + using handletype = ::fast_io::containers::details::deque_controller; handletype *thisdeq; explicit constexpr emplace_front_guard(handletype *other) noexcept : thisdeq{other} { @@ -2146,7 +2132,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE } else { - emplace_front_guard guard(this->controller); + emplace_front_guard guard(__builtin_addressof(this->controller)); front_curr_ptr = ::std::construct_at(front_curr_ptr - 1, ::std::forward(args)...); guard.thisdeq = nullptr; return *(controller.front_block.curr_ptr = front_curr_ptr); @@ -2363,9 +2349,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE size_type pos; iterator it; }; - template <::std::ranges::range R> - requires ::std::constructible_from> - inline constexpr insert_range_result insert_range_front_impl(size_type pos, R &&rg, size_type rgsize) noexcept(::std::is_nothrow_constructible_v>) + inline constexpr insert_range_result insert_n_front_common_impl(size_type pos, size_type rgsize) noexcept { ::fast_io::containers::details::deque_reserve_front_spaces(this->controller, rgsize); @@ -2374,15 +2358,19 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE auto thisbgrgsize{thisbg - rgsize}; auto thisbgrgsizenew{::fast_io::freestanding::uninitialized_relocate(thisbg, posit, thisbgrgsize)}; - ::fast_io::freestanding::uninitialized_copy_n(::std::ranges::cbegin(rg), rgsize, thisbgrgsizenew); - this->controller.front_block = thisbgrgsize.itercontent; this->controller.front_end_ptr = thisbgrgsize.itercontent.begin_ptr + block_size; return {pos, thisbgrgsizenew}; } template <::std::ranges::range R> requires ::std::constructible_from> - inline constexpr insert_range_result insert_range_back_impl(size_type pos, R &&rg, size_type rgsize) noexcept(::std::is_nothrow_constructible_v>) + inline constexpr insert_range_result insert_range_front_impl(size_type pos, R &&rg, size_type rgsize) noexcept(::std::is_nothrow_constructible_v>) + { + auto ret{this->insert_n_front_common_impl(pos, rgsize)}; + ::fast_io::freestanding::uninitialized_copy_n(::std::ranges::cbegin(rg), rgsize, ret.it); + return ret; + } + inline constexpr insert_range_result insert_n_back_common_impl(size_type pos, size_type rgsize) noexcept { ::fast_io::containers::details::deque_reserve_back_spaces(this->controller, rgsize); @@ -2391,7 +2379,6 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE auto thisendrgsize{thisend + rgsize}; ::fast_io::freestanding::uninitialized_relocate_backward(posit, thisend, thisendrgsize); - ::fast_io::freestanding::uninitialized_copy_n(::std::ranges::cbegin(rg), rgsize, posit); if (thisendrgsize.itercontent.begin_ptr == thisendrgsize.itercontent.curr_ptr) { thisendrgsize.itercontent.curr_ptr = @@ -2401,6 +2388,14 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE this->controller.back_end_ptr = thisendrgsize.itercontent.begin_ptr + block_size; return {pos, posit}; } + template <::std::ranges::range R> + requires ::std::constructible_from> + inline constexpr insert_range_result insert_range_back_impl(size_type pos, R &&rg, size_type rgsize) noexcept(::std::is_nothrow_constructible_v>) + { + auto ret{this->insert_n_back_common_impl(pos, rgsize)}; + ::fast_io::freestanding::uninitialized_copy_n(::std::ranges::cbegin(rg), rgsize, ret.it); + return ret; + } 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>) @@ -2413,14 +2408,17 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE return {pos, this->begin() + pos}; } size_type const half_size{old_size >> 1u}; + insert_range_result ret; if (pos < half_size) { - return this->insert_range_front_impl(pos, ::std::forward(rg), rgsize); + ret = this->insert_n_front_common_impl(pos, rgsize); } else { - return this->insert_range_back_impl(pos, ::std::forward(rg), rgsize); + ret = this->insert_n_back_common_impl(pos, rgsize); } + ::fast_io::freestanding::uninitialized_copy_n(::std::ranges::cbegin(rg), rgsize, ret.it); + return ret; } else { @@ -2592,6 +2590,277 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE } } +private: + inline constexpr insert_range_result emplace_index_n_impl(size_type pos, size_type n, size_type old_size) noexcept + { + size_type const half_size{old_size >> 1u}; + insert_range_result ret; + if (pos < half_size) + { + ret = this->insert_n_front_common_impl(pos, n); + } + else + { + ret = this->insert_n_back_common_impl(pos, n); + } + return ret; + } + inline constexpr insert_range_result emplace_index_impl(size_type pos, size_type n) noexcept + { + return this->emplace_index_n_impl(pos, 1u, n); + } + inline constexpr insert_range_result emplace_impl(size_type pos) noexcept + { + return this->emplace_index_impl(pos, this->size()); + } + + struct emplace_decision + { + ::std::size_t pos; + ::std::int_fast8_t decision; + }; + template + inline constexpr ::std::conditional_t + emplace_decision_common(const_iterator iter) noexcept + { + // eh safety for being and end. + auto iter_curr_ptr{iter.itercontent.curr_ptr}; + if (iter_curr_ptr == this->controller.back_block.curr_ptr || + this->controller.back_block.controller_ptr < iter.itercontent.controller_ptr) + { + if (this->controller.back_block.curr_ptr != controller.back_end_ptr) [[likely]] + { + iterator retit{this->controller.back_block.begin_ptr, + this->controller.back_block.curr_ptr++, + this->controller.back_block.controller_ptr}; + if constexpr (isnothrow) + { + return retit; + } + else + { + return emplace_decision{retit, 1}; + } + } + } + else if (iter_curr_ptr == this->controller.front_block.curr_ptr) + { + if (this->controller.front_block.curr_ptr != this->controller.front_block.begin_ptr) [[likely]] + { + iterator retit{this->controller.front_block.begin_ptr, + --this->controller.front_block.curr_ptr, + this->controller.front_block.controller_ptr}; + if constexpr (isnothrow) + { + return retit; + } + else + { + return emplace_decision{retit, -1}; + } + } + } + iterator retit{this->emplace_impl(::fast_io::containers::details::deque_iter_difference_unsigned_common(iter.itercontent, this->controller.front_block)).it}; + if constexpr (isnothrow) + { + return retit; + } + else + { + return emplace_decision{retit, 0}; + } + } + struct emplace_guard + { + deque *thisdeq; + iterator retit; + ::std::int_fast8_t decision; + constexpr ~emplace_guard() + { + if (thisdeq) [[unlikely]] + { + auto &thiscontroller{thisdeq->controller}; + if (decision < 0) + { + ++thiscontroller.front_block.curr_ptr; + } + else if (0 < decision) + { + --thiscontroller.back_block.curr_ptr; + } + else + { + ::std::size_t const distofront{ + ::fast_io::containers::details::deque_iter_difference_unsigned_common(retit.itercontent, thisdeq->controller.front_block)}; + ::std::size_t const deqsize{thisdeq->size()}; + thisdeq->erase_unchecked_single_nodestroy_impl(retit, static_cast<::std::size_t>(deqsize - distofront) < distofront); + } + } + } + }; + struct emplace_index_decision + { + pointer retptr; + ::std::int_fast8_t decision; + }; + template + inline constexpr ::std::conditional_t + emplace_index_decision_common(::std::size_t idx) noexcept + { + + auto oldsize{this->size()}; + if (oldsize < idx) [[unlikely]] + { + ::fast_io::fast_terminate(); +#if __has_cpp_attribute(unreachable) + [[unreachable]]; +#endif + } +#if 1 + else if (idx == oldsize) + { + if (this->controller.back_block.curr_ptr != controller.back_end_ptr) [[likely]] + { + pointer retptr{this->controller.back_block.curr_ptr++}; + if constexpr (isnothrow) + { + return retptr; + } + else + { + return emplace_index_decision{retptr, 1}; + } + } + } + else if (!idx) + { + if (this->controller.front_block.curr_ptr != this->controller.front_block.begin_ptr) [[likely]] + { + pointer retptr{--this->controller.front_block.curr_ptr}; + if constexpr (isnothrow) + { + return retptr; + } + else + { + return emplace_index_decision{retptr, -1}; + } + } + } +#endif + auto result{this->emplace_index_impl(idx, oldsize)}; + pointer retptr{result.it.itercontent.curr_ptr}; + if constexpr (isnothrow) + { + return retptr; + } + else + { + return emplace_index_decision{retptr, 0}; + } + } + + struct emplace_index_guard + { + deque *thisdeq; + ::std::size_t pos; + ::std::size_t oldsize; + ::std::int_fast8_t decision; + constexpr ~emplace_index_guard() + { + if (thisdeq) [[unlikely]] + { + auto &thiscontroller{thisdeq->controller}; + if (decision < 0) + { + ++thiscontroller.front_block.curr_ptr; + } + else if (0 < decision) + { + --thiscontroller.back_block.curr_ptr; + } + else + { + thisdeq->erase_unchecked_single_nodestroy_impl( + thisdeq->begin() + static_cast<::std::ptrdiff_t>(pos), + static_cast<::std::size_t>(oldsize - pos) <= pos); + } + } + } + }; + +public: + template + inline constexpr iterator emplace(const_iterator iter, Args &&...args) noexcept(::std::is_nothrow_constructible_v) + { + if constexpr (::std::is_nothrow_constructible_v) + { + auto retit = this->emplace_decision_common(iter); + ::std::construct_at(retit.itercontent.curr_ptr, ::std::forward(args)...); + return retit; + } + else + { + auto [retit, decision] = this->emplace_decision_common(iter); + emplace_guard guard{this, retit, decision}; + ::std::construct_at(retit.itercontent.curr_ptr, ::std::forward(args)...); + guard.thisdeq = nullptr; + return retit; + } + } + template + inline constexpr reference emplace_index(size_type idx, Args &&...args) noexcept(::std::is_nothrow_constructible_v) + { + // bounds checking && eh safety for being and end. + auto oldsize{this->size()}; + if (oldsize < idx) [[unlikely]] + { + ::fast_io::fast_terminate(); + } + if constexpr (::std::is_nothrow_constructible_v) + { + auto retptr = this->emplace_index_decision_common(idx); + ::std::construct_at(retptr, ::std::forward(args)...); + return *retptr; + } + else + { + auto [retptr, decision] = this->emplace_index_decision_common(idx); + emplace_index_guard guard{this, idx, oldsize, decision}; + ::std::construct_at(retptr, ::std::forward(args)...); + guard.thisdeq = nullptr; + return *retptr; + } + } + + inline constexpr iterator insert(const_iterator iter, const_reference val) noexcept(::std::is_nothrow_copy_constructible_v) + { + return this->emplace(iter, val); + } + inline constexpr iterator insert(const_iterator iter, value_type &&val) noexcept(::std::is_nothrow_move_constructible_v) + { + return this->emplace(iter, ::std::move(val)); + } + inline constexpr reference insert_index(size_type idx, const_reference val) noexcept(::std::is_nothrow_copy_constructible_v) + { + return this->emplace_index(idx, val); + } + inline constexpr reference insert_index(size_type idx, value_type &&val) noexcept(::std::is_nothrow_move_constructible_v) + { + return this->emplace_index(idx, ::std::move(val)); + } + +#if 0 + 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) + { + + } +#endif private: inline constexpr iterator erase_no_destroy_common_impl(iterator first, iterator last, bool moveleft) noexcept { @@ -2642,12 +2911,8 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE } return this->erase_no_destroy_common_impl(first, last, moveleft); } - inline constexpr iterator erase_unchecked_single_impl(iterator pos, bool moveleft) noexcept + inline constexpr iterator erase_unchecked_single_nodestroy_impl(iterator pos, bool moveleft) noexcept { - if constexpr (!::std::is_trivially_destructible_v) - { - ::std::destroy(pos.itercontent.curr_ptr); - } if constexpr (::fast_io::freestanding::is_trivially_copyable_or_relocatable_v) { if !consteval @@ -2673,6 +2938,14 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE ++posp1; return this->erase_no_destroy_common_impl(pos, posp1, moveleft); } + inline constexpr iterator erase_unchecked_single_impl(iterator pos, bool moveleft) noexcept + { + if constexpr (!::std::is_trivially_destructible_v) + { + ::std::destroy(pos.itercontent.curr_ptr); + } + return this->erase_unchecked_single_nodestroy_impl(pos, moveleft); + } public: inline constexpr iterator erase(const_iterator first, const_iterator last) noexcept @@ -2697,11 +2970,11 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE inline constexpr iterator erase(const_iterator first) noexcept { - auto firstp1{first}; - ++firstp1; + ::std::size_t const n{this->size()}; + ::std::size_t const distofront{ + ::fast_io::containers::details::deque_iter_difference_unsigned_common(first.itercontent, this->controller.front_block)}; return this->erase_unchecked_single_impl(iterator{first.itercontent}, - static_cast(first - this->cbegin()) < - static_cast(this->cend() - firstp1)); + distofront < static_cast<::std::size_t>(n - distofront)); } inline constexpr size_type erase_index(size_type firstidx) noexcept @@ -2712,7 +2985,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE ::fast_io::fast_terminate(); } this->erase_unchecked_single_impl(this->begin() + firstidx, - firstidx < static_cast(n - static_cast(firstidx + 1u))); + firstidx < static_cast(n - firstidx)); return firstidx; } @@ -2724,7 +2997,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE template requires ::std::equality_comparable -inline constexpr bool operator==(deque const &lhs, deque const &rhs) noexcept +inline constexpr bool operator==(::fast_io::containers::deque const &lhs, ::fast_io::containers::deque const &rhs) noexcept { return ::std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend()); } @@ -2733,7 +3006,7 @@ inline constexpr bool operator==(deque const &lhs, deque requires ::std::three_way_comparable -inline constexpr auto operator<=>(deque const &lhs, deque const &rhs) noexcept +inline constexpr auto operator<=>(::fast_io::containers::deque const &lhs, ::fast_io::containers::deque const &rhs) noexcept { return ::fast_io::freestanding::lexicographical_compare_three_way(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend(), ::std::compare_three_way{}); } diff --git a/include/fast_io_dsal/impl/vector.h b/include/fast_io_dsal/impl/vector.h index 9c8520c1..b29f6ec8 100644 --- a/include/fast_io_dsal/impl/vector.h +++ b/include/fast_io_dsal/impl/vector.h @@ -903,6 +903,79 @@ class vector FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE return *p; } +private: + struct append_range_guard + { + vector *thisvec{}; + size_type oldn{}; + constexpr ~append_range_guard() + { + if (thisvec) + { + thisvec->erase(thisvec->cbegin() + oldn, thisvec->cend()); + } + } + }; + +public: + template <::std::ranges::range R> + requires ::std::constructible_from> + inline constexpr void append_range(R &&rg) noexcept(::std::is_nothrow_constructible_v>) + { + if constexpr (::std::ranges::sized_range) + { + size_type const rgsize{::std::ranges::size(rg)}; + if (!rgsize) + { + return; + } + size_type const old_size{static_cast(imp.curr_ptr - imp.begin_ptr)}; + size_type const new_size{old_size + rgsize}; + size_type const cap{static_cast(imp.end_ptr - imp.begin_ptr)}; + if (new_size > cap) + { + this->grow_to_size_impl(new_size); + } + if constexpr (::std::is_nothrow_constructible_v>) + { + for (auto &e : rg) + { + ::std::construct_at(imp.curr_ptr, ::std::forward(e)); + ++imp.curr_ptr; + } + } + else + { + append_range_guard guard{this, old_size}; + for (auto &e : rg) + { + ::std::construct_at(imp.curr_ptr, ::std::forward(e)); + ++imp.curr_ptr; + } + guard.thisvec = nullptr; + } + } + else + { + if constexpr (::std::is_nothrow_constructible_v>) + { + for (auto &e : rg) + { + this->emplace_back(::std::forward(e)); + } + } + else + { + append_range_guard guard{this, this->size()}; + for (auto &e : rg) + { + this->emplace_back(::std::forward(e)); + } + guard.thisvec = nullptr; + } + } + } + private: inline constexpr iterator insert_impl(pointer iter, value_type &&tmp) noexcept { diff --git a/include/fast_io_legacy_impl/c/musl.h b/include/fast_io_legacy_impl/c/musl.h index 34020d6b..35e33c26 100644 --- a/include/fast_io_legacy_impl/c/musl.h +++ b/include/fast_io_legacy_impl/c/musl.h @@ -49,7 +49,42 @@ struct fp_model #endif void *locale; }; - +#elif defined(__OHOS__) +struct fp_model +{ + unsigned flags; + unsigned char *rpos, *rend; + int (*close)(FILE *); + unsigned char *wend, *wpos; + unsigned char *mustbezero_1; + unsigned char *wbase; + size_t (*read)(FILE *, unsigned char *, size_t); + size_t (*readx)(FILE *, unsigned char *, size_t); + size_t (*write)(FILE *, const unsigned char *, size_t); + off_t (*seek)(FILE *, off_t, int); + unsigned char *buf; + size_t buf_size; + unsigned char *base; +#ifndef __LITEOS__ + FILE **prev, *next; +#else + FILE *prev, *next; +#endif + int fd; + int pipe_pid; + long lockcount; + int mode; + volatile int lock; + int lbf; + void *cookie; + off_t off; + char *getln_buf; + void *mustbezero_2; + unsigned char *shend; + off_t shlim, shcnt; + FILE *prev_locked, *next_locked; + void *locale; +}; #else // https://github.com/EOSIO/musl/blob/master/src/internal/stdio_impl.h struct fp_model diff --git a/tests/0026.container/0003.deque/deque_erase_to_empty_boundary.cc b/tests/0026.container/0003.deque/deque_erase_to_empty_boundary.cc new file mode 100644 index 00000000..b177f104 --- /dev/null +++ b/tests/0026.container/0003.deque/deque_erase_to_empty_boundary.cc @@ -0,0 +1,85 @@ +#include +#include +#include +#include +#include + +namespace +{ +inline void test_deque(::std::uint_least8_t flag) +{ + bool const toback{static_cast(flag & 0x1)}; + bool const useeraseindex{static_cast(flag & 0x3)}; + ::std::deque<::std::uint_least32_t> ref; + ::fast_io::deque<::std::uint_least32_t> deq; + for (::std::uint_least32_t i{}; i != 1024u; ++i) + { + if (toback) + { + deq.push_back(i); + ref.push_back(i); + } + else + { + deq.push_front(i); + ref.push_front(i); + } + } + if (!::std::equal(deq.cbegin(), deq.cend(), ref.cbegin(), ref.cend())) + { + ::fast_io::fast_terminate(); + } + + using namespace ::fast_io::manipulators; + if (useeraseindex) + { + ::std::size_t first{}; + ::std::size_t last{deq.size()}; + ::std::size_t mid{last >> 1}; + if (toback) + { + deq.erase_index(mid, last); + deq.erase_index(first, mid - 1u); + } + else + { + deq.erase_index(first, mid); + deq.erase_index(1u, mid); + } + deq.erase_index(0u); + } + else + { + ::std::size_t mid{deq.size() >> 1u}; + if (toback) + { + deq.erase(deq.cbegin() + mid, deq.cend()); + deq.erase(deq.cbegin(), deq.cbegin() + (mid - 1u)); + } + else + { + deq.erase(deq.cbegin(), deq.cbegin() + mid); + deq.erase(++deq.cbegin(), deq.cbegin() + mid); + } + deq.erase(deq.cbegin()); + } + { + auto first{ref.cbegin()}; + auto last{ref.cend()}; + ref.erase(first, last); + } + + if (!::std::equal(deq.cbegin(), deq.cend(), ref.cbegin(), ref.cend())) + { + ::fast_io::fast_terminate(); + } +} +} // namespace + +int main() +{ + for (::std::uint_least8_t i{}; i != 4u; ++i) + { + test_deque(i); + } +} diff --git a/tests/0026.container/0003.deque/insert.cc b/tests/0026.container/0003.deque/insert.cc new file mode 100644 index 00000000..5cac0a48 --- /dev/null +++ b/tests/0026.container/0003.deque/insert.cc @@ -0,0 +1,415 @@ +#include +#include +#include +#include +#include + +namespace +{ +inline constexpr ::std::size_t throw_threshold{50}; + +// Throwing type for exception safety testing - must be at namespace scope for static members +struct ThrowingType +{ + static ::std::size_t construct_count; + + ::std::size_t value; + + ThrowingType() : value{0} + { + ++construct_count; + check_threshold(); + } + + ThrowingType(::std::size_t v) : value{v} + { + ++construct_count; + check_threshold(); + } + + ThrowingType(ThrowingType &&other) noexcept : value{other.value} + { + other.value = 0; + // Move constructor is noexcept to avoid issues during relocation + } + + ThrowingType(ThrowingType const &other) : value{other.value} + { + ++construct_count; + check_threshold(); + } + + ThrowingType &operator=(ThrowingType &&other) noexcept + { + value = other.value; + other.value = 0; + return *this; + } + + ThrowingType &operator=(ThrowingType const &other) + { + value = other.value; + return *this; + } + + ~ThrowingType() noexcept = default; + + static void check_threshold() + { + if (construct_count > throw_threshold) + { + throw ::std::runtime_error("construction threshold exceeded"); + } + } + + static void reset() noexcept + { + construct_count = 0; + } +}; + +::std::size_t ThrowingType::construct_count{0}; + +inline void test_insert_single() +{ + ::fast_io::io::perr("=== deque insert single element test ===\n"); + + ThrowingType::reset(); + + using T = ::std::size_t; + ::fast_io::deque dq; + ::std::deque ref; + + 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 (empty deque) + { + dq.insert(dq.begin(), 1000); + ref.insert(ref.begin(), 1000); + check_equal("insert at front (empty)"); + } + + // 2. Insert at back + { + dq.insert(dq.end(), 1001); + ref.insert(ref.end(), 1001); + check_equal("insert at back"); + } + + // 3. Insert at front (non-empty) + { + dq.insert(dq.begin(), 999); + ref.insert(ref.begin(), 999); + check_equal("insert at front (non-empty)"); + } + + // 4. Insert in middle + { + ::std::size_t pos{dq.size() / 2}; + dq.insert(dq.begin() + pos, 500); + ref.insert(ref.begin() + pos, 500); + check_equal("insert in middle"); + } + + // 5. Insert_index at front + { + dq.insert_index(0, 1); + ref.insert(ref.begin(), 1); + check_equal("insert_index at front"); + } + + // 6. Insert_index at back + { + ::std::size_t pos{dq.size()}; + dq.insert_index(pos, 2); + ref.insert(ref.end(), 2); + check_equal("insert_index at back"); + } + + // 7. Insert_index in middle + { + ::std::size_t pos{dq.size() / 2}; + dq.insert_index(pos, 3); + ref.insert(ref.begin() + pos, 3); + check_equal("insert_index in middle"); + } + + // 8. Emplace at front + { + dq.emplace(dq.begin(), 10); + ref.emplace(ref.begin(), 10); + check_equal("emplace at front"); + } + + // 9. Emplace at back + { + dq.emplace(dq.end(), 11); + ref.emplace(ref.end(), 11); + check_equal("emplace at back"); + } + + // 10. Emplace in middle + { + ::std::size_t pos{dq.size() / 2}; + dq.emplace(dq.begin() + pos, 12); + ref.emplace(ref.begin() + pos, 12); + check_equal("emplace in middle"); + } + + // 11. Emplace_index at front + { + dq.emplace_index(0, 20); + ref.emplace(ref.begin(), 20); + check_equal("emplace_index at front"); + } + + // 12. Emplace_index at back + { + ::std::size_t pos{dq.size()}; + dq.emplace_index(pos, 21); + ref.emplace(ref.end(), 21); + check_equal("emplace_index at back"); + } + + // 13. Emplace_index in middle + { + ::std::size_t pos{dq.size() / 2}; + dq.emplace_index(pos, 22); + ref.emplace(ref.begin() + pos, 22); + check_equal("emplace_index in middle"); + } + + // 14. Insert with move + { + T val{300}; + dq.insert(dq.begin() + 1, ::std::move(val)); + ref.insert(ref.begin() + 1, 300); + check_equal("insert with move"); + } + + // 15. Insert_index with move + { + T val{301}; + dq.insert_index(1, ::std::move(val)); + ref.insert(ref.begin() + 1, 301); + check_equal("insert_index with move"); + } + + // 16. Randomized insertions + for (::std::size_t iter{}; iter != 500u; ++iter) + { + ::std::size_t pos{iter % (dq.size() + 1)}; + T val{iter + 10000}; + + dq.insert_index(pos, val); + ref.insert(ref.begin() + pos, val); + + check_equal("randomized insert_index"); + } + + // 17. Randomized insert with iterator + for (::std::size_t iter{}; iter != 500u; ++iter) + { + ::std::size_t pos{iter % (dq.size() + 1)}; + T val{iter + 20000}; + + dq.insert(dq.begin() + pos, val); + ref.insert(ref.begin() + pos, val); + + check_equal("randomized insert iterator"); + } + + ::fast_io::io::print("deque insert single element test finished\n"); +} + +inline void test_insert_return_value() +{ + ::fast_io::io::perr("=== deque insert return value test ===\n"); + + using T = ::std::size_t; + ::fast_io::deque dq; + + // Fill some initial data + for (::std::size_t i{}; i != 100u; ++i) + { + dq.push_back(i); + } + + // 1. Insert returns iterator pointing to inserted element + { + auto it = dq.insert(dq.begin(), 9999); + if (*it != 9999) + { + ::fast_io::io::panic("insert return value wrong\n"); + } + if (it != dq.begin()) + { + ::fast_io::io::panic("insert iterator position wrong\n"); + } + } + + // 2. Insert in middle returns correct iterator + { + ::std::size_t pos{50}; + auto it = dq.insert(dq.begin() + pos, 8888); + if (*it != 8888) + { + ::fast_io::io::panic("insert middle return value wrong\n"); + } + if (static_cast<::std::size_t>(it - dq.begin()) != pos) + { + ::fast_io::io::panic("insert middle iterator position wrong\n"); + } + } + + // 3. Insert at end returns correct iterator + { + auto old_end = dq.end(); + auto it = dq.insert(dq.end(), 7777); + if (*it != 7777) + { + ::fast_io::io::panic("insert end return value wrong\n"); + } + if (it != old_end) + { + ::fast_io::io::panic("insert end iterator position wrong\n"); + } + } + + // 4. Insert_index returns reference to inserted element + { + ::std::size_t pos{25}; + auto &ref = dq.insert_index(pos, 6666); + if (ref != 6666) + { + ::fast_io::io::panic("insert_index return value wrong\n"); + } + if (dq[pos] != 6666) + { + ::fast_io::io::panic("insert_index element position wrong\n"); + } + } + + // 5. Emplace returns iterator + { + auto it = dq.emplace(dq.begin(), 5555); + if (*it != 5555) + { + ::fast_io::io::panic("emplace return value wrong\n"); + } + } + + // 6. Emplace_index returns reference + { + auto &ref = dq.emplace_index(0, 4444); + if (ref != 4444) + { + ::fast_io::io::panic("emplace_index return value wrong\n"); + } + } + + ::fast_io::io::print("deque insert return value test finished\n"); +} + +inline void test_insert_exception_safety() +{ + ::fast_io::io::perr("=== deque insert exception safety test ===\n"); + + ThrowingType::reset(); + + ::fast_io::deque dq; + + // Fill below threshold + for (::std::size_t i{}; i != 30u; ++i) + { + dq.emplace_back(i); + } + + ::std::size_t old_size{dq.size()}; + + // Try to insert at front and back only (simple rollback) + // Middle insertions have complex rollback that's harder to test + bool threw{false}; + try + { + for (::std::size_t i{}; i != 100u; ++i) + { + // Alternate between front and back insertions + if (i % 2 == 0) + { + dq.emplace_front(i + 100); + } + else + { + dq.emplace_back(i + 100); + } + } + } + catch (::std::runtime_error const &) + { + threw = true; + } + + if (!threw) + { + ::fast_io::io::panic("expected exception but none thrown\n"); + } + + // Check that size is at least old_size (elements weren't lost) + if (dq.size() < old_size) + { + ::fast_io::io::panic("exception safety failed: size decreased below original\n"); + } + + // Verify original elements are still present (values 0-29) + // Note: due to front insertions, positions have shifted + for (::std::size_t i{}; i != old_size; ++i) + { + // Find value i in the deque + bool found{false}; + for (::std::size_t j{}; j != dq.size(); ++j) + { + if (dq[j].value == i) + { + found = true; + break; + } + } + if (!found) + { + ::fast_io::io::panic("exception safety failed: original element lost\n"); + } + } + + ::fast_io::io::print("deque insert exception safety test finished\n"); +} + +} // namespace + +int main() +{ + test_insert_single(); + test_insert_return_value(); + test_insert_exception_safety(); +} \ No newline at end of file