From a7272165a9dc6a1e9c408e77f96530a7d3aa24e1 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Tue, 4 Dec 2012 10:32:43 +0200 Subject: [PATCH] More flexible system for handling base classes in Collection Items are now stored with their original type, but can be retrieved with a base class as well. --- source/collection.cpp | 15 ++++-- source/collection.h | 110 ++++++++++++++++++++++++------------------ 2 files changed, 74 insertions(+), 51 deletions(-) diff --git a/source/collection.cpp b/source/collection.cpp index 87982e8..2333aaf 100644 --- a/source/collection.cpp +++ b/source/collection.cpp @@ -35,6 +35,14 @@ const Variant &Collection::get_var(const string &name, const CollectionItemTypeB return get_item(items, name); } +CollectionItemTypeBase *Collection::get_type_for_item(const Variant &var) const +{ + for(TypeList::const_iterator i=types.begin(); i!=types.end(); ++i) + if((*i)->check_item_type(var)) + return *i; + return 0; +} + void Collection::add_source(CollectionSource &s) { sources.push_back(&s); @@ -49,13 +57,10 @@ Collection::Loader::Loader(Collection &c): } -CollectionItemTypeBase::CollectionItemTypeBase(): - tag(0) -{ } - CollectionItemTypeBase::~CollectionItemTypeBase() { - delete tag; + for(vector::iterator i=extractors.begin(); i!=extractors.end(); ++i) + delete *i; } void CollectionItemTypeBase::set_keyword(const string &k) diff --git a/source/collection.h b/source/collection.h index 1f4b556..2243715 100644 --- a/source/collection.h +++ b/source/collection.h @@ -125,10 +125,7 @@ private: const Variant &get_var(const std::string &, const CollectionItemTypeBase *); template - T &extract(const Variant &var) const - { - return *var.value::Type> >(); - } + T &extract(const Variant &var) const; template void collect_items(std::list *objects, std::list *names, std::list *future_names) const @@ -255,10 +252,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 &); }; @@ -284,20 +284,22 @@ public: class CollectionItemTypeBase { protected: - struct TagBase + struct ExtractorBase { - virtual ~TagBase() { } + virtual ~ExtractorBase() { } }; template - struct Tag: 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(); @@ -305,14 +307,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; + } }; @@ -344,37 +361,23 @@ private: { return (static_cast(coll).*func)(name); } }; - struct StoreBase + template + struct Extractor: CollectionItemTypeBase::Extractor { - virtual ~StoreBase() { } - - virtual void store(Collection &, const std::string &, T *) = 0; - - virtual void add_to_loader(Collection::Loader &, const std::string &) = 0; - }; - - template - struct Store: StoreBase - { - 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 @@ -410,20 +413,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; } @@ -434,7 +436,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 @@ -442,12 +444,25 @@ public: RefPtr obj = new T; Collection::ItemLoader ldr(*obj, coll); ldr.load(parser); - store->store(coll, name, obj.get()); - obj.release(); + // Collection::add will delete the object if it fails + coll.add(name, obj.release()); } }; +template +T &Collection::extract(const Variant &var) const +{ + typedef RefPtr::Type> RPNCT; + + if(!var.check_type()) + if(CollectionItemTypeBase *type = get_type_for_item(var)) + if(T *item = type->extract(var)) + return *item; + + return *var.value(); +} + template CollectionItemType &Collection::add_type() { @@ -460,7 +475,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; } -- 2.43.0