1 #ifndef MSP_DATAFILE_COLLECTION_H_
2 #define MSP_DATAFILE_COLLECTION_H_
4 #include <msp/core/maputils.h>
5 #include <msp/core/meta.h>
6 #include <msp/core/refptr.h>
13 Helper struct to determine whether a Loader has a Collection typedef.
16 struct NeedsCollection
18 struct Yes { char c[2]; };
19 struct No { char c; };
22 static Yes f(typename U::Collection *);
26 enum { value = (sizeof(f<T>(0))==sizeof(Yes)) };
29 class CollectionItemTypeBase;
32 class CollectionItemType;
35 A collection of objects that can be loaded from a datafile. Each object is
36 identified by a name, which must be unique across the entire collection.
42 Loads objects into a Collection.
44 class Loader: public DataFile::Loader
46 template<typename T> friend class CollectionItemType;
49 template<typename T, typename S, bool = NeedsCollection<typename T::Loader>::value>
56 Collection &get_object() const { return coll; }
58 template<typename T, typename S, typename C>
59 void coll_item(const std::string &n)
62 load_sub(*it, dynamic_cast<C &>(coll));
63 coll.add<S>(n, it.get());
67 template<typename T, typename S>
68 void item(const std::string &n)
72 coll.add<S>(n, it.get());
78 typedef std::map<std::string, Variant> ItemMap;
79 typedef std::list<CollectionItemTypeBase *> TypeList;
84 Collection(const Collection &);
85 Collection &operator=(const Collection &);
88 virtual ~Collection();
91 Adds an object into the collection. If a name collision occurs, an
92 exception is thrown. The collection takes ownership of the object.
95 void add(const std::string &name, T *item)
98 throw std::invalid_argument("Collection::add(item)");
100 RefPtr<typename RemoveConst<T>::Type> ptr(item);
103 insert_unique(items, name, ptr);
107 // Avoid deleting the object
114 Gets an object of a specific type from the collection.
117 T &get(const std::string &name) const
119 typedef typename RemoveConst<T>::Type NCT;
121 return *get_item(items, name).value<RefPtr<NCT> >();
125 Gets an object of a specific type from the collection. If the name is not
126 found in the collection and there is a creator for the item type, it is
130 T &get(const std::string &);
133 Returns a list of the names of objects of a specific type in the collection.
136 std::list<std::string> get_names() const
138 std::list<std::string> result;
139 for(ItemMap::const_iterator i=items.begin(); i!=items.end(); ++i)
140 if(i->second.check_type<RefPtr<typename RemoveConst<T>::Type> >())
141 result.push_back(i->first);
146 Returns a list of objects of a specific type in the collection.
149 std::list<T *> get_list() const
151 typedef RefPtr<typename RemoveConst<T>::Type> RPNCT;
153 std::list<T *> result;
154 for(ItemMap::const_iterator i=items.begin(); i!=items.end(); ++i)
155 if(i->second.check_type<RPNCT>())
156 result.push_back(i->second.value<RPNCT>().get());
161 Checks whether a name exists in the collection. Does not care about the
164 bool contains(const std::string &n) const;
167 Returns the name of an item in the collection.
170 const std::string &get_name(T *d) const
172 typedef RefPtr<typename RemoveConst<T>::Type> RPNCT;
174 for(ItemMap::const_iterator i=items.begin(); i!=items.end(); ++i)
175 if(i->second.check_type<RPNCT>())
176 if(i->second.value<RPNCT>().get()==d)
179 // XXX Need better exception class
180 throw std::runtime_error("Item not found in collection");
185 CollectionItemType<T> &add_type();
189 template<typename T, typename S>
190 struct Collection::Loader::Add<T, S, false>
192 static void add(Loader &loader, const std::string &kwd)
193 { loader.add(kwd, &Loader::item<T, S>); }
196 template<typename T, typename S>
197 struct Collection::Loader::Add<T, S, true>
199 static void add(Loader &loader, const std::string &kwd)
200 { loader.add(kwd, &Loader::coll_item<T, S, typename T::Loader::Collection>); }
204 class CollectionItemTypeBase
212 virtual ~TagBase() { }
216 class Tag: public TagBase
225 CollectionItemTypeBase(): tag(0) { }
227 virtual ~CollectionItemTypeBase()
230 virtual void add_to_loader(Collection::Loader &) const = 0;
231 virtual bool can_create() const = 0;
232 virtual void create_item(Collection &, const std::string &) const = 0;
235 bool check_type() const
236 { return dynamic_cast<Tag<T> *>(tag); }
241 class CollectionItemType: public CollectionItemTypeBase
249 virtual ~CreatorBase() { }
251 virtual T *create(Collection &, const std::string &) const = 0;
255 class Creator: public CreatorBase
258 typedef T *(C::*FuncPtr)(const std::string &);
264 Creator(FuncPtr f): func(f) { }
266 virtual T *create(Collection &coll, const std::string &name) const
267 { return (static_cast<C &>(coll).*func)(name); }
275 virtual ~StoreBase() { }
277 virtual void store(Collection &, const std::string &, T *) = 0;
279 virtual void add_to_loader(Collection::Loader &, const std::string &) = 0;
283 class Store: public StoreBase
286 virtual void store(Collection &coll, const std::string &name, T *obj)
287 { coll.add(name, static_cast<S *>(obj)); }
289 virtual void add_to_loader(Collection::Loader &loader, const std::string &kwd)
290 { Collection::Loader::Add<T, S>::add(loader, kwd); }
297 CollectionItemType():
298 creat(0), store(new Store<T>)
299 { tag = new Tag<T>; }
301 ~CollectionItemType()
307 CollectionItemType &keyword(const std::string &k)
314 CollectionItemType &creator(T *(C::*func)(const std::string &))
317 creat = new Creator<C>(func);
322 CollectionItemType &store_as()
327 store = new Store<S>;
331 virtual void add_to_loader(Collection::Loader &loader) const
332 { store->add_to_loader(loader, kwd); }
334 virtual bool can_create() const
337 virtual void create_item(Collection &coll, const std::string &name) const
340 throw std::runtime_error("no creator");
341 T *obj = creat->create(coll, name);
343 store->store(coll, name, obj);
349 T &Collection::get(const std::string &name)
351 typedef typename RemoveConst<T>::Type NCT;
353 if(!items.count(name))
355 for(TypeList::iterator i=types.begin(); i!=types.end(); ++i)
356 if((*i)->can_create() && (*i)->check_type<NCT>())
357 (*i)->create_item(*this, name);
360 return *get_item(items, name).value<RefPtr<NCT> >();
364 CollectionItemType<T> &Collection::add_type()
366 CollectionItemType<T> *type = new CollectionItemType<T>;
367 types.push_back(type);
371 } // namespace DataFile