]> git.tdb.fi Git - libs/datafile.git/commitdiff
Add a class for loading dynamically typed objects
authorMikko Rasa <tdb@tdb.fi>
Tue, 5 Oct 2021 10:55:37 +0000 (13:55 +0300)
committerMikko Rasa <tdb@tdb.fi>
Tue, 5 Oct 2021 10:58:45 +0000 (13:58 +0300)
source/dynamicobjectloader.h [new file with mode: 0644]

diff --git a/source/dynamicobjectloader.h b/source/dynamicobjectloader.h
new file mode 100644 (file)
index 0000000..c83d914
--- /dev/null
@@ -0,0 +1,118 @@
+#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