/******************************************************************************* * This file is part of the "Enduro2D" * For conditions of distribution and use, see copyright notice in LICENSE.md * Copyright (C) 2018-2019, by Matvey Cherevko (blackmatov@gmail.com) ******************************************************************************/ #include "_utils.hpp" using namespace e2d; namespace { class obj_t : public ref_counter { public: obj_t() { ++ctor_counter; } obj_t(int ni) : i(ni) { ++ctor_counter; } virtual ~obj_t() noexcept { ++dtor_counter; } int i{42}; public: static int ctor_counter; static int dtor_counter; static void reset_counters() { ctor_counter = 0u; dtor_counter = 0u; } }; int obj_t::ctor_counter = 0; int obj_t::dtor_counter = 0; class derived_t final : public obj_t { public: derived_t() : obj_t(84) {} int j{100500}; }; class derived2_t final : public obj_t { public: derived2_t() : obj_t(21) {} int j{500100}; }; class obj2_t : public ref_counter> { public: obj2_t() { ++ctor_counter; } obj2_t(int ni) : i(ni) { ++ctor_counter; } virtual ~obj2_t() noexcept { ++dtor_counter; } int i{42}; public: static int ctor_counter; static int dtor_counter; static void reset_counters() { ctor_counter = 0u; dtor_counter = 0u; } }; int obj2_t::ctor_counter = 0; int obj2_t::dtor_counter = 0; } TEST_CASE("intrusive_ptr") { { intrusive_ptr p; REQUIRE_FALSE(p); REQUIRE(p.get() == nullptr); REQUIRE(p.release() == nullptr); } { obj_t::reset_counters(); intrusive_ptr p(new obj_t()); REQUIRE(p); REQUIRE(p.get()); REQUIRE(p.get()->i == 42); REQUIRE(p->i == 42); REQUIRE((*p).i == 42); REQUIRE(p->use_count() == 1u); REQUIRE(obj_t::ctor_counter == 1u); REQUIRE(obj_t::dtor_counter == 0); p.reset(); REQUIRE_FALSE(p); REQUIRE(p.get() == nullptr); REQUIRE(p.release() == nullptr); REQUIRE(obj_t::dtor_counter == 1u); } { obj_t::reset_counters(); intrusive_ptr p(new obj_t()); obj_t* o = p.release(); REQUIRE_FALSE(p); REQUIRE(p.get() == nullptr); REQUIRE(obj_t::ctor_counter == 1u); REQUIRE(obj_t::dtor_counter == 0u); REQUIRE(o->use_count() == 1u); { intrusive_ptr p2(o, false); REQUIRE(p2); REQUIRE(p2->use_count() == 1u); o = p2.release(); REQUIRE_FALSE(p2); p2.reset(o, false); REQUIRE(p2); REQUIRE(p2->use_count() == 1u); REQUIRE(obj_t::ctor_counter == 1u); REQUIRE(obj_t::dtor_counter == 0u); p2.reset(new obj_t()); REQUIRE(p2); REQUIRE(obj_t::ctor_counter == 2u); REQUIRE(obj_t::dtor_counter == 1u); } REQUIRE(obj_t::ctor_counter == 2u); REQUIRE(obj_t::dtor_counter == 2u); } { obj_t::reset_counters(); { intrusive_ptr p1(new obj_t(10)); intrusive_ptr p2(new obj_t(20)); p1.swap(p2); REQUIRE(p1->i == 20); REQUIRE(p2->i == 10); } REQUIRE(obj_t::ctor_counter == 2u); REQUIRE(obj_t::dtor_counter == 2u); } { intrusive_ptr p1(new obj_t(10)); intrusive_ptr p2(new obj_t(20)); { intrusive_ptr p3; REQUIRE_FALSE(p2 == nullptr); REQUIRE_FALSE(nullptr == p2); REQUIRE(p2 != nullptr); REQUIRE(nullptr != p2); REQUIRE(p3 == nullptr); REQUIRE(nullptr == p3); REQUIRE_FALSE(p3 != nullptr); REQUIRE_FALSE(nullptr != p3); } { REQUIRE((p1 == p1) == (p1.get() == p1.get())); REQUIRE((p1 != p1) == (p1.get() != p1.get())); REQUIRE((p1 == p1.get()) == (p1.get() == p1.get())); REQUIRE((p1 != p1.get()) == (p1.get() != p1.get())); REQUIRE((p1.get() == p1) == (p1.get() == p1.get())); REQUIRE((p1.get() != p1) == (p1.get() != p1.get())); REQUIRE((p1 < p1) == p1.get() < p1.get()); REQUIRE((p1 <= p1) == p1.get() <= p1.get()); REQUIRE((p1 > p1) == p1.get() > p1.get()); REQUIRE((p1 >= p1) == p1.get() >= p1.get()); } { REQUIRE((p2 == p1) == (p2.get() == p1.get())); REQUIRE((p2 != p1) == (p2.get() != p1.get())); REQUIRE((p2 == p1.get()) == (p2.get() == p1.get())); REQUIRE((p2 != p1.get()) == (p2.get() != p1.get())); REQUIRE((p2.get() == p1) == (p2.get() == p1.get())); REQUIRE((p2.get() != p1) == (p2.get() != p1.get())); REQUIRE((p2 < p1) == p2.get() < p1.get()); REQUIRE((p2 <= p1) == p2.get() <= p1.get()); REQUIRE((p2 > p1) == p2.get() > p1.get()); REQUIRE((p2 >= p1) == p2.get() >= p1.get()); } } { obj_t::reset_counters(); { intrusive_ptr p1(new derived_t()); REQUIRE(p1->i == 84); intrusive_ptr p2 = p1; REQUIRE(p2->i == 84); REQUIRE(p2->use_count() == 2u); } REQUIRE(obj_t::ctor_counter == 1u); REQUIRE(obj_t::dtor_counter == 1u); { intrusive_ptr p1(new derived_t()); intrusive_ptr p2; p2 = p1; REQUIRE(p2->i == 84); } REQUIRE(obj_t::ctor_counter == 2u); REQUIRE(obj_t::dtor_counter == 2u); { intrusive_ptr p1(new derived_t()); intrusive_ptr p2 = std::move(p1); REQUIRE(p2->i == 84); REQUIRE_FALSE(p1); } REQUIRE(obj_t::ctor_counter == 3u); REQUIRE(obj_t::dtor_counter == 3u); { intrusive_ptr p1(new derived_t()); intrusive_ptr p2; p2 = std::move(p1); REQUIRE(p2->i == 84); REQUIRE_FALSE(p1); } REQUIRE(obj_t::ctor_counter == 4u); REQUIRE(obj_t::dtor_counter == 4u); } { E2D_UNUSED(std::make_unique(10)); intrusive_ptr p1(new derived2_t()); intrusive_ptr p2 = static_pointer_cast(p1); REQUIRE(p2->i == 21); REQUIRE(p2->j == 500100); intrusive_ptr p3 = dynamic_pointer_cast(p1); REQUIRE(p3->i == 21); REQUIRE(p3->j == 500100); intrusive_ptr p4 = dynamic_pointer_cast(p1); REQUIRE_FALSE(p4); intrusive_ptr p5 = const_pointer_cast(p1); REQUIRE(p5); REQUIRE(p5->i == 21); } { auto p1 = make_intrusive(10); hash_set> s; s.insert(p1); } { auto p = make_intrusive(10); REQUIRE(p->i == 10); REQUIRE(p->use_count() == 1u); p.reset(); REQUIRE(obj2_t::ctor_counter == 1u); REQUIRE(obj2_t::dtor_counter == 1u); } }