+
+class CollectionItemTypeBase
+{
+protected:
+ class TagBase
+ {
+ protected:
+ TagBase() { }
+ public:
+ virtual ~TagBase() { }
+ };
+
+ template<typename T>
+ class Tag: public TagBase
+ { };
+
+ std::string kwd;
+ std::vector<std::string> suffixes;
+ TagBase *tag;
+
+ CollectionItemTypeBase();
+public:
+ virtual ~CollectionItemTypeBase();
+
+ void set_keyword(const std::string &);
+ void add_suffix(const std::string &);
+ 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;
+
+ template<typename T>
+ bool check_type() const
+ { return dynamic_cast<Tag<T> *>(tag); }
+};
+
+
+/**
+Describes a type of item that can be loaded by a Collection. These are created
+by Collection::add_type.
+*/
+template<typename T>
+class CollectionItemType: public CollectionItemTypeBase
+{
+private:
+ class CreatorBase
+ {
+ protected:
+ CreatorBase() { }
+ public:
+ virtual ~CreatorBase() { }
+
+ virtual T *create(Collection &, const std::string &) const = 0;
+ };
+
+ template<typename C>
+ class Creator: public 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<C &>(coll).*func)(name); }
+ };
+
+ class StoreBase
+ {
+ protected:
+ StoreBase() { }
+ public:
+ 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;
+ };
+
+ template<typename S>
+ class Store: public StoreBase
+ {
+ public:
+ virtual void store(Collection &coll, const std::string &name, T *obj)
+ { coll.add(name, static_cast<S *>(obj)); }
+
+ virtual Variant create_future() const
+ { return RefPtr<S>(0); }
+
+ virtual void add_to_loader(Collection::Loader &loader, const std::string &kwd)
+ { Collection::Loader::Add<T, S>::add(loader, kwd); }
+ };
+
+ CreatorBase *creat;
+ StoreBase *store;
+
+public:
+ CollectionItemType():
+ creat(0), store(new Store<T>)
+ { tag = new Tag<T>; }
+
+ ~CollectionItemType()
+ {
+ delete creat;
+ delete store;
+ }
+
+ /** Sets a datafile keyword for this item type. The Collection's loader
+ will accept a statement with this keyword and a single string argument - the
+ item's name. */
+ CollectionItemType &keyword(const std::string &k)
+ {
+ set_keyword(k);
+ return *this;
+ }
+
+ /** Adds a suffix that is used to match names when looking for future
+ objects. There is no implied separator; a name matches if it ends with the
+ suffix. If a keyword is defined before any suffixes, then "."+keyword is
+ added as a suffix. */
+ CollectionItemType &suffix(const std::string &s)
+ {
+ add_suffix(s);
+ return *this;
+ }
+
+ /** Attaches a creator function to this item type. If an item is not found
+ in the Collection, the creator function for its type is called to create it.
+ The function must be a member of the Collection subclass containing the
+ type. It must return the created object, or null if it could not be
+ created. It's also permissible to load the item via other means and then
+ return null. */
+ template<typename C>
+ CollectionItemType &creator(T *(C::*func)(const std::string &))
+ {
+ delete creat;
+ creat = new Creator<C>(func);
+ 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()
+ {
+ delete tag;
+ tag = new Tag<S>;
+ delete store;
+ store = new Store<S>;
+ return *this;
+ }
+
+ virtual void add_to_loader(Collection::Loader &loader) const
+ { store->add_to_loader(loader, kwd); }
+
+ virtual bool can_create() const
+ { return creat!=0; }
+
+ virtual void create_item(Collection &coll, const std::string &name) const
+ {
+ if(!creat)
+ throw std::runtime_error("no creator");
+ T *obj = creat->create(coll, name);
+ if(obj)
+ store->store(coll, name, obj);
+ }
+
+ virtual Variant create_future() const
+ { return store->create_future(); }
+};
+
+
+template<typename T>
+T &Collection::get(const std::string &name)
+{
+ typedef typename RemoveConst<T>::Type NCT;
+
+ ItemMap::iterator i = items.find(name);
+ if(i!=items.end())
+ {
+ NCT *ptr = i->second.value<RefPtr<NCT> >().get();
+ if(ptr)
+ return *ptr;
+ }
+
+ for(TypeList::iterator j=types.begin(); j!=types.end(); ++j)
+ if((*j)->can_create() && (*j)->check_type<NCT>())
+ (*j)->create_item(*this, name);
+
+ return *get_item(items, name).value<RefPtr<NCT> >();
+}
+
+template<typename T>
+CollectionItemType<T> &Collection::add_type()
+{
+ CollectionItemType<T> *type = new CollectionItemType<T>;
+ types.push_back(type);
+ return *type;
+}
+