#include #include #include #include static int mybase_construct; static int mybase_destruct; static int myderived_construct; static int myderived_destruct; class MyBase { rcp_managed_root(MyBase); protected: MyBase(int x, int y) { this->x = x; this->y = y; mybase_construct++; } virtual ~MyBase() { mybase_destruct++; } public: int x; int y; }; typedef rcp MyB; class MyDerived : public MyBase { rcp_managed(MyDerived); protected: MyDerived(double v) : MyBase(1, 2) { this->v = v; myderived_construct++; } virtual ~MyDerived() { myderived_destruct++; } public: double v; }; void test_class_hierarchy() { { rcp mybase = MyBase::create(4, 5); rcp myderived = MyDerived::create(42.5); } assert(mybase_construct == 2); assert(mybase_destruct == 2); assert(myderived_construct == 1); assert(myderived_destruct == 1); } void test_dereference() { rcp mybase = MyBase::create(2, 3); assert(mybase->x == 2); assert(mybase->y == 3); assert((*mybase).x == 2); assert((*mybase).y == 3); rcp mybase2 = mybase; assert(mybase == mybase2); assert(!(mybase != mybase2)); } void test_booleans() { rcp mybase = MyBase::create(2, 3); assert(mybase); assert(mybase != nullptr); rcp myderived; assert(!myderived); assert(myderived == nullptr); } void test_create() { MyB myb = MyB::create(8, 9); assert(myb->x == 8); } struct MyObj { rcp_managed_root(MyObj); public: int v = {42}; template void add_to(R & receiver) { receiver.add(this); } }; struct Receiver { std::vector> objects; void add(MyObj * o) { objects.push_back(rcp(o)); } }; void test_multi_construct_from_raw_pointers() { Receiver r; auto myo = MyObj::create(); for (int i = 0; i < 5; i++) { myo->add_to(r); } for (int i = 0; i < 5; i++) { assert(r.objects[i]->v == 42); } } struct EventListener; static std::vector> g_listeners; struct EventListener { rcp_managed_root(EventListener); public: int events_received = 0; void attach() { g_listeners.push_back(this); } }; void test_listener_self_registration() { g_listeners.clear(); auto a = EventListener::create(); auto b = EventListener::create(); a->attach(); b->attach(); for (auto & l : g_listeners) l->events_received++; assert(a->events_received == 1); assert(b->events_received == 1); g_listeners.clear(); } void test_copy_assignment_decrements_previous_reference() { MyB myb = MyB::create(12, 13); MyB myb2 = MyB::create(14, 15); myb = myb2; assert(myb->x == 14); } void test_move_constructor() { int constructed_before = mybase_construct; int destructed_before = mybase_destruct; { MyB a = MyB::create(1, 2); MyB b = std::move(a); assert(!a); assert(b); assert(b->x == 1); assert(mybase_destruct == destructed_before); } assert(mybase_construct == constructed_before + 1); assert(mybase_destruct == destructed_before + 1); } void test_move_assignment() { int constructed_before = mybase_construct; int destructed_before = mybase_destruct; { MyB a = MyB::create(1, 2); MyB b; b = std::move(a); assert(!a); assert(b); assert(b->x == 1); assert(mybase_destruct == destructed_before); } assert(mybase_construct == constructed_before + 1); assert(mybase_destruct == destructed_before + 1); } void test_move_assignment_releases_existing() { int constructed_before = mybase_construct; int destructed_before = mybase_destruct; { MyB a = MyB::create(1, 2); MyB b = MyB::create(3, 4); b = std::move(a); assert(!a); assert(b->x == 1); assert(mybase_destruct == destructed_before + 1); } assert(mybase_construct == constructed_before + 2); assert(mybase_destruct == destructed_before + 2); } void test_cross_type_comparison() { rcp derived = MyDerived::create(1.5); rcp base = derived; assert(base == derived); assert(!(base != derived)); rcp other = MyBase::create(1, 2); assert(base != other); assert(!(base == other)); } void test_reset() { int destructed_before = mybase_destruct; MyB p = MyB::create(1, 2); p.reset(); assert(!p); assert(mybase_destruct == destructed_before + 1); } void test_upcast() { rcp derived = MyDerived::create(1.5); rcp base = derived; assert(base); assert(base->x == 1); } void test_move_upcast() { int constructed_before = mybase_construct; int destructed_before = mybase_destruct; { rcp derived = MyDerived::create(1.5); rcp base = std::move(derived); assert(!derived); assert(base); assert(base->x == 1); assert(mybase_destruct == destructed_before); } assert(mybase_construct == constructed_before + 1); assert(mybase_destruct == destructed_before + 1); } void test_dynamic_cast_success() { rcp derived = MyDerived::create(1.5); rcp base = derived; rcp back = rcp_dynamic_cast(base); assert(back); assert(back->v == 1.5); } void test_dynamic_cast_move_success() { int constructed_before = mybase_construct; int destructed_before = mybase_destruct; { rcp base = MyDerived::create(1.5); rcp derived = rcp_dynamic_cast(std::move(base)); assert(!base); assert(derived); assert(derived->v == 1.5); assert(mybase_destruct == destructed_before); } assert(mybase_construct == constructed_before + 1); assert(mybase_destruct == destructed_before + 1); } void test_dynamic_cast_move_failure() { rcp base = MyBase::create(1, 2); rcp derived = rcp_dynamic_cast(std::move(base)); assert(!derived); assert(base); } void test_dynamic_cast_failure() { rcp base = MyBase::create(1, 2); rcp derived = rcp_dynamic_cast(base); assert(!derived); } /* Simulate a external class that cannot be modified */ namespace external { class Counter { public: int start; int count; Counter(int start) : start(start), count(start) {} virtual ~Counter() {} }; } static int external_destruct; /* Create a managed wrapper for the external class. */ class Counter : public external::Counter { rcp_managed_root(Counter); protected: Counter(int start) : external::Counter(start) {} ~Counter() { external_destruct++; } }; void test_swap() { MyB a = MyB::create(1, 2); MyB b = MyB::create(3, 4); a.swap(b); assert(a->x == 3); assert(b->x == 1); } void test_hash() { MyB a = MyB::create(1, 2); MyB b = a; std::unordered_map map; map[a] = 42; assert(map[b] == 42); MyB c = MyB::create(3, 4); assert(map.find(c) == map.end()); } void test_external_class() { int before = external_destruct; { auto a = Counter::create(10); auto b = Counter::create(20); assert(a->count == 10); assert(b->count == 20); a->count++; assert(a->count == 11); } assert(external_destruct == before + 2); } int main(int argc, char * argv[]) { test_class_hierarchy(); test_dereference(); test_booleans(); test_create(); test_multi_construct_from_raw_pointers(); test_listener_self_registration(); test_copy_assignment_decrements_previous_reference(); test_cross_type_comparison(); test_reset(); test_move_constructor(); test_move_assignment(); test_move_assignment_releases_existing(); test_upcast(); test_move_upcast(); test_dynamic_cast_success(); test_dynamic_cast_failure(); test_dynamic_cast_move_success(); test_dynamic_cast_move_failure(); test_swap(); test_hash(); test_external_class(); return 0; }