ALib C++ Library
Library Version: 2402 R1
Documentation generated by doxygen
Loading...
Searching...
No Matches
recordparser.hpp
Go to the documentation of this file.
1/** ************************************************************************************************
2 * \file
3 * This header file is part of module \alib_enums of the \aliblong.
4 *
5 * \emoji :copyright: 2013-2024 A-Worx GmbH, Germany.
6 * Published under \ref mainpage_license "Boost Software License".
7 **************************************************************************************************/
8#ifndef HPP_ALIB_ENUMS_RECORDPARSER
9#define HPP_ALIB_ENUMS_RECORDPARSER 1
10
11#if !defined(HPP_ALIB) && !defined(ALIB_DOX)
12# include "alib/alib.hpp"
13#endif
14
16ALIB_ASSERT_MODULE(STRINGS)
17
18
19#if ALIB_STRINGS && !defined(HPP_ALIB_STRINGS_SUBSTRING)
21#endif
22
23namespace alib { namespace enums {
24
25/**
26 * This is a pure static type used for parsing enum records from strings.
27 * The static fields are initialized with each method of type \alib{enums;EnumRecords}
28 * and therefore implementations of \alib{enums;EnumRecordPrototype::Parse} can rely on finding
29 * these fields properly set.
30 *
31 * This concept makes use of the restriction, that the setup of
32 * \ref alib_enums_records "ALib Enum Records" must exclusively be done during
33 * \ref alib_manual_bootstrapping "bootstrapping" of a software process, where no multi-threading
34 * is active, yet.
35 *
36 * If parse errors occur, a <c>std::runtime_error</c> is thrown.
37 *
38 * \note
39 * This is the only occasion where any \alib module throws an exception of type \c std.
40 * If (in presence of module \alib_basecamp) an \alib{lang;Exception} was thrown,
41 * this had to be resourced likewise.
42 * The rational for this design decision is that enum records usually are defined by
43 * potentially externalized resources. The maintenance of such resources must not lead to
44 * corrupted exceptions that are thrown when parsing those resources.
45 * Consequently, the exception messages are using english language and are not externalized.
46 * An end user will not be faced with these exception unless an errorneous "roll-out"
47 * of a software using malicious externalized resources was performed.
48 *
49 * The methods of this type perform strict checks about unnecessary whitespaces, <c>'+'</c>-signs,
50 * etc, which also raise an exception. The rationale for this design decision
51 * (to not allow unnecessary, but maybe unharmful characters in resources) besides saving memory is,
52 * that the occurrence of unnecessary characters, indicates an errorneous maintenance of
53 * externalized resources, and such should be detected as soon as possible.
54 *
55 * The main interface into this class is given with the overloaded #Get methods.
56 * Enum Records are usually rather simple structs, consisting of strings, characters, integers
57 * and floating point values. If so, a simple list of invocations of #Get for each
58 * field of the struct has to be placed in implementations of method
59 * \alib{enums;EnumRecordPrototype::Parse}. For the last field, optional parameter
60 * \p{isLastField} has to be given as \c true4.
61 * As an example, the following code shows the implementation of \alib{config;VariableDecl::Parse}:
62 * \snippet "alib/config/variable.cpp" DOX_ALIB_ENUMS_RECORD_PARSER
63 * This parse method omits reading the value for inherited field
64 * \alib{enums;ERSerializable::MinimumRecognitionLength}, and sets it to fixed \c 0 instead.
65 * This is often an option when custom enumeration record types
66 * are derived from \b ERSerializable but are not supposed to be deserialized or de-serialization
67 * forcing the whole string to read is acceptable.
68 * Note that it is still is possible to deserialize elements, but not with abbreviated names.
69 *
70 * An implementation for a custom record type might perform more complex parsing operations.
71 * For this, some helper methods are publicly provided and finally, the direct use of the
72 * substring #Input is likewise allowed.
73 */
75{
76 /** The remaining input string. */
78
79 /** The delimiter of fields of a record. */
81
82 /** The delimiter of records. */
84
85 /** A backup of the originally given string to parse. */
87
88 /** The resource category (if a resourced string was parsed). */
90
91 /** The resource name (if a resourced string was parsed). */
93
94 /**
95 * Initializes this parser. This is done once prior to reading a resource (or static) string
96 * with enum record definitions.
97 *
98 * @param input The input string.
99 * @param innerDelim The delimiter of fields of a record.
100 * @param outerDelim The delimiter of records.
101 * @param resourceCategory The delimiter of records.
102 * @param resourceName The delimiter of records.
103 */
104 ALIB_API static void Initialize( const String& input ,
105 character innerDelim , character outerDelim,
106 const NString& resourceCategory, const NString& resourceName )
107 {
108 // Test for double initialization call, what is not easily avoidable for resourced strings.
109 // This protects the resource information, of the first call.
110 if( input.Buffer() != Input.Buffer() || Input.IsNull() )
111 {
112 Input =
113 OriginalInput = input;
114 InnerDelimChar = innerDelim;
115 OuterDelimChar = outerDelim;
116 ResourceCategory = resourceCategory;
117 ResourceName = resourceName;
118 if( input.IsNull () ) error( "Input string is nulled" );
119 if( input.IsEmpty() ) error( "Input string is empty" );
120 }
121 }
122
123 // #############################################################################################
124 // Helpers
125 // #############################################################################################
126
127 /**
128 * Raises an error.
129 * @param what Textual description about what has bien tried to do.
130 */
131 ALIB_API static void error[[noreturn]] (const NCString& what);
132
133 /**
134 * Asserts that no whitespaces follow in input.
135 * @param where Textual description about what is currently done.
136 */
137 ALIB_API static void assertNoWhitespaces(const NCString& where);
138
139 /**
140 * Asserts that no trailing whitespaces are in \p{token}.
141 * @param token The string to test for trailing whitespaces.
142 */
144
145
146 /**
147 * Asserts that a specific redundant character is not given, for example a leading
148 * <c>'+'</c> sign for an integral value.
149 * @param specificChar The character to check.
150 * @param where Textual description about what is currently done.
151 */
152 ALIB_API static void assertNoUnnecessary(character specificChar, const NCString& where);
153
154 /**
155 * Asserts that either \p{specificChar} follows. The character will also be consumed.
156 * @param specificChar The character to consume next.
157 * @param where Textual description about what is currently done.
158 */
159 ALIB_API static void assertChar(character specificChar, const NCString& where);
160
161 /**
162 * Asserts that either #Input is empty, or an #OuterDelimChar follows.
163 */
165
166 /**
167 * Asserts that the #Input is empty.
168 */
170
171 /**
172 * Used by #Get(TIntegral&, bool).
173 * Reads special values \b min, \b max and \b ^N. The latter provides the power of two.
174 * @param isLastField Has to be given as \c true, if this is the last field to parse,
175 * otherwise \c false.
176 * @return The value parsed.
177 */
178 ALIB_API static integer getInteger( bool isLastField );
179
180
181 // #############################################################################################
182 // Main methods for parsing fields.
183 // #############################################################################################
184 /**
185 * Parses a field of string type. Parsing ends with an #InnerDelimChar.
186 * The string is checked for not containing leading or trailing whitespaces.<br>
187 *
188 * @param result A reference to the record's field to be read.
189 * @param isLastField Has to be given as \c true, if this is the last field to parse.
190 * Defaults to \c false.
191 */
192 ALIB_API static void Get( String& result, bool isLastField= false );
193
194 /**
195 * Parses a field of character type.
196 *
197 * @param result A reference to the record's field to be read.
198 * @param isLastField Has to be given as \c true, if this is the last field to parse.
199 * Defaults to \c false.
200 */
201 ALIB_API static void Get( character& result, bool isLastField= false );
202
203#if defined(ALIB_DOX)
204 /**
205 * Parses an integral field of a record. Accepts <c>'-'</c> signs, while <c>'+'</c>
206 * is considered an unnecessary token.
207 * Furthermore asserts that at least one digit was parsed.
208 *
209 * Allows special values \b min, \b max and \b ^N. The latter provides the power of two.
210 *
211 * @tparam TIntegral The integer type to parse.
212 * Must be statically castable from \b uint64_t.
213 * Deduced by the compiler.
214 * @param result A reference to the record's field to be read.
215 * @param isLastField Has to be given as \c true, if this is the last field to parse.
216 * Defaults to \c false.
217 */
218 template<typename TIntegral>
219 static inline
220 void Get( TIntegral& result, bool isLastField= false );
221#else
222 template<typename TIntegral>
223 static
224 ATMP_VOID_IF( ATMP_IS_INT(TIntegral) )
225 Get( TIntegral& result, bool isLastField= false )
226 {
227 integer bigInt= getInteger( isLastField );
228 if( bigInt == (std::numeric_limits<integer>::max)() ) result= (std::numeric_limits<TIntegral>::max)();
229 else if( bigInt == (std::numeric_limits<integer>::min)() ) result= (std::numeric_limits<TIntegral>::min)();
230 else result= static_cast<TIntegral>( bigInt );
231 }
232#endif // defined(ALIB_DOX)
233
234#if defined(ALIB_DOX)
235 /**
236 * Parses an enumeration element value, which has to be given in the source string by its
237 * underlying integral value. (It is not possible to parse "named" enumerations in
238 * bootstrapping, yet.)
239 *
240 * \note
241 * This method uses #Get(TIntegral&, bool) to read the value and thus special values
242 * \b min, \b max and \b ^N are allowed
243 *
244 * @tparam TEnum The enum type to parse an element from.
245 * @param result A reference to the integer variable to parse.
246 * @param isLastField Has to be given as \c true, if this is the last field to parse.
247 * Defaults to \c false.
248 */
249 template<typename TEnum>
250 static inline
251 void Get( TEnum& result, bool isLastField= false );
252#else
253 template<typename TEnum>
254 static
255 ATMP_VOID_IF( std::is_enum<TEnum>::value )
256 Get( TEnum& result, bool isLastField= false )
257 {
258 typename std::underlying_type<TEnum>::type resultIntegral;
259 EnumRecordParser::Get( resultIntegral, isLastField );
260 result= TEnum( resultIntegral );
261 }
262#endif // defined(ALIB_DOX)
263
264 /**
265 * Parses the next floating point field of a record. Accepts <c>'-'</c> signs, while <c>'+'</c>
266 * is considered an unnecessary token.
267 * Furthermore asserts that at least one digit was parsed.
268 *
269 * @param result A reference to the record's field to be read.
270 * @param isLastField Has to be given as \c true, if this is the last field to parse.
271 * Defaults to \c false.
272 */
273 ALIB_API static void Get( double& result, bool isLastField= false );
274
275
276 /**
277 * Removes an #InnerDelimChar.
278 * The #Input is checked for not containing whitespaces before or after the delimiter.
279 */
280 ALIB_API static void Delim();
281
282 /**
283 * Removes an #OuterDelimChar.
284 * The #Input is checked for not containing whitespaces before or after the delimiter.
285 */
286 ALIB_API static void OuterDelim();
287
288};
289
290}} // namespace [alib::enums]
291
292#endif // HPP_ALIB_ENUMS_RECORDPARSER
constexpr bool IsNull() const
Definition string.hpp:395
constexpr bool IsEmpty() const
Definition string.hpp:414
constexpr const TChar * Buffer() const
Definition string.hpp:350
#define ATMP_IS_INT(T)
Definition tmp.hpp:29
#define ALIB_ASSERT_MODULE(modulename)
Definition alib.hpp:190
#define ATMP_VOID_IF(Cond)
Definition tmp.hpp:52
#define ALIB_API
Definition alib.hpp:538
Definition alib.cpp:57
characters::character character
Type alias in namespace alib.
lang::integer integer
Type alias in namespace alib.
Definition integers.hpp:286
static ALIB_API void Get(String &result, bool isLastField=false)
static ALIB_API void Get(character &result, bool isLastField=false)
static void Get(TIntegral &result, bool isLastField=false)
static ALIB_API void assertNoUnnecessary(character specificChar, const NCString &where)
static ALIB_API NString ResourceCategory
static ALIB_API integer getInteger(bool isLastField)
static ALIB_API void Delim()
static ALIB_API void Get(double &result, bool isLastField=false)
static ALIB_API void assertEndOfInput()
static ALIB_API void OuterDelim()
static ALIB_API void assertChar(character specificChar, const NCString &where)
static ALIB_API void assertNoWhitespaces(const NCString &where)
static ALIB_API Substring Input
static ALIB_API String OriginalInput
static ALIB_API void assertEndOfRecord()
static ALIB_API void Initialize(const String &input, character innerDelim, character outerDelim, const NString &resourceCategory, const NString &resourceName)
static ALIB_API character InnerDelimChar
static ALIB_API NString ResourceName
static ALIB_API void assertNoTrailingWhitespaces(String &token)
static ALIB_API character OuterDelimChar
static ALIB_API void error(const NCString &what)
static void Get(TEnum &result, bool isLastField=false)