diff --git a/benchmark/0008/CMakeLists.txt b/benchmark/0008/CMakeLists.txt deleted file mode 100644 index f59f9492a..000000000 --- a/benchmark/0008/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -cmake_minimum_required(VERSION 3.22) - -project(example CXX) - -include(FetchContent) -FetchContent_Declare( - dragonbox - GIT_REPOSITORY https://github.com/jk-jeon/dragonbox -) -FetchContent_MakeAvailable(dragonbox) - -add_executable( - comparison - ${CMAKE_CURRENT_LIST_DIR}/comparison.cpp -) -target_include_directories(comparison PRIVATE ../include) -target_compile_features(comparison PRIVATE cxx_std_20) -target_link_libraries(comparison dragonbox::dragonbox_to_chars) diff --git a/benchmark/0008/comparison.cpp b/benchmark/0008/comparison.cpp deleted file mode 100644 index 82e5cd650..000000000 --- a/benchmark/0008/comparison.cpp +++ /dev/null @@ -1,112 +0,0 @@ -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "dragonbox/dragonbox_to_chars.h" - -// both fast_io::pr_rsv_size and jkj::dragonbox::max_output_string_length are 24 so 25 with trailing null terminator -constexpr int buf_size = 25; - -inline void charconv_ofstream(std::vector const &vec) -{ - fast_io::timer t(u8"charconv"); - std::ofstream ofs{"charconv.txt"}; - for (auto const e : vec) - { - char buf[buf_size]{0}; - std::to_chars(buf, buf + buf_size, e, std::chars_format::scientific); - ofs << buf << '\n'; - } -} - -inline void charconv_fast_io(std::vector const &vec) -{ - fast_io::timer t(u8"charconv2"); - fast_io::obuf_file file{u8"charconv2.txt"}; - for (auto const e : vec) - { - char buf[buf_size]{0}; - std::to_chars(buf, buf + buf_size, e, std::chars_format::scientific); - println(file, fast_io::mnp::os_c_str(buf)); - } -} - -inline void fast_io_ofstream(std::vector const &vec) -{ - fast_io::timer t(u8"fast_io"); - std::ofstream ofs{"fast_io.txt"}; - for (auto const e : vec) - { - char buf[buf_size]{0}; - fast_io::pr_rsv_to_c_array(buf, fast_io::mnp::scientific(e)); - ofs << buf << '\n'; - } -} - -inline void fast_io_fast_io(std::vector const &vec) -{ - fast_io::timer t(u8"fast_io2"); - fast_io::obuf_file file{u8"fast_io2.txt"}; - for (auto const e : vec) - { - char buf[buf_size]{0}; - fast_io::pr_rsv_to_c_array(buf, fast_io::mnp::scientific(e)); - println(file, fast_io::mnp::os_c_str(buf)); - } -} - -inline void dragonbox_ofstream(std::vector const &vec) -{ - fast_io::timer t(u8"dragonbox"); - std::ofstream ofs{"dragonbox.txt"}; - for (auto const e : vec) - { - char buf[buf_size]{0}; - jkj::dragonbox::to_chars(e, buf); - ofs << buf << '\n'; - } -} - -inline void dragonbox_fast_io(std::vector const &vec) -{ - fast_io::timer t(u8"dragonbox2"); - fast_io::obuf_file file{u8"dragonbox2.txt"}; - for (auto const e : vec) - { - char buf[buf_size]{0}; - jkj::dragonbox::to_chars(e, buf); - println(file, fast_io::mnp::os_c_str(buf)); - } -} - -int main() -{ - constexpr std::size_t N = 10'000'000; - - std::mt19937_64 eng{}; - std::uniform_real_distribution dis(DBL_MIN, DBL_MAX); - std::vector vec; - vec.reserve(N); - for (std::size_t i{}; i != N; ++i) - { - vec.emplace_back(dis(eng)); - } - - charconv_ofstream(vec); - charconv_fast_io(vec); - - fast_io_ofstream(vec); - fast_io_fast_io(vec); - - dragonbox_ofstream(vec); - dragonbox_fast_io(vec); - - return 0; -} \ No newline at end of file diff --git a/benchmark/0008/seperate/charconv.cc b/benchmark/0008/seperate/charconv.cc deleted file mode 100644 index a19c018e6..000000000 --- a/benchmark/0008/seperate/charconv.cc +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -using namespace fast_io::io; - -constexpr int buf_size = 25; - -inline void charconv_fast_io(std::vector const &vec) -{ - fast_io::timer t(u8"charconv2"); - fast_io::obuf_file file{u8"charconv2.txt"}; - for (auto const e : vec) - { - char buf[buf_size]{0}; - std::to_chars(buf, buf + buf_size, e, std::chars_format::scientific); - println(file, fast_io::mnp::os_c_str(buf)); - } -} - -int main() -{ - constexpr std::size_t N = 10'000'000; - - std::mt19937_64 eng{}; - std::uniform_real_distribution dis(DBL_MIN, DBL_MAX); - std::vector vec; - vec.reserve(N); - for (std::size_t i{}; i != N; ++i) - { - vec.emplace_back(dis(eng)); - } - charconv_fast_io(vec); -} diff --git a/benchmark/0008/seperate/charconv_no_c_str.cc b/benchmark/0008/seperate/charconv_no_c_str.cc deleted file mode 100644 index c1a554ae2..000000000 --- a/benchmark/0008/seperate/charconv_no_c_str.cc +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -constexpr int buf_size = 25; - -inline void charconv_fast_io(std::vector const &vec) -{ - fast_io::timer t(u8"charconv2"); - fast_io::obuf_file file{u8"charconv2.txt"}; - for (auto const e : vec) - { - char buf[buf_size]{0}; - auto [p, ec] = std::to_chars(buf, buf + buf_size, e, std::chars_format::scientific); - *p = '\n'; - ++p; - fast_io::operations::write_all(file, buf, p); - } -} - -int main() -{ - constexpr std::size_t N = 10'000'000; - - std::mt19937_64 eng{}; - std::uniform_real_distribution dis(DBL_MIN, DBL_MAX); - std::vector vec; - vec.reserve(N); - for (std::size_t i{}; i != N; ++i) - { - vec.emplace_back(dis(eng)); - } - charconv_fast_io(vec); -} diff --git a/benchmark/0008/seperate/dragonbox.cc b/benchmark/0008/seperate/dragonbox.cc deleted file mode 100644 index 7134b60dc..000000000 --- a/benchmark/0008/seperate/dragonbox.cc +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include -#include -#include "dragonbox/dragonbox_to_chars.h" -#include -#include -#include -using namespace fast_io::io; - -constexpr int buf_size = 25; - -inline void dragonbox_fast_io(std::vector const &vec) -{ - fast_io::timer t(u8"dragonbox2"); - fast_io::obuf_file file{u8"dragonbox2.txt"}; - for (auto const e : vec) - { - char buf[buf_size]{0}; - jkj::dragonbox::to_chars(e, buf); - println(file, fast_io::mnp::os_c_str(buf)); - } -} - -int main() -{ - constexpr std::size_t N = 10'000'000; - - std::mt19937_64 eng{}; - std::uniform_real_distribution dis(DBL_MIN, DBL_MAX); - std::vector vec; - vec.reserve(N); - for (std::size_t i{}; i != N; ++i) - { - vec.emplace_back(dis(eng)); - } - dragonbox_fast_io(vec); -} diff --git a/benchmark/0008/seperate/dragonbox_no_c_str.cc b/benchmark/0008/seperate/dragonbox_no_c_str.cc deleted file mode 100644 index 7a6adf1d7..000000000 --- a/benchmark/0008/seperate/dragonbox_no_c_str.cc +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include -#include -#include "dragonbox/dragonbox_to_chars.h" -#include -#include -#include - -constexpr int buf_size = 25; - -inline void dragonbox_fast_io(std::vector const &vec) -{ - fast_io::timer t(u8"dragonbox2"); - fast_io::obuf_file file{u8"dragonbox2.txt"}; - for (auto const e : vec) - { - char buf[buf_size]{0}; - auto i{jkj::dragonbox::to_chars(e, buf)}; - *i = '\n'; - ++i; - fast_io::operations::write_all(file, buf, i); - } -} - -int main() -{ - constexpr std::size_t N = 10'000'000; - - std::mt19937_64 eng{}; - std::uniform_real_distribution dis(DBL_MIN, DBL_MAX); - std::vector vec; - vec.reserve(N); - for (std::size_t i{}; i != N; ++i) - { - vec.emplace_back(dis(eng)); - } - dragonbox_fast_io(vec); -} diff --git a/benchmark/0008/seperate/fast_io.cc b/benchmark/0008/seperate/fast_io.cc deleted file mode 100644 index 8c757fa54..000000000 --- a/benchmark/0008/seperate/fast_io.cc +++ /dev/null @@ -1,36 +0,0 @@ -#include -#include -#include -#include -#include -#include -using namespace fast_io::io; - -constexpr int buf_size = 25; - -inline void fast_io_fast_io(std::vector const &vec) -{ - fast_io::timer t(u8"fast_io2"); - fast_io::obuf_file file{u8"fast_io2.txt"}; - for (auto const e : vec) - { - char buf[buf_size]{0}; - fast_io::pr_rsv_to_c_array(buf, fast_io::mnp::scientific(e)); - println(file, fast_io::mnp::os_c_str(buf)); - } -} - -int main() -{ - constexpr std::size_t N = 10'000'000; - - std::mt19937_64 eng{}; - std::uniform_real_distribution dis(DBL_MIN, DBL_MAX); - std::vector vec; - vec.reserve(N); - for (std::size_t i{}; i != N; ++i) - { - vec.emplace_back(dis(eng)); - } - fast_io_fast_io(vec); -} diff --git a/benchmark/0008/seperate/fast_io_direct.cc b/benchmark/0008/seperate/fast_io_direct.cc deleted file mode 100644 index 204371994..000000000 --- a/benchmark/0008/seperate/fast_io_direct.cc +++ /dev/null @@ -1,34 +0,0 @@ -#include -#include -#include -#include -#include -#include -using namespace fast_io::io; - -[[maybe_unused]] constexpr int buf_size = 25; - -inline void fast_io_fast_io(std::vector const &vec) -{ - fast_io::timer t(u8"fast_io_direct"); - fast_io::obuf_file file{u8"fast_io_direct.txt"}; - for (auto const e : vec) - { - println(file, fast_io::mnp::scientific(e)); - } -} - -int main() -{ - constexpr std::size_t N = 10'000'000; - - std::mt19937_64 eng{}; - std::uniform_real_distribution dis(DBL_MIN, DBL_MAX); - std::vector vec; - vec.reserve(N); - for (std::size_t i{}; i != N; ++i) - { - vec.emplace_back(dis(eng)); - } - fast_io_fast_io(vec); -} diff --git a/benchmark/0008/seperate/fast_io_no_c_str.cc b/benchmark/0008/seperate/fast_io_no_c_str.cc deleted file mode 100644 index 7132d256e..000000000 --- a/benchmark/0008/seperate/fast_io_no_c_str.cc +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include -#include -#include -#include -#include - -constexpr int buf_size = 25; - -inline void fast_io_fast_io(std::vector const &vec) -{ - fast_io::timer t(u8"fast_io2"); - fast_io::obuf_file file{u8"fast_io2.txt"}; - for (auto const e : vec) - { - char buf[buf_size]{0}; - auto i{fast_io::pr_rsv_to_c_array(buf, fast_io::mnp::scientific(e))}; - *i = '\n'; - ++i; - fast_io::operations::write_all(file, buf, i); - } -} - -int main() -{ - constexpr std::size_t N = 10'000'000; - - std::mt19937_64 eng{}; - std::uniform_real_distribution dis(DBL_MIN, DBL_MAX); - std::vector vec; - vec.reserve(N); - for (std::size_t i{}; i != N; ++i) - { - vec.emplace_back(dis(eng)); - } - fast_io_fast_io(vec); -} diff --git a/benchmark/0008/seperate_short/charconv_no_c_str.cc b/benchmark/0008/seperate_short/charconv_no_c_str.cc deleted file mode 100644 index 7c8184303..000000000 --- a/benchmark/0008/seperate_short/charconv_no_c_str.cc +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -constexpr int buf_size = 25; - -inline void charconv_fast_io(std::vector const &vec) -{ - fast_io::timer t(u8"charconv2"); - fast_io::obuf_file file{u8"charconv2.txt"}; - for (auto const e : vec) - { - char buf[buf_size]{0}; - auto [p, ec] = std::to_chars(buf, buf + buf_size, e, std::chars_format::scientific); - *p = '\n'; - ++p; - fast_io::operations::write_all(file, buf, p); - } -} - -int main() -{ - constexpr std::size_t N = 1'000'000; - - std::mt19937_64 eng{}; - std::uniform_real_distribution dis(DBL_MIN, DBL_MAX); - std::vector vec; - vec.reserve(N); - for (std::size_t i{}; i != N; ++i) - { - vec.emplace_back(dis(eng)); - } - charconv_fast_io(vec); -} diff --git a/benchmark/0008/seperate_short/dragonbox_no_c_str.cc b/benchmark/0008/seperate_short/dragonbox_no_c_str.cc deleted file mode 100644 index 94e1a6b58..000000000 --- a/benchmark/0008/seperate_short/dragonbox_no_c_str.cc +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include -#include -#include "dragonbox/dragonbox_to_chars.h" -#include -#include -#include - -constexpr int buf_size = 25; - -inline void dragonbox_fast_io(std::vector const &vec) -{ - fast_io::timer t(u8"dragonbox2"); - fast_io::obuf_file file{u8"dragonbox2.txt"}; - for (auto const e : vec) - { - char buf[buf_size]{0}; - auto i{jkj::dragonbox::to_chars(e, buf)}; - *i = '\n'; - ++i; - fast_io::operations::write_all(file, buf, i); - } -} - -int main() -{ - constexpr std::size_t N = 1'000'000; - - std::mt19937_64 eng{}; - std::uniform_real_distribution dis(DBL_MIN, DBL_MAX); - std::vector vec; - vec.reserve(N); - for (std::size_t i{}; i != N; ++i) - { - vec.emplace_back(dis(eng)); - } - dragonbox_fast_io(vec); -} diff --git a/benchmark/0008/seperate_short/fast_io_no_c_str.cc b/benchmark/0008/seperate_short/fast_io_no_c_str.cc deleted file mode 100644 index 417622d3d..000000000 --- a/benchmark/0008/seperate_short/fast_io_no_c_str.cc +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include -#include -#include -#include -#include - -constexpr int buf_size = 25; - -inline void fast_io_fast_io(std::vector const &vec) -{ - fast_io::timer t(u8"fast_io2"); - fast_io::obuf_file file{u8"fast_io2.txt"}; - for (auto const e : vec) - { - char buf[buf_size]{0}; - auto i{fast_io::pr_rsv_to_c_array(buf, fast_io::mnp::scientific(e))}; - *i = '\n'; - ++i; - fast_io::operations::write_all(file, buf, i); - } -} - -int main() -{ - constexpr std::size_t N = 1'000'000; - - std::mt19937_64 eng{}; - std::uniform_real_distribution dis(DBL_MIN, DBL_MAX); - std::vector vec; - vec.reserve(N); - for (std::size_t i{}; i != N; ++i) - { - vec.emplace_back(dis(eng)); - } - fast_io_fast_io(vec); -} diff --git a/benchmark/0011.containers/deque/0000.initialization/fast_io.cc b/benchmark/0011.containers/deque/0000.initialization/fast_io.cc new file mode 100644 index 000000000..671c10c55 --- /dev/null +++ b/benchmark/0011.containers/deque/0000.initialization/fast_io.cc @@ -0,0 +1,9 @@ +#include +#include +#include + +int main() +{ + fast_io::timer t(u8"fast_io::deque"); + ::fast_io::deque deq(100000000); +} \ No newline at end of file diff --git a/benchmark/0011.containers/deque/0000.initialization/std.cc b/benchmark/0011.containers/deque/0000.initialization/std.cc new file mode 100644 index 000000000..f94c136a9 --- /dev/null +++ b/benchmark/0011.containers/deque/0000.initialization/std.cc @@ -0,0 +1,9 @@ +#include +#include +#include + +int main() +{ + fast_io::timer t(u8"std::deque"); + std::deque vec(100000000); +} \ No newline at end of file diff --git a/benchmark/0011.containers/deque/0002.multi_push_back/fast_io.cc b/benchmark/0011.containers/deque/0002.multi_push_back/fast_io.cc new file mode 100644 index 000000000..e2874e3d0 --- /dev/null +++ b/benchmark/0011.containers/deque/0002.multi_push_back/fast_io.cc @@ -0,0 +1,8 @@ +#include +namespace test +{ +template +using vector = ::fast_io::deque; +} +#define BENCH_VECTOR_COMMENT_STRING u8"fast_io::deque" +#include "main.h" diff --git a/benchmark/0011.containers/deque/0002.multi_push_back/main.h b/benchmark/0011.containers/deque/0002.multi_push_back/main.h new file mode 100644 index 000000000..61dcd0af9 --- /dev/null +++ b/benchmark/0011.containers/deque/0002.multi_push_back/main.h @@ -0,0 +1,130 @@ +#include +#include + +int main() +{ + fast_io::timer t(BENCH_VECTOR_COMMENT_STRING); + for (std::size_t j{}; j != 50; ++j) + { + test::vector vec1; + test::vector vec2; + test::vector vec3; + test::vector vec4; + test::vector vec5; + test::vector vec6; + test::vector vec7; + test::vector vec8; + test::vector vec9; + test::vector vec10; + test::vector vec11; + test::vector vec12; + test::vector vec13; + for (std::size_t i{}; i != 100000; ++i) + { + vec1.push_back(42); + vec2.push_back(42); + vec3.push_back(43); + vec4.push_back(43); + vec5.push_back(43); + vec6.push_back(43); + vec7.push_back(42); + vec8.push_back(42); + vec9.push_back(43); + vec10.push_back(43); + vec11.push_back(43); + vec12.push_back(43); + vec13.push_back(44); + vec1.push_back(42); + vec2.push_back(42); + vec3.push_back(43); + vec4.push_back(43); + vec5.push_back(43); + vec6.push_back(43); + vec7.push_back(42); + vec8.push_back(42); + vec9.push_back(43); + vec10.push_back(43); + vec11.push_back(43); + vec12.push_back(43); + vec13.push_back(44); + vec1.push_back(42); + vec2.push_back(42); + vec3.push_back(43); + vec4.push_back(43); + vec5.push_back(43); + vec6.push_back(43); + vec7.push_back(42); + vec8.push_back(42); + vec9.push_back(43); + vec10.push_back(43); + vec11.push_back(43); + vec12.push_back(43); + vec13.push_back(44); + vec1.push_back(42); + vec2.push_back(42); + vec3.push_back(43); + vec4.push_back(43); + vec5.push_back(43); + vec6.push_back(43); + vec7.push_back(42); + vec8.push_back(42); + vec9.push_back(43); + vec10.push_back(43); + vec11.push_back(43); + vec12.push_back(43); + vec13.push_back(44); + vec1.push_back(42); + vec2.push_back(42); + vec3.push_back(43); + vec4.push_back(43); + vec5.push_back(43); + vec6.push_back(43); + vec7.push_back(42); + vec8.push_back(42); + vec9.push_back(43); + vec10.push_back(43); + vec11.push_back(43); + vec12.push_back(43); + vec13.push_back(44); + vec1.push_back(42); + vec2.push_back(42); + vec3.push_back(43); + vec4.push_back(43); + vec5.push_back(43); + vec6.push_back(43); + vec7.push_back(42); + vec8.push_back(42); + vec9.push_back(43); + vec10.push_back(43); + vec11.push_back(43); + vec12.push_back(43); + vec13.push_back(44); + vec1.push_back(42); + vec2.push_back(42); + vec3.push_back(43); + vec4.push_back(43); + vec5.push_back(43); + vec6.push_back(43); + vec7.push_back(42); + vec8.push_back(42); + vec9.push_back(43); + vec10.push_back(43); + vec11.push_back(43); + vec12.push_back(43); + vec13.push_back(44); + vec1.push_back(42); + vec2.push_back(42); + vec3.push_back(43); + vec4.push_back(43); + vec5.push_back(43); + vec6.push_back(43); + vec7.push_back(42); + vec8.push_back(42); + vec9.push_back(43); + vec10.push_back(43); + vec11.push_back(43); + vec12.push_back(43); + vec13.push_back(44); + } + } +} \ No newline at end of file diff --git a/benchmark/0011.containers/deque/0002.multi_push_back/std.cc b/benchmark/0011.containers/deque/0002.multi_push_back/std.cc new file mode 100644 index 000000000..a1c15c1c1 --- /dev/null +++ b/benchmark/0011.containers/deque/0002.multi_push_back/std.cc @@ -0,0 +1,9 @@ +#include +#include +namespace test +{ +template +using vector = ::std::deque; +} +#define BENCH_VECTOR_COMMENT_STRING u8"std::deque" +#include "main.h" \ No newline at end of file diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index 52f37ae05..f92ffae95 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -13,8 +13,8 @@ struct #endif deque_control_block_common { - void **controller_ptr; - void *begin_ptr, *curr_ptr, *end_ptr; + ::std::byte **controller_ptr; + ::std::byte *begin_ptr, *curr_ptr, *end_ptr; }; template @@ -37,11 +37,11 @@ struct #endif deque_controller_block_common { - using replacetype = char unsigned; - void **controller_start_ptr; - void **controller_start_reserved_ptr; - void **controller_after_reserved_ptr; - void **controller_after_ptr; + using replacetype = ::std::byte; + ::std::byte **controller_start_ptr; + ::std::byte **controller_start_reserved_ptr; + ::std::byte **controller_after_reserved_ptr; + ::std::byte **controller_after_ptr; }; template @@ -70,8 +70,8 @@ struct #endif deque_controller_common { - using replacetype = char unsigned; - using controlreplacetype = void *; + using replacetype = ::std::byte; + using controlreplacetype = ::std::byte *; ::fast_io::containers::details::deque_control_block_common front_block; ::fast_io::containers::details::deque_control_block_common back_block; ::fast_io::containers::details::deque_controller_block_common controller_block; @@ -475,8 +475,7 @@ inline constexpr void deque_allocate_on_empty_common_impl(dequecontroltype &cont auto &front_block{controller.front_block}; auto &back_block{controller.back_block}; - constexpr bool isvoidplaceholder{::std::same_as}; - using begin_ptrtype = ::std::conditional_t; + using begin_ptrtype = typename dequecontroltype::replacetype *; auto begin_ptr{static_cast(allocator::allocate_aligned(align, bytes))}; @@ -587,7 +586,7 @@ inline constexpr void deque_grow_back_common_impl( * then advance controller_after_reserved_ptr and write the sentinel. */ auto pos{controller.controller_block.controller_after_reserved_ptr}; - std::construct_at(pos, new_block); + ::std::construct_at(pos, new_block); *(controller.controller_block.controller_after_reserved_ptr = pos + 1) = nullptr; } } @@ -736,9 +735,7 @@ inline constexpr void deque_clear_common_impl(dequecontroltype &controller, ::st static_cast<::std::size_t>(reserved_blocks_count >> 1u)}; auto reserved_pivot{start_reserved_ptr + half_reserved_blocks_count}; using replacetype = typename dequecontroltype::replacetype; - constexpr bool isvoidplaceholder = std::same_as; - using begin_ptrtype = - std::conditional_t; + using begin_ptrtype = replacetype *; auto begin_ptr{static_cast(*reserved_pivot)}; auto end_ptr{begin_ptr + blockbytes}; auto mid_ptr{begin_ptr + static_cast<::std::size_t>(blockbytes >> 1u)}; @@ -755,6 +752,181 @@ inline constexpr void deque_clear_common(dequecontroltype &controller) noexcept ::fast_io::containers::details::deque_clear_common_impl(controller, blockbytes); } +template +inline constexpr void deque_allocate_init_blocks_dezeroing_impl(dequecontroltype &controller, ::std::size_t align, ::std::size_t blockbytes, ::std::size_t blocks_count_least, bool zeroing) noexcept +{ + if (!blocks_count_least) + { + controller = {{}, {}, {}}; + return; + } + constexpr ::std::size_t mx{::std::numeric_limits<::std::size_t>::max()}; + if (blocks_count_least == mx) + { + ::fast_io::fast_terminate(); + } + using block_typed_allocator = ::fast_io::typed_generic_allocator_adapter; + auto [start_ptr, blocks_count] = block_typed_allocator::allocate_at_least(blocks_count_least + 1u); + --blocks_count; + ::std::size_t const half_blocks_count{blocks_count >> 1u}; + ::std::size_t const half_blocks_count_least{blocks_count_least >> 1u}; + ::std::size_t const offset{half_blocks_count - half_blocks_count_least}; + auto reserve_start{start_ptr + offset}, reserve_after{reserve_start + blocks_count_least}; + using begin_ptrtype = typename dequecontroltype::replacetype *; + for (auto it{reserve_start}, ed{reserve_after}; it != ed; ++it) + { + if (zeroing) + { + ::std::construct_at(it, static_cast(allocator::allocate_aligned_zero(align, blockbytes))); + } + else + { + ::std::construct_at(it, static_cast(allocator::allocate_aligned(align, blockbytes))); + } + } + ::std::construct_at(reserve_after, nullptr); + 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}; + 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.controller_block = { + start_ptr, reserve_start, reserve_after, start_ptr + blocks_count}; +} +template +inline constexpr void deque_allocate_init_blocks_impl(dequecontroltype &controller, ::std::size_t align, ::std::size_t blockbytes, ::std::size_t blocks_count_least) noexcept +{ + ::fast_io::containers::details::deque_allocate_init_blocks_dezeroing_impl(controller, align, blockbytes, blocks_count_least, zeroing); +} + +template +inline constexpr void deque_init_space_common(dequecontroltype &controller, ::std::size_t n) noexcept +{ + constexpr ::std::size_t blockbytes{sz * block_size}; + ::std::size_t const ndivsz{n / block_size}; + ::std::size_t const nmodsz{n % block_size}; + ::std::size_t const counts{ndivsz + static_cast<::std::size_t>(nmodsz != 0u)}; + + ::fast_io::containers::details::deque_allocate_init_blocks_impl(controller, align, blockbytes, counts); + if (!n) + { + return; + } + auto &back_curr_ptr{controller.back_block.curr_ptr}; + ::std::size_t offset_for_back{blockbytes}; + if (nmodsz) + { + offset_for_back = nmodsz * sz; + } + back_curr_ptr += offset_for_back; +} + +template +struct uninitialized_copy_n_for_deque_guard +{ + bool torecover{true}; + ToIter d_first, ¤t; + constexpr explicit uninitialized_copy_n_for_deque_guard(ToIter &toiter) noexcept + : d_first(toiter), current(toiter) + {} + uninitialized_copy_n_for_deque_guard(uninitialized_copy_n_for_deque_guard const &) = delete; + uninitialized_copy_n_for_deque_guard &operator=(uninitialized_copy_n_for_deque_guard const &) = delete; + constexpr ~uninitialized_copy_n_for_deque_guard() + { + if (torecover) + { + ::std::destroy(d_first, current); + } + } +}; + +template +struct uninitialized_copy_n_for_deque_in_out_result +{ + FromIter from; + ToIter to; +}; +template +inline constexpr ::fast_io::containers::details::uninitialized_copy_n_for_deque_in_out_result uninitialized_copy_n_for_deque(FromIter fromiter, ::std::size_t count, ToIter toiter) +{ +#if 0 + using fromvaluet = ::std::iter_value_t; + using tovaluet = ::std::iter_value_t; + if constexpr(::std::is_trivially_copyable_v&& + ::std::is_trivially_copyable_v) + { + + } +#endif + { + uninitialized_copy_n_for_deque_guard g(toiter); + for (; count; --count) + { + ::std::construct_at(::std::addressof(*toiter), *fromiter); + ++fromiter; + ++toiter; + } + g.torecover = false; + } + return {fromiter, toiter}; +} + +template +inline constexpr void deque_clone_trivial_impl(dequecontroltype &controller, dequecontroltype const &fromcontroller, + ::std::size_t align, ::std::size_t blockbytes) noexcept +{ + if (fromcontroller.front_block.curr_ptr == fromcontroller.back_block.curr_ptr) + { + controller = {{}, {}, {}}; + return; + } + auto front_controller_ptr{fromcontroller.front_block.controller_ptr}; + auto back_controller_ptr{fromcontroller.back_block.controller_ptr}; + ::std::size_t blocks_required{static_cast<::std::size_t>(back_controller_ptr - + front_controller_ptr + 1)}; + + ::fast_io::containers::details::deque_allocate_init_blocks_dezeroing_impl(controller, align, blockbytes, blocks_required, false); + using replacetype = typename dequecontroltype::replacetype; + using begin_ptrtype = replacetype *; + + begin_ptrtype lastblockbegin; + if (front_controller_ptr == back_controller_ptr) + { + lastblockbegin = controller.front_block.curr_ptr; + } + else + { + auto destit{controller.front_block.controller_ptr}; + auto pos{fromcontroller.front_block.curr_ptr - fromcontroller.front_block.begin_ptr}; + controller.front_block.end_ptr = + ::fast_io::freestanding::non_overlapped_copy(fromcontroller.front_block.curr_ptr, + fromcontroller.front_block.end_ptr, + (controller.front_block.curr_ptr = + pos + controller.front_block.begin_ptr)); + ++destit; + for (begin_ptrtype *it{front_controller_ptr + 1}, *ed{back_controller_ptr}; it != ed; ++it) + { + begin_ptrtype blockptr{*it}; + ::fast_io::freestanding::non_overlapped_copy_n(blockptr, blockbytes, *destit); + ++destit; + } + lastblockbegin = fromcontroller.back_block.begin_ptr; + } + controller.back_block.curr_ptr = + ::fast_io::freestanding::non_overlapped_copy(lastblockbegin, + fromcontroller.back_block.curr_ptr, controller.back_block.begin_ptr); +} + +template +inline constexpr void deque_clone_trivial_common(dequecontroltype &controller, dequecontroltype const &fromcontroller) noexcept +{ + constexpr ::std::size_t blockbytes{sz * block_size}; + ::fast_io::containers::details::deque_clone_trivial_impl(controller, fromcontroller, align, blockbytes); +} + } // namespace details template @@ -772,40 +944,289 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE using reverse_iterator = ::std::reverse_iterator; using const_reverse_iterator = ::std::reverse_iterator; - ::fast_io::containers::details::deque_controller controller; +private: + using controller_type = ::fast_io::containers::details::deque_controller; + +public: + controller_type controller; static inline constexpr size_type block_size{::fast_io::containers::details::deque_block_size}; inline constexpr deque() noexcept : controller{{}, {}, {}} {} - inline constexpr deque(deque const &) = delete; + inline constexpr deque(deque const &other) noexcept(::std::is_nothrow_copy_constructible_v) + { + this->copy_construct_impl(other.controller); + } inline constexpr deque &operator=(deque const &) = delete; - inline constexpr deque(deque &&) noexcept = default; - inline constexpr deque &operator=(deque &&) noexcept = default; + inline constexpr deque(deque &&other) noexcept : controller(other.controller) + { + other.controller = {{}, {}, {}}; + } + inline constexpr deque &operator=(deque &&other) noexcept + { + if (__builtin_addressof(other) == this) + { + return *this; + } + destroy_deque_controller(this->controller); + this->controller = other.controller; + other.controller = {{}, {}, {}}; + return *this; + } private: - inline constexpr void destroy_all_elements() noexcept + struct run_destroy + { + controller_type *thiscontroller{}; + inline constexpr run_destroy() noexcept = default; + inline explicit constexpr run_destroy(controller_type *p) noexcept + : thiscontroller(p) + {} + inline run_destroy(run_destroy const &) = delete; + inline run_destroy &operator=(run_destroy const &) = delete; + inline constexpr ~run_destroy() + { + if (thiscontroller) + { + destroy_deque_controller(*thiscontroller); + } + } + }; + inline constexpr void copy_construct_impl(controller_type const &fromcontroller) + { + if constexpr (::std::is_trivially_copyable_v) + { + if (__builtin_is_constant_evaluated()) + { + ::fast_io::containers::details::deque_clone_trivial_common(controller, fromcontroller); + } + else + { + ::fast_io::containers::details::deque_clone_trivial_common(*reinterpret_cast<::fast_io::containers::details::deque_controller_common *>(__builtin_addressof(controller)), + *reinterpret_cast<::fast_io::containers::details::deque_controller_common const *>(__builtin_addressof(fromcontroller))); + } + return; + } + else + { + if (fromcontroller.front_block.curr_ptr == fromcontroller.back_block.curr_ptr) + { + this->controller = {{}, {}, {}}; + return; + } + + auto front_controller_ptr{fromcontroller.front_block.controller_ptr}; + auto back_controller_ptr{fromcontroller.back_block.controller_ptr}; + ::std::size_t blocks_required{static_cast<::std::size_t>(back_controller_ptr - + front_controller_ptr + 1)}; + constexpr ::std::size_t block_bytes{block_size * sizeof(value_type)}; + ::fast_io::containers::details::deque_allocate_init_blocks_dezeroing_impl(controller, alignof(value_type), block_bytes, blocks_required, false); + + run_destroy destroyer(__builtin_addressof(this->controller)); + auto dq_back_backup{this->controller.back_block}; + this->controller.back_block = this->controller.front_block; + pointer lastblockbegin; + if (front_controller_ptr == back_controller_ptr) + { + lastblockbegin = controller.front_block.curr_ptr; + } + else + { + auto destit{controller.front_block.controller_ptr}; + 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, + (controller.front_block.curr_ptr = + pos + controller.front_block.begin_ptr)); + this->controller.back_block.curr_ptr = controller.front_block.end_ptr = + controller.front_block.begin_ptr + block_size; + ++destit; + for (pointer *it{front_controller_ptr + 1}, *ed{back_controller_ptr}; it != ed; ++it) + { + pointer blockptr{*it}; + ::fast_io::freestanding::uninitialized_copy_n(blockptr, block_size, *destit); + this->controller.back_block = {destit, blockptr, blockptr, blockptr + block_size}; + ++destit; + } + lastblockbegin = fromcontroller.back_block.begin_ptr; + } + + dq_back_backup.curr_ptr = + ::fast_io::freestanding::uninitialized_copy(lastblockbegin, + fromcontroller.back_block.curr_ptr, dq_back_backup.begin_ptr); + + this->controller.back_block = dq_back_backup; + destroyer.thiscontroller = nullptr; + } + } + inline constexpr void default_construct_impl() + { + run_destroy des(__builtin_addressof(this->controller)); + + auto dq_back_backup{controller.back_block}; + controller.back_block = controller.front_block; + + 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) + { + lastblockbegin = controller.front_block.curr_ptr; + } + 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; + for (T **it{front_controller_ptr + 1}, **ed{back_controller_ptr}; it != ed; ++it) + { + 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}; + } + 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; + des.thiscontroller = nullptr; + } + +public: + inline explicit constexpr deque(size_type n) noexcept(::fast_io::freestanding::is_zero_default_constructible_v || + ::std::is_nothrow_default_constructible_v) + { + constexpr bool iszeroconstr{::fast_io::freestanding::is_zero_default_constructible_v}; + this->init_blocks_common(n); + if constexpr (!iszeroconstr) + { + this->default_construct_impl(); + } + } + + inline explicit constexpr deque(size_type n, ::fast_io::for_overwrite_t) noexcept(::fast_io::freestanding::is_zero_default_constructible_v || + ::std::is_nothrow_default_constructible_v) + { + if constexpr (::std::is_trivially_default_constructible_v) + { + this->init_blocks_common(n); + } + else if constexpr (::fast_io::freestanding::is_zero_default_constructible_v) + { + this->init_blocks_common(n); + } + else + { + this->init_blocks_common(n); + this->default_construct_impl(); + } + } + + template <::std::ranges::range R> + inline explicit constexpr deque(::fast_io::freestanding::from_range_t, R &&rg) + { + this->construct_deque_common_impl(::std::ranges::begin(rg), ::std::ranges::end(rg)); + } + + inline explicit constexpr deque(::std::initializer_list ilist) noexcept(::std::is_nothrow_copy_constructible_v) + { + this->construct_deque_common_impl(ilist.begin(), ilist.end()); + } + +private: + template + inline constexpr void construct_deque_common_impl(Iter first, Sentinel last) + { + if (first == last) + { + controller = {{}, {}, {}}; + return; + } + run_destroy des(__builtin_addressof(this->controller)); + if constexpr (::std::sized_sentinel_for) + { + auto const dist{::std::ranges::distance(first, last)}; + + this->init_blocks_common(static_cast<::std::size_t>(dist)); + + auto dq_back_backup{this->controller.back_block}; + 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) + { + lastblockbegin = controller.front_block.curr_ptr; + } + else + { + for (T **it{front_controller_ptr}, **ed{back_controller_ptr}; it != ed; ++it) + { + 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}; + } + lastblockbegin = dq_back_backup.begin_ptr; + } + ::fast_io::containers::details::uninitialized_copy_n_for_deque( + first, + static_cast<::std::size_t>(dq_back_backup.curr_ptr - lastblockbegin), + lastblockbegin); + this->controller.back_block = dq_back_backup; + } + else + { + controller = {{}, {}, {}}; + for (; first != last; ++first) + { + this->push_back(*first); + } + } + des.thiscontroller = nullptr; + } + + template + inline constexpr void init_blocks_common(::std::size_t n) noexcept + { + if (__builtin_is_constant_evaluated()) + { + ::fast_io::containers::details::deque_init_space_common(controller, n); + } + else + { + ::fast_io::containers::details::deque_init_space_common(*reinterpret_cast<::fast_io::containers::details::deque_controller_common *>(__builtin_addressof(controller)), n); + } + } + inline static constexpr void destroy_all_elements(controller_type &controller) noexcept { - ::std::destroy(controller.front_block.curr_ptr, controller.front_block.end_ptr); auto front_controller_ptr{controller.front_block.controller_ptr}; auto back_controller_ptr{controller.back_block.controller_ptr}; - if (front_controller_ptr != back_controller_ptr) + T *lastblockbegin; + if (front_controller_ptr == back_controller_ptr) { + lastblockbegin = controller.front_block.curr_ptr; + } + else + { + ::std::destroy(controller.front_block.curr_ptr, controller.front_block.end_ptr); for (T **it{front_controller_ptr + 1}, **ed{back_controller_ptr}; it != ed; ++it) { T *blockptr{*it}; ::std::destroy(blockptr, blockptr + block_size); } + lastblockbegin = controller.back_block.begin_ptr; } - ::std::destroy(controller.back_block.begin_ptr, controller.back_block.curr_ptr); + ::std::destroy(lastblockbegin, controller.back_block.curr_ptr); } - inline constexpr void destroy() noexcept + inline static constexpr void destroy_deque_controller(controller_type &controller) noexcept { if constexpr (!::std::is_trivially_destructible_v) { - this->destroy_all_elements(); + destroy_all_elements(controller); } ::fast_io::containers::details::deque_destroy_trivial_common(controller.controller_block); } @@ -860,7 +1281,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE { if constexpr (!::std::is_trivially_destructible_v) { - this->destroy_all_elements(); + destroy_all_elements(this->controller); } if (__builtin_is_constant_evaluated()) { @@ -873,7 +1294,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE } template requires ::std::constructible_from - inline constexpr reference emplace_back(Args &&...args) + 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]] { @@ -890,7 +1311,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE this->emplace_back(value); } - inline constexpr void push_back(value_type &&value) + inline constexpr void push_back(value_type &&value) noexcept { this->emplace_back(::std::move(value)); } @@ -947,16 +1368,53 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE return controller.back_block.curr_ptr[-1]; } +private: + struct emplace_front_guard + { + using handletype = ::fast_io::containers::details::deque_controller_block; + handletype *thisdeq; + explicit constexpr emplace_front_guard(handletype *other) noexcept : thisdeq{other} + { + } + emplace_front_guard(emplace_front_guard const &) = delete; + emplace_front_guard &operator=(emplace_front_guard const &) = delete; + constexpr ~emplace_front_guard() + { + if (this->thisdeq) + { + auto &frontblock{this->thisdeq->front_block}; + if (frontblock.curr_ptr == + frontblock.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); + } + } + } + }; + +public: template requires ::std::constructible_from - inline constexpr reference emplace_front(Args &&...args) + inline constexpr reference emplace_front(Args &&...args) noexcept(::std::is_nothrow_constructible_v) { if (controller.front_block.curr_ptr == controller.front_block.begin_ptr) [[unlikely]] { grow_front(); } - ::std::construct_at(--controller.front_block.curr_ptr, ::std::forward(args)...); - return *controller.front_block.curr_ptr; + auto front_curr_ptr{controller.front_block.curr_ptr}; + if constexpr (::std::is_nothrow_constructible_v) + { + return *(controller.front_block.curr_ptr = ::std::construct_at(front_curr_ptr - 1, ::std::forward(args)...)); + } + else + { + emplace_front_guard guard(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); + } } inline constexpr void push_front(value_type const &value) @@ -964,7 +1422,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE this->emplace_front(value); } - inline constexpr void push_front(value_type &&value) + inline constexpr void push_front(value_type &&value) noexcept { this->emplace_front(::std::move(value)); } @@ -1187,13 +1645,13 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE inline constexpr void clear_destroy() noexcept { - this->destroy(); + destroy_deque_controller(this->controller); this->controller = {{}, {}, {}}; } inline constexpr ~deque() { - this->destroy(); + destroy_deque_controller(this->controller); } }; diff --git a/include/fast_io_dsal/impl/vector.h b/include/fast_io_dsal/impl/vector.h index 28341c27c..7fbd3f463 100644 --- a/include/fast_io_dsal/impl/vector.h +++ b/include/fast_io_dsal/impl/vector.h @@ -391,7 +391,7 @@ class vector FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE this->construct_vector_common_impl(::std::ranges::begin(rg), ::std::ranges::end(rg)); } - inline explicit constexpr vector(::std::initializer_list ilist) noexcept(::std::is_nothrow_move_constructible_v) + inline explicit constexpr vector(::std::initializer_list ilist) noexcept(::std::is_nothrow_copy_constructible_v) { this->construct_vector_common_impl(ilist.begin(), ilist.end()); } diff --git a/tests/0026.container/0003.deque/constructors/copy_constructor.cc b/tests/0026.container/0003.deque/constructors/copy_constructor.cc new file mode 100644 index 000000000..4e1519850 --- /dev/null +++ b/tests/0026.container/0003.deque/constructors/copy_constructor.cc @@ -0,0 +1,102 @@ +#include +#include +#include +#include + +template +inline void test_copy_constructor() +{ + ::fast_io::io::perr("=== copy constructor test for type ===\n"); + + // Fill original deque + ::fast_io::deque dq; + for (::std::size_t i{}; i != 4096u; ++i) + { + if constexpr (::std::same_as) + { + dq.push_back(i); + } + else + { + dq.emplace_back(::fast_io::concat_fast_io(i)); + } + } + // Copy construct + ::fast_io::deque dq2(dq); + + // Size must match + if (dq2.size() != dq.size()) + { + ::fast_io::io::panic("ERROR: dq2.size() != dq.size() after copy construction\n"); + } + + // Elements must match + ::std::size_t idx{}; + for (T const &e : dq2) + { + if constexpr (::std::same_as) + { + if (e != idx) + { + ::fast_io::io::panicln("ERROR: dq2 element mismatch: ", e); + } + } + else + { + ::fast_io::string expected(::fast_io::concat_fast_io(idx)); + if (e != expected) + { + ::fast_io::io::panicln("ERROR: dq2 string mismatch: ", e); + } + } + ++idx; + } + + // Modify original to ensure deep copy + if constexpr (::std::same_as) + { + for (auto &e : dq) + { + ++e; + } + } + else + { + for (auto &e : dq) + { + e.append("_changed"); + } + } + + // dq2 must remain unchanged + idx = 0u; + for (T const &e : dq2) + { + if constexpr (::std::same_as) + { + if (e != idx) + { + ::fast_io::io::panicln("ERROR: dq2 changed after modifying dq: ", e); + } + } + else + { + ::fast_io::string expected(::fast_io::concat_fast_io(idx)); + if (e != expected) + { + ::fast_io::io::panicln("ERROR: dq2 string changed after modifying dq: ", e); + } + } + ++idx; + } + + ::fast_io::io::print("copy constructor test finished\n"); +} + +int main() +{ + test_copy_constructor<::std::size_t>(); + test_copy_constructor<::fast_io::string>(); + + ::fast_io::io::print("All copy constructor tests finished\n"); +} diff --git a/tests/0026.container/0003.deque/constructors/from_range.cc b/tests/0026.container/0003.deque/constructors/from_range.cc new file mode 100644 index 000000000..bd5b8b730 --- /dev/null +++ b/tests/0026.container/0003.deque/constructors/from_range.cc @@ -0,0 +1,33 @@ +#include +#include +#include + +int main() +{ + ::fast_io::io::perr("=== deque(from_range_t, R) test ===\n"); + + ::fast_io::vector<::std::size_t> vec; + for (::std::size_t i{}; i != 4096u; ++i) + { + vec.push_back(i); + } + + ::fast_io::deque<::std::size_t> dq(::fast_io::freestanding::from_range, vec); + + if (dq.size() != vec.size()) + { + ::fast_io::io::panic("ERROR: dq.size() != vec.size()\n"); + } + + ::std::size_t idx{}; + for (auto const& e : dq) + { + if (e != vec[idx]) + { + ::fast_io::io::panicln("ERROR: element mismatch: ", e); + } + ++idx; + } + + ::fast_io::io::print("deque(from_range_t, R) test finished\n"); +} diff --git a/tests/0026.container/0003.deque/constructors/initializer_list.cc b/tests/0026.container/0003.deque/constructors/initializer_list.cc new file mode 100644 index 000000000..7c006eaba --- /dev/null +++ b/tests/0026.container/0003.deque/constructors/initializer_list.cc @@ -0,0 +1,26 @@ +#include +#include + +int main() +{ + ::fast_io::io::perr("=== deque(initializer_list) test ===\n"); + + ::fast_io::deque<::std::size_t> dq{1u, 2u, 3u, 4u, 5u}; + + if (dq.size() != 5u) + { + ::fast_io::io::panic("ERROR: dq.size() != 5\n"); + } + + ::std::size_t expected{}; + for (auto const& e : dq) + { + ++expected; + if (e != expected) + { + ::fast_io::io::panicln("ERROR: element mismatch: ", e); + } + } + + ::fast_io::io::print("deque(initializer_list) test finished\n"); +} diff --git a/tests/0026.container/0003.deque/constructors/n.cc b/tests/0026.container/0003.deque/constructors/n.cc new file mode 100644 index 000000000..1def5850a --- /dev/null +++ b/tests/0026.container/0003.deque/constructors/n.cc @@ -0,0 +1,26 @@ +#include +#include + +int main() +{ + ::fast_io::io::perr("=== deque(size_type n) test ===\n"); + + constexpr ::std::size_t n{4096u}; + ::fast_io::deque<::std::size_t> dq(n); + + if (dq.size() != n) + { + ::fast_io::io::panic("ERROR: dq.size() != n\n"); + } + + // All elements must be default constructed (0 for size_t) + for (auto const& e : dq) + { + if (e != 0u) + { + ::fast_io::io::panicln("ERROR: default constructed element != 0: ", e); + } + } + + ::fast_io::io::print("deque(size_type n) test finished\n"); +} diff --git a/tests/0026.container/0003.deque/constructors/n_for_overwrite.cc b/tests/0026.container/0003.deque/constructors/n_for_overwrite.cc new file mode 100644 index 000000000..44e0d8b9b --- /dev/null +++ b/tests/0026.container/0003.deque/constructors/n_for_overwrite.cc @@ -0,0 +1,41 @@ +#include +#include + +int main() +{ + ::fast_io::io::perr("=== deque(size_type n, for_overwrite_t) test ===\n"); + + constexpr ::std::size_t n{4096u}; + ::fast_io::deque<::std::size_t> dq(n, ::fast_io::for_overwrite); + + if (dq.size() != n) + { + ::fast_io::io::panic("ERROR: dq.size() != n\n"); + } + + // Assign values to ensure iteration works and references are valid + ::std::size_t value{}; + for (auto &e : dq) + { + e = value; + ++value; + } + + // Verify values were written correctly + value = 0; + for (auto const& e : dq) + { + if (e != value) + { + ::fast_io::io::panicln("ERROR: assigned value mismatch: ", e); + } + ++value; + } + + if (value != n) + { + ::fast_io::io::panic("ERROR: iteration count != n\n"); + } + + ::fast_io::io::print("deque(size_type n, for_overwrite_t) test finished\n"); +} diff --git a/tests/0026.container/0003.deque/moveops.cc b/tests/0026.container/0003.deque/moveops.cc new file mode 100644 index 000000000..b45632003 --- /dev/null +++ b/tests/0026.container/0003.deque/moveops.cc @@ -0,0 +1,79 @@ +#include +#include + +int main() +{ + ::fast_io::io::perr("=== move() test ===\n"); + + ::fast_io::deque<::std::size_t> dq; + + // Fill with enough elements to force growth + for (::std::size_t i{}; i != 4096u; ++i) + { + dq.push_back(i); + } + + // Move-construct + ::fast_io::deque<::std::size_t> dq2{::std::move(dq)}; + + // dq must be empty after move + if (!dq.is_empty()) + { + ::fast_io::io::panic("ERROR: moved-from dq is not empty\n"); + } + if (dq.size() != 0u) + { + ::fast_io::io::panic("ERROR: moved-from dq.size() != 0\n"); + } + + // dq2 must contain all elements + ::std::size_t expected{}; + for (auto const &e : dq2) + { + if (e != expected) + { + ::fast_io::io::panicln("ERROR: dq2 element mismatch: ", e); + } + ++expected; + } + + // Now test move assignment + ::fast_io::deque<::std::size_t> dq3; + + for (::std::size_t i{}; i != 2048u; ++i) + { + dq3.push_front(i); + } + + dq3 = ::std::move(dq2); + + // dq2 must be empty + if (!dq2.is_empty()) + { + ::fast_io::io::panic("ERROR: moved-from dq2 is not empty after assignment\n"); + } + + // dq3 must contain the original dq2 contents + expected = 0u; + for (auto const &e : dq3) + { + if (e != expected) + { + ::fast_io::io::panicln("ERROR: dq3 element mismatch: ", e); + } + ++expected; + } + + // Reuse dq2 after move + for (::std::size_t i{}; i != 1024u; ++i) + { + dq2.push_back(i); + } + + for (auto const &e : dq2) + { + ::fast_io::io::println(e); + } + + ::fast_io::io::print("move() test finished\n"); +}