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