diff options
-rw-r--r-- | compat/borrowed-ptr-fwd.hpp | 2 | ||||
-rw-r--r-- | compat/borrowed-ptr.inl | 9 | ||||
-rw-r--r-- | test/bptr.cpp | 192 |
3 files changed, 200 insertions, 3 deletions
diff --git a/compat/borrowed-ptr-fwd.hpp b/compat/borrowed-ptr-fwd.hpp index 01dd20f7..28ea3c55 100644 --- a/compat/borrowed-ptr-fwd.hpp +++ b/compat/borrowed-ptr-fwd.hpp @@ -69,4 +69,6 @@ public: template<typename U, typename Tʹ> friend bptr<U> static_pointer_cast(const bptr<Tʹ>& p) noexcept; }; +template<typename T> bptr(T* ptr) -> bptr<T>; + } // namespace floormat diff --git a/compat/borrowed-ptr.inl b/compat/borrowed-ptr.inl index 6b72192c..05724fcd 100644 --- a/compat/borrowed-ptr.inl +++ b/compat/borrowed-ptr.inl @@ -5,7 +5,9 @@ #define FM_BPTR_DEBUG -#if defined FM_BPTR_DEBUG && !defined FM_NO_DEBUG +#ifdef __CLION_IDE__ +#define fm_bptr_assert(...) (void(__VA_ARGS__)) +#elif defined FM_BPTR_DEBUG && !defined FM_NO_DEBUG #define fm_bptr_assert(...) fm_assert(__VA_ARGS__) #else #define fm_bptr_assert(...) void() @@ -175,7 +177,8 @@ bptr<T>& bptr<T>::_copy_assign(const bptr<Y>& other) noexcept blk->decrement(blk); casted_ptr = other.casted_ptr; blk = other.blk; - ++blk->_count; + if (blk) + ++blk->_count; } return *this; } @@ -204,7 +207,7 @@ bptr<T>& bptr<T>::_move_assign(bptr<Y>&& other) noexcept template<typename T> T* bptr<T>::get() const noexcept { - if (blk && blk->_ptr) + if (blk && blk->_ptr) [[likely]] { fm_bptr_assert(casted_ptr); return casted_ptr; diff --git a/test/bptr.cpp b/test/bptr.cpp index 6f823344..55b10fe0 100644 --- a/test/bptr.cpp +++ b/test/bptr.cpp @@ -1,6 +1,7 @@ #include "app.hpp" #include "compat/assert.hpp" #include "compat/borrowed-ptr.inl" +#include <array> namespace floormat { @@ -94,12 +95,203 @@ void test2() fm_assert(A_alive == 0); } +void test3() +{ + A_total = 0; A_alive = 0; + + auto p1 = bptr<A>{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<A>& p) +{ + fm_assert(!p); + fm_assert(p.use_count() == 0); + fm_assert(!p.get()); +} + +void check_nonempty(const bptr<A>& 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<A>{} == bptr<A>{nullptr}); + fm_assert(bptr<A>{} == bptr<A>{(A*)nullptr}); + fm_assert(A_total == 0 && A_alive == 0); + + { + auto p1 = bptr<A>{InPlace, 42}; + auto p2 = bptr<A>{InPlace, 41}; + auto p3 = bptr<A>{}; + 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>{(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<A>{InPlace, -1}; + auto p2 = bptr<A>{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<bptr<A>, size> array; + for (auto n = 0u; n < size; n++) + { + A_total = 0; A_alive = 0; + bptr<A> p0; + array[0] = bptr<A>{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>((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<bptr<A>, size>{}); + } +} + +void test7() +{ + A_total = 0; A_alive = 0; + auto p1 = bptr<A>{InPlace, 7}; + auto p2 = bptr<A>{}; + 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); + + A_total = 0; A_alive = 0; +} + } // namespace void test_app::test_bptr() { test1(); test2(); + test3(); + test4(); + test5(); + test6(); + test7(); } } // namespace floormat |