X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fcollection.h;h=be9ae88c491595f925db46e30aeff2daa67deb5f;hb=698d4ae13da87b7c53aa96bca99c3deaff397eec;hp=3d5b7f0a6abce95bc8aa5d6ec05749be3ec6f8b2;hpb=60e8000566e2b1510ccd52697793ab049b62b07c;p=libs%2Fdatafile.git diff --git a/source/collection.h b/source/collection.h index 3d5b7f0..be9ae88 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,9 +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. +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 { @@ -79,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 &); @@ -97,60 +102,34 @@ 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))); + insert_unique(items, name, RefPtr::Type>(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. */ + /// Gets a typed object from the collection. template - void add_future(const std::string &name) + T &get(const std::string &name) const { - RefPtr::Type> ptr(0); - insert_unique(items, name, ptr); + return extract(get_item(items, name)); } - void add_future(const std::string &name); - -public: - /// Gets a typed object from the collection. + /** 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 &name) const + T &get(const std::string &name) { - typedef typename RemoveConst::Type NCT; - - T *ptr = get_item(items, name).value >().get(); - if(!ptr) - throw key_error(typeid(ItemMap)); - return *ptr; + return extract(get_var(name, get_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. */ +private: + const Variant &get_var(const std::string &, const CollectionItemTypeBase *); + template - T &get(const std::string &); + T &extract(const Variant &var) const + { + return *var.value::Type> >(); + } -private: template void collect_items(std::list *objects, std::list *names, std::list *future_names) const { @@ -159,22 +138,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 { @@ -183,8 +167,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() { @@ -193,7 +177,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 { @@ -202,8 +186,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() { @@ -221,24 +205,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; } @@ -263,6 +254,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 @@ -308,12 +305,13 @@ public: virtual ~CollectionItemTypeBase(); void set_keyword(const std::string &); + const std::string &get_keyword() const { return kwd; } void add_suffix(const std::string &); + bool match_name(const std::string &) const; 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; - bool match_name(const std::string &) const; - virtual Variant create_future() const = 0; + virtual void load_item(Collection &, Parser &, const std::string &) const = 0; template bool check_type() const @@ -363,7 +361,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; }; @@ -375,9 +372,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); } }; @@ -456,30 +450,16 @@ public: store->store(coll, name, obj); } - virtual Variant create_future() const - { return store->create_future(); } -}; - - -template -T &Collection::get(const std::string &name) -{ - typedef typename RemoveConst::Type NCT; - - ItemMap::iterator i = items.find(name); - if(i!=items.end()) + virtual void load_item(Collection &coll, Parser &parser, const std::string &name) const { - NCT *ptr = i->second.value >().get(); - if(ptr) - return *ptr; + RefPtr obj = new T; + Collection::ItemLoader ldr(*obj, coll); + ldr.load(parser); + store->store(coll, name, obj.get()); + obj.release(); } +}; - for(TypeList::iterator j=types.begin(); j!=types.end(); ++j) - if((*j)->can_create() && (*j)->check_type()) - (*j)->create_item(*this, name); - - return *get_item(items, name).value >(); -} template CollectionItemType &Collection::add_type() @@ -489,6 +469,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