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