#include <msp/core/attributes.h>
#include <msp/core/maputils.h>
+#include <msp/core/noncopyable.h>
#include <msp/core/refptr.h>
#include "collectionsource.h"
#include "loader.h"
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.
between the collections, and are only deleted when all collections in the chain
have been destroyed.
*/
-class Collection
+class Collection: private NonCopyable
{
public:
/**
*/
class Loader: public DataFile::Loader
{
- template<typename T> friend class CollectionItemType;
+ template<typename T> friend class LoadableCollectionItemType;
private:
Collection &coll;
private:
typedef std::map<std::string, Variant> ItemMap;
- typedef std::list<CollectionItemTypeBase *> TypeList;
- typedef std::list<const CollectionSource *> SourceList;
+ typedef std::vector<CollectionItemTypeBase *> TypeList;
+ typedef std::vector<const CollectionSource *> SourceList;
TypeList types;
ItemMap items;
SourceList sources;
Collection *fallback;
- Collection(const Collection &);
- Collection &operator=(const Collection &);
public:
Collection();
virtual ~Collection();
return extract<NCT>(get_var(name, get_type<NCT>(name)));
}
+ /** Finds a typed object in the collection. Returns null if the name does
+ not exist. Throws if the name exists but the object is of an incorrect
+ type. */
+ template<typename T>
+ T *find(const std::string &name) const
+ {
+ ItemMap::const_iterator i = items.find(name);
+ return (i!=items.end() ? extract<typename RemoveConst<T>::Type>(i->second) : 0);
+ }
+
+ template<typename T>
+ T *find(const std::string &name)
+ {
+ typedef typename RemoveConst<T>::Type NCT;
+ const Variant *var = find_var(name, get_type<NCT>(name));
+ return (var ? &extract<NCT>(*var) : 0);
+ }
+
private:
const Variant &get_var(const std::string &, const CollectionItemTypeBase *);
+ const Variant *find_var(const std::string &, const CollectionItemTypeBase *);
template<typename T>
T &extract(const Variant &var) const;
template<typename T>
- std::list<T *> extract_list(const std::list<const Variant *> &vars) const
+ std::list<T *> extract_list(const std::vector<const Variant *> &vars) const
{
std::list<T *> result;
- for(std::list<const Variant *>::const_iterator i=vars.begin(); i!=vars.end(); ++i)
+ for(std::vector<const Variant *>::const_iterator i=vars.begin(); i!=vars.end(); ++i)
result.push_back(&extract<T>(**i));
return result;
}
- void gather_items(std::list<const Variant *> *, std::list<std::string> *, const CollectionItemTypeBase &, bool) const;
+ void gather_items(std::vector<const Variant *> *, std::list<std::string> *, const CollectionItemTypeBase &, bool) const;
template<typename T>
- void gather_items(std::list<const Variant *> *vars, std::list<std::string> *names, const CollectionItemTypeBase *type, bool include_sources) const
+ void gather_items(std::vector<const Variant *> *vars, std::list<std::string> *names, const CollectionItemTypeBase *type, bool include_sources) const
{
if(type || (type = get_type<T>()))
gather_items(vars, names, *type, include_sources);
template<typename T>
std::list<T *> get_list() const
{
- std::list<const Variant *> vars;
+ std::vector<const Variant *> vars;
gather_items<typename RemoveConst<T>::Type>(&vars, 0, 0, false);
return extract_list<T>(vars);
}
if(type)
load_items_from_sources(*type);
- std::list<const Variant *> vars;
+ std::vector<const Variant *> vars;
gather_items<typename RemoveConst<T>::Type>(&vars, 0, type, true);
return extract_list<T>(vars);
}
/** 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>
+ typename CollectionItemTypeChooser<T>::Type &modify_type();
private:
/** Returns the descriptor for a type, or null if one isn't defined. An
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;
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; }
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;
}
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>
+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))
+ return *t;
+
+ throw std::logic_error("type not found in collection");
+}
+
template<typename T>
CollectionItemTypeBase *Collection::get_type(const std::string &name) const
{