1 #ifndef Corrade_Utility_TweakableParser_h
2 #define Corrade_Utility_TweakableParser_h
3 /*
4     This file is part of Corrade.
5 
6     Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016,
7                 2017, 2018, 2019, 2020 Vladimír Vondruš <mosra@centrum.cz>
8 
9     Permission is hereby granted, free of charge, to any person obtaining a
10     copy of this software and associated documentation files (the "Software"),
11     to deal in the Software without restriction, including without limitation
12     the rights to use, copy, modify, merge, publish, distribute, sublicense,
13     and/or sell copies of the Software, and to permit persons to whom the
14     Software is furnished to do so, subject to the following conditions:
15 
16     The above copyright notice and this permission notice shall be included
17     in all copies or substantial portions of the Software.
18 
19     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22     THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25     DEALINGS IN THE SOFTWARE.
26 */
27 
28 /** @file
29  * @brief Class @ref Corrade::Utility::TweakableParser, enum @ref Corrade::Utility::TweakableState
30  */
31 
32 #include <utility>
33 
34 #include "Corrade/Containers/Containers.h"
35 #include "Corrade/Utility/Utility.h"
36 #include "Corrade/Utility/visibility.h"
37 
38 namespace Corrade { namespace Utility {
39 
40 /** @relatesalso Tweakable
41 @brief Parser for @ref Tweakable types
42 
43 Support for basic types that are expressible with plain literals is implemented
44 in @ref TweakableParser<int>, @ref TweakableParser<unsigned int>,
45 @ref TweakableParser<long>, @ref TweakableParser<unsigned long>,
46 @ref TweakableParser<long long>, @ref TweakableParser<unsigned long long>,
47 @ref TweakableParser<float>, @ref TweakableParser<double>,
48 @ref TweakableParser<long double> and @ref TweakableParser<char>.
49 
50 @section TweakableParser-subclassing Implementing support for custom literals
51 
52 The parser support is limited to what's expressible with C++11 user-defined
53 literals, together with an optional unary @cpp + @ce or @cpp - @ce in front.
54 Current implementation supports only trivially copyable and trivially
55 destructible types of a limited size --- in particular, saving strings is not
56 possible.
57 
58 In order to implement support for a custom type, create a (partial) template
59 specialization with a @cpp parse() @ce function with the following sigature
60 for given type `T` --- assuming there's a user-defined C++11 literal that
61 returns `T` as well:
62 
63 @snippet Utility.cpp TweakableParser
64 
65 The function gets a view onto the contents of the annotation, with outer
66 whitespace stripped (so e.g. for string literals you get also the quotes
67 around). It returns the parsed value and a parser state. The state should be
68 one of the following:
69 
70 -   @ref TweakableState::Success if parsing consumed the whole input and there
71     was no error
72 -   @ref TweakableState::Error if parsing failed and the parser is *sure* that
73     this is a compile error (and not suddenly a different type, for example
74     --- @cpp 0xa901g0f @ce might look like an error, but it could be also a
75     user-defined literal `g0f`). Examples of such errors can be unterminated
76     string/char literals or unknown escape characters in them.
77 -   @ref TweakableState::Recompile if parsing failed and the parser is *not*
78     sure that this is a compile error
79 
80 Returning @ref TweakableState::NoChange is not allowed.
81 
82 Note that the user-defined literal has to return a custom type that's not
83 already handled by the implementation. So for example a custom C++11 binary
84 literal @cpp 110110110_b @ce, returning @cpp int @ce and supplementing the
85 builtin C++14 literal @cpp 0b110110110 @ce, wouldn't be possible to implement,
86 since @ref TweakableParser<int> is already defined.
87 
88 @experimental
89 */
90 template<class T> struct TweakableParser;
91 
92 /**
93 @brief Tweakable state
94 
95 @see @ref Tweakable::update()
96 @experimental
97 */
98 enum class TweakableState: std::uint8_t {
99     /**
100      * No source file has any changes that affect tweakable values. Nothing to
101      * do.
102      */
103     NoChange = 0,
104 
105     /**
106      * Tweakable values in some source files were changed and successfully
107      * updated. Values that are neither accessed in the main event loop nor
108      * were part of any @ref Tweakable::scope() call should be updated manually
109      * on the caller side.
110      */
111     Success = 1,
112 
113     /**
114      * Source files were changed in a way that can't be handled by updating
115      * just the tweakable values alone. No values were updated, hot-reload the
116      * affected code or restart a recompiled version of the app to pick up the
117      * changes.
118      *
119      * Note that this state is optimistic --- it may happen that the changes
120      * will lead to a compile error similarly as with @ref TweakableState::Error,
121      * but detecting that is out of scope of this utility.
122      */
123     Recompile = 2,
124 
125     /**
126      * Source files were changed in a way that caused a parse error. No values
127      * were updated, fix the error and save the file again to retry the
128      * parsing.
129      *
130      * This state is returned only when the utility is absolutely sure there is
131      * a syntax error (for example when a char literal is not terminated). If
132      * not sure, @ref TweakableState::Recompile is returned (and then the
133      * compiler might or might not report an error).
134      */
135     Error = 3
136 };
137 
138 /** @debugoperatorenum{TweakableState} */
139 CORRADE_UTILITY_EXPORT Debug& operator<<(Debug& debug, TweakableState value);
140 
141 /** @relatesalso Tweakable
142 @brief Tweakable constant parser for the `int` type
143 
144 Expects literals in the form @cpp 42 @ce, @cpp 0x2a @ce, @cpp 052 @ce or
145 @cpp 0b101010 @ce, case-insensitive, with no suffixes. Unary @cpp + @ce or
146 @cpp - @ce is allowed. C++14 group separator @c ' is not supported at the
147 moment.
148 @experimental
149 */
150 template<> struct CORRADE_UTILITY_EXPORT TweakableParser<int> {
151     TweakableParser() = delete;
152 
153     /** @brief Parse the value */
154     static std::pair<TweakableState, int> parse(Containers::ArrayView<const char> value);
155 };
156 
157 /** @relatesalso Tweakable
158 @brief Tweakable constant parser for the `unsigned int` type
159 
160 Expects literals in the form @cpp 42u @ce, @cpp 0x2au @ce, @cpp 052u @ce or
161 @cpp 0b101010u @ce, case-insensitive. The `u` suffix is *not* optional, unary
162 @cpp + @ce or @cpp - @ce is allowed. C++14 group separator @c ' is not
163 supported at the moment.
164 @experimental
165 */
166 template<> struct CORRADE_UTILITY_EXPORT TweakableParser<unsigned int> {
167     TweakableParser() = delete;
168 
169     /** @brief Parse the value */
170     static std::pair<TweakableState, unsigned int> parse(Containers::ArrayView<const char> value);
171 };
172 
173 /** @relatesalso Tweakable
174 @brief Tweakable constant parser for the `long int` type
175 
176 Expects literals in the form @cpp 42l @ce, @cpp 0x2al @ce, @cpp 052l @ce or
177 @cpp 0b101010l @ce, case-insensitive. The `l` suffix is *not* optional, unary
178 @cpp + @ce or @cpp - @ce is allowed. C++14 group separator @c ' is not
179 supported at the moment.
180 @experimental
181 */
182 template<> struct CORRADE_UTILITY_EXPORT TweakableParser<long> {
183     TweakableParser() = delete;
184 
185     /** @brief Parse the value */
186     static std::pair<TweakableState, long> parse(Containers::ArrayView<const char> value);
187 };
188 
189 /** @relatesalso Tweakable
190 @brief Tweakable constant parser for the `unsigned long int` type
191 
192 Expects literals in the form @cpp 42ul @ce, @cpp 0x2aul @ce, @cpp 052ul @ce or
193 @cpp 0b101010ul @ce, case-insensitive. The `ul` suffix is *not* optional, unary
194 @cpp + @ce or @cpp - @ce is allowed. C++14 group separator @c ' is not
195 supported at the moment.
196 @experimental
197 */
198 template<> struct CORRADE_UTILITY_EXPORT TweakableParser<unsigned long> {
199     TweakableParser() = delete;
200 
201     /** @brief Parse the value */
202     static std::pair<TweakableState, unsigned long> parse(Containers::ArrayView<const char> value);
203 };
204 
205 /** @relatesalso Tweakable
206 @brief Tweakable constant parser for the `long long int` type
207 
208 Expects literals in the form @cpp 42ll @ce, @cpp 0x2all @ce, @cpp 052ll @ce or
209 @cpp 0b101010ll @ce, case-insensitive. The `ll` suffix is *not* optional, unary
210 @cpp + @ce or @cpp - @ce is allowed. C++14 group separator @c ' is not
211 supported at the moment.
212 @experimental
213 */
214 template<> struct CORRADE_UTILITY_EXPORT TweakableParser<long long> {
215     TweakableParser() = delete;
216 
217     /** @brief Parse the value */
218     static std::pair<TweakableState, long long> parse(Containers::ArrayView<const char> value);
219 };
220 
221 /** @relatesalso Tweakable
222 @brief Tweakable constant parser for the `unsigned long long int` type
223 
224 Expects literals in the form @cpp 42ull @ce, @cpp 0x2aull @ce, @cpp 052ull @ce
225 or @cpp 0b101010ull @ce, case-insensitive. The `ull` suffix is *not* optional,
226 unary @cpp + @ce or @cpp - @ce is allowed. C++14 group separator @c ' is not
227 supported at the moment.
228 @experimental
229 */
230 template<> struct CORRADE_UTILITY_EXPORT TweakableParser<unsigned long long> {
231     TweakableParser() = delete;
232 
233     /** @brief Parse the value */
234     static std::pair<TweakableState, unsigned long long> parse(Containers::ArrayView<const char> value);
235 };
236 
237 /** @relatesalso Tweakable
238 @brief Tweakable constant parser for the `float` type
239 
240 Expects literals in the form @cpp 0.42f @ce, @cpp 4.2e-1f @ce, @cpp .42f @ce
241 and variants, case-insensitive. The `f` suffix is *not* optional, unary
242 @cpp + @ce or @cpp - @ce is allowed.
243 @experimental
244 */
245 template<> struct CORRADE_UTILITY_EXPORT TweakableParser<float> {
246     TweakableParser() = delete;
247 
248     /** @brief Parse the value */
249     static std::pair<TweakableState, float> parse(Containers::ArrayView<const char> value);
250 };
251 
252 /** @relatesalso Tweakable
253 @brief Tweakable constant parser for the `double` type
254 
255 Expects literals in the form @cpp 0.42 @ce, @cpp 4.2e-1 @ce, @cpp .42 @ce
256 and variants, case-insensitive, with no suffixes. Unary @cpp + @ce or
257 @cpp - @ce is allowed.
258 @experimental
259 */
260 template<> struct CORRADE_UTILITY_EXPORT TweakableParser<double> {
261     TweakableParser() = delete;
262 
263     /** @brief Parse the value */
264     static std::pair<TweakableState, double> parse(Containers::ArrayView<const char> value);
265 };
266 
267 #ifndef CORRADE_TARGET_EMSCRIPTEN
268 /** @relatesalso Tweakable
269 @brief Tweakable constant parser for the `long double` type
270 
271 Expects literals in the form @cpp 0.42l @ce, @cpp 4.2e-1l @ce, @cpp .42l @ce
272 and variants, case-insensitive. The `l` suffix is *not* optional, unary
273 @cpp + @ce or @cpp - @ce is allowed.
274 @experimental
275 @partialsupport Not available in @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten"
276     as JavaScript doesn't support doubles larger than 64 bits.
277 */
278 template<> struct CORRADE_UTILITY_EXPORT TweakableParser<long double> {
279     TweakableParser() = delete;
280 
281     /** @brief Parse the value */
282     static std::pair<TweakableState, long double> parse(Containers::ArrayView<const char> value);
283 };
284 #endif
285 
286 /** @relatesalso Tweakable
287 @brief Tweakable constant parser for the `char` type
288 
289 Expects literals in the form @cpp 'a' @ce. Escape characters other than
290 <tt>\'</tt> and unicode char literals are not supported at the moment.
291 @experimental
292 */
293 template<> struct CORRADE_UTILITY_EXPORT TweakableParser<char> {
294     TweakableParser() = delete;
295 
296     /** @brief Parse the value */
297     static std::pair<TweakableState, char> parse(Containers::ArrayView<const char> value);
298 };
299 
300 /** @relatesalso Tweakable
301 @brief Tweakable constant parser for the `bool` type
302 
303 Expects literals in the form @cpp true @ce or @cpp false @ce.
304 @experimental
305 */
306 template<> struct CORRADE_UTILITY_EXPORT TweakableParser<bool> {
307     TweakableParser() = delete;
308 
309     /** @brief Parse the value */
310     static std::pair<TweakableState, bool> parse(Containers::ArrayView<const char> value);
311 };
312 
313 }}
314 
315 #endif
316 
317