--- /dev/null
+#ifndef MSP_DATAFILE_DYNAMICOBJECTLOADER_H_
+#define MSP_DATAFILE_DYNAMICOBJECTLOADER_H_
+
+#include <msp/core/typeregistry.h>
+#include "except.h"
+#include "loader.h"
+
+namespace Msp {
+namespace DataFile {
+
+class Collection;
+
+/**
+Loads a dynamically typed object, with the type specified as a statement. The
+T template parameter is the common base class for all possible loaded types.
+*/
+template<typename T, typename C = Collection>
+class DynamicObjectLoader: public Loader
+{
+public:
+ typedef C Collection;
+
+protected:
+ template<typename U>
+ struct CreateObject
+ {
+ void operator()(const std::string &, DynamicObjectLoader &) const;
+ };
+
+ typedef Msp::TypeRegistry<CreateObject, DynamicObjectLoader &> TypeRegistry;
+
+ Collection *coll;
+private:
+ T *object;
+ Loader *obj_loader;
+
+ static ActionMap shared_actions;
+
+protected:
+ DynamicObjectLoader(Collection *);
+public:
+ ~DynamicObjectLoader() { delete object; delete obj_loader; }
+
+ T *get_object() { T *o = object; object = 0; return o; }
+private:
+ virtual void init_actions();
+
+ void type(const Symbol &);
+
+ template<typename U>
+ typename std::enable_if<NeedsCollection<typename U::Loader>::value, typename U::Loader *>::type create_object_loader(U &obj) const;
+
+ template<typename U>
+ typename std::enable_if<!NeedsCollection<typename U::Loader>::value, typename U::Loader *>::type create_object_loader(U &obj) const;
+
+protected:
+ virtual const TypeRegistry &get_type_registry() const = 0;
+};
+
+
+template<typename T, typename C>
+Loader::ActionMap DynamicObjectLoader<T, C>::shared_actions;
+
+template<typename T, typename C>
+DynamicObjectLoader<T, C>::DynamicObjectLoader(Collection *c):
+ coll(c),
+ object(0),
+ obj_loader(0)
+{
+ set_actions(shared_actions);
+}
+
+template<typename T, typename C>
+void DynamicObjectLoader<T, C>::init_actions()
+{
+ add("type", &DynamicObjectLoader::type);
+}
+
+template<typename T, typename C>
+void DynamicObjectLoader<T, C>::type(const Symbol &t)
+{
+ if(obj_loader)
+ throw std::logic_error("duplicate type statement");
+
+ get_type_registry().invoke(t.name, *this);
+}
+
+template<typename T, typename C>
+template<typename U>
+typename std::enable_if<NeedsCollection<typename U::Loader>::value, typename U::Loader *>::type DynamicObjectLoader<T, C>::create_object_loader(U &obj) const
+{
+ if(!coll)
+ throw no_collection(typeid(U));
+ return new typename U::Loader(obj, *coll);
+}
+
+template<typename T, typename C>
+template<typename U>
+typename std::enable_if<!NeedsCollection<typename U::Loader>::value, typename U::Loader *>::type DynamicObjectLoader<T, C>::create_object_loader(U &obj) const
+{
+ return new typename U::Loader(obj);
+}
+
+
+template<typename T, typename C>
+template<typename U>
+void DynamicObjectLoader<T, C>::CreateObject<U>::operator()(const std::string &, DynamicObjectLoader &ldr) const
+{
+ U *obj = new U;
+ ldr.object = obj;
+ ldr.obj_loader = ldr.create_object_loader<U>(*obj);
+ ldr.add_auxiliary_loader(*ldr.obj_loader);
+}
+
+} // namespace DataFile
+} // namespace Msp
+
+#endif