/* AssetManager - Facade for the Asset subsystem Copyright (C) 2008, Hermann Vosseler   **Lumiera** 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. See the file COPYING for further details. * *****************************************************************/ /** @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 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 lumiera { namespace error { // ------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"); }} 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; }; struct UnknownID : IDErr { UnknownID (ID 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::instance; AssetManager::AssetManager () : registry (Depend() ()) { } /** provide the unique ID for given Asset::Ident tuple */ ID 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 ID AssetManager::reg (KIND* obj, const Asset::Ident& idi) { AssetManager& _aMang (AssetManager::instance()); DB& registry (_aMang.registry); //////////////////////////////////////////////////////////TICKET #840 check validity of Ident Category ID asset_id (getID (idi)); DB::Lock guard{®istry}; //////////////////////////////////////////////////////////TICKET #840 handle duplicate Registrations lib::P 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 lib::P AssetManager::getAsset (const ID& id) { if (lib::P obj = registry.get (id)) return obj; else if (known (id)) // provide Ident tuple of existing Asset throw WrongKind (registry.get(ID(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), the call to registry.get() * can bypass the dynamic cast, because the type of the asset * is explicitly given by type KIND. */ template lib::P AssetManager::wrap (const KIND& asset) { ENSURE (instance().known(asset.id), "unregistered asset instance encountered."); return static_pointer_cast (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(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 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 * _together with all its dependents_ */ 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 AssetManager::listContent() const { list 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 AssetManager::reg (Asset* obj, const Asset::Ident& idi); template P AssetManager::getAsset (const ID& id); template P AssetManager::getAsset (const ID& id); template P AssetManager::getAsset (const ID& id); template P AssetManager::getAsset (const ID& id); template P AssetManager::getAsset (const ID& id); template P AssetManager::getAsset (const ID& id); template P AssetManager::wrap (const Asset& asset); template P AssetManager::wrap (const Media& asset); template P AssetManager::wrap (const Clip& asset); template P AssetManager::wrap (const Pipe& asset); template P AssetManager::wrap (const ProcPatt& asset); template P AssetManager::wrap (const Timeline& asset); template P AssetManager::wrap (const Sequence& asset); using meta::TimeGrid; using meta::ErrorLog; template P AssetManager::wrap (const TimeGrid& asset); template P AssetManager::wrap (const ErrorLog& asset); }} // namespace steam::asset