TEST_F(HazptrTest, Array) { struct Foo : hazptr_obj_base<Foo> { int a; }; for (int i = 0; i < 100; ++i) { Foo* x = new Foo; x->a = i; hazptr_array<10> hptr; // Protect object hptr[9].reset(x); // Empty array hazptr_array<10> h(nullptr); // Move assignment h = std::move(hptr); // Retire object x->retire(); // Unprotect object - hptr2 is nonempty h[9].reset(); } { // Abnormal case hazptr_array<HAZPTR_TC_SIZE + 1> h; hazptr_array<HAZPTR_TC_SIZE + 1> h2(std::move(h)); } }
TEST_F(HazptrTest, Move) { struct Foo : hazptr_obj_base<Foo> { int a; }; for (int i = 0; i < 100; ++i) { Foo* x = new Foo; x->a = i; hazptr_holder hptr0; // Protect object hptr0.reset(x); // Retire object x->retire(); // Move constructor - still protected hazptr_holder hptr1(std::move(hptr0)); // Self move is no-op - still protected hazptr_holder* phptr1 = &hptr1; CHECK_EQ(phptr1, &hptr1); hptr1 = std::move(*phptr1); // Empty constructor hazptr_holder hptr2(nullptr); // Move assignment - still protected hptr2 = std::move(hptr1); // Access object CHECK_EQ(x->a, i); // Unprotect object - hptr2 is nonempty hptr2.reset(); } }
TEST_F(HazptrTest, basic_refcount) { constructed.store(0); destroyed.store(0); Foo* p = nullptr; int num = 20; for (int i = 0; i < num; ++i) { p = new Foo(i, p); if (i & 1) { p->acquire_ref_safe(); } else { p->acquire_ref(); } } hazptr_holder hptr; hptr.reset(p); for (auto q = p->next_; q; q = q->next_) { q->retire(); } int v = num; for (auto q = p; q; q = q->next_) { CHECK_GT(v, 0); --v; CHECK_EQ(q->val_, v); } CHECK(!p->release_ref()); CHECK_EQ(constructed.load(), num); CHECK_EQ(destroyed.load(), 0); p->retire(); CHECK_EQ(constructed.load(), num); CHECK_EQ(destroyed.load(), 0); hptr.reset(); /* retire enough objects to guarantee reclamation of Foo objects */ for (int i = 0; i < 100; ++i) { auto a = new Dummy; a->retire(); } CHECK_EQ(constructed.load(), num); CHECK_EQ(destroyed.load(), num); }
TEST_F(HazptrTest, Local) { struct Foo : hazptr_obj_base<Foo> { int a; }; for (int i = 0; i < 100; ++i) { Foo* x = new Foo; x->a = i; hazptr_local<10> hptr; // Protect object hptr[9].reset(x); // Retire object x->retire(); // Unprotect object - hptr2 is nonempty hptr[9].reset(); } { // Abnormal case hazptr_local<HAZPTR_TC_SIZE + 1> h; } }