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