]> git.tdb.fi Git - libs/datafile.git/blob - source/loader.h
7799a7eacb5dd404915f25cbfe87f0665f515436
[libs/datafile.git] / source / loader.h
1 #ifndef MSP_DATAFILE_LOADER_H_
2 #define MSP_DATAFILE_LOADER_H_
3
4 #include <map>
5 #include <msp/io/file.h>
6 #include "loaderaction.h"
7 #include "meta.h"
8 #include "parser.h"
9 #include "statement.h"
10
11 namespace Msp {
12 namespace DataFile {
13
14 /**
15 Base class for data loaders.  This class only provides core functionality.
16 You'll almost certainly want to use one of the BasicLoader classes instead.
17
18 Under normal circumstances, a class capable of being loaded should have a
19 nested typed called Loader which resolves to a descendant of this class.  If
20 another structure is used, the loader object must be constructed manually.
21
22 A loader class should execute one or more calls to the various add() functions
23 to register actions with expected keywords.  Currently possible actions are
24 calling a function of the loader, storing values in member variables of an
25 object and ignoring the statement.  If a unexpected keyword is encountered, an
26 exception is thrown and the loading is aborted.
27
28 A sub-object can be loaded with one of the load_sub functions.
29
30 When loading has finished successfully, the virtual function finish() is
31 called.  Any post-processing of the data should be placed here and not in the
32 destructor.
33
34 See also classes ObjectLoader and CollectionObjectLoader in objectloader.h.
35 */
36 class Loader
37 {
38 private:
39         typedef std::map<StatementKey, LoaderAction *> ActionMap;
40
41         ActionMap actions;
42         Parser *cur_parser;
43         unsigned cur_level;
44         const Statement *cur_st;
45         bool sub_loaded;
46         bool direct;
47         std::vector<Loader *> aux_loaders;
48 protected:
49         bool check_sub_loads;
50
51         Loader();
52 public:
53         virtual ~Loader();
54
55         /** Loads statements from a parser. */
56         void load(Parser &p);
57
58 private:
59         /** Loads data from a statement. */
60         void load(const Statement &st);
61
62         /** Loads statemsnts from a parser, feeding them directly to actions. */
63         void load_direct(Parser &, unsigned);
64
65         /** Processes a single statement */
66         void load_statement(const Statement &st);
67
68 protected:
69         /** Loads a sub-object from the statement being processed.  The Loader class
70         of the sub-object is automatically used. */
71         template<typename S>
72         void load_sub(S &s)
73         {
74                 typename S::Loader ldr(s);
75                 load_sub_with(ldr);
76         }
77
78         /** Loads a sub-object from the statement being processed with an extra
79         parameter for the Loader.  The Loader class of the sub-object is
80         automatically used. */
81         template<typename S, typename T>
82         void load_sub(S &s, T &p)
83         {
84                 typename S::Loader ldr(s, p);
85                 load_sub_with(ldr);
86         }
87
88         /** Processes the current statement's substatements with another Loader. */
89         void load_sub_with(Loader &);
90
91         /** Adds a keyword that is loaded by calling a function. */
92         template<typename L>
93         void add(const std::string &k, void (L::*func)())
94         { add(k, new LoaderFunc0<L>(func)); }
95
96         template<typename L, typename A0>
97         void add(const std::string &k, void (L::*func)(A0))
98         { add(k, new LoaderFunc1<L, A0>(func)); }
99
100 #if __cplusplus>=201103L
101         template<typename L, typename... Args>
102         void add(const std::string &k, void (L::*func)(Args...))
103         { add(k, new LoaderFuncN<L, Args...>(func)); }
104
105 #else
106         template<typename L, typename A0, typename A1>
107         void add(const std::string &k, void (L::*func)(A0, A1))
108         { add(k, new LoaderFunc2<L, A0, A1>(func)); }
109
110         template<typename L, typename A0, typename A1, typename A2>
111         void add(const std::string &k, void (L::*func)(A0, A1, A2))
112         { add(k, new LoaderFunc3<L, A0, A1, A2>(func)); }
113
114         template<typename L, typename A0, typename A1, typename A2, typename A3>
115         void add(const std::string &k, void (L::*func)(A0, A1, A2, A3))
116         { add(k, new LoaderFunc4<L, A0, A1, A2, A3>(func)); }
117
118         template<typename L, typename A0, typename A1, typename A2, typename A3, typename A4>
119         void add(const std::string &k, void (L::*func)(A0, A1, A2, A3, A4))
120         { add(k, new LoaderFunc5<L, A0, A1, A2, A3, A4>(func)); }
121 #endif
122
123 #if __cplusplus>=201103L
124         /** Adds a keyword that is loaded by calling a function with a bound
125         first argument. */
126         template<typename L, typename B0, typename... Args>
127         void add(const std::string &k, void (L::*func)(B0, Args...), const typename RemoveReference<B0>::Type &b0)
128         { add(k, new LoaderFuncNBound1<L, B0, Args...>(func, b0)); }
129 #endif
130
131         /** Adds a keyword that is loaded into a member of the loaded object. */
132         template<typename L, typename T0>
133         void add(const std::string &k, T0 L::*p0)
134         { add(k, new LoadValue1<L, T0>(p0)); }
135
136         template<typename L, typename T0, typename T1>
137         void add(const std::string &k, T0 L::*p0, T1 L::*p1)
138         { add(k, new LoadValue2<L, T0, T1>(p0, p1)); }
139
140         /** Adds a keyword that is recognized but ignored. */
141         void add(const std::string &k)
142         { add(k, 0); }
143
144 private:
145         void add(const std::string &, LoaderAction *);
146
147 protected:
148         void add_auxiliary_loader(Loader &);
149
150 private:
151         bool has_action(const StatementKey &) const;
152         LoaderAction *find_action(const StatementKey &) const;
153
154 protected:
155         /** Returns the source of the statement being processed.  This can be used
156         to implement relative paths in include-like statements.  Note that the
157         source may not necessarily be a file. */
158         const std::string &get_source() const;
159
160         /** Returns the keyword of the statement being processed.  Can be used to
161         implement dynamic keywords. */
162         const std::string &get_keyword() const;
163
164         virtual void finish() { }
165 };
166
167
168 #if __cplusplus>=201103L
169 /**
170 Loads an object from a file.  The object must have a public Loader class.  Any
171 extra arguments are passed to the Loader constructor.
172 */
173 template<typename T, typename... Args>
174 void load(T &obj, const std::string &fn, Args &... args)
175 {
176         IO::BufferedFile in(fn);
177
178         Parser parser(in, fn);
179         typename T::Loader loader(obj, args...);
180         loader.load(parser);
181 }
182
183 /**
184 Loads an object from a file stored in a collection.  The object must havea
185 public Loader class.  The collection is passed to the Loader constructor,
186 followed by any extra arguments.
187 */
188 template<typename T, typename... Args>
189 void load(T &obj, typename T::Loader::Collection &coll, const std::string &fn, Args &... args)
190 {
191         RefPtr<IO::Seekable> in = coll.open_raw(fn);
192         if(!in)
193                 throw IO::file_not_found(fn);
194
195         Parser parser(*in, fn);
196         typename T::Loader loader(obj, coll, args...);
197         loader.load(parser);
198 }
199
200 /**
201 Loads an object from a file stored in a collection.  The object must havea
202 public Loader class.  Any extra arguments are passed to the Loader constructor.
203 */
204 template<typename T, typename C, typename... Args>
205 typename EnableIf<NeedsCollection<typename T::Loader>::value, void>::No load(T &obj, C &coll, const std::string &fn, Args &... args)
206 {
207         RefPtr<IO::Seekable> in = coll.open_raw(fn);
208         if(!in)
209                 throw IO::file_not_found(fn);
210
211         Parser parser(*in, fn);
212         typename T::Loader loader(obj, args...);
213         loader.load(parser);
214 }
215
216 #else
217
218 /**
219 Loads an object from a file.  The object must have a public Loader class.
220 */
221 template<typename T>
222 void load(T &obj, const std::string &fn)
223 {
224         IO::BufferedFile in(fn);
225
226         Parser parser(in, fn);
227         typename T::Loader loader(obj);
228         loader.load(parser);
229 }
230
231 /**
232 Loads an object from a file, passing one extra argument to the Loader
233 constructor.  The object must have a public Loader class.
234 */
235 template<typename T, typename U>
236 void load(T &obj, const std::string &fn, U &arg)
237 {
238         IO::BufferedFile in(fn);
239
240         Parser parser(in, fn);
241         typename T::Loader loader(obj, arg);
242         loader.load(parser);
243 }
244 #endif
245
246 } // namespace DataFile
247 } // namespace Msp
248
249 #endif