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