#ifndef MSP_DATAFILE_COLLECTION_H_
#define MSP_DATAFILE_COLLECTION_H_
+#include <msp/core/attributes.h>
#include <msp/core/maputils.h>
-#include <msp/core/meta.h>
#include <msp/core/refptr.h>
#include "collectionsource.h"
#include "loader.h"
+#include "meta.h"
/* XXX This file is a big mess with too many things in it. However, the
dependencies between those things make it difficult to split up. */
namespace Msp {
namespace DataFile {
-/**
-Helper struct to determine whether a Loader has a Collection typedef.
-*/
-template<typename T>
-struct NeedsCollection: public Sfinae
-{
- template<typename U>
- static Yes f(typename U::Collection *);
- template<typename U>
- static No f(...);
-
- enum { value = Evaluate<sizeof(f<T>(0))>::value };
-};
-
class CollectionItemTypeBase;
template<typename T>
private:
typedef std::map<std::string, Variant> ItemMap;
typedef std::list<CollectionItemTypeBase *> TypeList;
- typedef std::list<CollectionSource *> SourceList;
+ typedef std::list<const CollectionSource *> SourceList;
TypeList types;
ItemMap items;
T &get(const std::string &name)
{
typedef typename RemoveConst<T>::Type NCT;
- return extract<NCT>(get_var(name, get_type<NCT>()));
+ return extract<NCT>(get_var(name, get_type<NCT>(name)));
}
private:
template<typename T>
CollectionItemType<T> &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();
+
private:
- /// 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. An
+ optional name can be given to prioritize matching types. */
template<typename T>
- CollectionItemTypeBase *get_type() const;
+ CollectionItemTypeBase *get_type(const std::string & = std::string()) const;
+
+ /// Gets a descriptor with the same type as another descriptor.
+ CollectionItemTypeBase *get_type(const CollectionItemTypeBase &) const;
/// Returns the descriptor for an item, or null if it's of an unknown type.
CollectionItemTypeBase *get_type_for_item(const Variant &) const;
protected:
/** Adds a source for automatically loading items. Sources are consulted
in the order they are added. */
- void add_source(CollectionSource &);
+ void add_source(const CollectionSource &);
public:
/** Opens a raw resource, without interpreting it as object data. Null is
IO::Seekable *open_raw(const std::string &) const;
protected:
- IO::Seekable *open_from_sources(const std::string &n) { return open_raw(n); }
+ // Deprecated. Use open_raw instead.
+ DEPRECATED IO::Seekable *open_from_sources(const std::string &n) { return open_raw(n); }
private:
void gather_names_from_sources(std::list<std::string> &, const CollectionItemTypeBase &) const;
/** Sets a fallback collection, which will be consulted if an item is not
found. */
void set_fallback(Collection *);
+
+ Collection *get_fallback() const { return fallback; }
};
template<typename T>
return *this;
}
- /** Adds a suffix that is used to match names when looking for future
+ /** Adds a suffix that is used to match names when looking for loadable
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. */
}
template<typename T>
-CollectionItemTypeBase *Collection::get_type() const
+CollectionItemType<T> &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
{
for(TypeList::const_iterator j=types.begin(); j!=types.end(); ++j)
if(dynamic_cast<CollectionItemType<T> *>(*j))
return *j;
+ CollectionItemTypeBase *type = 0;
for(TypeList::const_iterator j=types.begin(); j!=types.end(); ++j)
if((*j)->can_extract<T>())
- return *j;
- return 0;
+ {
+ if(!name.empty() && (*j)->match_name(name))
+ return *j;
+ type = *j;
+ }
+ return type;
}
} // namespace DataFile