]> git.tdb.fi Git - libs/datafile.git/blob - source/loader.h
Require C++11 for building
[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: private NonCopyable
37 {
38 protected:
39         class ActionMap: public std::map<StatementKey, LoaderAction *>, private NonCopyable
40         {
41         public:
42                 ~ActionMap();
43         };
44
45 private:
46         ActionMap local_actions;
47         ActionMap *actions;
48         Parser *cur_parser;
49         unsigned cur_level;
50         const Statement *cur_st;
51         bool sub_loaded;
52         bool direct;
53         std::vector<Loader *> aux_loaders;
54 protected:
55         bool check_sub_loads;
56
57         Loader();
58 public:
59         virtual ~Loader() { }
60
61         /** Loads statements from a parser. */
62         void load(Parser &p);
63
64 private:
65         /** Loads data from a statement. */
66         void load(const Statement &st);
67
68         /** Loads statemsnts from a parser, feeding them directly to actions. */
69         void load_direct(Parser &, unsigned);
70
71         /** Processes a single statement */
72         void load_statement(const Statement &st);
73
74 protected:
75         /** Loads a sub-object from the statement being processed.  The Loader class
76         of the sub-object is automatically used. */
77         template<typename S>
78         void load_sub(S &s)
79         {
80                 typename S::Loader ldr(s);
81                 load_sub_with(ldr);
82         }
83
84         /** Loads a sub-object from the statement being processed with an extra
85         parameter for the Loader.  The Loader class of the sub-object is
86         automatically used. */
87         template<typename S, typename T>
88         void load_sub(S &s, T &p)
89         {
90                 typename S::Loader ldr(s, p);
91                 load_sub_with(ldr);
92         }
93
94         /** Processes the current statement's substatements with another Loader. */
95         void load_sub_with(Loader &);
96
97         /** Sets the actions to be used when loading.  If the map is empty,
98         init_actions will be called. */
99         void set_actions(ActionMap &);
100         virtual void init_actions() { }
101
102         /** Adds a keyword that is loaded by calling a function. */
103         template<typename L>
104         void add(const std::string &k, void (L::*func)())
105         { add(k, new LoaderFunc0<L>(func)); }
106
107         template<typename L, typename A0>
108         void add(const std::string &k, void (L::*func)(A0))
109         { add(k, new LoaderFunc1<L, A0>(func)); }
110
111         template<typename L, typename... Args>
112         void add(const std::string &k, void (L::*func)(Args...))
113         { add(k, new LoaderFuncN<L, Args...>(func)); }
114
115         /** Adds a keyword that is loaded by calling a function with a bound
116         first argument. */
117         template<typename L, typename B0, typename... Args>
118         void add(const std::string &k, void (L::*func)(B0, Args...), const typename RemoveReference<B0>::Type &b0)
119         { add(k, new LoaderFuncNBound1<L, B0, Args...>(func, b0)); }
120
121         /** Adds a keyword that is loaded into a member of the loaded object. */
122         template<typename L, typename T0>
123         void add(const std::string &k, T0 L::*p0)
124         { add(k, new LoadValue1<L, T0>(p0)); }
125
126         template<typename L, typename T0, typename T1>
127         void add(const std::string &k, T0 L::*p0, T1 L::*p1)
128         { add(k, new LoadValue2<L, T0, T1>(p0, p1)); }
129
130         /** Adds a keyword that is recognized but ignored. */
131         void add(const std::string &k)
132         { add(k, 0); }
133
134 private:
135         void add(const std::string &, LoaderAction *);
136
137 protected:
138         void add_auxiliary_loader(Loader &);
139
140 private:
141         bool has_action(const StatementKey &) const;
142         LoaderAction *find_action(const StatementKey &) const;
143
144 protected:
145         /** Returns the source of the statement being processed.  This can be used
146         to implement relative paths in include-like statements.  Note that the
147         source may not necessarily be a file. */
148         const std::string &get_source() const;
149
150         /** Returns the keyword of the statement being processed.  Can be used to
151         implement dynamic keywords. */
152         const std::string &get_keyword() const;
153
154         virtual void finish() { }
155 };
156
157
158 /**
159 Loads an object from a file.  The object must have a public Loader class.  Any
160 extra arguments are passed to the Loader constructor.
161 */
162 template<typename T, typename... Args>
163 void load(T &obj, const std::string &fn, Args &... args)
164 {
165         IO::BufferedFile in(fn);
166
167         Parser parser(in, fn);
168         typename T::Loader loader(obj, args...);
169         loader.load(parser);
170 }
171
172 /**
173 Loads an object from a file stored in a collection.  The object must have a
174 public Loader class.  The collection is passed to the Loader constructor,
175 followed by any extra arguments.
176 */
177 template<typename T, typename... Args>
178 void load(T &obj, typename T::Loader::Collection &coll, const std::string &fn, Args &... args)
179 {
180         RefPtr<IO::Seekable> in = coll.open_raw(fn);
181         if(!in)
182                 throw IO::file_not_found(fn);
183
184         Parser parser(*in, fn);
185         typename T::Loader loader(obj, coll, args...);
186         loader.load(parser);
187 }
188
189 /**
190 Loads an object from a file stored in a collection.  The object must havea
191 public Loader class.  Any extra arguments are passed to the Loader constructor.
192 */
193 template<typename T, typename C, typename... Args>
194 typename EnableIf<NeedsCollection<typename T::Loader>::value, void>::No load(T &obj, C &coll, const std::string &fn, Args &... args)
195 {
196         RefPtr<IO::Seekable> in = coll.open_raw(fn);
197         if(!in)
198                 throw IO::file_not_found(fn);
199
200         Parser parser(*in, fn);
201         typename T::Loader loader(obj, args...);
202         loader.load(parser);
203 }
204
205 } // namespace DataFile
206 } // namespace Msp
207
208 #endif