]> git.tdb.fi Git - libs/datafile.git/commitdiff
More flexible system for handling base classes in Collection
authorMikko Rasa <tdb@tdb.fi>
Tue, 4 Dec 2012 08:32:43 +0000 (10:32 +0200)
committerMikko Rasa <tdb@tdb.fi>
Tue, 4 Dec 2012 08:32:43 +0000 (10:32 +0200)
Items are now stored with their original type, but can be retrieved with
a base class as well.

source/collection.cpp
source/collection.h

index 87982e8f4baa5df80ec1dbe257e33ba4b83af594..2333aaf2726082a6214d2b950aa4570ebc1ea64b 100644 (file)
@@ -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<ExtractorBase *>::iterator i=extractors.begin(); i!=extractors.end(); ++i)
+               delete *i;
 }
 
 void CollectionItemTypeBase::set_keyword(const string &k)
index 1f4b5562107a338190cf221355692aaa4c64d04f..2243715b1d121d8fd64093f1a4b59b94e53e60e0 100644 (file)
@@ -125,10 +125,7 @@ private:
        const Variant &get_var(const std::string &, const CollectionItemTypeBase *);
 
        template<typename T>
-       T &extract(const Variant &var) const
-       {
-               return *var.value<RefPtr<typename RemoveConst<T>::Type> >();
-       }
+       T &extract(const Variant &var) const;
 
        template<typename T>
        void collect_items(std::list<T *> *objects, std::list<std::string> *names, std::list<std::string> *future_names) const
@@ -255,10 +252,13 @@ protected:
        template<typename T>
        CollectionItemType<T> &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<typename T>
        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<typename T>
-       struct Tag: TagBase
-       { };
+       struct Extractor: ExtractorBase
+       {
+               virtual T &extract(const Variant &) const = 0;
+       };
 
        std::string kwd;
        std::vector<std::string> suffixes;
-       TagBase *tag;
+       std::vector<ExtractorBase *> 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<typename T>
-       bool check_type() const
-       { return dynamic_cast<Tag<T> *>(tag); }
+       bool can_extract() const
+       {
+               for(std::vector<ExtractorBase *>::const_iterator i=extractors.begin(); i!=extractors.end(); ++i)
+                       if(dynamic_cast<Extractor<T> *>(*i))
+                               return true;
+               return false;
+       }
+
+       template<typename T>
+       T *extract(const Variant &var) const
+       {
+               for(std::vector<ExtractorBase *>::const_iterator i=extractors.begin(); i!=extractors.end(); ++i)
+                       if(Extractor<T> *ex = dynamic_cast<Extractor<T> *>(*i))
+                               return &ex->extract(var);
+               return 0;
+       }
 };
 
 
@@ -344,37 +361,23 @@ private:
                { return (static_cast<C &>(coll).*func)(name); }
        };
 
-       struct StoreBase
+       template<typename B>
+       struct Extractor: CollectionItemTypeBase::Extractor<B>
        {
-               virtual ~StoreBase() { }
-
-               virtual void store(Collection &, const std::string &, T *) = 0;
-
-               virtual void add_to_loader(Collection::Loader &, const std::string &) = 0;
-       };
-
-       template<typename S>
-       struct Store: StoreBase
-       {
-               virtual void store(Collection &coll, const std::string &name, T *obj)
-               { coll.add(name, static_cast<S *>(obj)); }
-
-               virtual void add_to_loader(Collection::Loader &loader, const std::string &kwd)
-               { loader.add(kwd, &Collection::Loader::item<T, S>); }
+               virtual B &extract(const Variant &var) const
+               { return *var.value<RefPtr<T> >(); }
        };
 
        CreatorBase *creat;
-       StoreBase *store;
 
 public:
        CollectionItemType():
-               creat(0), store(new Store<T>)
-       { tag = new Tag<T>; }
+               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<typename S>
-       CollectionItemType &store_as()
+       /** Makes items of this type available through a base class. */
+       template<typename B>
+       CollectionItemType &base()
        {
-               delete tag;
-               tag = new Tag<S>;
-               delete store;
-               store = new Store<S>;
+               extractors.push_back(new Extractor<B>);
                return *this;
        }
 
+       virtual bool check_item_type(const Variant &var) const
+       { return var.check_type<RefPtr<T> >(); }
+
        virtual void add_to_loader(Collection::Loader &loader) const
-       { store->add_to_loader(loader, kwd); }
+       { loader.add(kwd, &Collection::Loader::item<T, T>); }
 
        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<T> obj = new T;
                Collection::ItemLoader<T> 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<typename T>
+T &Collection::extract(const Variant &var) const
+{
+       typedef RefPtr<typename RemoveConst<T>::Type> RPNCT;
+
+       if(!var.check_type<RPNCT>())
+               if(CollectionItemTypeBase *type = get_type_for_item(var))
+                       if(T *item = type->extract<T>(var))
+                               return *item;
+
+       return *var.value<RPNCT>();
+}
+
 template<typename T>
 CollectionItemType<T> &Collection::add_type()
 {
@@ -460,7 +475,10 @@ template<typename T>
 CollectionItemTypeBase *Collection::get_type() const
 {
        for(TypeList::const_iterator j=types.begin(); j!=types.end(); ++j)
-               if((*j)->check_type<typename RemoveConst<T>::Type>())
+               if(dynamic_cast<CollectionItemType<typename RemoveConst<T>::Type> *>(*j))
+                       return *j;
+       for(TypeList::const_iterator j=types.begin(); j!=types.end(); ++j)
+               if((*j)->can_extract<T>())
                        return *j;
        return 0;
 }