From c1c4788e88b8fee7094da5d19b685ccf8b80745e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 31 Jul 2013 01:04:56 +0200 Subject: [PATCH] Ability to force cleanup of ResourceManager. Assumes that no resources of given type are referenced. The test case for this is awful, as I can't think of a way to test which would work without trying to decrement reference counter on already deleted resource. Added just-to-be-sure assertion to make it fail early and not somewhere deep in STL. --- src/ResourceManager.h | 33 +++++++++++++++++++++++++++++++- src/Test/ResourceManagerTest.cpp | 33 ++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/src/ResourceManager.h b/src/ResourceManager.h index 8451472a5..2c28df4a1 100644 --- a/src/ResourceManager.h +++ b/src/ResourceManager.h @@ -122,6 +122,8 @@ template class ResourceManagerData { void free(); + void clear() { _data.clear(); } + AbstractResourceLoader* loader() { return _loader; } const AbstractResourceLoader* loader() const { return _loader; } @@ -353,6 +355,28 @@ template class ResourceManager: private Implementation::Resource return this; } + /** + * @brief Clear all resources of given type + * @return Pointer to self (for method chaining) + * + * Unlike free() this function assumes that no resource is referenced. + */ + template ResourceManager* clear() { + this->Implementation::ResourceManagerData::clear(); + return this; + } + + /** + * @brief Clear all resources + * @return Pointer to self (for method chaining) + * + * Unlike free() this function assumes that no resource is referenced. + */ + ResourceManager* clear() { + clearInternal(); + return this; + } + /** @brief Loader for given type of resources */ template AbstractResourceLoader* loader() { return this->Implementation::ResourceManagerData::loader(); @@ -383,6 +407,12 @@ template class ResourceManager: private Implementation::Resource } template void freeInternal() const {} + template void clearInternal() { + clear(); + clearInternal(); + } + template void clearInternal() const {} + template void freeLoaders() { Implementation::ResourceManagerData::freeLoader(); freeLoaders(); @@ -513,6 +543,7 @@ template void ResourceManagerData::freeLoader() { template void ResourceManagerData::decrementReferenceCount(ResourceKey key) { auto it = _data.find(key); + CORRADE_INTERNAL_ASSERT(it != _data.end()); /* Free the resource if it is reference counted */ if(--it->second.referenceCount == 0 && it->second.policy == ResourcePolicy::ReferenceCounted) @@ -541,7 +572,7 @@ template struct ResourceManagerData::Data { template inline ResourceManagerData::Data::~Data() { CORRADE_ASSERT(referenceCount == 0, - "ResourceManager::~ResourceManager(): destroyed while data are still referenced", ); + "ResourceManager: cleared/destroyed while data are still referenced", ); delete data; } diff --git a/src/Test/ResourceManagerTest.cpp b/src/Test/ResourceManagerTest.cpp index e9bfafbf2..1e977c70e 100644 --- a/src/Test/ResourceManagerTest.cpp +++ b/src/Test/ResourceManagerTest.cpp @@ -43,6 +43,8 @@ class ResourceManagerTest: public TestSuite::Tester { void residentPolicy(); void referenceCountedPolicy(); void manualPolicy(); + void clear(); + void clearWhileReferenced(); void loader(); }; @@ -66,6 +68,8 @@ ResourceManagerTest::ResourceManagerTest() { &ResourceManagerTest::residentPolicy, &ResourceManagerTest::referenceCountedPolicy, &ResourceManagerTest::manualPolicy, + &ResourceManagerTest::clear, + &ResourceManagerTest::clearWhileReferenced, &ResourceManagerTest::loader}); } @@ -226,6 +230,35 @@ void ResourceManagerTest::manualPolicy() { CORRADE_COMPARE(Data::count, 1); } +void ResourceManagerTest::clear() { + ResourceManager rm; + + rm.set("blah", new Data); + CORRADE_COMPARE(Data::count, 1); + + rm.free(); + CORRADE_COMPARE(Data::count, 1); + + rm.clear(); + CORRADE_COMPARE(Data::count, 0); +} + +void ResourceManagerTest::clearWhileReferenced() { + /* Should cover also the destruction case */ + + std::ostringstream out; + Error::setOutput(&out); + + ResourceManager rm; + rm.set("blah", new Int); + /** @todo this will leak, is there any better solution without hitting + assertion in decrementReferenceCount()? */ + new Resource(rm.get("blah")); + + rm.clear(); + CORRADE_COMPARE(out.str(), "ResourceManager: cleared/destroyed while data are still referenced\n"); +} + void ResourceManagerTest::loader() { class IntResourceLoader: public AbstractResourceLoader { public: