#include "app.hpp" #include "compat/borrowed-ptr.inl" #include "compat/assert.hpp" #include "compat/defs.hpp" #include namespace floormat { namespace { struct Foo : bptr_base { int x; fm_DECLARE_DELETED_COPY_MOVE_ASSIGNMENTS(Foo); Foo(int x) : x{x} {} }; struct Bar : Foo {}; struct Baz : bptr_base {}; } // namespace // NOLINTBEGIN(*-use-anonymous-namespace) template class bptr; template class bptr; template class bptr; template bptr static_pointer_cast(const bptr&) noexcept; template bptr static_pointer_cast(const bptr&) noexcept; template bptr static_pointer_cast(const bptr&) noexcept; template bptr static_pointer_cast(const bptr&) noexcept; template bptr static_pointer_cast(const bptr&) noexcept; //template bptr static_pointer_cast(const bptr&) noexcept; // must fail //template bptr static_pointer_cast(const bptr&) noexcept; // must fail //template bptr static_pointer_cast(const bptr&) noexcept; // must fail // NOLINTEND(*-use-anonymous-namespace) namespace { int A_total = 0, A_alive = 0; // NOLINT struct A : bptr_base { int val, serial; explicit A(int val) : val{val}, serial{++A_total} { ++A_alive; } ~A() noexcept override { --A_alive; fm_assert(A_alive >= 0); } fm_DECLARE_DELETED_COPY_MOVE_ASSIGNMENTS(A); }; void test1() { A_total = 0; A_alive = 0; auto p1 = bptr{InPlace, 1}; fm_assert(p1.use_count() == 1); fm_assert(p1.get()); fm_assert(A_total == 1); fm_assert(A_alive == 1); p1 = nullptr; fm_assert(p1.use_count() == 0); fm_assert(!p1.get()); fm_assert(A_total == 1); fm_assert(A_alive == 0); } void test2() { A_total = 0; A_alive = 0; auto p1 = bptr{InPlace, 2}; auto p2 = p1; fm_assert(p1.get()); fm_assert(p1.get() == p2.get()); fm_assert(p1->val == 2); fm_assert(p1->serial == 1); fm_assert(A_total == 1); fm_assert(A_alive == 1); p1 = nullptr; fm_assert(!p1.get()); fm_assert(p2.get()); fm_assert(p2->val == 2); fm_assert(p2->serial == 1); fm_assert(A_total == 1); fm_assert(A_alive == 1); p2 = nullptr; fm_assert(!p1.get()); fm_assert(!p2.get()); fm_assert(A_total == 1); fm_assert(A_alive == 0); } void test3() { A_total = 0; A_alive = 0; auto p1 = bptr{InPlace, 3}; (void)p1; auto p2 = p1; auto p3 = p2; fm_assert(p1.use_count() == 3); fm_assert(p1.get()); fm_assert(p1.get() == p2.get()); fm_assert(p1.get() == p3.get()); fm_assert(A_total == 1); fm_assert(A_alive == 1); p3 = nullptr; (void)p3; fm_assert(p1.use_count() == 2); p3 = p2; fm_assert(p1.use_count() == 3 && p3->val == 3 && p3->serial == 1 && p2 == p3 && p1 == p3); } void check_empty(const bptr& p) { fm_assert(!p); fm_assert(p.use_count() == 0); fm_assert(!p.get()); } void check_nonempty(const bptr& p) { fm_assert(p); fm_assert(p.use_count() > 0); fm_assert(p.get()); } void test4() { A_total = 0; A_alive = 0; fm_assert(bptr{} == bptr{nullptr}); fm_assert(bptr{} == bptr{(A*)nullptr}); fm_assert(A_total == 0 && A_alive == 0); { auto p1 = bptr{InPlace, 42}; auto p2 = bptr{InPlace, 41}; auto p3 = bptr{}; check_empty(p3); (void)p1.operator=(p1); (void)p2.operator=(p2); fm_assert(p1->val == 42 && p1->serial == 1); fm_assert(p2->val == 41 && p2->serial == 2); fm_assert(A_total == 2); fm_assert(A_alive == 2); check_nonempty(p1); check_nonempty(p2); p1.swap(p2); fm_assert(p1->val == 41 && p1->serial == 2); fm_assert(p2->val == 42 && p2->serial == 1); fm_assert(A_total == 2); fm_assert(A_alive == 2); check_nonempty(p1); check_nonempty(p2); p1 = nullptr; fm_assert(A_total == 2); fm_assert(A_alive == 1); check_empty(p1); check_nonempty(p2); (void)p2; p1 = p2; fm_assert(p1 == p2); fm_assert(A_total == 2); fm_assert(A_alive == 1); check_nonempty(p1); check_nonempty(p2); p2 = bptr{(A*)nullptr}; check_empty(p2); check_nonempty(p1); fm_assert(A_total == 2); fm_assert(A_alive == 1); p1.reset(); fm_assert(A_total == 2); fm_assert(A_alive == 0); p1 = p2; p2 = p1; fm_assert(A_total == 2); fm_assert(A_alive == 0); } } void test5() { A_total = 0; A_alive = 0; auto p1 = bptr{InPlace, -1}; auto p2 = bptr{InPlace, -2}; fm_assert(A_total == 2); fm_assert(A_alive == 2); (void)p1; auto p3 = p1; fm_assert(p1.use_count() == 2); fm_assert(p2.use_count() == 1); fm_assert(A_total == 2); fm_assert(A_alive == 2); fm_assert(p1->serial == 1 && p1->val == -1); fm_assert(p2->serial == 2 && p2->val == -2); fm_assert(p3->serial == 1 && p3->val == -1); p1 = nullptr; fm_assert(!p1.get()); fm_assert(p2->serial == 2 && p2->val == -2); fm_assert(p3->serial == 1 && p3->val == -1); fm_assert(A_total == 2); fm_assert(A_alive == 2); p2 = nullptr; fm_assert(!p1.get()); fm_assert(!p2.get()); fm_assert(p3->serial == 1 && p3->val == -1); } void test6() { constexpr size_t size = 5; std::array, size> array; for (auto n = 0u; n < size; n++) { A_total = 0; A_alive = 0; bptr p0; array[0] = bptr{InPlace, 6}; for (auto i = 1u; i < size; i++) array[i] = array[i-1]; fm_assert(array[0].use_count() == size); fm_assert(A_total == 1 && A_alive == 1); array[(n + 1) % size].reset(); array[(n + 2) % size] = bptr((A*)nullptr); array[(n + 3) % size] = move(p0); array[(n + 4) % size].swap(p0); array[(n + 0) % size] = nullptr; p0 = nullptr; for (auto k = 0u; k < size; k++) { for (auto i = 1u; i < size; i++) array[i-1] = array[(i+k) % size]; for (auto i = 1u; i < size; i++) check_empty(array[i]); } fm_assert(A_total == 1); fm_assert(A_alive == 0); fm_assert(array == std::array, size>{}); } } void test7() { A_total = 0; A_alive = 0; auto p1 = bptr{InPlace, 7}; auto p2 = bptr{}; p2 = move(p1); fm_assert(A_total == 1 && A_alive == 1); check_empty(p1); check_nonempty(p2); p1.reset(); check_empty(p1); check_nonempty(p2); p1 = move(p2); fm_assert(A_total == 1 && A_alive == 1); check_nonempty(p1); check_empty(p2); p1 = move(p2); check_empty(p1); check_empty(p2); fm_assert(A_total == 1 && A_alive == 0); } void test8() { A_total = 0; A_alive = 0; auto p1 = bptr{InPlace, 81}; auto p2 = bptr{InPlace, 82}; fm_assert(A_total == 2 && A_alive == 2); p1 = p2; fm_assert(A_total == 2 && A_alive == 1); p2 = move(p1); fm_assert(A_total == 2 && A_alive == 1); p1.reset(); p2 = nullptr; (void)p2; fm_assert(A_total == 2 && A_alive == 0); } void test9() { A_total = 0; A_alive = 0; auto p1 = bptr{InPlace, 9}; auto p2 = p1; p1 = p2; fm_assert(p1.use_count() == 2); fm_assert(A_total == 1); fm_assert(A_alive == 1); p1.destroy(); fm_assert(!p1); fm_assert(!p2); fm_assert(p1.use_count() == 0); fm_assert(p2.use_count() == 0); fm_assert(A_total == 1); fm_assert(A_alive == 0); p1.swap(p2); fm_assert(!p1 && !p2); fm_assert(p1.use_count() == 0 && p2.use_count() == 0); fm_assert(A_total == 1); fm_assert(A_alive == 0); p1.reset(); fm_assert(p1.use_count() == 0); fm_assert(p2.use_count() == 0); p2 = bptr{(A*)nullptr}; fm_assert(p1.use_count() == 0); fm_assert(p2.use_count() == 0); fm_assert(A_total == 1 && A_alive == 0); }; void test10() { static_assert(std::is_same_v, std::decay_t()} )>>); fm_assert(bptr{} == bptr{}); fm_assert(bptr{} == bptr{}); fm_assert(bptr{} == bptr{}); auto p1 = bptr{InPlace, 1}; (void)p1; //auto p2 = bptr{p1}; auto p3 = bptr{p1}; (void)p3; fm_assert(p1->x == 1); fm_assert(p3->x == 1); fm_assert(p1 == p3); auto p4 = bptr{InPlace, 4}; (void)p4; auto p5 = bptr{p4}; (void)p5; //p4 = p5; fm_assert(p4->x == 4); fm_assert(p5->x == 4); fm_assert(p4 == p5); p5 = p4; fm_assert(p5->x == 4); fm_assert(p4 == p5); auto p6 = bptr{p5}; (void)p6; //p4.swap(p5); p5.swap(p6); fm_assert(p5 == p6); p6.destroy(); fm_assert(!p6); fm_assert(p5 == p6); fm_assert(!bptr{p6}); //fm_assert(bptr{p6}); } void test11() { auto p1 = bptr{new Foo{1}}; auto p2 = static_pointer_cast(p1); auto p3 = static_pointer_cast(p1); fm_assert(p2->x == 1); fm_assert(p3); p1.destroy(); fm_assert(!p2); fm_assert(!p3); } void test12() { auto p1 = bptr{new Foo{1}}; { fm_assert(p1.use_count() == 1); auto p2 = static_pointer_cast(p1); fm_assert(p1.use_count() == 2); } fm_assert(p1.use_count() == 1); } } // namespace void Test::test_bptr() { test1(); test2(); test3(); test4(); test5(); test6(); test7(); test8(); test9(); test10(); test11(); test12(); } } // namespace floormat