LUMIERA.clone/src/steam/assetmanager.cpp

287 lines
8 KiB
C++

/*
AssetManager - Facade for the Asset subsystem
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *****************************************************/
/** @file assetmanager.cpp
** Implementation of Asset lookup and organisation functions
*/
#include "steam/assetmanager.hpp"
#include "steam/asset/db.hpp"
#include "lib/sync.hpp"
#include "lib/util-foreach.hpp"
#include "lib/format-string.hpp"
#include <functional>
using std::static_pointer_cast;
using std::function;
using std::placeholders::_1;
using util::for_each;
using util::_Fmt;
using lib::Depend;
using lib::Sync;
namespace steam {
namespace asset {
namespace error = lumiera::error;
/**
* AssetManager error responses, caused by querying
* invalid Asset IDs from the internal DB.
*/
struct IDErr
: error::Invalid
{
using error::Invalid::Invalid;
};
// ------pre-defined-common-error-cases---------------
//
LUMIERA_ERROR_DEFINE (UNKNOWN_ASSET_ID, "non-registered Asset ID");
LUMIERA_ERROR_DEFINE (WRONG_ASSET_KIND, "wrong Asset kind, unable to cast");
struct UnknownID : IDErr
{
UnknownID (ID<Asset> aID)
: IDErr(_Fmt("Query for Asset with ID=%d, which up to now "
"hasn't been created or encountered.") % aID
,LERR_(UNKNOWN_ASSET_ID))
{ }
};
struct WrongKind : IDErr
{
WrongKind (Asset::Ident idi)
: IDErr (_Fmt("Request for Asset(%s), specifying an Asset kind, "
"that doesn't match the actual type (and can't be "
"casted either).") % idi
,LERR_(WRONG_ASSET_KIND))
{ }
};
/** get at the system-wide asset manager instance.
* Implemented as singleton.
*/
Depend<AssetManager> AssetManager::instance;
AssetManager::AssetManager ()
: registry (Depend<asset::DB>() ())
{ }
/** provide the unique ID for given Asset::Ident tuple */
ID<Asset>
AssetManager::getID (const Asset::Ident& idi)
{
return asset::hash_value (idi);
}
/**
* registers an asset object in the internal DB, providing its unique key.
* This includes creating the smart ptr in charge of the asset's lifecycle
* @throw error::Invalid in case of invalid identity spec
*/
template<class KIND>
ID<KIND>
AssetManager::reg (KIND* obj, const Asset::Ident& idi)
{
AssetManager& _aMang (AssetManager::instance());
DB& registry (_aMang.registry);
//////////////////////////////////////////////////////////TICKET #840 check validity of Ident Category
ID<KIND> asset_id (getID (idi));
DB::Lock guard(&registry);
//////////////////////////////////////////////////////////TICKET #840 handle duplicate Registrations
lib::P<KIND> smart_ptr (obj, &destroy);
registry.put (asset_id, smart_ptr);
return asset_id;
}
/** @note the KIND of asset needs to be assignable by the actual stored asset
* @throw error::Invalid if nothing is found or if the actual KIND
* of the stored object differs and can't be casted.
*/
template<class KIND>
lib::P<KIND>
AssetManager::getAsset (const ID<KIND>& id)
{
if (lib::P<KIND> obj = registry.get (id))
return obj;
else
if (known (id)) // provide Ident tuple of existing Asset
throw WrongKind (registry.get(ID<Asset>(id))->ident);
else
throw UnknownID (id);
}
/** Convenience shortcut for fetching the registered smart-ptr
* which is in charge of the given asset instance. By querying
* directly asset.id (of type ID<Asset>), the call to registry.get()
* can bypass the dynamic cast, because the type of the asset
* is explicitly given by type KIND.
*/
template<class KIND>
lib::P<KIND>
AssetManager::wrap (const KIND& asset)
{
ENSURE (instance().known(asset.id),
"unregistered asset instance encountered.");
return static_pointer_cast<KIND,Asset>
(instance().registry.get (asset.id));
}
/**
* @return true if the given id is registered in the internal asset DB
*/
bool
AssetManager::known (IDA id)
{
return bool(registry.get (ID<Asset>(id)));
} // query most general Asset ID-kind and use implicit
// conversion from smart-ptr to bool (test if empty)
/**
* @return true if the given id is registered with the given Category
*/
bool
AssetManager::known (IDA id, const Category& cat)
{
PAsset pA = registry.get (id);
return ( pA && pA->ident.category.isWithin(cat));
}
namespace { // details implementing AssetManager::remove
void
recursive_call (AssetManager* instance, PAsset& pA)
{
instance->remove (pA->getID());
}
function<void(PAsset&)>
detach_child_recursively () ///< @return a functor recursively invoking remove(child)
{
return bind( &recursive_call, &AssetManager::instance(), _1 );
}
}
/**
* remove the given asset from the internal DB
* <i>together with all its dependents</i>
*/
void
AssetManager::remove (IDA id)
{
PAsset asset = getAsset (id);
for_each (asset->dependants, detach_child_recursively());
asset->unlink();
registry.del(id);
}
void
AssetManager::clear()
{
INFO (progress, "Clearing the Asset registry...");
registry.clear();
}
list<PcAsset>
AssetManager::listContent() const
{
list<PcAsset> res;
registry.asList (res);
res.sort();
return res;
}
}} // namespace steam::asset
/************************************************************/
/* explicit template instantiations for various Asset Kinds */
/************************************************************/
#include "steam/asset/media.hpp"
#include "steam/asset/clip.hpp"
#include "steam/asset/proc.hpp"
#include "steam/asset/struct.hpp"
#include "steam/asset/pipe.hpp"
#include "steam/asset/meta.hpp"
#include "steam/asset/procpatt.hpp"
#include "steam/asset/timeline.hpp"
#include "steam/asset/sequence.hpp"
#include "steam/asset/meta/time-grid.hpp"
#include "steam/asset/meta/error-log.hpp"
namespace steam {
namespace asset {
using lib::P;
template ID<Asset> AssetManager::reg (Asset* obj, const Asset::Ident& idi);
template P<Asset> AssetManager::getAsset (const ID<Asset>& id);
template P<Media> AssetManager::getAsset (const ID<Media>& id);
template P<Proc> AssetManager::getAsset (const ID<Proc>& id);
template P<Struct> AssetManager::getAsset (const ID<Struct>& id);
template P<Meta> AssetManager::getAsset (const ID<Meta>& id);
template P<Pipe> AssetManager::getAsset (const ID<Pipe>& id);
template P<Asset> AssetManager::wrap (const Asset& asset);
template P<Media> AssetManager::wrap (const Media& asset);
template P<Clip> AssetManager::wrap (const Clip& asset);
template P<Pipe> AssetManager::wrap (const Pipe& asset);
template P<ProcPatt> AssetManager::wrap (const ProcPatt& asset);
template P<Timeline> AssetManager::wrap (const Timeline& asset);
template P<Sequence> AssetManager::wrap (const Sequence& asset);
using meta::TimeGrid;
using meta::ErrorLog;
template P<TimeGrid> AssetManager::wrap (const TimeGrid& asset);
template P<ErrorLog> AssetManager::wrap (const ErrorLog& asset);
}} // namespace steam::asset