if(!item)
throw std::invalid_argument("Collection::add(item)");
- insert_unique(items, name, RefPtr<typename RemoveConst<T>::Type>(item));
+ RefPtr<typename RemoveConst<T>::Type> ptr(item);
+ try
+ {
+ insert_unique(items, name, ptr);
+ }
+ catch(...)
+ {
+ // Avoid deleting the object
+ ptr.release();
+ throw;
+ }
}
/// Gets a typed object from the collection.
template<typename T>
T &get(const std::string &name) const
{
- return *get_item(items, name).value<RefPtr<typename RemoveConst<T>::Type> >();
+ return extract<T>(get_item(items, name));
}
/** Gets a typed object from the collection. If the name is not found,
automatic creation with the type's creator function (if defined) or from
sources (if present) is attempted. */
template<typename T>
- T &get(const std::string &);
+ T &get(const std::string &name)
+ {
+ return extract<T>(get_var(name, get_type<T>()));
+ }
private:
+ const Variant &get_var(const std::string &, const CollectionItemTypeBase *);
+
+ template<typename T>
+ 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
{
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 &);
};
class CollectionItemTypeBase
{
protected:
- class TagBase
+ struct ExtractorBase
{
- protected:
- TagBase() { }
- public:
- virtual ~TagBase() { }
+ virtual ~ExtractorBase() { }
};
template<typename T>
- class Tag: public 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();
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;
+ }
};
class CollectionItemType: public CollectionItemTypeBase
{
private:
- class CreatorBase
+ struct CreatorBase
{
- protected:
- CreatorBase() { }
- public:
virtual ~CreatorBase() { }
virtual T *create(Collection &, const std::string &) const = 0;
};
template<typename C>
- class Creator: public CreatorBase
+ struct Creator: 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
+ template<typename B>
+ struct Extractor: CollectionItemTypeBase::Extractor<B>
{
- protected:
- StoreBase() { }
- public:
- 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>
- class Store: public StoreBase
- {
- public:
- 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
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; }
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
RefPtr<T> obj = new T;
Collection::ItemLoader<T> ldr(*obj, coll);
ldr.load(parser);
- store->store(coll, name, obj.get());
+ coll.add(name, obj.get());
obj.release();
}
};
template<typename T>
-T &Collection::get(const std::string &name)
+T &Collection::extract(const Variant &var) const
{
typedef RefPtr<typename RemoveConst<T>::Type> RPNCT;
- ItemMap::iterator i = items.find(name);
- if(i!=items.end())
- return *i->second.value<RPNCT>();
-
- if(CollectionItemTypeBase *type = get_type<T>())
- {
- bool loaded = false;
- if(type->can_create())
- {
- type->create_item(*this, name);
- loaded = items.count(name);
- }
- for(SourceList::iterator j=sources.begin(); (!loaded && j!=sources.end()); ++j)
- {
- (*j)->load(*this, *type, name);
- loaded = items.count(name);
- }
- }
+ if(!var.check_type<RPNCT>())
+ if(CollectionItemTypeBase *type = get_type_for_item(var))
+ if(T *item = type->extract<T>(var))
+ return *item;
- return *get_item(items, name).value<RPNCT>();
+ return *var.value<RPNCT>();
}
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;
}