]> git.tdb.fi Git - libs/datafile.git/blob - source/loader.h
Add reverse name lookup to Collection
[libs/datafile.git] / source / loader.h
1 /* $Id$
2
3 This file is part of libmspdatafile
4 Copyright © 2006  Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7
8 #ifndef MSP_DATAFILE_LOADER_H_
9 #define MSP_DATAFILE_LOADER_H_
10
11 #include <map>
12 #include <msp/io/buffered.h>
13 #include <msp/io/file.h>
14 #include "except.h"
15 #include "parser.h"
16 #include "statement.h"
17 #include "value.h"
18
19 namespace Msp {
20 namespace DataFile {
21
22 class Loader;
23 class Statement;
24
25 /**
26 Base class for loader actions.
27 */
28 class LoaderAction
29 {
30 public:
31         /**
32         Called when a statement is to be loaded.
33         */
34         virtual void execute(Loader &, const Statement &) const=0;
35         virtual ~LoaderAction() { }
36 protected:
37         LoaderAction() { }
38 };
39
40
41 /**
42 Loads a statement by calling a function that takes no arguments.
43 */
44 template<typename L>
45 class LoaderFunc0: public LoaderAction
46 {
47 public:
48         typedef void (L::*FuncType)();
49
50         LoaderFunc0(FuncType f): func(f) { }
51         void execute(Loader &l, const Statement &st) const
52         {
53                 if(st.args.size()!=0) throw TypeError(st.get_location()+": Wrong number of arguments");
54                 (dynamic_cast<L &>(l).*func)();
55         };
56 private:
57         FuncType func;
58 };
59
60
61 /**
62 Loads a statement by calling a function that takes one argument.
63 */
64 template<typename L, typename A0>
65 class LoaderFunc1: public LoaderAction
66 {
67 public:
68         typedef void (L::*FuncType)(A0);
69
70         LoaderFunc1(FuncType f): func(f) { }
71         void execute(Loader &l, const Statement &st) const
72         {
73                 if(st.args.size()!=1) throw TypeError(st.get_location()+": Wrong number of arguments");
74                 (dynamic_cast<L &>(l).*func)(st.args[0].get<A0>());
75         }
76 private:
77         FuncType func;
78 };
79
80
81 /**
82 Loads a statement by calling a function that takes an array of values.
83 */
84 template<typename L, typename A0>
85 class LoaderFunc1<L, const std::vector<A0> &>: public LoaderAction
86 {
87 public:
88         typedef void (L::*FuncType)(const std::vector<A0> &);
89
90         LoaderFunc1(FuncType f): func(f) { }
91         void execute(Loader &l, const Statement &st) const
92         {
93                 std::vector<A0> values;
94                 values.reserve(st.args.size());
95                 for(ValueArray::const_iterator i=st.args.begin(); i!=st.args.end(); ++i)
96                         values.push_back(i->get<A0>());
97                 (dynamic_cast<L &>(l).*func)(values);
98         }
99 private:
100         FuncType func;
101 };
102
103
104 template<typename L, typename A0, typename A1>
105 class LoaderFunc2: public LoaderAction
106 {
107 public:
108         typedef void (L::*FuncType)(A0, A1);
109
110         LoaderFunc2(FuncType f): func(f) { }
111         void execute(Loader &l, const Statement &st) const
112         {
113                 if(st.args.size()!=2) throw TypeError(st.get_location()+": Wrong number of arguments");
114                 (dynamic_cast<L &>(l).*func)(st.args[0].get<A0>(), st.args[1].get<A1>());
115         }
116 private:
117         FuncType func;
118 };
119
120
121 template<typename L, typename A0, typename A1, typename A2>
122 class LoaderFunc3: public LoaderAction
123 {
124 public:
125         typedef void (L::*FuncType)(A0, A1, A2);
126
127         LoaderFunc3(FuncType f): func(f) { }
128         void execute(Loader &l, const Statement &st) const
129         {
130                 if(st.args.size()!=3) throw TypeError(st.get_location()+": Wrong number of arguments");
131                 (dynamic_cast<L &>(l).*func)(st.args[0].get<A0>(), st.args[1].get<A1>(), st.args[2].get<A2>());
132         }
133 private:
134         FuncType func;
135 };
136
137
138 template<typename L, typename A0, typename A1, typename A2, typename A3>
139 class LoaderFunc4: public LoaderAction
140 {
141 public:
142         typedef void (L::*FuncType)(A0, A1, A2, A3);
143
144         LoaderFunc4(FuncType f): func(f) { }
145         void execute(Loader &l, const Statement &st) const
146         {
147                 if(st.args.size()!=4) throw TypeError(st.get_location()+": Wrong number of arguments");
148                 (dynamic_cast<L &>(l).*func)(st.args[0].get<A0>(), st.args[1].get<A1>(), st.args[2].get<A2>(), st.args[3].get<A3>());
149         }
150 private:
151         FuncType func;
152 };
153
154
155 template<typename L, typename A0, typename A1, typename A2, typename A3, typename A4>
156 class LoaderFunc5: public LoaderAction
157 {
158 public:
159         typedef void (L::*FuncType)(A0, A1, A2, A3, A4);
160
161         LoaderFunc5(FuncType f): func(f) { }
162         void execute(Loader &l, const Statement &st) const
163         {
164                 if(st.args.size()!=5) throw TypeError(st.get_location()+": Wrong number of arguments");
165                 (dynamic_cast<L &>(l).*func)(st.args[0].get<A0>(), st.args[1].get<A1>(), st.args[2].get<A2>(), st.args[3].get<A3>(), st.args[4].get<A4>());
166         }
167 private:
168         FuncType func;
169 };
170
171
172 template<typename L, typename T0>
173 class LoadValue1: public LoaderAction
174 {
175 public:
176         typedef T0 L::*Pointer0Type;
177
178         LoadValue1(Pointer0Type p0): ptr0(p0) { }
179         void execute(Loader &l, const Statement &st) const
180         {
181                 if(st.args.size()!=1) throw TypeError(st.get_location()+": Wrong number of arguments");
182                 dynamic_cast<typename L::Loader &>(l).get_object().*ptr0=st.args[0].get<T0>();
183         }
184 private:
185         Pointer0Type ptr0;
186 };
187
188
189 template<typename L, typename T0>
190 class LoadValue1<L, T0 *>: public LoaderAction
191 {
192 public:
193         typedef T0 *L::*Pointer0Type;
194
195         LoadValue1(Pointer0Type p0): ptr0(p0) { }
196         void execute(Loader &l, const Statement &st) const
197         {
198                 if(st.args.size()!=1) throw TypeError(st.get_location()+": Wrong number of arguments");
199                 typename L::Loader &ldr=dynamic_cast<typename L::Loader &>(l);
200                 ldr.get_object().*ptr0=ldr.get_collection().template get<T0>(st.args[0].get<std::string>());
201         }
202 private:
203         Pointer0Type ptr0;
204 };
205
206
207 template<typename L, typename T0, typename T1>
208 class LoadValue2: public LoaderAction
209 {
210 public:
211         typedef T0 L::*Pointer0Type;
212         typedef T1 L::*Pointer1Type;
213
214         LoadValue2(Pointer0Type p0, Pointer1Type p1): ptr0(p0), ptr1(p1) { }
215         void execute(Loader &l, const Statement &st) const
216         {
217                 if(st.args.size()!=2) throw TypeError(st.get_location()+": Wrong number of arguments");
218                 dynamic_cast<typename L::Loader &>(l).get_object().*ptr0=st.args[0].get<T0>();
219                 dynamic_cast<typename L::Loader &>(l).get_object().*ptr1=st.args[1].get<T1>();
220         }
221 private:
222         Pointer0Type ptr0;
223         Pointer1Type ptr1;
224 };
225
226
227 /**
228 Base class for data loaders.  To give loading capabilities to a class, create a
229 public Loader class in it, derived from this class.  Typically a loader object
230 contains a reference to the loaded object.  To make use of loading directly
231 into data members, the Loader class must have a get_object() member function,
232 returning that reference.  If direct loading of pointers is desired, the Loader
233 class must also have a get_collection() member function, returning a collection
234 to get pointers from.
235 */
236 class Loader
237 {
238 public:
239         /**
240         Loads data from a statement.  This is normally only used by the Loader class
241         itself for loading sub-items, but needs to be public so it can be accessed
242         in derived objects.
243         */
244         void load(const Statement &st);
245
246         /**
247         Loads statements from a parser.
248         */
249         void load(Parser &p);
250
251         virtual ~Loader();
252 protected:
253         Loader(): cur_st(0) { }
254
255         /**
256         Adds a keyword that is loaded with a zero-argument function.
257         */
258         template<typename L>
259         void add(const std::string &k, void (L::*func)())
260         { add(k, new LoaderFunc0<L>(func)); }
261
262         template<typename L, typename A0>
263         void add(const std::string &k, void (L::*func)(A0))
264         { add(k, new LoaderFunc1<L, A0>(func)); }
265
266         template<typename L, typename A0, typename A1>
267         void add(const std::string &k, void (L::*func)(A0, A1))
268         { add(k, new LoaderFunc2<L, A0, A1>(func)); }
269
270         template<typename L, typename A0, typename A1, typename A2>
271         void add(const std::string &k, void (L::*func)(A0, A1, A2))
272         { add(k, new LoaderFunc3<L, A0, A1, A2>(func)); }
273
274         template<typename L, typename A0, typename A1, typename A2, typename A3>
275         void add(const std::string &k, void (L::*func)(A0, A1, A2, A3))
276         { add(k, new LoaderFunc4<L, A0, A1, A2, A3>(func)); }
277
278         template<typename L, typename A0, typename A1, typename A2, typename A3, typename A4>
279         void add(const std::string &k, void (L::*func)(A0, A1, A2, A3, A4))
280         { add(k, new LoaderFunc5<L, A0, A1, A2, A3, A4>(func)); }
281
282         /**
283         Adds a keyword that is loaded into a variable of the loaded object.
284         */
285         template<typename L, typename T0>
286         void add(const std::string &k, T0 L::*p0)
287         { add(k, new LoadValue1<L, T0>(p0)); }
288
289         template<typename L, typename T0, typename T1>
290         void add(const std::string &k, T0 L::*p0, T1 L::*p1)
291         { add(k, new LoadValue2<L, T0, T1>(p0, p1)); }
292
293         /**
294         Adds a keyword that is recognized but ignored.
295         */
296         void add(const std::string &k)
297         { add(k, 0); }
298
299         /**
300         Loads a sub-object from the statement being processed.  The Loader class of
301         the sub-object is automatically used.
302         */
303         template<typename S>
304         void load_sub(S &s)
305         {
306                 typename S::Loader ldr(s);
307                 load_sub_with(ldr);
308         }
309
310         /**
311         Loads a sub-object from the statement being processed with an extra parameter
312         for the Loader.  The Loader class of the sub-object is automatically used.
313         */
314         template<typename S, typename T>
315         void load_sub(S &s, T &p)
316         {
317                 typename S::Loader ldr(s, p);
318                 load_sub_with(ldr);
319         }
320
321         /**
322         Processes the current statement's substatements with another Loader.
323         */
324         void load_sub_with(Loader &);
325
326         /**
327         Returns the source of the statement being processed.  This can be used to
328         implement relative paths in include-like statements.  Note that the source
329         may not necessarily be a file.
330         */
331         const std::string &get_source() const
332         {
333                 if(!cur_st)
334                         throw InvalidState("get_source called without current statement");
335                 return cur_st->source;
336         }
337
338         virtual void finish() { }
339 private:
340         typedef std::map<std::string, LoaderAction *> ActionMap;
341
342         ActionMap       actions;
343         const Statement *cur_st;
344
345         void add(const std::string &, LoaderAction *);
346         void load_statement(const Statement &st);
347 };
348
349 /**
350 Loads an object from a file.  The object must have a public Loader class.
351 */
352 template<typename T>
353 void load(T &obj, const std::string &fn)
354 {
355         IO::File in(fn);
356         IO::Buffered buf(in);
357
358         Parser parser(buf, fn);
359         typename T::Loader loader(obj);
360         loader.load(parser);
361 }
362
363 template<typename T, typename U>
364 void load(T &obj, const std::string &fn, U &arg)
365 {
366         IO::File in(fn);
367         IO::Buffered buf(in);
368
369         Parser parser(in, fn);
370         typename T::Loader loader(obj, arg);
371         loader.load(parser);
372 }
373
374 } // namespace DataFile
375 } // namespace Msp
376
377 #endif