From 2284b517e15c7397d1271cb948fb1d24fce24841 Mon Sep 17 00:00:00 2001 From: Alan Conway Date: Tue, 19 Feb 2008 22:58:41 +0000 Subject: sys::RefCountedMap - reference-counted weak map of reference-counted objects. Ensures objects are atomically deleted and removed from the map. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid@629263 13f79535-47bb-0310-9956-ffa450edef68 --- cpp/src/tests/RefCountedMap.cpp | 154 ++++++++++++++++++++-------------------- 1 file changed, 76 insertions(+), 78 deletions(-) (limited to 'cpp/src/tests/RefCountedMap.cpp') diff --git a/cpp/src/tests/RefCountedMap.cpp b/cpp/src/tests/RefCountedMap.cpp index 1875b8161c..79a0d94eb7 100644 --- a/cpp/src/tests/RefCountedMap.cpp +++ b/cpp/src/tests/RefCountedMap.cpp @@ -17,9 +17,10 @@ */ #include "qpid/sys/RefCountedMap.h" - #include "unit_test.h" +#include "test_tools.h" #include +#include QPID_AUTO_TEST_SUITE(RefCountedMapTestSuite) @@ -27,99 +28,96 @@ using namespace std; using namespace qpid; using namespace qpid::sys; -template struct CountEm { +template struct Counted { static int instances; - CountEm() { instances++; } - ~CountEm() { instances--; } - CountEm(const CountEm&) { instances++; } + Counted() { ++instances; } + Counted(const Counted&) { ++instances; } + ~Counted() { --instances; } }; -template int CountEm::instances = 0; - -struct Data; +template int Counted::instances=0; -struct Attachment : public RefCounted, public CountEm<1> { - intrusive_ptr link; +struct Data : public RefCountedMapData, public Counted<2> { + Data(int i=0) : value(i) {} + int value; + void inc() { value++; } }; -struct Data : public RefCounted, public CountEm<2> { - intrusive_ptr link; - void attach(intrusive_ptr a) { - if (!a) return; - a->link=this; - link=a; - } - void detach() { - if (!link) return; - intrusive_ptr protect(this); - link->link=0; - link=0; - } +struct Container : public RefCounted, public Counted<3> { + Data::Map map; + Container() : map(*this) {} }; -typedef intrusive_ptr DataPtr; - -struct Map : public RefCountedMap, public CountEm<3> {}; - - - - -BOOST_AUTO_TEST_CASE(testRefCountedMap) { - BOOST_CHECK_EQUAL(0, Map::instances); - BOOST_CHECK_EQUAL(0, Data::instances); - - intrusive_ptr map=new Map(); - BOOST_CHECK_EQUAL(1, Map::instances); - - // Empty map - BOOST_CHECK(!map->isClosed()); - BOOST_CHECK(map->empty()); - BOOST_CHECK_EQUAL(map->size(), 0u); - BOOST_CHECK(!map->find(1)); - + +struct RefCountedMapFixture { + intrusive_ptr cont; + intrusive_ptr p, q; + RefCountedMapFixture() : + cont(new Container()), p(new Data(1)), q(new Data(2)) { - // Add entries - DataPtr p=map->get(1); - DataPtr q=map->get(2); + cont->map.insert(1,p); + cont->map.insert(2,q); + } + ~RefCountedMapFixture() { if (cont) cont->map.clear(); } +}; - BOOST_CHECK_EQUAL(Data::instances, 2); - BOOST_CHECK_EQUAL(map->size(), 2u); +BOOST_FIXTURE_TEST_CASE(testFixtureSetup, RefCountedMapFixture) { + BOOST_CHECK_EQUAL(1, Container::instances); + BOOST_CHECK_EQUAL(2, Data::instances); + BOOST_CHECK_EQUAL(cont->map.size(), 2u); + BOOST_CHECK_EQUAL(cont->map.find(1)->value, 1); + BOOST_CHECK_EQUAL(cont->map.find(2)->value, 2); +} - p=0; // verify erased - BOOST_CHECK_EQUAL(Data::instances, 1); - BOOST_CHECK_EQUAL(map->size(), 1u); +BOOST_FIXTURE_TEST_CASE(testReleaseRemoves, RefCountedMapFixture) +{ + // Release external ref, removes from map + p = 0; + BOOST_CHECK_EQUAL(Data::instances, 1); + BOOST_CHECK_EQUAL(cont->map.size(), 1u); + BOOST_CHECK(!cont->map.find(1)); + BOOST_CHECK_EQUAL(cont->map.find(2)->value, 2); + + q = 0; + BOOST_CHECK(cont->map.empty()); +} - p=map->find(2); - BOOST_CHECK(q==p); +// Functor that releases values as a side effect. +struct Release { + RefCountedMapFixture& f ; + Release(RefCountedMapFixture& ff) : f(ff) {} + void operator()(const intrusive_ptr& ptr) { + BOOST_CHECK(ptr->value > 0); // Make sure ptr is not released. + f.p = 0; + f.q = 0; + BOOST_CHECK(ptr->value > 0); // Make sure ptr is not released. } +}; - BOOST_CHECK(map->empty()); - BOOST_CHECK_EQUAL(1, Map::instances); - BOOST_CHECK_EQUAL(0, Data::instances); - { - // Hold the map via a reference to an entry. - DataPtr p=map->get(3); - map=0; - BOOST_CHECK_EQUAL(1, Map::instances); // Held by entry. - } - BOOST_CHECK_EQUAL(0, Map::instances); // entry released +BOOST_FIXTURE_TEST_CASE(testApply, RefCountedMapFixture) { + cont->map.apply(boost::bind(&Data::inc, _1)); + BOOST_CHECK_EQUAL(2, p->value); + BOOST_CHECK_EQUAL(3, q->value); + + // Allow functors to release valuse as side effects. + cont->map.apply(Release(*this)); + BOOST_CHECK(cont->map.empty()); + BOOST_CHECK_EQUAL(Data::instances, 0); } +BOOST_FIXTURE_TEST_CASE(testClearFunctor, RefCountedMapFixture) { + cont->map.clear(boost::bind(&Data::inc, _1)); + BOOST_CHECK(cont->map.empty()); + BOOST_CHECK_EQUAL(2, p->value); + BOOST_CHECK_EQUAL(3, q->value); +} -BOOST_AUTO_TEST_CASE(testRefCountedMapAttachClose) { - intrusive_ptr map=new Map(); - DataPtr d=map->get(5); - d->attach(new Attachment()); - d=0; - // Attachment keeps entry pinned - BOOST_CHECK_EQUAL(1u, map->size()); - BOOST_CHECK(map->find(5)); - - // Close breaks attachment - map->close(boost::bind(&Data::detach, _1)); - BOOST_CHECK(map->empty()); - BOOST_CHECK(map->isClosed()); - BOOST_CHECK_EQUAL(0, Data::instances); - BOOST_CHECK_EQUAL(0, Attachment::instances); +BOOST_FIXTURE_TEST_CASE(testReleaseEmptyMap, RefCountedMapFixture) { + // Container must not be deleted till map is empty. + cont = 0; + BOOST_CHECK_EQUAL(1, Container::instances); // Not empty. + p = 0; + q = 0; + BOOST_CHECK_EQUAL(0, Container::instances); // Deleted } QPID_AUTO_TEST_SUITE_END() -- cgit v1.2.1