ALib C++ Library
Library Version: 2402 R1
Documentation generated by doxygen
Loading...
Searching...
No Matches
records.cpp
1// #################################################################################################
2// ALib C++ Library
3//
4// Copyright 2013-2024 A-Worx GmbH, Germany
5// Published under 'Boost Software License' (a free software license, see LICENSE.txt)
6// #################################################################################################
8
9#if !defined(ALIB_DOX)
10# if !defined(HPP_ALIB_LANG_COMMONENUMS)
12# endif
13# if !defined(HPP_ALIB_ENUMS_DETAIL_ENUMRECORDMAP)
15# endif
16
17# if ALIB_STRINGS
18# if !defined(HPP_ALIB_ENUMS_RECORDBOOTSTRAP)
20# endif
21# if !defined (HPP_ALIB_STRINGS_LOCALSTRING)
23# endif
24# endif
25#
26#endif // !defined(ALIB_DOX)
27
28
29namespace alib { namespace enums {
30
31
32// #################################################################################################
33// Details
34// #################################################################################################
35namespace detail {
36
37namespace
38{
39 #if ALIB_MONOMEM
40 HashMap < EnumRecordKey, const void*,
43 3.0, 6.0 );
44 #else
45 std::unordered_map< EnumRecordKey, const void*,
47 EnumRecordKey::EqualTo > EnumRecordMap;
48 #endif
49}
50
51void setEnumRecord( const std::type_info& rtti, integer elementValue, const void* record )
52{
53 #if ALIB_MONOMEM
54 EnumRecordMap.EmplaceIfNotExistent( EnumRecordKey(rtti, elementValue ), record );
55 #else
56 EnumRecordMap.try_emplace( EnumRecordKey(rtti, elementValue ), record );
57 #endif
58}
59
60const void* getEnumRecord( const std::type_info& rtti, integer elementValue )
61{
62
63#if ALIB_MONOMEM
64 auto it= EnumRecordMap.Find( EnumRecordKey( rtti, elementValue ) );
65#else
66 auto it= EnumRecordMap.find( EnumRecordKey( rtti, elementValue ) );
67#endif
68 if ( it != EnumRecordMap.end() )
69 return it->second;
70
71 return nullptr;
72}
73
74#if ALIB_MONOMEM
75const HashMap < EnumRecordKey, const void*,
76 EnumRecordKey::Hash,
78#else
79const std::unordered_map< EnumRecordKey, const void*,
82#endif
83{
84 return EnumRecordMap;
85}
86
87
88
89} // namespace alib::enums[::detail]
90
91// #################################################################################################
92// EnumRecordParser
93// #################################################################################################
94#if ALIB_STRINGS && !defined(ALIB_DOX)
95
96namespace {
97 void assembleMsgAndThrow [[noreturn]] ( const NString& error )
98 {
101
102 NAString msg;
103 msg << "ERROR WHILE PARSING ENUMERATION RECORD STRING" << NewLine()
104 << " Detail: " << error << NewLine()
105 << " Resrc : "; if(EnumRecordParser::ResourceCategory.IsNotEmpty() )
107 << "\" / \"" << EnumRecordParser::ResourceName << '"';
108 else
109 msg << "(Not resourced)";
110 msg << NewLine()
111 << " Column: " << column + 1 << NewLine()
112 << " Input : \"" << EnumRecordParser::OriginalInput << '"' << NewLine()
113 << " ";
114 for( integer i= column ; i >= 0 ; --i )
115 msg << (i != 0 ? '-' : '>');
116 msg << "^<--";
117
118 throw std::runtime_error( msg.Terminate() );
119 }
120} // anonymous namespace
121
128
129void EnumRecordParser::error [[noreturn]] (const NCString& what)
130{
131 assembleMsgAndThrow( NString256() << what << '.' );
132}
133
135{
136 if( Input.IsNotEmpty()
138 assembleMsgAndThrow( NString256() << "Found whitespaces "
139 << where );
140}
141
143{
144 if( token.LastIndexOfAny<lang::Inclusion::Exclude>( DefaultWhitespaces() ) != token.Length() -1 )
145 assembleMsgAndThrow( NString256() << "Found trailing whitespaces in string value \""
146 << token << '"' );
147}
148
149void EnumRecordParser::assertNoUnnecessary(character specificChar, const NCString& where)
150{
151 if( Input.CharAtStart() == specificChar )
152 assembleMsgAndThrow( NString256() << "Unnecessary character \""
153 << specificChar
154 << "\" found " << where );
155}
156
157void EnumRecordParser::assertChar(character specificChar, const NCString& where)
158{
159 if( !Input.ConsumeChar(specificChar) )
160 assembleMsgAndThrow( NString256() << where << '\"' << specificChar << '\"');
161}
162
164{
165 if ( Input.IsEmpty() )
166 return;
167 assertNoWhitespaces( "after record" );
169 assembleMsgAndThrow( NString256() << "Expected outer delimiter or end of input" );
170}
171
173{
174 if ( !Input.IsEmpty() )
175 assembleMsgAndThrow( NString256() << "Expected end of parsable input string" );
176}
177
178integer EnumRecordParser::getInteger( bool isLastField )
179{
180 integer bigInt;
181 assertNoWhitespaces( "before integral value" );
182 assertNoUnnecessary( A_CHAR('+'), "before integral value" );
183
185 bigInt= (std::numeric_limits<integer>::max)();
186 else if( Input.ConsumeString<lang::Case::Ignore>( A_CHAR("min") ) ) bigInt= (std::numeric_limits<integer>::min)();
187 else if( Input.ConsumeChar( A_CHAR('^') ) )
188 {
189 int exp;
190 if( !Input.ConsumeDec( exp ) )
191 error("Power of 2 symbol '^' is not followed by a number" );
192 bigInt= static_cast<integer>(1LL << exp);
193 }
194 else
195 {
196 if( (!isLastField && ( Input.CharAtStart() == InnerDelimChar ) )
197 || ( isLastField && ( Input.CharAtStart() == OuterDelimChar || Input.IsEmpty()) ) )
198 bigInt= 0;
199 else
200 if( ! Input.ConsumeInt( bigInt ) )
201 error( "Not an integral value" );
202 }
203
204 if( !isLastField )
205 Delim();
206 else
208 return bigInt;
209}
210
211
212void EnumRecordParser::Get( String& result, bool isLastField )
213{
214 assertNoWhitespaces( "before string" );
215 if( !isLastField )
217 else
220 if( isLastField )
222}
223
224void EnumRecordParser::Get( character& result, bool isLastField )
225{
226 assertNoWhitespaces( "before a character value" );
228 if( (!isLastField && ( result == InnerDelimChar ) )
229 || ( isLastField && ( result == OuterDelimChar || result == '\0' ) ) )
230 result= '\0';
231 else
232 {
233 if( result == '\0' )
234 error("End of input when parsing a character." );
235 assertNoWhitespaces( "after a character value" );
236 if( !isLastField )
237 Delim();
238 else
240 }
241}
242
243void EnumRecordParser::Get( double& result, bool isLastField )
244{
245 assertNoWhitespaces( "before a floating point value" );
246 assertNoUnnecessary( A_CHAR('+'), "before floating point value" );
247 if( (!isLastField && ( Input.CharAtStart() == InnerDelimChar ) )
248 || ( isLastField && ( Input.CharAtStart() == OuterDelimChar || Input.IsEmpty()) ) )
249 result= 0.0;
250 else
251 if( !Input.ConsumeFloat( result ) )
252 error("Not a floating point value" );
253
254 if( !isLastField )
255 Delim();
256 else
258}
259
260
261
263{
264 assertNoWhitespaces( "prior to a delimiter");
265 assertChar(InnerDelimChar,"expected inner delimiter" );
266 assertNoWhitespaces( "after an inner delimiter");
267}
268
270{
271 assertNoWhitespaces( "prior to an outer delimiter");
272 assertChar(OuterDelimChar,"expected outer delimiter" );
273 assertNoWhitespaces( "after an outer delimiter");
274}
275
276
277// #################################################################################################
278// Implementation of parsing methods of built-in record types.
279// #################################################################################################
281{
284}
285
286#endif // ALIB_STRINGS && defined(ALIB_DOX)
287
288
289// #################################################################################################
290// enums::Bootstrap()
291// #################################################################################################
292#if !ALIB_CAMP
293void Bootstrap()
294{
295#if ALIB_STRINGS
296DOX_MARKER([DOX_ALIB_ENUMS_MULTIPLE_RECORDS])
298{
299 { lang::Bool::True , A_CHAR("False"), 1 },
300 { lang::Bool::False, A_CHAR("True" ), 1 },
301 { lang::Bool::True , A_CHAR("0" ), 1 },
302 { lang::Bool::False, A_CHAR("1" ), 1 },
303 { lang::Bool::True , A_CHAR("No" ), 1 },
304 { lang::Bool::False, A_CHAR("Yes" ), 1 },
305 { lang::Bool::True , A_CHAR("Off" ), 2 },
306 { lang::Bool::False, A_CHAR("On" ), 2 },
307 { lang::Bool::True , A_CHAR("-" ), 1 },
308 { lang::Bool::False, A_CHAR("Ok" ), 2 }
309} );
310DOX_MARKER([DOX_ALIB_ENUMS_MULTIPLE_RECORDS])
311
313{
314 { lang::Case::Sensitive, A_CHAR("Sensitive"), 1 },
315 { lang::Case::Ignore , A_CHAR("Ignore" ), 1 },
316} );
317
318DOX_MARKER([DOX_ALIB_ENUMS_MULTIPLE_RECORDS_2])
320{
321 { lang::ContainerOp::Insert , A_CHAR("Insert" ), 1 }, // integral 0
322 { lang::ContainerOp::Remove , A_CHAR("Remove" ), 1 }, // integral 1
323 { lang::ContainerOp::GetCreate, A_CHAR("GetCreate"), 4 }, // integral 3 <-- Switched order
324 { lang::ContainerOp::Get , A_CHAR("Get" ), 1 }, // integral 2 <--
325 { lang::ContainerOp::Create , A_CHAR("Create" ), 1 }, // integral 4
326} );
327DOX_MARKER([DOX_ALIB_ENUMS_MULTIPLE_RECORDS_2])
328
330{
331 { lang::Switch::Off , A_CHAR("Off") , 2 },
332 { lang::Switch::On , A_CHAR("On" ) , 2 },
333} );
334
336{
337 { lang::Alignment::Left , A_CHAR("Left" ) , 1 },
338 { lang::Alignment::Right , A_CHAR("Right" ) , 1 },
339 { lang::Alignment::Center , A_CHAR("Center") , 1 },
340} );
341
343{
344 { lang::SortOrder::Ascending , A_CHAR("Ascending" ) , 1 },
345 { lang::SortOrder::Descending , A_CHAR("Descending") , 1 },
346} );
347
349{
350 { lang::Inclusion::Include , A_CHAR("Include") , 1 },
351 { lang::Inclusion::Exclude , A_CHAR("Exclude") , 1 },
352} );
353
355{
356 { lang::Reach::Global , A_CHAR("Global") , 1 },
357 { lang::Reach::Local , A_CHAR("Local" ) , 1 },
358} );
359
361{
362 { lang::CurrentData::Keep , A_CHAR("Keep" ) , 1 },
363 { lang::CurrentData::Clear , A_CHAR("Clear") , 1 },
364} );
365
367{
368 { lang::SourceData::Copy , A_CHAR("Copy") , 1 },
369 { lang::SourceData::Move , A_CHAR("Move") , 1 },
370} );
371
372
374{
375 { lang::Safeness::Safe , A_CHAR("Safe" ) , 1 },
376 { lang::Safeness::Unsafe , A_CHAR("Unsafe") , 1 },
377} );
378
380{
381 { lang::Responsibility::KeepWithSender , A_CHAR("KeepWithSender"), 1 },
382 { lang::Responsibility::Transfer , A_CHAR("Transfer" ), 1 },
383} );
384
386{
387 { lang::Side::Left , A_CHAR("Left" ) , 1 },
388 { lang::Side::Right , A_CHAR("Right") , 1 },
389} );
390
392{
393 { lang::Timezone::Local , A_CHAR("v" ) , 1 },
394 { lang::Timezone::UTC , A_CHAR("UTC") , 1 },
395} );
396
398{
399 { lang::Whitespaces::Trim , A_CHAR("Trim") , 1 },
400 { lang::Whitespaces::Keep , A_CHAR("Keep") , 1 },
401} );
402
404{
405 { lang::Propagation::Omit , A_CHAR("Omit" ) , 1 },
406 { lang::Propagation::ToDescendants , A_CHAR("ToDescendants") , 1 },
407} );
408
410{
411 { lang::Phase::Begin , A_CHAR("Begin") , 1 },
412 { lang::Phase::End , A_CHAR("End" ) , 1 },
413} );
414
416{
417 { lang::Initialization::Suppress , A_CHAR("Suppress") , 1 },
418 { lang::Initialization::Perform , A_CHAR("Perform" ) , 1 },
419 { lang::Initialization::Suppress , A_CHAR("NoInit" ) , 1 },
420 { lang::Initialization::Perform , A_CHAR("Init" ) , 1 },
421 { lang::Initialization::Perform , A_CHAR("Yes" ) , 1 },
422} );
423
425{
426 { lang::Timing::Async , A_CHAR("Async" ) , 1 },
427 { lang::Timing::Sync , A_CHAR("Sync" ) , 1 },
428 { lang::Timing::Async , A_CHAR("Asynchronous") , 1 },
429 { lang::Timing::Sync , A_CHAR("Synchronous" ) , 1 },
430 { lang::Timing::Sync , A_CHAR("Synchronized") , 1 },
431} );
432
434{
435 { lang::Caching::Disabled , A_CHAR("Disabled") , 1 },
436 { lang::Caching::Enabled , A_CHAR("Enabled" ) , 1 },
437 { lang::Caching::Auto , A_CHAR("Auto" ) , 1 },
438} );
439
440#endif // ALIB_STRINGS
441
442
443} // enums::Bootstrap()
444#endif // !ALIB_CAMP
445
446
447
448
449// #################################################################################################
450// EnumRecordPrototype (Doxygen only)
451// #################################################################################################
452
453#if defined(ALIB_DOX)
454/** ************************************************************************************************
455 * This struct is \b not part of the library but only provided with the documentation of this
456 * \alibmod_nl.
457 *
458 * The struct prototypes what module \alib_enums_nl \b expects from custom types that are
459 * associated to enumerations as the type of \ref alib_enums_records "ALib Enum Records".
460 *
461 * Usually, enum records are rather simple structs with fields of scalar or
462 * \https{POD types,en.cppreference.com/w/cpp/types/is_pod} like, \c int, \c double or
463 * \alib{strings;TString;String} and this way remain POD types themselves.
464 *
465 * When parsed or otherwise otherwise initialized, String members do not need to copy data to an
466 * own buffer, because the input string for parsing
467 * an instance, as well as the parameters of alternative constructors, are deemed to be static data.
468 *
469 * The life-cycle of instances of enumeration record is from bootstrapping an application
470 * to its termination. After creation, the data can not be modified.
471 **************************************************************************************************/
473{
474 /**
475 * Default constructor leaving the record undefined. For efficiency, this usually does
476 * not initialize fields, as those will be overwritten by a subsequent invocation to #Parse.
477 *
478 * This constructor is only needed when method #Parse is given. Note that it is advised to
479 * provide the parsing option and this way also this constructor.
480 */
481 EnumRecordPrototype() noexcept = default;
482
483 /**
484 * Constructor accepting all necessary arguments to completely define the record.
485 * This constructor is needed only in the case that records should be defined in a statical
486 * way which is an alternative to implementing the definition by parsing an (externalized)
487 * initialization strings. Static definition can be performed with method
488 * \alib{enums;EnumRecords<TEnum;TEnableIf>::Bootstrap(std::initializer_list<Initializer> definitions)}
489 * but is not recommended and the definition from parsable stings is preferred.
490 *
491 * Note that the parameter's passed when this constructor is invoked, have to be of
492 * "static nature". For example, the buffers and contents of passed string values are
493 * deemed to survive the life-cycle of an application. Usually, C++ string literals are passed.
494 *
495 * @param myArg1 Assigned to the first custom field.
496 * @param myArg2 Assigned to the second custom field.
497 * @param ... Further parameters, assigned to further fields.
498 */
499 EnumRecordPrototype( const MyType1& myArg1, MyType2 myArg2, ... ) noexcept;
500
501 /**
502 * Implementation has to parse the fields of this record from static interface struct
503 * \alib{enums;EnumRecordParser}.
504 *
505 * For - usually simple - enum records, the process of parsing is limited to reading
506 * values separated by delimiters. Convenient methods to do so are given by static type
507 * \alib{enums;EnumRecordParser}. More complex parsing logic may be implemented by
508 * using the "parser" substring found with \alib{enums;EnumRecordParser::Input} and further
509 * of its entities.<br>
510 * Please refer to the documentation of \alib{enums;EnumRecordParser} for all details.
511 * A source code sample is given in chapter \ref alib_enums_records_resourced_parsing of the
512 * Programmer's Manual of module \alib_enums_nl.
513 *
514 * The contents (buffer) of the string parsed is by contract of static nature. This means
515 * that no copies of portions need to be allocated when used as a field value of string type.
516 * This is in alignment with the static nature of \ref alib_enums_records "ALib Enum Records"
517 * and their creation during bootstrap, either from C++ string literals or
518 * \ref alib_basecamp_resources "ALib Externalized Resources", which comply to the same contract.
519 *
520 * On the same token, in case of an error, an implementation should raise an exception in
521 * debug-compilations, as parsing is deemed to succeed on static data, even if externalized.
522 */
524 void Parse() noexcept;
525}; // EnumRecordPrototype
526#endif // defined(ALIB_DOX)
527
528}} // namespace [alib::enums]
const TChar * Terminate() const
Definition astring.hpp:758
constexpr bool IsEmpty() const
Definition string.hpp:414
constexpr bool IsNotEmpty() const
Definition string.hpp:420
constexpr integer Length() const
Definition string.hpp:357
TChar CharAtStart() const
Definition string.hpp:459
integer IndexOfAny(const TString &needles, integer startIdx=0) const
Definition string.hpp:1083
integer IndexOfOrLength(TChar needle) const
Definition string.hpp:965
TString< TChar > ConsumeToken(TChar separator=',')
bool ConsumeString(const TString< TChar > &consumable)
ALIB_API bool ConsumeFloat(double &result, TNumberFormat< TChar > *numberFormat=nullptr)
integer ConsumeChars(integer regionLength, TSubstring *target=nullptr)
bool ConsumeDec(TIntegral &result, TNumberFormat< TChar > *numberFormat=nullptr)
bool ConsumeInt(TIntegral &result, TNumberFormat< TChar > *numberFormat=nullptr)
#define A_CHAR(STR)
#define ALIB_API
Definition alib.hpp:538
ALIB_API void setEnumRecord(const std::type_info &rtti, integer integral, const void *record)
Definition records.cpp:51
ALIB_API const void * getEnumRecord(const std::type_info &rtti, integer integral)
Definition records.cpp:60
const HashMap< EnumRecordKey, const void *, EnumRecordKey::Hash, EnumRecordKey::EqualTo > & getInternalRecordMap()
Definition records.cpp:77
ALIB_API void Bootstrap()
@ Exclude
Chooses exclusion.
@ Include
Chooses inclusion.
@ Keep
Keep whitespaces in string.
@ Trim
Trim whitespaces away.
@ Enabled
Caching is enabled.
@ Auto
Auto/default mode.
@ Disabled
Caching is disabled.
@ Right
Denotes the right side of something.
@ Left
Denotes the left side of something.
@ Omit
Do not propagate changes.
@ ToDescendants
Propagate changes to descendants/children/sub-components.
@ True
True value.
@ False
False value.
@ On
Switch it on, switched on, etc.
@ Off
Switch it off, switched off, etc.
@ Safe
Do it or treat it with safety.
@ Unsafe
Omit checks or perform unsafe operations.
@ Ascending
Chooses ascending sort oder.
@ Descending
Chooses descending sort oder.
@ Global
Denotes global reach.
@ Local
Denotes local reach.
@ Copy
Chooses not to clear existing data.
@ Move
Chooses to clear existing data.
@ Local
Denotes local time.
@ UTC
Denotes UTC (coordinated universal time).
@ Keep
Chooses not no clear existing data.
@ Clear
Chooses to clear existing data.
@ KeepWithSender
Keeps responsibility, e.g. when passing an object.
@ Transfer
Transfers responsibility to the receiving party.
@ Center
Chooses centered alignment.
@ Right
Chooses right alignment.
@ Left
Chooses left alignment.
@ Begin
The start of a transaction.
@ End
The end of a transaction.
@ Remove
Denotes removals.
@ GetCreate
Denotes to create data if not found.
@ Create
Denotes to create data.
@ Insert
Denotes insertions.
@ Get
Denotes to search data.
MonoAllocator GlobalAllocator(8 *1024)
Definition alib.cpp:57
constexpr CString DefaultWhitespaces()
Definition cstring.hpp:554
constexpr CString NewLine()
Definition cstring.hpp:528
strings::TString< nchar > NString
Type alias in namespace alib.
strings::TSubstring< character > Substring
Type alias in namespace alib.
NLocalString< 256 > NString256
Type alias name for TLocalString<nchar,256> .
strings::TCString< nchar > NCString
Type alias in namespace alib.
characters::character character
Type alias in namespace alib.
strings::TString< character > String
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 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 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 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)
EnumRecordPrototype() noexcept=default
ALIB_API void Parse() noexcept
static void Bootstrap(TEnum element, TArgs &&... args) noexcept