From 5da016aa5a4b7f91022170e10d2a4cd5248f9851 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 16 Sep 2007 03:02:05 +0200 Subject: [PATCH] WIP integration of Asset types and AssetManager --- src/common/multithread.hpp | 54 +++++++++++++++++ src/common/singletonpolicies.hpp | 8 +-- src/common/util.cpp | 6 +- src/proc/asset.hpp | 1 + src/proc/asset/category.cpp | 17 ++++++ src/proc/asset/category.hpp | 3 +- src/proc/asset/db.hpp | 32 +++++++--- src/proc/asset/media.hpp | 3 - src/proc/asset/meta.cpp | 28 ++++++++- src/proc/asset/meta.hpp | 64 +++++++++++++++++++- src/proc/asset/proc.cpp | 28 ++++++++- src/proc/asset/proc.hpp | 61 ++++++++++++++++++- src/proc/asset/struct.cpp | 28 +++++++++ src/proc/asset/struct.hpp | 62 ++++++++++++++++++- src/proc/assetmanager.cpp | 101 ++++++++++++++++++++++++++++--- src/proc/assetmanager.hpp | 10 +++ 16 files changed, 468 insertions(+), 38 deletions(-) create mode 100644 src/common/multithread.hpp diff --git a/src/common/multithread.hpp b/src/common/multithread.hpp new file mode 100644 index 000000000..9451ada05 --- /dev/null +++ b/src/common/multithread.hpp @@ -0,0 +1,54 @@ +/* + MULTITHREAD.hpp - generic interface for multithreading primitives + + Copyright (C) CinelerraCV + 2007, Christian Thaeter + + 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. + +*/ + + + +#ifndef CINELERRA_MULTITHREAD_H +#define CINELERRA_MULTITHREAD_H + + + +namespace cinelerra + { + + /** + * Interface/Policy for managing parallelism issues. + * Basically everything is forwarded to the corresponding backend functions, + * because managing threads and locking belongs to the cinelerra backend layer. + * + * @todo actually implement this policy using the cinelerra databackend. + */ + struct Thread + { + template + class Lock + { + public: + Lock() { TODO ("aquire Thread Lock for Class"); } + Lock(X*) { TODO ("aquire Thread Lock for Instance"); } + ~Lock() { TODO ("release Thread Lock"); } + }; + }; + + +} // namespace cinelerra +#endif diff --git a/src/common/singletonpolicies.hpp b/src/common/singletonpolicies.hpp index 6cb212660..a5d499c12 100644 --- a/src/common/singletonpolicies.hpp +++ b/src/common/singletonpolicies.hpp @@ -34,6 +34,7 @@ This code is heavily inspired by #ifndef CINELERRA_SINGLETONPOLICIES_H #define CINELERRA_SINGLETONPOLICIES_H +#include "common/multithread.hpp" #include "common/error.hpp" #include @@ -136,12 +137,7 @@ namespace cinelerra struct Multithreaded { typedef volatile S* VolatileType; - class Lock - { - public: - Lock() { UNIMPLEMENTED ("aquire Thread Lock"); } - ~Lock() { UNIMPLEMENTED ("release Thread Lock"); } - }; + typedef cinelerra::Thread::Lock Lock; }; diff --git a/src/common/util.cpp b/src/common/util.cpp index 28958ade9..6adc93ab2 100644 --- a/src/common/util.cpp +++ b/src/common/util.cpp @@ -39,9 +39,9 @@ namespace util typedef boost::function ChPredicate; ChPredicate operator! (ChPredicate p) { return ! boost::bind(p,_1); } - // character classes used for sanitizing strings - ChPredicate isValid (is_alnum() || is_any_of("-_.:+$'()@")); - ChPredicate isPunct (is_space() || is_any_of(",;#*~´`?\\=/&%![]{}")); + // character classes used for sanitizing a string + ChPredicate isValid (is_alnum() || is_any_of("-_.:+$'()@")); ///< characters to be retained + ChPredicate isPunct (is_space() || is_any_of(",;#*~´`?\\=/&%![]{}")); ///< punctuation to be replaced by '_' string diff --git a/src/proc/asset.hpp b/src/proc/asset.hpp index fb7fab2e5..dc20e28ec 100644 --- a/src/proc/asset.hpp +++ b/src/proc/asset.hpp @@ -181,6 +181,7 @@ namespace asset const Ident ident; ///< Asset identification tuple virtual const ID& getID() const { return id; } + protected: const ID id; ///< Asset primary key. diff --git a/src/proc/asset/category.cpp b/src/proc/asset/category.cpp index 520b9d830..2e07c8b3a 100644 --- a/src/proc/asset/category.cpp +++ b/src/proc/asset/category.cpp @@ -25,6 +25,9 @@ #include "common/util.hpp" #include "nobugcfg.h" +#include + +using boost::algorithm::starts_with; using util::isnil; namespace asset @@ -48,6 +51,20 @@ namespace asset str += "/"+path_; return str; } + + + + /** hierarchical inclusion test. + * @return true if \c this can be considered + * a subcategory of the given reference + */ + bool + Category::isWithin (const Category& ref) const + { + return ( ref.hasKind (kind_) + && starts_with (path_, ref.path_) + ); + } } // namespace asset diff --git a/src/proc/asset/category.hpp b/src/proc/asset/category.hpp index 69137ae1b..f27f46845 100644 --- a/src/proc/asset/category.hpp +++ b/src/proc/asset/category.hpp @@ -76,7 +76,8 @@ namespace asset bool operator== (const Category& other) const { return kind_== other.kind_ && path_== other.path_; } bool operator!= (const Category& other) const { return kind_!= other.kind_ || path_!= other.path_; } - bool hasKind (Kind refKind) const { return kind_ == refKind; } + bool hasKind (Kind refKind) const { return kind_ == refKind; } + bool isWithin (const Category&) const; operator string () const; diff --git a/src/proc/asset/db.hpp b/src/proc/asset/db.hpp index ea3c41a67..8ac4207a6 100644 --- a/src/proc/asset/db.hpp +++ b/src/proc/asset/db.hpp @@ -33,7 +33,9 @@ namespace asset { - + using std::tr1::static_pointer_cast; + using std::tr1::dynamic_pointer_cast; + /* ===== hash implementations ===== */ @@ -45,14 +47,14 @@ namespace asset boost::hash_combine(hash, idi.name); boost::hash_combine(hash, idi.category); return hash; - } + } - size_t + size_t hash_value (const Asset& asset) { return asset.getID(); } - + /** * trivial hash functor. @@ -66,12 +68,12 @@ namespace asset size_t operator() (size_t val) const { return val; } }; - + typedef std::tr1::unordered_map IdHashtable; - - - - + + + + /** * Implementation of the registry holding all Asset * instances known to the Asset Manager subsystem. @@ -85,6 +87,18 @@ namespace asset ~DB () {} friend class cinelerra::singleton::Static; + + public: + template + void put (ID hash, shared_ptr& ptr) { table[hash] = static_pointer_cast (ptr); } + void put (ID hash, PAsset& ptr) { table[hash] = ptr; } + + template + shared_ptr + get (ID hash) + { + return dynamic_pointer_cast (table[hash]); + } }; diff --git a/src/proc/asset/media.hpp b/src/proc/asset/media.hpp index 4e6507a2a..cc1a1bdc7 100644 --- a/src/proc/asset/media.hpp +++ b/src/proc/asset/media.hpp @@ -103,9 +103,6 @@ namespace asset PType operator() (Asset::Ident& key, const char* file); ///< convienience overload using C-String PType operator() (const char* file, Category& cat); PType operator() (const char* file, asset::Kind); - - protected: - static void destroy (Media* m) { delete m; } }; diff --git a/src/proc/asset/meta.cpp b/src/proc/asset/meta.cpp index fb0ff7c05..be2382f1f 100644 --- a/src/proc/asset/meta.cpp +++ b/src/proc/asset/meta.cpp @@ -21,13 +21,37 @@ * *****************************************************/ +#include "proc/assetmanager.hpp" #include "proc/asset/meta.hpp" +#include "common/util.hpp" +#include "nobugcfg.h" + namespace asset { - /** */ - + namespace // Implementation details + { + /** helper: .....*/ + } + + MetaFactory Meta::create; ///< storage for the static MetaFactory instance + + + + /** Factory method for Metadata Asset instances. .... + * @todo actually define + * @return an Meta smart ptr linked to the internally registered smart ptr + * created as a side effect of calling the concrete Meta subclass ctor. + */ + MetaFactory::PType + MetaFactory::operator() (Asset::Ident& key) ////TODO + { + UNIMPLEMENTED ("Meta-Factory"); + } + + + } // namespace asset diff --git a/src/proc/asset/meta.hpp b/src/proc/asset/meta.hpp index 4cbd3f9c1..21715fe0f 100644 --- a/src/proc/asset/meta.hpp +++ b/src/proc/asset/meta.hpp @@ -21,26 +21,86 @@ */ +/** @file meta.hpp + ** Some Metatdata elements (e.g. Automation Datasets) can be treated as + ** specific Kind of Asset. + ** For the different Kinds of Assets, we use sub-intefaces inheriting + ** from the general Asset interface. To be able to get asset::Meta instances + ** directly from the AssetManager, we define a specialization of the Asset ID. + ** + ** @see asset.hpp for explanation + ** @see MetaFactory creating concrete asset::Meta instances + ** + */ + #ifndef ASSET_META_H #define ASSET_META_H #include "proc/asset.hpp" +#include "common/factory.hpp" namespace asset { + + class Meta; + class MetaFactory; + + + template<> + class ID : public ID + { + public: + ID (size_t id); + ID (const Meta&); + }; - + + /** * key abstraction: metadata and organisational asset + * @todo just a stub, have to figure out what a asset::Proc is */ - class Meta : public proc_interface::Asset + class Meta : public Asset { + public: + static MetaFactory create; + virtual const ID& getID() const ///< @return ID of kind Meta + { + return static_cast& > (Asset::getID()); + } + + protected: + Meta (const Asset::Ident& idi) : Asset(idi) {} //////////////TODO + friend class MetaFactory; }; + // definition of ID ctors is possible now, + // after providing full definition of class Proc + + inline ID::ID(size_t id) : ID (id) {}; + inline ID::ID(const Meta& meta) : ID (meta.getID()) {}; + + + + + /** + * Factory specialized for createing Metadata Asset objects. + */ + class MetaFactory : public cinelerra::Factory + { + public: + typedef shared_ptr PType; + + PType operator() (Asset::Ident& key); ////////////TODO define actual operation + + }; + + + } // namespace asset #endif diff --git a/src/proc/asset/proc.cpp b/src/proc/asset/proc.cpp index b82ea49d7..7f66edcca 100644 --- a/src/proc/asset/proc.cpp +++ b/src/proc/asset/proc.cpp @@ -21,13 +21,37 @@ * *****************************************************/ +#include "proc/assetmanager.hpp" #include "proc/asset/proc.hpp" +#include "common/util.hpp" +#include "nobugcfg.h" + namespace asset { - /** */ - + namespace // Implementation details + { + /** helper: .....*/ + } + + ProcFactory Proc::create; ///< storage for the static ProcFactory instance + + + + /** Factory method for Processor Asset instances. .... + * @todo actually define + * @return an Proc smart ptr linked to the internally registered smart ptr + * created as a side effect of calling the concrete Proc subclass ctor. + */ + ProcFactory::PType + ProcFactory::operator() (Asset::Ident& key) ////TODO + { + UNIMPLEMENTED ("Proc-Factory"); + } + + + } // namespace asset diff --git a/src/proc/asset/proc.hpp b/src/proc/asset/proc.hpp index 003635b4f..0c201705b 100644 --- a/src/proc/asset/proc.hpp +++ b/src/proc/asset/proc.hpp @@ -21,26 +21,85 @@ */ +/** @file proc.hpp + ** Data processing Plugins and Codecs can be treated as a specific Kind of Asset. + ** For the different Kinds of Assets, we use sub-intefaces inheriting + ** from the general Asset interface. To be able to get asset::Proc instances + ** directly from the AssetManager, we define a specialization of the Asset ID. + ** + ** @see asset.hpp for explanation + ** @see ProcFactory creating concrete asset::Proc instances + ** + */ + #ifndef ASSET_PROC_H #define ASSET_PROC_H #include "proc/asset.hpp" +#include "common/factory.hpp" namespace asset { + + class Proc; + class ProcFactory; + + + template<> + class ID : public ID + { + public: + ID (size_t id); + ID (const Proc&); + }; - + + /** * key abstraction: data processing asset + * @todo just a stub, have to figure out what a asset::Proc is */ class Proc : public Asset { + public: + static ProcFactory create; + virtual const ID& getID() const ///< @return ID of kind Proc + { + return static_cast& > (Asset::getID()); + } + + protected: + Proc (const Asset::Ident& idi) : Asset(idi) {} //////////////TODO + friend class ProcFactory; }; + // definition of ID ctors is possible now, + // after providing full definition of class Proc + + inline ID::ID(size_t id) : ID (id) {}; + inline ID::ID(const Proc& proc) : ID (proc.getID()) {}; + + + + + /** + * Factory specialized for createing Processor Asset objects. + */ + class ProcFactory : public cinelerra::Factory + { + public: + typedef shared_ptr PType; + + PType operator() (Asset::Ident& key); ////////////TODO define actual operation + + }; + + + } // namespace asset #endif diff --git a/src/proc/asset/struct.cpp b/src/proc/asset/struct.cpp index 18769f497..8af2b2e94 100644 --- a/src/proc/asset/struct.cpp +++ b/src/proc/asset/struct.cpp @@ -21,10 +21,38 @@ * *****************************************************/ +#include "proc/assetmanager.hpp" #include "proc/asset/struct.hpp" +#include "common/util.hpp" +#include "nobugcfg.h" namespace asset { + + namespace // Implementation details + { + /** helper: .....*/ + } + + + + StructFactory Struct::create; ///< storage for the static StructFactory instance + + + + /** Factory method for Structural Asset instances. .... + * @todo actually define + * @return an Struct smart ptr linked to the internally registered smart ptr + * created as a side effect of calling the concrete Struct subclass ctor. + */ + StructFactory::PType + StructFactory::operator() (Asset::Ident& key) ////TODO + { + UNIMPLEMENTED ("Struct-Factory"); + } + + + diff --git a/src/proc/asset/struct.hpp b/src/proc/asset/struct.hpp index 787c172dc..dd1b635aa 100644 --- a/src/proc/asset/struct.hpp +++ b/src/proc/asset/struct.hpp @@ -21,23 +21,83 @@ */ +/** @file struct.hpp + ** Structural facilities of the EDL (e.g. Tracks) can be treated in the + ** "bookkeeping view" as a specific Kind of Asset. + ** For the different Kinds of Assets, we use sub-intefaces inheriting + ** from the general Asset interface. To be able to get asset::Struct instances + ** directly from the AssetManager, we define a specialization of the Asset ID. + ** + ** @see asset.hpp for explanation + ** @see StructFactory creating concrete asset::Struct instances + ** + */ + + #ifndef ASSET_STRUCT_H #define ASSET_STRUCT_H #include "proc/asset.hpp" +#include "common/factory.hpp" namespace asset { + + class Struct; + class StructFactory; + + + template<> + class ID : public ID + { + public: + ID (size_t id); + ID (const Struct&); + }; - + + /** * key abstraction: structural asset + * @todo just a stub, have to figure out what a asset::Proc is */ class Struct : public Asset { + public: + static StructFactory create; + virtual const ID& getID() const ///< @return ID of kind asset::Struct + { + return static_cast& > (Asset::getID()); + } + + protected: + Struct (const Asset::Ident& idi) : Asset(idi) {} //////////////TODO + friend class StructFactory; + }; + + + // definition of ID ctors is possible now, + // after providing full definition of class Proc + + inline ID::ID(size_t id) : ID (id) {}; + inline ID::ID(const Struct& stru) : ID (stru.getID()) {}; + + + + + /** + * Factory specialized for createing Structural Asset objects. + */ + class StructFactory : public cinelerra::Factory + { + public: + typedef shared_ptr PType; + + PType operator() (Asset::Ident& key); ////////////TODO define actual operation + }; diff --git a/src/proc/assetmanager.cpp b/src/proc/assetmanager.cpp index 3a8111fb8..0fba91b52 100644 --- a/src/proc/assetmanager.cpp +++ b/src/proc/assetmanager.cpp @@ -24,13 +24,65 @@ #include "proc/assetmanager.hpp" #include "proc/asset/db.hpp" -//#include +#include "common/multithread.hpp" +#include "common/util.hpp" + +#include +#include + +#include +#include + +using boost::format; +using boost::bind; +//using boost::lambda::_1; +using util::for_each; using cinelerra::Singleton; +using cinelerra::Thread; + namespace asset { + /** + * AssetManager error responses, cause by querying + * invalid Asset IDs from the internal DB. + */ + class IDErr : public cinelerra::error::Invalid + { + public: + IDErr (const char* eID, format fmt) + : cinelerra::error::Invalid(fmt.str(),eID) {} + }; + + + // ------pre-defined-common-error-cases--------------- + // + CINELERRA_ERROR_DEFINE (UNKNOWN_ASSET_ID, "non-registered Asset ID"); + CINELERRA_ERROR_DEFINE (WRONG_ASSET_KIND, "wrong Asset kind, unable to cast"); + + class UnknownID : public IDErr + { + public: + UnknownID (ID aID) : IDErr (CINELERRA_ERROR_UNKNOWN_ASSET_ID, + format("Query for Asset with ID=%d, which up to now " + "hasn't been created or encountered.") % aID) {} + }; + + class WrongKind : public IDErr + { + public: + WrongKind (Asset::Ident idi) : IDErr (CINELERRA_ERROR_WRONG_ASSET_KIND, + format("Request for Asset(%s), specifying an Asset kind, " + "that doesn't match the actual type (and can't be " + "casted either).") % string(idi)) {} + }; + + + + + /** get at the system-wide asset manager instance. * Implemented as singleton. */ @@ -52,26 +104,45 @@ namespace asset /** - * registers an asset object in the internal DB, providing its unique key + * 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 */ template ID AssetManager::reg (KIND* obj, const Asset::Ident& idi) throw(cinelerra::error::Invalid) { - UNIMPLEMENTED ("AssetManager::reg"); + typedef shared_ptr PType; + AssetManager& _aMang (AssetManager::instance()); + TODO ("check validity of Ident Category"); + ID asset_id (getID (idi)); + + Thread::Lock guard SIDEEFFECT; + TODO ("handle duplicate Registrations"); + PType smart_ptr (obj, &destroy); + + _aMang.registry.put (asset_id, smart_ptr); + return asset_id; } /** - * find and return corresponging object + * find and return the object registered with the given ID. + * @throws Invalid if nothing is found or if the actual KIND + * of the stored object differs and can't be casted. */ template shared_ptr AssetManager::getAsset (const ID& id) throw(cinelerra::error::Invalid) { - UNIMPLEMENTED ("AssetManager::getAsset"); + if (shared_ptr 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); } @@ -81,8 +152,9 @@ namespace asset bool AssetManager::known (IDA id) { - UNIMPLEMENTED ("asset search"); - } + return ( registry.get (ID(id)) ); + } // query most general Asset ID-kind and use implicit + // conversion from shared_ptr to bool (test if empty) /** @@ -91,9 +163,16 @@ namespace asset bool AssetManager::known (IDA id, const Category& cat) { - UNIMPLEMENTED ("asset search"); + PAsset pA = registry.get (id); + return ( pA && pA->ident.category.isWithin(cat)); } + + void + AssetManager::detach_child (PAsset& pA, IDA id) + { + pA->unlink(id); + } /** * remove the given asset together with all its dependants from the internal DB @@ -103,6 +182,12 @@ namespace asset throw(cinelerra::error::Invalid, cinelerra::error::State) { + UNIMPLEMENTED ("remove Asset with all dependecies"); + + PAsset pA = getAsset (id); + vector par = pA->getParents(); + boost::function func = bind(&detach_child, _1,id ); + for_each (par, func); // ,boost::lambda::var(id))); } diff --git a/src/proc/assetmanager.hpp b/src/proc/assetmanager.hpp index d7effe221..9055c13f8 100644 --- a/src/proc/assetmanager.hpp +++ b/src/proc/assetmanager.hpp @@ -40,6 +40,7 @@ #include "common/error.hpp" #include "common/singleton.hpp" + #include #include #include @@ -94,13 +95,22 @@ namespace asset static ID reg (KIND* obj, const Asset::Ident& idi) throw(cinelerra::error::Invalid); + /** deleter function used by the Asset smart pointers to delet Asset objects */ + static void destroy (Asset* m) { delete m; } + friend Asset::Asset (const Asset::Ident& idi); AssetManager (); friend class cinelerra::singleton::Static; + private: + static void detach_child (PAsset&, IDA); }; + + + CINELERRA_ERROR_DECLARE (UNKNOWN_ASSET_ID); ///< use of a non-registered Asset ID. + CINELERRA_ERROR_DECLARE (WRONG_ASSET_KIND); ///< Asset ID of wrong Asset kind, unable to cast. } // namespace asset