]> git.tdb.fi Git - libs/datafile.git/commitdiff
Allow non-loadable types in collections
authorMikko Rasa <tdb@tdb.fi>
Sun, 19 Apr 2020 14:09:07 +0000 (17:09 +0300)
committerMikko Rasa <tdb@tdb.fi>
Sun, 19 Apr 2020 14:31:49 +0000 (17:31 +0300)
Custom collection classes may wish to provide objects of such types
through creator functions.

source/collection.h
source/meta.h

index 5521975402d0526773a44bf6210c9577b87d0f79..d0e8a1a8bb9b25c636ab23a8c1e4bbdcfa5c04a7 100644 (file)
@@ -19,6 +19,20 @@ class CollectionItemTypeBase;
 template<typename T>
 class CollectionItemType;
 
+template<typename T>
+class LoadableCollectionItemType;
+
+template<typename T, bool = HasLoader<T>::value>
+struct CollectionItemTypeChooser;
+
+template<typename T>
+struct CollectionItemTypeChooser<T, true>
+{ typedef LoadableCollectionItemType<T> Type; };
+
+template<typename T>
+struct CollectionItemTypeChooser<T, false>
+{ typedef CollectionItemType<T> Type; };
+
 /**
 A collection of objects that can be loaded from a datafile.  Each object is
 identified by a name, which must be unique across the entire collection.
@@ -44,7 +58,7 @@ public:
        */
        class Loader: public DataFile::Loader
        {
-               template<typename T> friend class CollectionItemType;
+               template<typename T> friend class LoadableCollectionItemType;
 
        private:
                Collection &coll;
@@ -235,12 +249,12 @@ protected:
        /** Adds a type to the collection.  The returned descriptor object reference
        can be used to define how objects of that type can be loaded. */
        template<typename T>
-       CollectionItemType<T> &add_type();
+       typename CollectionItemTypeChooser<T>::Type &add_type();
 
        /** Returns a mutable reference to an existing type descriptor.  This can be
        used to e.g. override the creator function of a type added by a base class. */
        template<typename T>
-       CollectionItemType<T> &modify_type();
+       typename CollectionItemTypeChooser<T>::Type &modify_type();
 
 private:
        /** Returns the descriptor for a type, or null if one isn't defined.  An
@@ -323,9 +337,11 @@ protected:
 public:
        virtual ~CollectionItemTypeBase();
 
+protected:
        void set_keyword(const std::string &);
-       const std::string &get_keyword() const { return kwd; }
        void add_suffix(const std::string &);
+public:
+       const std::string &get_keyword() const { return kwd; }
        bool match_name(const std::string &) const;
        virtual bool is_same_type(const CollectionItemTypeBase &) const = 0;
        virtual bool check_item_type(const Variant &) const = 0;
@@ -448,8 +464,8 @@ public:
        virtual bool check_item_type(const Variant &var) const
        { return var.check_type<RefPtr<T> >(); }
 
-       virtual void add_to_loader(Collection::Loader &loader) const
-       { loader.add(kwd, &Collection::Loader::item<T, T>); }
+       virtual void add_to_loader(Collection::Loader &) const
+       { }
 
        virtual bool can_create() const
        { return creat!=0; }
@@ -463,6 +479,20 @@ public:
                        coll.add(name, obj);
        }
 
+       virtual void load_item(Collection &, Parser &, const std::string &) const
+       {
+               throw std::runtime_error("this type cannot be loaded");
+       }
+};
+
+
+template<typename T>
+class LoadableCollectionItemType: public CollectionItemType<T>
+{
+public:
+       virtual void add_to_loader(Collection::Loader &loader) const
+       { loader.add(this->kwd, &Collection::Loader::item<T, T>); }
+
        virtual void load_item(Collection &coll, Parser &parser, const std::string &name) const
        {
                RefPtr<T> obj = new T;
@@ -486,15 +516,15 @@ T &Collection::extract(const Variant &var) const
 }
 
 template<typename T>
-CollectionItemType<T> &Collection::add_type()
+typename CollectionItemTypeChooser<T>::Type &Collection::add_type()
 {
-       CollectionItemType<T> *type = new CollectionItemType<T>;
+       typename CollectionItemTypeChooser<T>::Type *type = new typename CollectionItemTypeChooser<T>::Type;
        types.push_back(type);
        return *type;
 }
 
 template<typename T>
-CollectionItemType<T> &Collection::modify_type()
+typename CollectionItemTypeChooser<T>::Type &Collection::modify_type()
 {
        for(TypeList::const_iterator j=types.begin(); j!=types.end(); ++j)
                if(CollectionItemType<T> *t = dynamic_cast<CollectionItemType<T> *>(*j))
index ac6ec1be2029e18b0a22c8f692be796687f2e03d..51bc924405d3bdc7861b054801f9f742ec90e226 100644 (file)
@@ -18,6 +18,18 @@ struct CheckCollectionType: Sfinae
 
 template<typename T> struct NeedsCollection: Sfinae::Evaluate<CheckCollectionType, T> { };
 
+/**
+Helper struct to determine whether a type has a Loader class.
+*/
+struct CheckLoader: Sfinae
+{
+       template<typename T>
+       static Yes f(typename T::Loader *);
+       using Sfinae::f;
+};
+
+template<typename T> struct HasLoader: Sfinae::Evaluate<CheckLoader, T> { };
+
 } // namespace DataFile
 } // namespace Msp