diff --git a/include/fast_io_dsal/impl/deque.h b/include/fast_io_dsal/impl/deque.h index c1f8607a6..f9b871ee7 100644 --- a/include/fast_io_dsal/impl/deque.h +++ b/include/fast_io_dsal/impl/deque.h @@ -2228,7 +2228,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE pointer lastblockbegin; if (front_controller_ptr == back_controller_ptr) { - lastblockbegin = controller.front_block.curr_ptr; + lastblockbegin = fromcontroller.front_block.curr_ptr; } else { @@ -2342,7 +2342,12 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE } inline explicit constexpr deque(size_type n, const_reference val) noexcept(::std::is_nothrow_copy_constructible_v) + : controller{} { + if (!n) + { + return; + } if constexpr (::std::is_nothrow_copy_constructible_v) { this->reserve_back(n); @@ -3303,7 +3308,7 @@ class deque FAST_IO_TRIVIALLY_RELOCATABLE_IF_ELIGIBLE struct emplace_decision { - ::std::size_t pos; + iterator pos; ::std::int_fast8_t decision; }; template diff --git a/tests/0026.container/0003.deque/access.cc b/tests/0026.container/0003.deque/access.cc new file mode 100644 index 000000000..0190aa0de --- /dev/null +++ b/tests/0026.container/0003.deque/access.cc @@ -0,0 +1,145 @@ +#include +#include +#include + +namespace +{ + +inline void test_operator_subscript() +{ + ::fast_io::io::perr("=== deque operator[] test ===\n"); + + ::fast_io::deque<::std::size_t> dq; + ::std::deque<::std::size_t> ref; + + // Fill with data + for (::std::size_t i{}; i != 4096u; ++i) + { + dq.push_back(i); + ref.push_back(i); + } + + // Test operator[] (non-const) + for (::std::size_t i{}; i != dq.size(); ++i) + { + if (dq[i] != ref[i]) + { + ::fast_io::io::panicln("operator[] mismatch at ", i); + } + } + + // Test operator[] (const) + { + auto const &cdq = dq; + for (::std::size_t i{}; i != cdq.size(); ++i) + { + if (cdq[i] != ref[i]) + { + ::fast_io::io::panicln("const operator[] mismatch at ", i); + } + } + } + + // Test index_unchecked + for (::std::size_t i{}; i != dq.size(); ++i) + { + if (dq.index_unchecked(i) != ref[i]) + { + ::fast_io::io::panicln("index_unchecked mismatch at ", i); + } + } + + // Modify via operator[] and verify + for (::std::size_t i{}; i != dq.size(); ++i) + { + dq[i] = i * 2u; + ref[i] = i * 2u; + } + + for (::std::size_t i{}; i != dq.size(); ++i) + { + if (dq[i] != ref[i]) + { + ::fast_io::io::panicln("operator[] modification mismatch at ", i); + } + } + + ::fast_io::io::print("deque operator[] test finished\n"); +} + +inline void test_front_back() +{ + ::fast_io::io::perr("=== deque front() / back() test ===\n"); + + ::fast_io::deque<::std::size_t> dq; + ::std::deque<::std::size_t> ref; + + for (::std::size_t i{}; i != 4096u; ++i) + { + dq.push_back(i); + ref.push_back(i); + } + + // front() and back() (non-const) + if (dq.front() != ref.front()) + { + ::fast_io::io::panic("front() mismatch\n"); + } + + if (dq.back() != ref.back()) + { + ::fast_io::io::panic("back() mismatch\n"); + } + + // front() and back() (const) + { + auto const &cdq = dq; + if (cdq.front() != ref.front()) + { + ::fast_io::io::panic("const front() mismatch\n"); + } + + if (cdq.back() != ref.back()) + { + ::fast_io::io::panic("const back() mismatch\n"); + } + } + + // front_unchecked and back_unchecked + if (dq.front_unchecked() != ref.front()) + { + ::fast_io::io::panic("front_unchecked() mismatch\n"); + } + + if (dq.back_unchecked() != ref.back()) + { + ::fast_io::io::panic("back_unchecked() mismatch\n"); + } + + // Modify and verify + dq.front() = 9999u; + ref.front() = 9999u; + + if (dq.front() != ref.front()) + { + ::fast_io::io::panic("front() modification mismatch\n"); + } + + dq.back() = 8888u; + ref.back() = 8888u; + + if (dq.back() != ref.back()) + { + ::fast_io::io::panic("back() modification mismatch\n"); + } + + ::fast_io::io::print("deque front() / back() test finished\n"); +} + +} // namespace + +int main() +{ + test_operator_subscript(); + test_front_back(); +} diff --git a/tests/0026.container/0003.deque/algorithm.cc b/tests/0026.container/0003.deque/algorithm.cc new file mode 100644 index 000000000..d86822d9a --- /dev/null +++ b/tests/0026.container/0003.deque/algorithm.cc @@ -0,0 +1,204 @@ +#include +#include +#include +#include +#include + +namespace +{ + +inline void test_copy() +{ + ::fast_io::io::perr("=== deque std::copy test ===\n"); + + // Test sizes at and around block boundaries + ::std::size_t const sizes[] = {0, 1, 2, 3, 1023, 1024, 1025, 2047, 2048, 2049}; + + for (::std::size_t n : sizes) + { + ::fast_io::deque<::std::size_t> src; + ::fast_io::deque<::std::size_t> dst; + + for (::std::size_t i{}; i != n; ++i) + { + src.push_back(i); + dst.push_back(0u); + } + + auto result = ::std::copy(src.cbegin(), src.cend(), dst.begin()); + if (result != dst.end()) + { + ::fast_io::io::panicln("copy result not at end for n=", n); + } + + for (::std::size_t i{}; i != n; ++i) + { + if (dst[i] != src[i]) + { + ::fast_io::io::panicln("copy value mismatch at ", i, " for n=", n); + } + } + } + + // Compare with std::deque + { + ::fast_io::deque<::std::size_t> fsrc, fdst; + ::std::deque<::std::size_t> ssrc, sdst; + + for (::std::size_t i{}; i != 4096u; ++i) + { + fsrc.push_back(i); + fdst.push_back(0u); + ssrc.push_back(i); + sdst.push_back(0); + } + + ::std::copy(fsrc.cbegin(), fsrc.cend(), fdst.begin()); + ::std::copy(ssrc.cbegin(), ssrc.cend(), sdst.begin()); + + for (::std::size_t i{}; i != 4096u; ++i) + { + if (fdst[i] != sdst[i]) + { + ::fast_io::io::panicln("copy mismatch with std::deque at ", i); + } + } + } + + ::fast_io::io::print("deque std::copy test finished\n"); +} + +inline void test_copy_backward() +{ + ::fast_io::io::perr("=== deque std::copy_backward test ===\n"); + + { + ::fast_io::deque<::std::size_t> dq; + for (::std::size_t i{}; i != 100u; ++i) + { + dq.push_back(i); + } + + dq.resize(110u); + ::std::copy_backward(dq.cbegin(), dq.cbegin() + 100, dq.end()); + + // First 10 elements unchanged (still 0..9) + for (::std::size_t i{}; i != 10u; ++i) + { + if (dq[i] != i) + { + ::fast_io::io::panicln("copy_backward: first elements wrong at ", i); + } + } + for (::std::size_t i{}; i != 100u; ++i) + { + if (dq[i + 10u] != i) + { + ::fast_io::io::panicln("copy_backward: shifted elements wrong at ", i); + } + } + } + + // Compare with std::deque + { + ::fast_io::deque<::std::size_t> fdq; + ::std::deque<::std::size_t> sdq; + + for (::std::size_t i{}; i != 100u; ++i) + { + fdq.push_back(i); + sdq.push_back(i); + } + + fdq.resize(110u); + sdq.resize(110); + ::std::copy_backward(fdq.cbegin(), fdq.cbegin() + 100, fdq.end()); + ::std::copy_backward(sdq.cbegin(), sdq.cbegin() + 100, sdq.end()); + + for (::std::size_t i{}; i != 110u; ++i) + { + if (fdq[i] != sdq[i]) + { + ::fast_io::io::panicln("copy_backward mismatch with std::deque at ", i); + } + } + } + + ::fast_io::io::print("deque std::copy_backward test finished\n"); +} + +inline void test_move() +{ + ::fast_io::io::perr("=== deque std::move test ===\n"); + + ::std::size_t const sizes[] = {0, 1, 2, 3, 1023, 1024, 1025, 2047, 2048, 2049}; + + for (::std::size_t n : sizes) + { + ::fast_io::deque<::std::size_t> src; + ::fast_io::deque<::std::size_t> dst; + + for (::std::size_t i{}; i != n; ++i) + { + src.push_back(i); + dst.push_back(0u); + } + + auto result = ::std::move(src.begin(), src.end(), dst.begin()); + if (result != dst.end()) + { + ::fast_io::io::panicln("move result not at end for n=", n); + } + + for (::std::size_t i{}; i != n; ++i) + { + if (dst[i] != i) + { + ::fast_io::io::panicln("move value mismatch at ", i, " for n=", n); + } + } + } + + ::fast_io::io::print("deque std::move test finished\n"); +} + +inline void test_move_backward() +{ + ::fast_io::io::perr("=== deque std::move_backward test ===\n"); + + ::fast_io::deque<::std::size_t> dq; + for (::std::size_t i{}; i != 100u; ++i) + { + dq.push_back(i); + } + + dq.resize(110u); + ::std::move_backward(dq.begin(), dq.begin() + 100, dq.end()); + + for (::std::size_t i{}; i != 10u; ++i) + { + if (dq[i] != i) + { + ::fast_io::io::panicln("move_backward: first elements wrong at ", i); + } + } + for (::std::size_t i{}; i != 100u; ++i) + { + if (dq[i + 10u] != i) + { + ::fast_io::io::panicln("move_backward: shifted elements wrong at ", i); + } + } + + ::fast_io::io::print("deque std::move_backward test finished\n"); +} + +} // namespace + +int main() +{ + test_copy(); + test_copy_backward(); + test_move(); + test_move_backward(); +} diff --git a/tests/0026.container/0003.deque/assign_range.cc b/tests/0026.container/0003.deque/assign_range.cc new file mode 100644 index 000000000..1a3b034f8 --- /dev/null +++ b/tests/0026.container/0003.deque/assign_range.cc @@ -0,0 +1,131 @@ +#include +#include +#include +#include +#include + +namespace +{ + +inline void test_assign_count_value() +{ + ::fast_io::io::perr("=== deque assign(count, value) test ===\n"); + + { + ::fast_io::deque<::std::size_t> dq; + ::std::deque<::std::size_t> ref; + + for (::std::size_t i{}; i != 100u; ++i) + { + dq.push_back(i); + ref.push_back(i); + } + + dq.assign(50u, 777u); + ref.assign(50, 777); + + if (dq.size() != ref.size()) + { + ::fast_io::io::panic("size mismatch after assign(count, value)\n"); + } + + for (::std::size_t i{}; i != dq.size(); ++i) + { + if (dq[i] != ref[i]) + { + ::fast_io::io::panicln("value mismatch at ", i, " after assign(count, value)"); + } + } + } + + // Assign zero count + { + ::fast_io::deque<::std::size_t> dq; + for (::std::size_t i{}; i != 100u; ++i) + { + dq.push_back(i); + } + + dq.assign(0u, 999u); + if (!dq.empty()) + { + ::fast_io::io::panic("deque should be empty after assign(0, val)\n"); + } + } + + // Test sizes at and around block boundaries + { + ::std::size_t const sizes[] = {0, 1, 2, 3, 1023, 1024, 1025, 2047, 2048, 2049}; + + for (::std::size_t n : sizes) + { + ::fast_io::deque<::std::size_t> dq; + ::std::deque<::std::size_t> ref; + + for (::std::size_t i{}; i != n; ++i) + { + dq.push_back(i); + ref.push_back(i); + } + + dq.assign(0u, 0u); + ref.assign(0, 0); + + if (dq.size() != ref.size()) + { + ::fast_io::io::panicln("size mismatch after assign to empty for n=", n); + } + } + } + + ::fast_io::io::print("deque assign(count, value) test finished\n"); +} + +inline void test_assign_range() +{ + ::fast_io::io::perr("=== deque assign_range test ===\n"); + + { + ::fast_io::deque<::std::size_t> dq; + ::std::deque<::std::size_t> ref; + + for (::std::size_t i{}; i != 100u; ++i) + { + dq.push_back(i); + ref.push_back(i); + } + + ::fast_io::vector<::std::size_t> src; + for (::std::size_t i{}; i != 50u; ++i) + { + src.push_back(i + 2000u); + } + + dq.assign_range(src); + ::std::vector<::std::size_t> std_src(src.begin(), src.end()); + ref.assign(std_src.begin(), std_src.end()); + + if (dq.size() != ref.size()) + { + ::fast_io::io::panic("size mismatch after assign_range\n"); + } + + for (::std::size_t i{}; i != dq.size(); ++i) + { + if (dq[i] != ref[i]) + { + ::fast_io::io::panicln("value mismatch at ", i, " after assign_range"); + } + } + } + + ::fast_io::io::print("deque assign_range test finished\n"); +} + +} // namespace + +int main() +{ + test_assign_count_value(); + test_assign_range(); +} diff --git a/tests/0026.container/0003.deque/capacity.cc b/tests/0026.container/0003.deque/capacity.cc new file mode 100644 index 000000000..0403d8a6b --- /dev/null +++ b/tests/0026.container/0003.deque/capacity.cc @@ -0,0 +1,169 @@ +#include +#include +#include + +namespace +{ + +inline void test_size_empty() +{ + ::fast_io::io::perr("=== deque size() / empty() test ===\n"); + + // Empty deque + { + ::fast_io::deque<::std::size_t> dq; + if (dq.size() != 0u) + { + ::fast_io::io::panic("default constructed deque size should be 0\n"); + } + if (!dq.empty()) + { + ::fast_io::io::panic("default constructed deque should be empty\n"); + } + if (!dq.is_empty()) + { + ::fast_io::io::panic("default constructed deque should be is_empty\n"); + } + } + + // Non-empty deque + { + ::fast_io::deque<::std::size_t> dq; + for (::std::size_t i{}; i != 4096u; ++i) + { + dq.push_back(i); + } + + if (dq.size() != 4096u) + { + ::fast_io::io::panic("size should be 4096\n"); + } + if (dq.empty()) + { + ::fast_io::io::panic("deque with elements should not be empty\n"); + } + } + + // After clear + { + ::fast_io::deque<::std::size_t> dq; + for (::std::size_t i{}; i != 4096u; ++i) + { + dq.push_back(i); + } + dq.clear(); + if (dq.size() != 0u) + { + ::fast_io::io::panic("size should be 0 after clear\n"); + } + if (!dq.empty()) + { + ::fast_io::io::panic("deque should be empty after clear\n"); + } + } + + ::fast_io::io::print("deque size() / empty() test finished\n"); +} + +inline void test_max_size() +{ + ::fast_io::io::perr("=== deque max_size() test ===\n"); + + ::fast_io::deque<::std::size_t> dq; + ::fast_io::deque dq_char; + + // max_size should be very large (at least millions) + if (dq.max_size() < 1000000u) + { + ::fast_io::io::panicln("max_size for size_t too small: ", dq.max_size()); + } + + if (dq_char.max_size() < 1000000u) + { + ::fast_io::io::panicln("max_size for char too small: ", dq_char.max_size()); + } + + // max_size and max_size_bytes should exist + if (dq.max_size_bytes() < 1000000u) + { + ::fast_io::io::panicln("max_size_bytes too small: ", dq.max_size_bytes()); + } + + ::fast_io::io::print("deque max_size() test finished\n"); +} + +inline void test_shrink_to_fit() +{ + ::fast_io::io::perr("=== deque shrink_to_fit() test ===\n"); + + // Test sizes at and around block boundaries + ::std::size_t const sizes[] = {0, 1, 2, 3, 1023, 1024, 1025, 2047, 2048, 2049}; + + for (::std::size_t n : sizes) + { + ::fast_io::deque<::std::size_t> dq; + ::std::deque<::std::size_t> ref; + + for (::std::size_t i{}; i != n; ++i) + { + dq.push_back(i); + ref.push_back(i); + } + + dq.shrink_to_fit(); + + // After shrink_to_fit, elements must be preserved + if (dq.size() != ref.size()) + { + ::fast_io::io::panicln("size mismatch after shrink_to_fit for n=", n); + } + + for (::std::size_t i{}; i != dq.size(); ++i) + { + if (dq[i] != ref[i]) + { + ::fast_io::io::panicln("value mismatch at ", i, " after shrink_to_fit for n=", n); + } + } + } + + // Shrink empty deque + { + ::fast_io::deque<::std::size_t> dq; + dq.shrink_to_fit(); + if (!dq.empty()) + { + ::fast_io::io::panic("empty deque should stay empty after shrink_to_fit\n"); + } + } + + ::fast_io::io::print("deque shrink_to_fit() test finished\n"); +} + +inline void test_size_bytes() +{ + ::fast_io::io::perr("=== deque size_bytes() test ===\n"); + + ::fast_io::deque<::std::size_t> dq; + for (::std::size_t i{}; i != 100u; ++i) + { + dq.push_back(i); + } + + if (dq.size_bytes() != dq.size() * sizeof(::std::size_t)) + { + ::fast_io::io::panic("size_bytes mismatch\n"); + } + + ::fast_io::io::print("deque size_bytes() test finished\n"); +} + +} // namespace + +int main() +{ + test_size_empty(); + test_max_size(); + test_shrink_to_fit(); + test_size_bytes(); +} diff --git a/tests/0026.container/0003.deque/compare.cc b/tests/0026.container/0003.deque/compare.cc new file mode 100644 index 000000000..e7c59020f --- /dev/null +++ b/tests/0026.container/0003.deque/compare.cc @@ -0,0 +1,194 @@ +#include +#include +#include +#include + +namespace +{ + +inline void test_operator_equal() +{ + ::fast_io::io::perr("=== deque operator== test ===\n"); + + // Equal empty deques + { + ::fast_io::deque<::std::size_t> a, b; + if (!(a == b)) + { + ::fast_io::io::panic("empty deques should be equal\n"); + } + } + + // Equal non-empty deques + { + ::fast_io::deque<::std::size_t> a, b; + for (::std::size_t i{}; i != 100u; ++i) + { + a.push_back(i); + b.push_back(i); + } + if (!(a == b)) + { + ::fast_io::io::panic("identical deques should be equal\n"); + } + } + + // Unequal deques (different size) + { + ::fast_io::deque<::std::size_t> a, b; + a.push_back(1u); + a.push_back(2u); + b.push_back(1u); + if (a == b) + { + ::fast_io::io::panic("deques with different sizes should not be equal\n"); + } + } + + // Unequal deques (same size, different values) + { + ::fast_io::deque<::std::size_t> a, b; + a.push_back(1u); + a.push_back(2u); + b.push_back(1u); + b.push_back(3u); + if (a == b) + { + ::fast_io::io::panic("deques with different values should not be equal\n"); + } + } + + // Self comparison + { + ::fast_io::deque<::std::size_t> a; + for (::std::size_t i{}; i != 100u; ++i) + { + a.push_back(i); + } + if (!(a == a)) + { + ::fast_io::io::panic("deque should equal itself\n"); + } + } + + // Compare with std::deque + { + ::fast_io::deque<::std::size_t> a; + ::std::deque<::std::size_t> ref; + for (::std::size_t i{}; i != 4096u; ++i) + { + a.push_back(i); + ref.push_back(i); + } + + // Verify fast_io deque == fast_io deque consistency + ::fast_io::deque<::std::size_t> b = a; + if (!(a == b)) + { + ::fast_io::io::panic("copy should be equal\n"); + } + } + + ::fast_io::io::print("deque operator== test finished\n"); +} + +inline void test_spaceship() +{ + ::fast_io::io::perr("=== deque operator<=> test ===\n"); + + // Equal deques + { + ::fast_io::deque<::std::size_t> a, b; + for (::std::size_t i{}; i != 100u; ++i) + { + a.push_back(i); + b.push_back(i); + } + auto cmp = (a <=> b); + if (!(cmp == 0)) + { + ::fast_io::io::panic("equal deques should compare equal\n"); + } + } + + // a < b (a is prefix) + { + ::fast_io::deque<::std::size_t> a, b; + a.push_back(1u); + a.push_back(2u); + b.push_back(1u); + b.push_back(2u); + b.push_back(3u); + + auto cmp = (a <=> b); + if (!(cmp < 0)) + { + ::fast_io::io::panic("prefix deque should be less\n"); + } + } + + // a < b (first differing element) + { + ::fast_io::deque<::std::size_t> a, b; + a.push_back(1u); + a.push_back(2u); + b.push_back(1u); + b.push_back(3u); + + auto cmp = (a <=> b); + if (!(cmp < 0)) + { + ::fast_io::io::panic("deque with smaller element should be less\n"); + } + } + + // a > b + { + ::fast_io::deque<::std::size_t> a, b; + a.push_back(1u); + a.push_back(3u); + b.push_back(1u); + b.push_back(2u); + + auto cmp = (a <=> b); + if (!(cmp > 0)) + { + ::fast_io::io::panic("deque with larger element should be greater\n"); + } + } + + // Empty deques + { + ::fast_io::deque<::std::size_t> a, b; + auto cmp = (a <=> b); + if (!(cmp == 0)) + { + ::fast_io::io::panic("empty deques should compare equal\n"); + } + } + + // Deque with non-trivial type + { + ::fast_io::deque<::fast_io::string> a, b; + a.emplace_back("apple"); + a.emplace_back("banana"); + b.emplace_back("apple"); + b.emplace_back("cherry"); + + auto cmp = (a <=> b); + if (!(cmp < 0)) + { + ::fast_io::io::panic("string spaceship should work\n"); + } + } + + ::fast_io::io::print("deque operator<=> test finished\n"); +} + +} // namespace + +int main() +{ + test_operator_equal(); + test_spaceship(); +} diff --git a/tests/0026.container/0003.deque/concepts.cc b/tests/0026.container/0003.deque/concepts.cc new file mode 100644 index 000000000..19df8ea06 --- /dev/null +++ b/tests/0026.container/0003.deque/concepts.cc @@ -0,0 +1,113 @@ +#include +#include +#include +#include +#include + +int main() +{ + using deque_type = ::fast_io::deque; + using iterator = deque_type::iterator; + using const_iterator = deque_type::const_iterator; + using reverse_iterator = deque_type::reverse_iterator; + using const_reverse_iterator = deque_type::const_reverse_iterator; + using value_type = int; + + // ===== Iterator concept conformance ===== + + // random_access_iterator (NOT contiguous_iterator) + static_assert(::std::random_access_iterator); + static_assert(!::std::contiguous_iterator); + + static_assert(::std::random_access_iterator); + static_assert(!::std::contiguous_iterator); + + // indirectly_writable + static_assert(::std::indirectly_writable); + static_assert(!::std::indirectly_writable); + + // sentinel_for + static_assert(::std::sentinel_for); + static_assert(::std::sentinel_for); + static_assert(!::std::sentinel_for); + static_assert(!::std::sentinel_for); + + static_assert(::std::sentinel_for); + static_assert(::std::sentinel_for); + static_assert(!::std::sentinel_for); + static_assert(!::std::sentinel_for); + + // sized_sentinel_for + static_assert(::std::sized_sentinel_for); + static_assert(::std::sized_sentinel_for); + static_assert(!::std::sized_sentinel_for); + static_assert(!::std::sized_sentinel_for); + + static_assert(::std::sized_sentinel_for); + static_assert(::std::sized_sentinel_for); + static_assert(!::std::sized_sentinel_for); + static_assert(!::std::sized_sentinel_for); + + // indirectly_movable / indirectly_movable_storable + static_assert(::std::indirectly_movable); + static_assert(::std::indirectly_movable_storable); + static_assert(!::std::indirectly_movable); + static_assert(!::std::indirectly_movable_storable); + static_assert(::std::indirectly_movable); + static_assert(::std::indirectly_movable_storable); + static_assert(!::std::indirectly_movable); + static_assert(!::std::indirectly_movable_storable); + + static_assert(::std::indirectly_movable); + static_assert(::std::indirectly_movable_storable); + static_assert(!::std::indirectly_movable); + static_assert(!::std::indirectly_movable_storable); + static_assert(::std::indirectly_movable); + static_assert(::std::indirectly_movable_storable); + static_assert(!::std::indirectly_movable); + static_assert(!::std::indirectly_movable_storable); + + // indirectly_copyable / indirectly_copyable_storable + static_assert(::std::indirectly_copyable); + static_assert(::std::indirectly_copyable_storable); + static_assert(!::std::indirectly_copyable); + static_assert(!::std::indirectly_copyable_storable); + static_assert(::std::indirectly_copyable); + static_assert(::std::indirectly_copyable_storable); + static_assert(!::std::indirectly_copyable); + static_assert(!::std::indirectly_copyable_storable); + + static_assert(::std::indirectly_copyable); + static_assert(::std::indirectly_copyable_storable); + static_assert(!::std::indirectly_copyable); + static_assert(!::std::indirectly_copyable_storable); + static_assert(::std::indirectly_copyable); + static_assert(::std::indirectly_copyable_storable); + static_assert(!::std::indirectly_copyable); + static_assert(!::std::indirectly_copyable_storable); + + // indirectly_swappable + static_assert(::std::indirectly_swappable); + static_assert(!::std::indirectly_swappable); + + // ===== Range concept conformance ===== + using range = deque_type; + + static_assert(::std::same_as<::std::ranges::iterator_t, range::iterator>); + static_assert(::std::ranges::common_range); + static_assert(::std::ranges::random_access_range); + static_assert(!::std::ranges::contiguous_range); + static_assert(!::std::ranges::view); + static_assert(::std::ranges::sized_range); + static_assert(!::std::ranges::borrowed_range); + static_assert(::std::ranges::viewable_range); + + static_assert(::std::same_as<::std::ranges::iterator_t, range::const_iterator>); + static_assert(::std::ranges::common_range); + static_assert(::std::ranges::random_access_range); + static_assert(!::std::ranges::contiguous_range); + static_assert(!::std::ranges::view); + static_assert(::std::ranges::sized_range); + static_assert(!::std::ranges::borrowed_range); + static_assert(!::std::ranges::viewable_range); +} diff --git a/tests/0026.container/0003.deque/constructors/iter_iter.cc b/tests/0026.container/0003.deque/constructors/iter_iter.cc new file mode 100644 index 000000000..e0a0f4fe0 --- /dev/null +++ b/tests/0026.container/0003.deque/constructors/iter_iter.cc @@ -0,0 +1,77 @@ +#include +#include +#include + +namespace +{ + +// fast_io::deque does not have an iterator-pair constructor. +// This test verifies that from_range construction works for vector ranges, +// which is the closest equivalent. +inline void test_from_range_with_vector() +{ + ::fast_io::io::perr("=== deque from_range with vector range test ===\n"); + + // Test from_range with vector + { + ::std::vector<::std::size_t> vec; + for (::std::size_t i{}; i != 4096u; ++i) + { + vec.push_back(i * 3u); + } + + ::fast_io::deque<::std::size_t> dq(::fast_io::freestanding::from_range, vec); + + if (dq.size() != vec.size()) + { + ::fast_io::io::panic("size mismatch with from_range vector\n"); + } + + for (::std::size_t i{}; i != dq.size(); ++i) + { + if (dq[i] != vec[i]) + { + ::fast_io::io::panicln("value mismatch at ", i, " with from_range vector"); + } + } + } + + // Test from_range empty vector + { + ::std::vector<::std::size_t> empty_vec; + ::fast_io::deque<::std::size_t> dq(::fast_io::freestanding::from_range, empty_vec); + if (!dq.empty()) + { + ::fast_io::io::panic("deque from empty range should be empty\n"); + } + } + + // Test from_range with initializer_list + { + ::fast_io::deque<::std::size_t> dq(::fast_io::freestanding::from_range, ::std::initializer_list<::std::size_t>{1, 2, 3, 4, 5}); + + if (dq.size() != 5u) + { + ::fast_io::io::panic("size mismatch with from_range initializer_list\n"); + } + + ::std::size_t expected{1u}; + for (auto const &e : dq) + { + if (e != expected) + { + ::fast_io::io::panicln("value mismatch: expected ", expected, " got ", e); + } + ++expected; + } + } + + ::fast_io::io::print("deque from_range with vector range test finished\n"); +} + +} // namespace + +int main() +{ + test_from_range_with_vector(); +} diff --git a/tests/0026.container/0003.deque/constructors/n_val.cc b/tests/0026.container/0003.deque/constructors/n_val.cc new file mode 100644 index 000000000..276612182 --- /dev/null +++ b/tests/0026.container/0003.deque/constructors/n_val.cc @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include +#include + +namespace +{ + +inline void test_n_val() +{ + ::fast_io::io::perr("=== deque(n, val) constructor test ===\n"); + + // Test sizes at and around block boundaries + // For std::size_t (8 bytes), block_size = 4096/8 = 512 + // Test with int (4 bytes): block_size = 1024 + ::std::size_t const sizes[] = {0, 1, 2, 3, 1023, 1024, 1025, 2047, 2048, 2049}; + + for (::std::size_t n : sizes) + { + ::fast_io::deque<::std::size_t> dq(n, 42u); + ::std::deque<::std::size_t> ref(n, 42u); + + if (dq.size() != ref.size()) + { + ::fast_io::io::panicln("size mismatch for n=", n); + } + + for (::std::size_t i{}; i != dq.size(); ++i) + { + if (dq[i] != ref[i]) + { + ::fast_io::io::panicln("value mismatch at ", i, " for n=", n); + } + } + } + + ::fast_io::io::print("deque(n, val) constructor test finished\n"); +} + +inline void test_n_val_string() +{ + ::fast_io::io::perr("=== deque(n, val) string test ===\n"); + + ::fast_io::string const hello("hello"); + ::fast_io::deque<::fast_io::string> dq(100u, hello); + + if (dq.size() != 100u) + { + ::fast_io::io::panic("size mismatch for string type\n"); + } + + for (::std::size_t i{}; i != dq.size(); ++i) + { + if (dq[i] != hello) + { + ::fast_io::io::panicln("value mismatch at ", i, " for string type"); + } + } + + ::fast_io::io::print("deque(n, val) string test finished\n"); +} + +} // namespace + +int main() +{ + test_n_val(); + test_n_val_string(); +} diff --git a/tests/0026.container/0003.deque/insert_initializer_list.cc b/tests/0026.container/0003.deque/insert_initializer_list.cc new file mode 100644 index 000000000..045e23f19 --- /dev/null +++ b/tests/0026.container/0003.deque/insert_initializer_list.cc @@ -0,0 +1,141 @@ +#include +#include +#include +#include + +namespace +{ + +// fast_io::deque does not have insert(const_iterator, initializer_list). +// This test verifies equivalent behavior using insert_range with a vector +// initialized from an initializer list. + +inline void test_insert_range_from_initializer_list() +{ + ::fast_io::io::perr("=== deque insert_range from initializer_list test ===\n"); + + // Insert at front + { + ::fast_io::deque<::std::size_t> dq; + ::std::deque<::std::size_t> ref; + + for (::std::size_t i{}; i != 10u; ++i) + { + dq.push_back(1u); + ref.push_back(1u); + } + + ::std::vector<::std::size_t> vec{3u, 4u, 5u, 6u}; + dq.insert_range(dq.cbegin() + 2, vec); + ref.insert(ref.cbegin() + 2, {3, 4, 5, 6}); + + if (dq.size() != ref.size()) + { + ::fast_io::io::panic("size mismatch\n"); + } + + for (::std::size_t i{}; i != dq.size(); ++i) + { + if (dq[i] != ref[i]) + { + ::fast_io::io::panicln("value mismatch at ", i); + } + } + } + + // Insert at end + { + ::fast_io::deque<::std::size_t> dq; + ::std::deque<::std::size_t> ref; + + for (::std::size_t i{}; i != 10u; ++i) + { + dq.push_back(i); + ref.push_back(i); + } + + ::std::vector<::std::size_t> vec{100u, 101u, 102u}; + dq.insert_range(dq.cend(), vec); + ref.insert(ref.cend(), {100, 101, 102}); + + if (dq.size() != ref.size()) + { + ::fast_io::io::panic("size mismatch\n"); + } + + for (::std::size_t i{}; i != dq.size(); ++i) + { + if (dq[i] != ref[i]) + { + ::fast_io::io::panicln("value mismatch at ", i); + } + } + } + + // Insert at middle with various sizes + { + ::std::size_t const sizes[] = {0, 1, 2, 3, 1023, 1024, 1025, 2047, 2048, 2049}; + + for (::std::size_t n : sizes) + { + ::fast_io::deque<::std::size_t> dq; + ::std::deque<::std::size_t> ref; + + for (::std::size_t i{}; i != n; ++i) + { + dq.push_back(i); + ref.push_back(i); + } + + ::std::size_t pos = n / 2; + ::std::vector<::std::size_t> vec{888u, 999u}; + dq.insert_range(dq.cbegin() + pos, vec); + ref.insert(ref.cbegin() + pos, {888, 999}); + + if (dq.size() != ref.size()) + { + ::fast_io::io::panicln("size mismatch for n=", n); + } + + for (::std::size_t i{}; i != dq.size(); ++i) + { + if (dq[i] != ref[i]) + { + ::fast_io::io::panicln("value mismatch at ", i, " for n=", n); + } + } + } + } + + // Insert into empty deque + { + ::fast_io::deque<::std::size_t> dq; + ::std::deque<::std::size_t> ref; + + ::std::vector<::std::size_t> vec{10u, 20u, 30u}; + dq.insert_range(dq.cbegin(), vec); + ref.insert(ref.cbegin(), {10, 20, 30}); + + if (dq.size() != ref.size()) + { + ::fast_io::io::panic("size mismatch\n"); + } + + for (::std::size_t i{}; i != dq.size(); ++i) + { + if (dq[i] != ref[i]) + { + ::fast_io::io::panicln("value mismatch at ", i); + } + } + } + + ::fast_io::io::print("deque insert_range from initializer_list test finished\n"); +} + +} // namespace + +int main() +{ + test_insert_range_from_initializer_list(); +} diff --git a/tests/0026.container/0003.deque/insert_range_iterator.cc b/tests/0026.container/0003.deque/insert_range_iterator.cc new file mode 100644 index 000000000..229b48c56 --- /dev/null +++ b/tests/0026.container/0003.deque/insert_range_iterator.cc @@ -0,0 +1,172 @@ +#include +#include +#include +#include +#include + +namespace +{ + +// fast_io::deque does not have insert(const_iterator, InputIterator, InputIterator). +// This test verifies insert_range with various range types, which is the equivalent. + +inline void test_insert_range_from_array() +{ + ::fast_io::io::perr("=== deque insert_range test ===\n"); + + // Insert from std::vector range + { + ::fast_io::deque<::std::size_t> dq; + ::std::deque<::std::size_t> ref; + + for (::std::size_t i{}; i != 100u; ++i) + { + dq.push_back(i); + ref.push_back(i); + } + + ::std::vector<::std::size_t> src{200u, 201u, 202u, 203u, 204u}; + + dq.insert_range(dq.cbegin() + 50, src); + ref.insert(ref.cbegin() + 50, src.begin(), src.end()); + + if (dq.size() != ref.size()) + { + ::fast_io::io::panic("size mismatch after insert_range from vector\n"); + } + + for (::std::size_t i{}; i != dq.size(); ++i) + { + if (dq[i] != ref[i]) + { + ::fast_io::io::panicln("value mismatch at ", i, " after insert_range from vector"); + } + } + } + + // Insert at front + { + ::fast_io::deque<::std::size_t> dq; + ::std::deque<::std::size_t> ref; + + for (::std::size_t i{}; i != 100u; ++i) + { + dq.push_back(i); + ref.push_back(i); + } + + ::std::vector<::std::size_t> src{1000u, 1001u, 1002u}; + + dq.insert_range(dq.cbegin(), src); + ref.insert(ref.cbegin(), src.begin(), src.end()); + + if (dq.size() != ref.size()) + { + ::fast_io::io::panic("size mismatch after insert_range at front\n"); + } + + for (::std::size_t i{}; i != dq.size(); ++i) + { + if (dq[i] != ref[i]) + { + ::fast_io::io::panicln("value mismatch at ", i, " after insert_range at front"); + } + } + } + + // Insert at end + { + ::fast_io::deque<::std::size_t> dq; + ::std::deque<::std::size_t> ref; + + for (::std::size_t i{}; i != 100u; ++i) + { + dq.push_back(i); + ref.push_back(i); + } + + ::std::vector<::std::size_t> src{2000u, 2001u, 2002u, 2003u}; + + dq.insert_range(dq.cend(), src); + ref.insert(ref.cend(), src.begin(), src.end()); + + if (dq.size() != ref.size()) + { + ::fast_io::io::panic("size mismatch after insert_range at end\n"); + } + + for (::std::size_t i{}; i != dq.size(); ++i) + { + if (dq[i] != ref[i]) + { + ::fast_io::io::panicln("value mismatch at ", i, " after insert_range at end"); + } + } + } + + // Insert with various sizes around block boundaries + { + ::std::size_t const sizes[] = {0, 1, 2, 3, 1023, 1024, 1025, 2047, 2048, 2049}; + + for (::std::size_t n : sizes) + { + ::fast_io::deque<::std::size_t> dq; + ::std::deque<::std::size_t> ref; + + for (::std::size_t i{}; i != n; ++i) + { + dq.push_back(i); + ref.push_back(i); + } + + ::std::vector<::std::size_t> src{777u, 888u, 999u}; + ::std::size_t pos = n / 2; + + dq.insert_range(dq.cbegin() + pos, src); + ref.insert(ref.cbegin() + pos, src.begin(), src.end()); + + if (dq.size() != ref.size()) + { + ::fast_io::io::panicln("size mismatch for n=", n); + } + + for (::std::size_t i{}; i != dq.size(); ++i) + { + if (dq[i] != ref[i]) + { + ::fast_io::io::panicln("value mismatch at ", i, " for n=", n); + } + } + } + } + + // Insert empty range + { + ::fast_io::deque<::std::size_t> dq; + ::std::deque<::std::size_t> ref; + + for (::std::size_t i{}; i != 50u; ++i) + { + dq.push_back(i); + ref.push_back(i); + } + + ::std::vector<::std::size_t> empty_src; + dq.insert_range(dq.cbegin() + 25, empty_src); + ref.insert(ref.cbegin() + 25, empty_src.begin(), empty_src.end()); + + if (dq.size() != ref.size()) + { + ::fast_io::io::panic("size mismatch after empty range insert\n"); + } + } + + ::fast_io::io::print("deque insert_range test finished\n"); +} + +} // namespace + +int main() +{ + test_insert_range_from_array(); +} diff --git a/tests/0026.container/0003.deque/invalidation.cc b/tests/0026.container/0003.deque/invalidation.cc new file mode 100644 index 000000000..3e0d77cd7 --- /dev/null +++ b/tests/0026.container/0003.deque/invalidation.cc @@ -0,0 +1,242 @@ +#include +#include +#include + +namespace +{ + +inline void test_pop_front_invalidation() +{ + ::fast_io::io::perr("=== deque pop_front invalidation test ===\n"); + + ::fast_io::deque<::std::size_t> dq; + for (::std::size_t i{}; i != 4098u; ++i) + { + dq.push_back(i); + } + + while (dq.size() > 1u) + { + auto it1 = dq.begin() + 1; // second element + auto it2 = dq.end() - 1; // last element + ::std::size_t val1 = *it1; + ::std::size_t val2 = *it2; + + dq.pop_front(); + + // After pop_front, it1 should still point to the same element (now at begin) + if (*dq.begin() != val1) + { + ::fast_io::io::panic("pop_front invalidated iterator to second element\n"); + } + + // it2 should still point to the last element + if (*(dq.end() - 1) != val2) + { + ::fast_io::io::panic("pop_front invalidated iterator to last element\n"); + } + + // Also verify via direct access + if (dq.front() != val1) + { + ::fast_io::io::panic("pop_front changed front value\n"); + } + + dq.pop_back(); // shrink for next iteration + } + + ::fast_io::io::print("deque pop_front invalidation test finished\n"); +} + +inline void test_pop_back_invalidation() +{ + ::fast_io::io::perr("=== deque pop_back invalidation test ===\n"); + + ::fast_io::deque<::std::size_t> dq; + for (::std::size_t i{}; i != 4098u; ++i) + { + dq.push_back(i); + } + + while (dq.size() > 1u) + { + auto it1 = dq.begin(); // first element + auto it2 = dq.end() - 2; // second-to-last element + ::std::size_t val1 = *it1; + ::std::size_t val2 = *it2; + + dq.pop_back(); + + // After pop_back, it1 should still point to the same element + if (*dq.begin() != val1) + { + ::fast_io::io::panic("pop_back invalidated iterator to first element\n"); + } + + // it2 should still point to what is now the last element + if (*(dq.end() - 1) != val2) + { + ::fast_io::io::panic("pop_back invalidated iterator to second-to-last element\n"); + } + + // Also verify via direct access + if (dq.back() != val2) + { + ::fast_io::io::panic("pop_back changed back value\n"); + } + } + + ::fast_io::io::print("deque pop_back invalidation test finished\n"); +} + +inline void test_erase_single_invalidation() +{ + ::fast_io::io::perr("=== deque erase single invalidation test ===\n"); + + // Erase first element + { + ::fast_io::deque<::std::size_t> dq; + for (::std::size_t i{}; i != 20u; ++i) + { + dq.push_back(i); + } + + dq.erase(dq.begin()); + + // After erasing first element, it1 should still be valid and point to what was index 1 + if (*dq.begin() != 1u) + { + ::fast_io::io::panic("erase front: begin value wrong\n"); + } + + if (*(dq.end() - 1) != 19u) + { + ::fast_io::io::panic("erase front: end value wrong\n"); + } + } + + // Erase last element + { + ::fast_io::deque<::std::size_t> dq; + for (::std::size_t i{}; i != 20u; ++i) + { + dq.push_back(i); + } + + dq.erase(dq.end() - 1); + + if (*dq.begin() != 0u) + { + ::fast_io::io::panic("erase back: begin value wrong\n"); + } + + if (*(dq.end() - 1) != 18u) + { + ::fast_io::io::panic("erase back: end value wrong\n"); + } + } + + ::fast_io::io::print("deque erase single invalidation test finished\n"); +} + +inline void test_erase_range_invalidation() +{ + ::fast_io::io::perr("=== deque erase range invalidation test ===\n"); + + // Erase range at start + { + ::fast_io::deque<::std::size_t> dq; + for (::std::size_t i{}; i != 20u; ++i) + { + dq.push_back(i); + } + + ::std::size_t num = 5u; + dq.erase(dq.begin(), dq.begin() + num); + + // Elements after the erased range should have been moved down, but iterators + // to the remaining elements should still be valid + if (*dq.begin() != num) + { + ::fast_io::io::panic("erase range front: first element wrong\n"); + } + + if (*(dq.end() - 1) != 19u) + { + ::fast_io::io::panic("erase range front: last element wrong\n"); + } + } + + // Erase range at end + { + ::fast_io::deque<::std::size_t> dq; + for (::std::size_t i{}; i != 20u; ++i) + { + dq.push_back(i); + } + + ::std::size_t num = 5u; + dq.erase(dq.end() - num, dq.end()); + + if (*dq.begin() != 0u) + { + ::fast_io::io::panic("erase range back: first element wrong\n"); + } + + if (*(dq.end() - 1) != 14u) + { + ::fast_io::io::panic("erase range back: last element wrong\n"); + } + } + + // Erase range at start with various sizes around block boundaries + { + ::std::size_t const sizes[] = {1, 2, 3, 1023, 1024, 1025, 2047, 2048, 2049}; + + for (::std::size_t n : sizes) + { + ::fast_io::deque<::std::size_t> dq; + ::std::deque<::std::size_t> ref; + + for (::std::size_t i{}; i != n; ++i) + { + dq.push_back(i); + ref.push_back(i); + } + + ::std::size_t num = (std::min)(n, static_cast<::std::size_t>(100u)); + if (num == 0u) + { + continue; + } + + dq.erase(dq.cbegin(), dq.cbegin() + num); + ref.erase(ref.cbegin(), ref.cbegin() + num); + + if (dq.size() != ref.size()) + { + ::fast_io::io::panicln("erase range size mismatch for n=", n); + } + + for (::std::size_t i{}; i != dq.size(); ++i) + { + if (dq[i] != ref[i]) + { + ::fast_io::io::panicln("erase range value mismatch at ", i, " for n=", n); + } + } + } + } + + ::fast_io::io::print("deque erase range invalidation test finished\n"); +} + +} // namespace + +int main() +{ + test_pop_front_invalidation(); + test_pop_back_invalidation(); + test_erase_single_invalidation(); + test_erase_range_invalidation(); +} diff --git a/tests/0026.container/0003.deque/move_only.cc b/tests/0026.container/0003.deque/move_only.cc new file mode 100644 index 000000000..b0f6e68b3 --- /dev/null +++ b/tests/0026.container/0003.deque/move_only.cc @@ -0,0 +1,166 @@ +#include +#include + +namespace +{ + +struct MoveOnly +{ + ::std::size_t value; + + explicit MoveOnly(::std::size_t v) : value(v) + {} + + MoveOnly(MoveOnly const &) = delete; + MoveOnly &operator=(MoveOnly const &) = delete; + + MoveOnly(MoveOnly &&other) noexcept : value(other.value) + { + other.value = 0; + } + + MoveOnly &operator=(MoveOnly &&other) noexcept + { + if (this != &other) + { + value = other.value; + other.value = 0; + } + return *this; + } +}; + +inline void test_move_only_push_back() +{ + ::fast_io::io::perr("=== deque move-only push_back test ===\n"); + + ::fast_io::deque dq; + for (::std::size_t i{}; i != 4096u; ++i) + { + dq.push_back(MoveOnly(i)); + } + + if (dq.size() != 4096u) + { + ::fast_io::io::panic("size wrong after push_back move-only\n"); + } + + for (::std::size_t i{}; i != dq.size(); ++i) + { + if (dq[i].value != i) + { + ::fast_io::io::panicln("value mismatch at ", i, " after push_back move-only"); + } + } + + ::fast_io::io::print("deque move-only push_back test finished\n"); +} + +inline void test_move_only_push_front() +{ + ::fast_io::io::perr("=== deque move-only push_front test ===\n"); + + ::fast_io::deque dq; + for (::std::size_t i{}; i != 4096u; ++i) + { + dq.push_front(MoveOnly(i)); + } + + if (dq.size() != 4096u) + { + ::fast_io::io::panic("size wrong after push_front move-only\n"); + } + + for (::std::size_t i{}; i != dq.size(); ++i) + { + if (dq[i].value != 4095u - i) + { + ::fast_io::io::panicln("value mismatch at ", i, " after push_front move-only"); + } + } + + ::fast_io::io::print("deque move-only push_front test finished\n"); +} + +inline void test_move_only_insert() +{ + ::fast_io::io::perr("=== deque move-only insert test ===\n"); + + ::fast_io::deque dq; + + dq.push_back(MoveOnly(1u)); + dq.push_back(MoveOnly(2u)); + dq.push_back(MoveOnly(3u)); + + // Insert by move at front + dq.insert(dq.begin(), MoveOnly(0u)); + if (dq.front().value != 0u) + { + ::fast_io::io::panic("insert move at front value wrong\n"); + } + + // Insert by move at end + dq.insert(dq.end(), MoveOnly(4u)); + if (dq.back().value != 4u) + { + ::fast_io::io::panic("insert move at end value wrong\n"); + } + + // Insert by move in middle + dq.insert(dq.begin() + 3, MoveOnly(99u)); + if (dq[3u].value != 99u) + { + ::fast_io::io::panic("insert move at middle value wrong\n"); + } + + if (dq.size() != 6u) + { + ::fast_io::io::panic("size wrong after insert move\n"); + } + + ::fast_io::io::print("deque move-only insert test finished\n"); +} + +inline void test_move_only_erase() +{ + ::fast_io::io::perr("=== deque move-only erase test ===\n"); + + ::fast_io::deque dq; + for (::std::size_t i{}; i != 100u; ++i) + { + dq.push_back(MoveOnly(i)); + } + + // Erase front + dq.erase(dq.begin()); + if (dq.front().value != 1u) + { + ::fast_io::io::panic("erase front of move-only deque wrong\n"); + } + + // Erase back + dq.erase(dq.end() - 1); + if (dq.back().value != 98u) + { + ::fast_io::io::panic("erase back of move-only deque wrong\n"); + } + + // Erase middle + dq.erase(dq.begin() + 10); + if (dq[10u].value != 12u) + { + ::fast_io::io::panic("erase middle of move-only deque wrong\n"); + } + + ::fast_io::io::print("deque move-only erase test finished\n"); +} + +} // namespace + +int main() +{ + test_move_only_push_back(); + test_move_only_push_front(); + test_move_only_insert(); + test_move_only_erase(); +} diff --git a/tests/0026.container/0003.deque/self_reference.cc b/tests/0026.container/0003.deque/self_reference.cc new file mode 100644 index 000000000..f4bd8cd06 --- /dev/null +++ b/tests/0026.container/0003.deque/self_reference.cc @@ -0,0 +1,95 @@ +#include +#include +#include +#include + +namespace +{ + +inline void test_self_reference_insert_single() +{ + ::fast_io::io::perr("=== deque self-reference insert single test ===\n"); + + // Insert element from the same deque at various positions + for (::std::size_t i{}; i != 20u; ++i) + { + for (::std::size_t j{}; j != 20u; ++j) + { + ::fast_io::deque<::std::size_t> dq; + ::std::deque<::std::size_t> ref; + + for (::std::size_t k{}; k != 20u; ++k) + { + dq.push_back(k); + ref.push_back(k); + } + + auto val = dq[j]; + dq.insert(dq.cbegin() + i, val); + ref.insert(ref.cbegin() + i, ref[j]); + + if (dq.size() != ref.size()) + { + ::fast_io::io::panicln("size mismatch for i=", i, " j=", j); + } + + for (::std::size_t k{}; k != dq.size(); ++k) + { + if (dq[k] != ref[k]) + { + ::fast_io::io::panicln("value mismatch at ", k, " for i=", i, " j=", j); + } + } + } + } + + ::fast_io::io::print("deque self-reference insert single test finished\n"); +} + +inline void test_self_reference_insert_count() +{ + ::fast_io::io::perr("=== deque self-reference insert count test ===\n"); + + // Insert count copies of element from the same deque + for (::std::size_t i{}; i != 20u; ++i) + { + for (::std::size_t j{}; j != 20u; ++j) + { + ::fast_io::deque<::std::size_t> dq; + ::std::deque<::std::size_t> ref; + + for (::std::size_t k{}; k != 20u; ++k) + { + dq.push_back(k); + ref.push_back(k); + } + + auto val = dq[j]; + dq.insert(dq.cbegin() + i, 5u, val); + ref.insert(ref.cbegin() + i, 5, ref[j]); + + if (dq.size() != ref.size()) + { + ::fast_io::io::panicln("size mismatch for i=", i, " j=", j); + } + + for (::std::size_t k{}; k != dq.size(); ++k) + { + if (dq[k] != ref[k]) + { + ::fast_io::io::panicln("value mismatch at ", k, " for i=", i, " j=", j); + } + } + } + } + + ::fast_io::io::print("deque self-reference insert count test finished\n"); +} + +} // namespace + +int main() +{ + test_self_reference_insert_single(); + test_self_reference_insert_count(); +} diff --git a/tests/0026.container/0003.deque/swap.cc b/tests/0026.container/0003.deque/swap.cc new file mode 100644 index 000000000..078028dbb --- /dev/null +++ b/tests/0026.container/0003.deque/swap.cc @@ -0,0 +1,171 @@ +#include +#include +#include +#include +#include + +namespace +{ + +inline void test_swap_member() +{ + ::fast_io::io::perr("=== deque swap member test ===\n"); + + ::std::size_t const sizes[] = {0, 1, 2, 3, 1023, 1024, 1025, 2047, 2048, 2049}; + + for (::std::size_t n : sizes) + { + for (::std::size_t m : sizes) + { + ::fast_io::deque<::std::size_t> a; + ::fast_io::deque<::std::size_t> b; + + for (::std::size_t i{}; i != n; ++i) + { + a.push_back(i); + } + for (::std::size_t i{}; i != m; ++i) + { + b.push_back(i + 1000u); + } + + ::fast_io::deque<::std::size_t> a_save = a; + ::fast_io::deque<::std::size_t> b_save = b; + + a.swap(b); + + // a should now equal b_save + if (a.size() != b_save.size()) + { + ::fast_io::io::panicln("a.size mismatch after swap for n=", n, " m=", m); + } + for (::std::size_t i{}; i != a.size(); ++i) + { + if (a[i] != b_save[i]) + { + ::fast_io::io::panicln("a[", i, "] mismatch after swap for n=", n, " m=", m); + } + } + + // b should now equal a_save + if (b.size() != a_save.size()) + { + ::fast_io::io::panicln("b.size mismatch after swap for n=", n, " m=", m); + } + for (::std::size_t i{}; i != b.size(); ++i) + { + if (b[i] != a_save[i]) + { + ::fast_io::io::panicln("b[", i, "] mismatch after swap for n=", n, " m=", m); + } + } + } + } + + ::fast_io::io::print("deque swap member test finished\n"); +} + +inline void test_swap_free_function() +{ + ::fast_io::io::perr("=== deque swap free function test ===\n"); + + ::fast_io::deque<::std::size_t> a; + ::fast_io::deque<::std::size_t> b; + + for (::std::size_t i{}; i != 100u; ++i) + { + a.push_back(i); + } + for (::std::size_t i{}; i != 200u; ++i) + { + b.push_back(i + 500u); + } + + ::fast_io::deque<::std::size_t> a_save = a; + ::fast_io::deque<::std::size_t> b_save = b; + + swap(a, b); + + if (a.size() != b_save.size() || b.size() != a_save.size()) + { + ::fast_io::io::panic("size mismatch after free function swap\n"); + } + + for (::std::size_t i{}; i != a.size(); ++i) + { + if (a[i] != b_save[i]) + { + ::fast_io::io::panic("a value mismatch after free function swap\n"); + } + } + + for (::std::size_t i{}; i != b.size(); ++i) + { + if (b[i] != a_save[i]) + { + ::fast_io::io::panic("b value mismatch after free function swap\n"); + } + } + + // Self swap + a.swap(a); + if (a.size() != b_save.size()) + { + ::fast_io::io::panic("self-swap changed size\n"); + } + for (::std::size_t i{}; i != a.size(); ++i) + { + if (a[i] != b_save[i]) + { + ::fast_io::io::panic("self-swap changed values\n"); + } + } + + ::fast_io::io::print("deque swap free function test finished\n"); +} + +inline void test_swap_non_trivial() +{ + ::fast_io::io::perr("=== deque swap non-trivial type test ===\n"); + + ::fast_io::deque<::fast_io::string> a; + ::fast_io::deque<::fast_io::string> b; + + for (::std::size_t i{}; i != 100u; ++i) + { + a.emplace_back(::fast_io::concat_fast_io("hello_", i)); + } + for (::std::size_t i{}; i != 50u; ++i) + { + b.emplace_back(::fast_io::concat_fast_io("world_", i)); + } + + ::fast_io::deque<::fast_io::string> a_save = a; + ::fast_io::deque<::fast_io::string> b_save = b; + + a.swap(b); + + if (a.size() != b_save.size() || b.size() != a_save.size()) + { + ::fast_io::io::panic("size mismatch after non-trivial swap\n"); + } + + for (::std::size_t i{}; i != a.size(); ++i) + { + if (a[i] != b_save[i]) + { + ::fast_io::io::panic("value mismatch after non-trivial swap\n"); + } + } + + ::fast_io::io::print("deque swap non-trivial type test finished\n"); +} + +} // namespace + +int main() +{ + test_swap_member(); + test_swap_free_function(); + test_swap_non_trivial(); +} diff --git a/tests/0026.container/0003.deque/type_traits.cc b/tests/0026.container/0003.deque/type_traits.cc new file mode 100644 index 000000000..e8e42b7f6 --- /dev/null +++ b/tests/0026.container/0003.deque/type_traits.cc @@ -0,0 +1,77 @@ +#include +#include +#include +#include + +int main() +{ + using deque_type = ::fast_io::deque<::std::size_t>; + + // --- value_type --- + static_assert(::std::same_as); + + // --- reference / const_reference --- + static_assert(::std::same_as); + static_assert(::std::same_as); + + // --- pointer / const_pointer --- + static_assert(::std::same_as); + static_assert(::std::same_as); + + // --- size_type / difference_type --- + static_assert(::std::same_as); + static_assert(::std::same_as); + static_assert(::std::is_signed_v); + static_assert(::std::is_unsigned_v); + + // --- iterator --- + static_assert(::std::same_as); + static_assert(::std::same_as); + static_assert(::std::same_as); + static_assert(::std::same_as); + static_assert(::std::same_as< + ::std::iterator_traits::iterator_category, + ::std::random_access_iterator_tag>); + static_assert(::std::same_as< + ::std::iterator_traits::value_type, + deque_type::value_type>); + static_assert(::std::same_as< + ::std::iterator_traits::difference_type, + deque_type::difference_type>); + + // --- const_iterator --- + static_assert(::std::same_as); + static_assert(::std::same_as); + static_assert(::std::same_as); + static_assert(::std::same_as); + static_assert(::std::same_as< + ::std::iterator_traits::iterator_category, + ::std::random_access_iterator_tag>); + static_assert(::std::same_as< + ::std::iterator_traits::value_type, + deque_type::value_type>); + static_assert(::std::same_as< + ::std::iterator_traits::difference_type, + deque_type::difference_type>); + + // --- difference_type consistency across iterator and const_iterator --- + static_assert(::std::same_as< + deque_type::difference_type, + ::std::iterator_traits::difference_type>); + static_assert(::std::same_as< + deque_type::difference_type, + ::std::iterator_traits::difference_type>); + + // --- reverse_iterator --- + static_assert(::std::same_as< + deque_type::reverse_iterator, + ::std::reverse_iterator>); + + // --- const_reverse_iterator --- + static_assert(::std::same_as< + deque_type::const_reverse_iterator, + ::std::reverse_iterator>); + + // --- mutable to const iterator conversion --- + static_assert(::std::convertible_to); +}