X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fcollection.h;h=6e6900cece1b0c3428e666e918e2e901b6a4541f;hb=2f73f948cd2f4bb0bdcc0f5f81816fb169819879;hp=ec7cde31786adda2049631226231d75731757346;hpb=b1bc25649c1f22abf940a807d934f1e9bb780c28;p=libs%2Fdatafile.git diff --git a/source/collection.h b/source/collection.h index ec7cde3..6e6900c 100644 --- a/source/collection.h +++ b/source/collection.h @@ -102,23 +102,41 @@ public: if(!item) throw std::invalid_argument("Collection::add(item)"); - insert_unique(items, name, RefPtr::Type>(item)); + RefPtr::Type> ptr(item); + try + { + insert_unique(items, name, ptr); + } + catch(...) + { + // Avoid deleting the object + ptr.release(); + throw; + } } /// Gets a typed object from the collection. template T &get(const std::string &name) const { - return *get_item(items, name).value::Type> >(); + return extract(get_item(items, name)); } /** 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 &); + T &get(const std::string &name) + { + return extract(get_var(name, get_type())); + } private: + const Variant &get_var(const std::string &, const CollectionItemTypeBase *); + + template + T &extract(const Variant &var) const; + template void collect_items(std::list *objects, std::list *names, std::list *future_names) const { @@ -244,10 +262,13 @@ protected: template CollectionItemType &add_type(); - /** Returns the descriptor for a type, or null if one isn't defined. */ + /// Returns the descriptor for a type, or null if one isn't defined. template CollectionItemTypeBase *get_type() const; + /// Returns the descriptor for an item, or null if it's of an unknown type. + CollectionItemTypeBase *get_type_for_item(const Variant &) const; + void add_source(CollectionSource &); }; @@ -273,23 +294,22 @@ public: class CollectionItemTypeBase { protected: - class TagBase + struct ExtractorBase { - protected: - TagBase() { } - public: - virtual ~TagBase() { } + virtual ~ExtractorBase() { } }; template - class Tag: public TagBase - { }; + struct Extractor: ExtractorBase + { + virtual T &extract(const Variant &) const = 0; + }; std::string kwd; std::vector suffixes; - TagBase *tag; + std::vector extractors; - CollectionItemTypeBase(); + CollectionItemTypeBase() { } public: virtual ~CollectionItemTypeBase(); @@ -297,14 +317,29 @@ public: const std::string &get_keyword() const { return kwd; } void add_suffix(const std::string &); bool match_name(const std::string &) const; + virtual bool check_item_type(const Variant &) const = 0; 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 void load_item(Collection &, Parser &, const std::string &) const = 0; template - bool check_type() const - { return dynamic_cast *>(tag); } + bool can_extract() const + { + for(std::vector::const_iterator i=extractors.begin(); i!=extractors.end(); ++i) + if(dynamic_cast *>(*i)) + return true; + return false; + } + + template + T *extract(const Variant &var) const + { + for(std::vector::const_iterator i=extractors.begin(); i!=extractors.end(); ++i) + if(Extractor *ex = dynamic_cast *>(*i)) + return &ex->extract(var); + return 0; + } }; @@ -316,67 +351,43 @@ template class CollectionItemType: public CollectionItemTypeBase { private: - class CreatorBase + struct CreatorBase { - protected: - CreatorBase() { } - public: virtual ~CreatorBase() { } virtual T *create(Collection &, const std::string &) const = 0; }; template - class Creator: public CreatorBase + struct Creator: CreatorBase { - public: typedef T *(C::*FuncPtr)(const std::string &); - private: FuncPtr func; - public: Creator(FuncPtr f): func(f) { } virtual T *create(Collection &coll, const std::string &name) const { return (static_cast(coll).*func)(name); } }; - class StoreBase + template + struct Extractor: CollectionItemTypeBase::Extractor { - protected: - StoreBase() { } - public: - virtual ~StoreBase() { } - - virtual void store(Collection &, const std::string &, T *) = 0; - - virtual void add_to_loader(Collection::Loader &, const std::string &) = 0; - }; - - template - class Store: public StoreBase - { - public: - virtual void store(Collection &coll, const std::string &name, T *obj) - { coll.add(name, static_cast(obj)); } - - virtual void add_to_loader(Collection::Loader &loader, const std::string &kwd) - { loader.add(kwd, &Collection::Loader::item); } + virtual B &extract(const Variant &var) const + { return *var.value >(); } }; CreatorBase *creat; - StoreBase *store; public: CollectionItemType(): - creat(0), store(new Store) - { tag = new Tag; } + creat(0) + { } ~CollectionItemType() { delete creat; - delete store; } /** Sets a datafile keyword for this item type. The Collection's loader @@ -412,20 +423,19 @@ public: return *this; } - /** Specifies the storage type for items of this type. It must be a base - class of the actual type. */ - template - CollectionItemType &store_as() + /** Makes items of this type available through a base class. */ + template + CollectionItemType &base() { - delete tag; - tag = new Tag; - delete store; - store = new Store; + extractors.push_back(new Extractor); return *this; } + virtual bool check_item_type(const Variant &var) const + { return var.check_type >(); } + virtual void add_to_loader(Collection::Loader &loader) const - { store->add_to_loader(loader, kwd); } + { loader.add(kwd, &Collection::Loader::item); } virtual bool can_create() const { return creat!=0; } @@ -436,7 +446,7 @@ public: throw std::runtime_error("no creator"); T *obj = creat->create(coll, name); if(obj) - store->store(coll, name, obj); + coll.add(name, obj); } virtual void load_item(Collection &coll, Parser &parser, const std::string &name) const @@ -444,37 +454,23 @@ public: RefPtr obj = new T; Collection::ItemLoader ldr(*obj, coll); ldr.load(parser); - store->store(coll, name, obj.get()); + coll.add(name, obj.get()); obj.release(); } }; template -T &Collection::get(const std::string &name) +T &Collection::extract(const Variant &var) const { typedef RefPtr::Type> RPNCT; - ItemMap::iterator i = items.find(name); - if(i!=items.end()) - return *i->second.value(); - - if(CollectionItemTypeBase *type = get_type()) - { - 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); - } - } + if(!var.check_type()) + if(CollectionItemTypeBase *type = get_type_for_item(var)) + if(T *item = type->extract(var)) + return *item; - return *get_item(items, name).value(); + return *var.value(); } template @@ -489,7 +485,10 @@ template CollectionItemTypeBase *Collection::get_type() const { for(TypeList::const_iterator j=types.begin(); j!=types.end(); ++j) - if((*j)->check_type::Type>()) + if(dynamic_cast::Type> *>(*j)) + return *j; + for(TypeList::const_iterator j=types.begin(); j!=types.end(); ++j) + if((*j)->can_extract()) return *j; return 0; }