X-Git-Url: http://git.tdb.fi/?p=libs%2Fdatafile.git;a=blobdiff_plain;f=source%2Fcollection.h;h=ec7cde31786adda2049631226231d75731757346;hp=f79e567d5c0e4e5fc1a5d6f8c2c9e481265a6d27;hb=b1bc25649c1f22abf940a807d934f1e9bb780c28;hpb=6e0e2c78766de3ae57449866b74e111a2af893cf diff --git a/source/collection.h b/source/collection.h index f79e567..ec7cde3 100644 --- a/source/collection.h +++ b/source/collection.h @@ -4,8 +4,12 @@ #include #include #include +#include "collectionsource.h" #include "loader.h" +/* XXX This file is a big mess with too many things in it. However, the +dependencies between those things make it difficult to split up. */ + namespace Msp { namespace DataFile { @@ -39,12 +43,8 @@ While this class can be instantiated by itself and used for storing objects, loading requires that a subclass defines the supported types. See the add_type method for details. -Collections also support a notion of "future objects". These are objects which -are known to be possible to load, but loading them is deferred to the first -time they are requested. - -Other classes are available to provide refined ways of loading objects from -files. See DirectoryCollection and PackCollection. +Collections can have sources for loading objects on demand. Automatic loading +only works on a non-const Collection. See class CollectionSource for details. */ class Collection { @@ -82,9 +82,11 @@ protected: private: typedef std::map ItemMap; typedef std::list TypeList; + typedef std::list SourceList; TypeList types; ItemMap items; + SourceList sources; Collection(const Collection &); Collection &operator=(const Collection &); @@ -100,62 +102,19 @@ public: if(!item) throw std::invalid_argument("Collection::add(item)"); - typedef RefPtr::Type> RPNCT; - - ItemMap::iterator i = items.find(name); - if(i!=items.end()) - { - if(i->second.check_type()) - { - // Replace a future object placeholder - RPNCT &ptr = i->second.value(); - if(!ptr) - { - ptr = item; - return; - } - } - - throw key_error(typeid(ItemMap)); - } - - items.insert(ItemMap::value_type(name, RPNCT(item))); - } - -protected: - /** Adds the name of a future object to the collection. The object itself - will be loaded on first access. The calling subclass should be prepared to - create the object on request. */ - template - void add_future(const std::string &name) - { - RefPtr::Type> ptr(0); - insert_unique(items, name, ptr); + insert_unique(items, name, RefPtr::Type>(item)); } - /** Adds the name of a future object, guessing its type. If a type matching - the name can't be found, nothing is done. */ - void add_future(const std::string &name); - - /** Adds the name of a future object, using a keyword to determine its type. - The keyword must be known to the collection. */ - void add_future_with_keyword(const std::string &name, const std::string &); - -public: /// Gets a typed object from the collection. template T &get(const std::string &name) const { - typedef typename RemoveConst::Type NCT; - - T *ptr = get_item(items, name).value >().get(); - if(!ptr) - throw key_error(typeid(ItemMap)); - return *ptr; + return *get_item(items, name).value::Type> >(); } - /** Gets a typed object from the collection. If the name is not found in - and a creator for the item type is defined, it is invoked. */ + /** Gets a typed object from the collection. If the name is not found, + automatic creation with the type's creator function (if defined) or from + sources (if present) is attempted. */ template T &get(const std::string &); @@ -168,22 +127,27 @@ private: for(ItemMap::const_iterator i=items.begin(); i!=items.end(); ++i) if(i->second.check_type()) { - T *ptr = i->second.value().get(); - if(ptr) + if(objects) + objects->push_back(i->second.value().get()); + if(names) + names->push_back(i->first); + } + + if(future_names) + if(CollectionItemTypeBase *type = get_type()) + { + for(SourceList::const_iterator i=sources.begin(); i!=sources.end(); ++i) { - if(objects) - objects->push_back(ptr); - if(names) - names->push_back(i->first); + std::list available_names = (*i)->get_names(*type); + for(std::list::iterator j=available_names.begin(); j!=available_names.end(); ++j) + if(!items.count(*j)) + future_names->push_back(*j); } - else if(future_names) - future_names->push_back(i->first); } } public: - /** Returns a list of the names of loaded objects of one type in the - collection. */ + /// Returns a list of the names of objects of one type in the collection. template std::list get_names() const { @@ -192,8 +156,8 @@ public: return result; } - /** Returns a list of the names of objects of one type in the collection, - including any future objects. */ + /** Returns a list of the names of objects of one type in the collection or + available from sources. */ template std::list get_names() { @@ -202,7 +166,7 @@ public: return result; } - /// Returns a list of loaded objects of one type in the collection. + /// Returns a list of objects of one type in the collection. template std::list get_list() const { @@ -211,8 +175,8 @@ public: return result; } - /** Returns a list of objects of one type in the collection. Any future - objects of that type are loaded and returned in the list. */ + /** Returns a list of objects of one type, loading them from sources if + necessary. */ template std::list get_list() { @@ -230,24 +194,31 @@ private: { ItemMap::const_iterator i = items.find(name); if(i==items.end()) - return false; + { + if(CollectionItemTypeBase *type = get_type()) + { + for(SourceList::const_iterator j=sources.begin(); j!=sources.end(); ++j) + if((*j)->is_loadable(*type, name)) + return 2; + } + return 0; + } typedef RefPtr::Type> RPNCT; if(!i->second.check_type()) - return false; + return 0; - T *ptr = i->second.value().get(); - return ptr ? 1 : 2; + return 1; } public: - /// Checks whether a typed object exists and is loaded in the collection. + /// Checks whether a typed object exists in the collection. template bool contains(const std::string &name) const { return get_status(name)==1; } - /** Checks whether a typed object exists in the collection, as either a - loaded or future object. */ + /** Checks whether a typed object exists in the collection or is loadable + from a source. */ template bool contains(const std::string &name) { return get_status(name)>0; } @@ -272,6 +243,12 @@ protected: can be used to define how objects of that type can be loaded. */ template CollectionItemType &add_type(); + + /** Returns the descriptor for a type, or null if one isn't defined. */ + template + CollectionItemTypeBase *get_type() const; + + void add_source(CollectionSource &); }; template @@ -323,7 +300,7 @@ public: virtual void add_to_loader(Collection::Loader &) const = 0; virtual bool can_create() const = 0; virtual void create_item(Collection &, const std::string &) const = 0; - virtual Variant create_future() const = 0; + virtual void load_item(Collection &, Parser &, const std::string &) const = 0; template bool check_type() const @@ -373,7 +350,6 @@ private: virtual ~StoreBase() { } virtual void store(Collection &, const std::string &, T *) = 0; - virtual Variant create_future() const = 0; virtual void add_to_loader(Collection::Loader &, const std::string &) = 0; }; @@ -385,9 +361,6 @@ private: virtual void store(Collection &coll, const std::string &name, T *obj) { coll.add(name, static_cast(obj)); } - virtual Variant create_future() const - { return RefPtr(0); } - virtual void add_to_loader(Collection::Loader &loader, const std::string &kwd) { loader.add(kwd, &Collection::Loader::item); } }; @@ -466,32 +439,42 @@ public: store->store(coll, name, obj); } - virtual Variant create_future() const - { return store->create_future(); } + virtual void load_item(Collection &coll, Parser &parser, const std::string &name) const + { + RefPtr obj = new T; + Collection::ItemLoader ldr(*obj, coll); + ldr.load(parser); + store->store(coll, name, obj.get()); + obj.release(); + } }; template T &Collection::get(const std::string &name) { - typedef typename RemoveConst::Type NCT; + typedef RefPtr::Type> RPNCT; ItemMap::iterator i = items.find(name); if(i!=items.end()) + return *i->second.value(); + + if(CollectionItemTypeBase *type = get_type()) { - NCT *ptr = i->second.value >().get(); - if(ptr) - return *ptr; + bool loaded = false; + if(type->can_create()) + { + type->create_item(*this, name); + loaded = items.count(name); + } + for(SourceList::iterator j=sources.begin(); (!loaded && j!=sources.end()); ++j) + { + (*j)->load(*this, *type, name); + loaded = items.count(name); + } } - for(TypeList::iterator j=types.begin(); j!=types.end(); ++j) - if((*j)->can_create() && (*j)->check_type()) - (*j)->create_item(*this, name); - - NCT *ptr = get_item(items, name).value >().get(); - if(!ptr) - throw key_error(typeid(ItemMap)); - return *ptr; + return *get_item(items, name).value(); } template @@ -502,6 +485,15 @@ CollectionItemType &Collection::add_type() return *type; } +template +CollectionItemTypeBase *Collection::get_type() const +{ + for(TypeList::const_iterator j=types.begin(); j!=types.end(); ++j) + if((*j)->check_type::Type>()) + return *j; + return 0; +} + } // namespace DataFile } // namespace Msp