]> git.tdb.fi Git - libs/datafile.git/blob - source/dynamicobjectloader.h
Add a class for loading dynamically typed objects
[libs/datafile.git] / source / dynamicobjectloader.h
1 #ifndef MSP_DATAFILE_DYNAMICOBJECTLOADER_H_
2 #define MSP_DATAFILE_DYNAMICOBJECTLOADER_H_
3
4 #include <msp/core/typeregistry.h>
5 #include "except.h"
6 #include "loader.h"
7
8 namespace Msp {
9 namespace DataFile {
10
11 class Collection;
12
13 /**
14 Loads a dynamically typed object, with the type specified as a statement.  The
15 T template parameter is the common base class for all possible loaded types.
16 */
17 template<typename T, typename C = Collection>
18 class DynamicObjectLoader: public Loader
19 {
20 public:
21         typedef C Collection;
22
23 protected:
24         template<typename U>
25         struct CreateObject
26         {
27                 void operator()(const std::string &, DynamicObjectLoader &) const;
28         };
29
30         typedef Msp::TypeRegistry<CreateObject, DynamicObjectLoader &> TypeRegistry;
31
32         Collection *coll;
33 private:
34         T *object;
35         Loader *obj_loader;
36
37         static ActionMap shared_actions;
38
39 protected:
40         DynamicObjectLoader(Collection *);
41 public:
42         ~DynamicObjectLoader() { delete object; delete obj_loader; }
43
44         T *get_object() { T *o = object; object = 0; return o; }
45 private:
46         virtual void init_actions();
47
48         void type(const Symbol &);
49
50         template<typename U>
51         typename std::enable_if<NeedsCollection<typename U::Loader>::value, typename U::Loader *>::type create_object_loader(U &obj) const;
52
53         template<typename U>
54         typename std::enable_if<!NeedsCollection<typename U::Loader>::value, typename U::Loader *>::type create_object_loader(U &obj) const;
55
56 protected:
57         virtual const TypeRegistry &get_type_registry() const = 0;
58 };
59
60
61 template<typename T, typename C>
62 Loader::ActionMap DynamicObjectLoader<T, C>::shared_actions;
63
64 template<typename T, typename C>
65 DynamicObjectLoader<T, C>::DynamicObjectLoader(Collection *c):
66         coll(c),
67         object(0),
68         obj_loader(0)
69 {
70         set_actions(shared_actions);
71 }
72
73 template<typename T, typename C>
74 void DynamicObjectLoader<T, C>::init_actions()
75 {
76         add("type", &DynamicObjectLoader::type);
77 }
78
79 template<typename T, typename C>
80 void DynamicObjectLoader<T, C>::type(const Symbol &t)
81 {
82         if(obj_loader)
83                 throw std::logic_error("duplicate type statement");
84
85         get_type_registry().invoke(t.name, *this);
86 }
87
88 template<typename T, typename C>
89 template<typename U>
90 typename std::enable_if<NeedsCollection<typename U::Loader>::value, typename U::Loader *>::type DynamicObjectLoader<T, C>::create_object_loader(U &obj) const
91 {
92         if(!coll)
93                 throw no_collection(typeid(U));
94         return new typename U::Loader(obj, *coll);
95 }
96
97 template<typename T, typename C>
98 template<typename U>
99 typename std::enable_if<!NeedsCollection<typename U::Loader>::value, typename U::Loader *>::type DynamicObjectLoader<T, C>::create_object_loader(U &obj) const
100 {
101         return new typename U::Loader(obj);
102 }
103
104
105 template<typename T, typename C>
106 template<typename U>
107 void DynamicObjectLoader<T, C>::CreateObject<U>::operator()(const std::string &, DynamicObjectLoader &ldr) const
108 {
109         U *obj = new U;
110         ldr.object = obj;
111         ldr.obj_loader = ldr.create_object_loader<U>(*obj);
112         ldr.add_auxiliary_loader(*ldr.obj_loader);
113 }
114
115 } // namespace DataFile
116 } // namespace Msp
117
118 #endif