Browse Source

ResourceManager: new Loading and NotFound data states.

Updated, cleaned up and extended unit tests.
pull/7/head
Vladimír Vondruš 14 years ago
parent
commit
d688cf2efc
  1. 48
      src/Resource.h
  2. 41
      src/ResourceManager.h
  3. 86
      src/Test/ResourceManagerTest.cpp
  4. 3
      src/Test/ResourceManagerTest.h

48
src/Resource.h

@ -33,11 +33,23 @@ namespace Magnum {
* @see Resource::state(), ResourceManager::state()
*/
enum class ResourceState: std::uint8_t {
/** The resource is not yet loaded. */
/** The resource is not yet loaded (and no fallback is available). */
NotLoaded,
/** The resource is not yet loaded and fallback resource is used instead. */
Fallback,
NotLoadedFallback,
/** The resource is currently loading (and no fallback is available). */
Loading,
/** The resource is currently loading and fallback resource is used instead. */
LoadingFallback,
/** The resource was not found (and no fallback is available). */
NotFound,
/** The resource was not found and fallback resource is used instead. */
NotFoundFallback,
/** The resource is loaded, but can be changed by the manager at any time. */
Mutable,
@ -157,7 +169,7 @@ class Resource {
/**
* @brief %Resource state
*
* @see operator bool()
* @see operator bool(), ResourceManager::state()
*/
inline ResourceState state() {
acquire();
@ -166,10 +178,11 @@ class Resource {
/**
* @brief Whether the resource is available
* @return False when resource is not loaded and no fallback is
* available, true otherwise.
*
* @see state()
* Returns `false` when resource is not loaded and no fallback is
* available (i.e. state() is either @ref ResourceState "ResourceState::NotLoaded",
* @ref ResourceState "ResourceState::Loading" or
* @ref ResourceState "ResourceState::NotFound"), true otherwise.
*/
inline operator bool() {
acquire();
@ -219,12 +232,23 @@ class Resource {
lastCheck = manager->lastChange();
/* Try to get the data */
if((data = d.data))
_state = static_cast<ResourceState>(d.state);
else if((data = manager->fallback()))
_state = ResourceState::Fallback;
else
_state = ResourceState::NotLoaded;
data = d.data;
_state = static_cast<ResourceState>(d.state);
/* Data are not available */
if(!data) {
/* Fallback found, add *Fallback to state */
if((data = manager->fallback())) {
if(_state == ResourceState::Loading)
_state = ResourceState::LoadingFallback;
else if(_state == ResourceState::NotFound)
_state = ResourceState::NotFoundFallback;
else _state = ResourceState::NotLoadedFallback;
/* Fallback not found and loading didn't start yet */
} else if(_state != ResourceState::Loading && _state != ResourceState::NotFound)
_state = ResourceState::NotLoaded;
}
}
Implementation::ResourceManagerData<T>* manager;

41
src/ResourceManager.h

@ -31,6 +31,18 @@ namespace Magnum {
* @see ResourceManager::set(), ResourceState
*/
enum class ResourceDataState: std::uint8_t {
/**
* The resource is currently loading. Parameter @p data in ResourceManager::set()
* should be set to `null`.
*/
Loading = int(ResourceState::Loading),
/**
* The resource was not found. Parameter @p data in ResourceManager::set()
* should be set to `null`.
*/
NotFound = int(ResourceState::NotFound),
/**
* The resource can be changed by the manager in the future. This is
* slower, as Resource needs to ask the manager for new version every time
@ -99,10 +111,25 @@ namespace Implementation {
ResourceState state(ResourceKey key) const {
auto it = _data.find(key);
if(it == _data.end() || !it->second.data)
return _fallback ? ResourceState::Fallback : ResourceState::NotLoaded;
else
return static_cast<ResourceState>(it->second.state);
/* Resource not loaded */
if(it == _data.end() || !it->second.data) {
/* Fallback found, add *Fallback to state */
if(_fallback) {
if(it != _data.end() && it->second.state == ResourceDataState::Loading)
return ResourceState::LoadingFallback;
else if(it != _data.end() && it->second.state == ResourceDataState::NotFound)
return ResourceState::NotFoundFallback;
else return ResourceState::NotLoadedFallback;
}
/* Fallback not found, loading didn't start yet */
if(it == _data.end() || (it->second.state != ResourceDataState::Loading && it->second.state != ResourceDataState::NotFound))
return ResourceState::NotLoaded;
}
/* Loading / NotFound without fallback, Mutable / Final */
return static_cast<ResourceState>(it->second.state);
}
template<class U> inline Resource<T, U> get(ResourceKey key) {
@ -112,9 +139,13 @@ namespace Implementation {
void set(ResourceKey key, T* data, ResourceDataState state, ResourcePolicy policy) {
auto it = _data.find(key);
/* NotFound / Loading state shouldn't have any data */
CORRADE_ASSERT((data == nullptr) == (state == ResourceDataState::NotFound || state == ResourceDataState::Loading),
"ResourceManager::set(): data should be null if and only if state is NotFound or Loading", );
/* Cannot change resource with already final state */
CORRADE_ASSERT(it == _data.end() || it->second.state != ResourceDataState::Final,
"ResourceManager: cannot change already final resource", );
"ResourceManager::set(): cannot change already final resource", );
/* If nothing is referencing reference-counted resource, we're done */
if(policy == ResourcePolicy::ReferenceCounted && (it == _data.end() || it->second.referenceCount == 0)) {

86
src/Test/ResourceManagerTest.cpp

@ -40,6 +40,9 @@ size_t Data::count = 0;
ResourceManagerTest::ResourceManagerTest() {
addTests(&ResourceManagerTest::state,
&ResourceManagerTest::stateFallback,
&ResourceManagerTest::stateDisallowed,
&ResourceManagerTest::basic,
&ResourceManagerTest::residentPolicy,
&ResourceManagerTest::referenceCountedPolicy,
&ResourceManagerTest::manualPolicy);
@ -48,19 +51,84 @@ ResourceManagerTest::ResourceManagerTest() {
void ResourceManagerTest::state() {
ResourceManager rm;
ResourceKey questionKey("the-question");
rm.set(questionKey, new int32_t(10), ResourceDataState::Mutable, ResourcePolicy::Resident);
Resource<int32_t> theQuestion = rm.get<int32_t>(questionKey);
CORRADE_COMPARE(theQuestion.state(), ResourceState::Mutable);
CORRADE_COMPARE(*theQuestion, 10);
Resource<Data> data = rm.get<Data>("data");
CORRADE_VERIFY(!data);
CORRADE_COMPARE(data.state(), ResourceState::NotLoaded);
CORRADE_COMPARE(rm.state<Data>("data"), ResourceState::NotLoaded);
rm.set<Data>("data", nullptr, ResourceDataState::Loading, ResourcePolicy::Resident);
CORRADE_VERIFY(!data);
CORRADE_COMPARE(data.state(), ResourceState::Loading);
CORRADE_COMPARE(rm.state<Data>("data"), ResourceState::Loading);
rm.set<Data>("data", nullptr, ResourceDataState::NotFound, ResourcePolicy::Resident);
CORRADE_VERIFY(!data);
CORRADE_COMPARE(data.state(), ResourceState::NotFound);
CORRADE_COMPARE(rm.state<Data>("data"), ResourceState::NotFound);
/* Nothing happened at all */
CORRADE_COMPARE(Data::count, 0);
}
void ResourceManagerTest::stateFallback() {
{
ResourceManager rm;
rm.setFallback<Data>(new Data);
Resource<Data> data = rm.get<Data>("data");
CORRADE_VERIFY(data);
CORRADE_COMPARE(data.state(), ResourceState::NotLoadedFallback);
CORRADE_COMPARE(rm.state<Data>("data"), ResourceState::NotLoadedFallback);
rm.set<Data>("data", nullptr, ResourceDataState::Loading, ResourcePolicy::Resident);
CORRADE_VERIFY(data);
CORRADE_COMPARE(data.state(), ResourceState::LoadingFallback);
CORRADE_COMPARE(rm.state<Data>("data"), ResourceState::LoadingFallback);
rm.set<Data>("data", nullptr, ResourceDataState::NotFound, ResourcePolicy::Resident);
CORRADE_VERIFY(data);
CORRADE_COMPARE(data.state(), ResourceState::NotFoundFallback);
CORRADE_COMPARE(rm.state<Data>("data"), ResourceState::NotFoundFallback);
/* Only fallback is here */
CORRADE_COMPARE(Data::count, 1);
}
/* Fallback gets destroyed */
CORRADE_COMPARE(Data::count, 0);
}
void ResourceManagerTest::stateDisallowed() {
ResourceManager rm;
stringstream out;
Error::setOutput(&out);
Data d;
rm.set("data", &d, ResourceDataState::Loading, ResourcePolicy::Resident);
CORRADE_COMPARE(out.str(), "ResourceManager::set(): data should be null if and only if state is NotFound or Loading\n");
out.str("");
rm.set<Data>("data", nullptr, ResourceDataState::Final, ResourcePolicy::Resident);
CORRADE_COMPARE(out.str(), "ResourceManager::set(): data should be null if and only if state is NotFound or Loading\n");
}
/* Check that hash function is working properly */
void ResourceManagerTest::basic() {
ResourceManager rm;
/* One mutable, one final */
ResourceKey questionKey("the-question");
ResourceKey answerKey("the-answer");
rm.set(questionKey, new int32_t(10), ResourceDataState::Mutable, ResourcePolicy::Resident);
rm.set(answerKey, new int32_t(42), ResourceDataState::Final, ResourcePolicy::Resident);
Resource<int32_t> theQuestion = rm.get<int32_t>(questionKey);
Resource<int32_t> theAnswer = rm.get<int32_t>(answerKey);
/* Check basic functionality */
CORRADE_COMPARE(theQuestion.state(), ResourceState::Mutable);
CORRADE_COMPARE(theAnswer.state(), ResourceState::Final);
CORRADE_COMPARE(*theQuestion, 10);
CORRADE_COMPARE(*theAnswer, 42);
CORRADE_COMPARE(rm.count<int32_t>(), 2);
/* Cannot change already final resource */
@ -68,9 +136,9 @@ void ResourceManagerTest::state() {
Error::setOutput(&out);
rm.set(answerKey, new int32_t(43), ResourceDataState::Mutable, ResourcePolicy::Resident);
CORRADE_COMPARE(*theAnswer, 42);
CORRADE_COMPARE(out.str(), "ResourceManager: cannot change already final resource\n");
CORRADE_COMPARE(out.str(), "ResourceManager::set(): cannot change already final resource\n");
/* Check non-final resource changes */
/* But non-final can be changed */
rm.set(questionKey, new int32_t(20), ResourceDataState::Final, ResourcePolicy::Resident);
CORRADE_COMPARE(theQuestion.state(), ResourceState::Final);
CORRADE_COMPARE(*theQuestion, 20);

3
src/Test/ResourceManagerTest.h

@ -24,6 +24,9 @@ class ResourceManagerTest: public Corrade::TestSuite::Tester<ResourceManagerTest
ResourceManagerTest();
void state();
void stateFallback();
void stateDisallowed();
void basic();
void residentPolicy();
void referenceCountedPolicy();
void manualPolicy();

Loading…
Cancel
Save