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