ALib C++ Library
Library Version: 2412 R0
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 !DOXYGEN
14#endif // !DOXYGEN
15
16#include <stdexcept>
17
18
19namespace alib { namespace enums {
20
21
22// #################################################################################################
23// Details
24// #################################################################################################
25namespace detail {
26
27namespace
28{
29 #if ALIB_MONOMEM
30 #if DOXYGEN
31 /// Global directory to find enum records.
33 EnumRecordKey, const void*,
36 #else
38 EnumRecordKey, const void*,
41 3.0, 6.0 );
42 #endif //if DOXYGEN
43 #else
44 std::unordered_map< EnumRecordKey, const void*,
47 #endif
48}
49
50void setEnumRecord( const std::type_info& rtti, integer elementValue, const void* record )
51{
52 #if ALIB_MONOMEM
53 ENUM_RECORD_MAP.EmplaceIfNotExistent( EnumRecordKey(rtti, elementValue ), record );
54 #else
55 ENUM_RECORD_MAP.try_emplace( EnumRecordKey(rtti, elementValue ), record );
56 #endif
57}
58
59const void* getEnumRecord( const std::type_info& rtti, integer elementValue )
60{
61
62#if ALIB_MONOMEM
63 auto it= ENUM_RECORD_MAP.Find( EnumRecordKey( rtti, elementValue ) );
64#else
65 auto it= ENUM_RECORD_MAP.find( EnumRecordKey( rtti, elementValue ) );
66#endif
67 if ( it != ENUM_RECORD_MAP.end() )
68 return it->second;
69
70 return nullptr;
71}
72
73#if ALIB_MONOMEM && ALIB_CONTAINERS
75 EnumRecordKey, const void*,
76 EnumRecordKey::Hash,
78#else
79std::unordered_map< EnumRecordKey, const void*,
82#endif
83{
84 return ENUM_RECORD_MAP;
85}
86
87
88
89} // namespace alib::enums[::detail]
90
91// #################################################################################################
92// EnumRecordParser
93// #################################################################################################
94#if !DOXYGEN
95
96namespace {
97 void assembleMsgAndThrow [[noreturn]] ( const NString& error )
98 {
101
102 NAString msg;
103 msg << "ERROR WHILE PARSING ENUMERATION RECORD STRING" << NEW_LINE
104 << " Detail: " << error << NEW_LINE
105 << " Resrc : "; if(EnumRecordParser::ResourceCategory.IsNotEmpty() )
107 << "\" / \"" << EnumRecordParser::ResourceName << '"';
108 else
109 msg << "(Not resourced)";
110 msg << NEW_LINE
111 << " Column: " << column + 1 << NEW_LINE
112 << " Input : \"" << EnumRecordParser::OriginalInput << '"' << NEW_LINE
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>( DEFAULT_WHITESPACES ) != 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( "before a delimiter");
265 assertChar(InnerDelimChar,"expected inner delimiter" );
266 assertNoWhitespaces( "after an inner delimiter");
267}
268
270{
271 assertNoWhitespaces( "before an outer delimiter");
272 assertChar(OuterDelimChar,"expected outer delimiter" );
273 assertNoWhitespaces( "after an outer delimiter");
274}
275
276#endif // #if !ALIB_DOX
277
278
279// #################################################################################################
280// Implementation of parsing methods of built-in record types.
281// #################################################################################################
287
288
289// #################################################################################################
290// enums::Bootstrap()
291// #################################################################################################
292#if ALIB_DEBUG && !DOXYGEN
293namespace{ unsigned int initFlag= 0; }
294#endif // !DOXYGEN
295
298{
299 ALIB_ASSERT_ERROR( initFlag == 0x92A3EF61, "ENUMS", "Not initialized when calling shutdown." )
300 ALIB_DBG(initFlag= 1);
301 #if ALIB_MONOMEM && ALIB_CONTAINERS
303 #endif
304}
305
307{
308 ALIB_ASSERT_ERROR( initFlag == 0, "ENUMS", "This method must not be invoked twice." )
309 ALIB_DBG(initFlag= 0x92A3EF61);
310
311#if !ALIB_CAMP
312DOX_MARKER([DOX_ENUMS_MULTIPLE_RECORDS])
314{
315 { lang::Bool::True , A_CHAR("False"), 1 },
316 { lang::Bool::False, A_CHAR("True" ), 1 },
317 { lang::Bool::True , A_CHAR("0" ), 1 },
318 { lang::Bool::False, A_CHAR("1" ), 1 },
319 { lang::Bool::True , A_CHAR("No" ), 1 },
320 { lang::Bool::False, A_CHAR("Yes" ), 1 },
321 { lang::Bool::True , A_CHAR("Off" ), 2 },
322 { lang::Bool::False, A_CHAR("On" ), 2 },
323 { lang::Bool::True , A_CHAR("-" ), 1 },
324 { lang::Bool::False, A_CHAR("Ok" ), 2 }
325} );
326DOX_MARKER([DOX_ENUMS_MULTIPLE_RECORDS])
327
329{
330 { lang::Case::Sensitive, A_CHAR("Sensitive"), 1 },
331 { lang::Case::Ignore , A_CHAR("Ignore" ), 1 },
332} );
333
334DOX_MARKER([DOX_ENUMS_MULTIPLE_RECORDS_2])
336{
337 { lang::ContainerOp::Insert , A_CHAR("Insert" ), 1 }, // integral 0
338 { lang::ContainerOp::Remove , A_CHAR("Remove" ), 1 }, // integral 1
339 { lang::ContainerOp::GetCreate, A_CHAR("GetCreate"), 4 }, // integral 3 <-- Switched order
340 { lang::ContainerOp::Get , A_CHAR("Get" ), 1 }, // integral 2 <--
341 { lang::ContainerOp::Create , A_CHAR("Create" ), 1 }, // integral 4
342} );
343DOX_MARKER([DOX_ENUMS_MULTIPLE_RECORDS_2])
344
346{
347 { lang::Switch::Off , A_CHAR("Off") , 2 },
348 { lang::Switch::On , A_CHAR("On" ) , 2 },
349} );
350
352{
353 { lang::Alignment::Left , A_CHAR("Left" ) , 1 },
354 { lang::Alignment::Right , A_CHAR("Right" ) , 1 },
355 { lang::Alignment::Center , A_CHAR("Center") , 1 },
356} );
357
359{
360 { lang::SortOrder::Ascending , A_CHAR("Ascending" ) , 1 },
361 { lang::SortOrder::Descending , A_CHAR("Descending") , 1 },
362} );
363
365{
366 { lang::Inclusion::Include , A_CHAR("Include") , 1 },
367 { lang::Inclusion::Exclude , A_CHAR("Exclude") , 1 },
368} );
369
371{
372 { lang::Reach::Global , A_CHAR("Global") , 1 },
373 { lang::Reach::Local , A_CHAR("Local" ) , 1 },
374} );
375
377{
378 { lang::CurrentData::Keep , A_CHAR("Keep" ) , 1 },
379 { lang::CurrentData::Clear , A_CHAR("Clear") , 1 },
380} );
381
383{
384 { lang::SourceData::Copy , A_CHAR("Copy") , 1 },
385 { lang::SourceData::Move , A_CHAR("Move") , 1 },
386} );
387
388
390{
391 { lang::Safeness::Safe , A_CHAR("Safe" ) , 1 },
392 { lang::Safeness::Unsafe , A_CHAR("Unsafe") , 1 },
393} );
394
396{
397 { lang::Responsibility::KeepWithSender , A_CHAR("KeepWithSender"), 1 },
398 { lang::Responsibility::Transfer , A_CHAR("Transfer" ), 1 },
399} );
400
402{
403 { lang::Side::Left , A_CHAR("Left" ) , 1 },
404 { lang::Side::Right , A_CHAR("Right") , 1 },
405} );
406
408{
409 { lang::Timezone::Local , A_CHAR("v" ) , 1 },
410 { lang::Timezone::UTC , A_CHAR("UTC") , 1 },
411} );
412
414{
415 { lang::Whitespaces::Trim , A_CHAR("Trim") , 1 },
416 { lang::Whitespaces::Keep , A_CHAR("Keep") , 1 },
417} );
418
420{
421 { lang::Propagation::Omit , A_CHAR("Omit" ) , 1 },
422 { lang::Propagation::ToDescendants , A_CHAR("ToDescendants") , 1 },
423} );
424
426{
427 { lang::Phase::Begin , A_CHAR("Begin") , 1 },
428 { lang::Phase::End , A_CHAR("End" ) , 1 },
429} );
430
432{
433 { lang::Initialization::Suppress , A_CHAR("Suppress" ) , 1 },
434 { lang::Initialization::Default , A_CHAR("Default" ) , 1 },
435 { lang::Initialization::Nulled , A_CHAR("Nulled" ) , 1 },
436 { lang::Initialization::Suppress , A_CHAR("None" ) , 2 },
437 { lang::Initialization::Default , A_CHAR("Initialize") , 1 },
438 { lang::Initialization::Nulled , A_CHAR("Zero" ) , 1 },
439} );
440
442{
443 { lang::Timing::Async , A_CHAR("Async" ) , 1 },
444 { lang::Timing::Sync , A_CHAR("Sync" ) , 1 },
445 { lang::Timing::Async , A_CHAR("Asynchronous") , 1 },
446 { lang::Timing::Sync , A_CHAR("Synchronous" ) , 1 },
447 { lang::Timing::Sync , A_CHAR("Synchronized") , 1 },
448} );
449
451{
452 { lang::Caching::Disabled , A_CHAR("Disabled") , 1 },
453 { lang::Caching::Enabled , A_CHAR("Enabled" ) , 1 },
454 { lang::Caching::Auto , A_CHAR("Auto" ) , 1 },
455} );
456
457#endif // !ALIB_CAMP
458
459} // enums::Bootstrap()
461
462// #################################################################################################
463// EnumRecordPrototype (Doxygen only)
464// #################################################################################################
465
466#if DOXYGEN
467//==================================================================================================
468/// This struct is \b not part of the library but only provided with the documentation of this
469/// \alibmod_nl.
470///
471/// The struct prototypes what module \alib_enums_nl \b expects from custom types that are
472/// associated to enumerations as the type of \ref alib_enums_records "ALib Enum Records".
473///
474/// Usually, enum records are rather simple structs with fields of scalar or
475/// \https{POD types,en.cppreference.com/w/cpp/types/is_pod} like, \c int, \c double or
476/// \alib{strings;TString;String} and this way remain POD types themselves.
477///
478/// When parsed or otherwise initialized, String members do not need to copy data to an
479/// own buffer, because the input string for parsing
480/// an instance, as well as the parameters of alternative constructors, are deemed to be static data.
481///
482/// The life-cycle of instances of enumeration record is from bootstrapping an application
483/// to its termination. After creation, the data cannot be modified.
484//==================================================================================================
486{
487 /// Default constructor leaving the record undefined. For efficiency, this usually does
488 /// not initialize fields, as those will be overwritten by a subsequent invocation to #Parse.
489 ///
490 /// This constructor is only needed when method #Parse is given. Note that it is advised to
491 /// provide the parsing option and this way also this constructor.
492 EnumRecordPrototype() noexcept = default;
493
494 /// Constructor accepting all necessary arguments to completely define the record.
495 /// This constructor is needed only in the case that records should be defined in a statical
496 /// way which is an alternative to implementing the definition by parsing an (externalized)
497 /// initialization strings. Static definition can be performed with method
498 /// \alib{enums;EnumRecords<TEnum;TEnableIf>::Bootstrap(std::initializer_list<Initializer> definitions)}
499 /// but is not recommended and the definition from parsable stings is preferred.
500 ///
501 /// Note that the parameter's passed when this constructor is invoked, have to be of
502 /// "static nature". For example, the buffers and contents of passed string values are
503 /// deemed to survive the life-cycle of an application. Usually, C++ string literals are passed.
504 ///
505 /// @param myArg1 Assigned to the first custom field.
506 /// @param myArg2 Assigned to the second custom field.
507 /// @param ... Further parameters, assigned to further fields.
508 EnumRecordPrototype( const MyType1& myArg1, MyType2 myArg2, ... ) noexcept;
509
510 /// Implementation has to parse the fields of this record from static interface struct
511 /// \alib{enums;EnumRecordParser}.
512 ///
513 /// For - usually simple - enum records, the process of parsing is limited to reading
514 /// values separated by delimiters. Convenient methods to do so are given by static type
515 /// \alib{enums;EnumRecordParser}. More complex parsing logic may be implemented by
516 /// using the "parser" substring found with \alib{enums;EnumRecordParser::Input} and further
517 /// of its entities.<br>
518 /// Please refer to the documentation of \alib{enums;EnumRecordParser} for all details.
519 /// A source code sample is given in chapter \ref alib_enums_records_resourced_parsing of the
520 /// Programmer's Manual of module \alib_enums_nl.
521 ///
522 /// The contents (buffer) of the string parsed is by contract of static nature. This means
523 /// that no copies of portions need to be allocated when used as a field value of string-type.
524 /// This is in alignment with the static nature of \ref alib_enums_records "ALib Enum Records"
525 /// and their creation during bootstrap, either from C++ string literals or
526 /// \ref alib_basecamp_resources "ALib Externalized Resources", which comply to the same contract.
527 ///
528 /// By the same token, in case of an error, an implementation should raise an exception in
529 /// debug-compilations, as parsing is deemed to succeed on static data, even if externalized.
531 void Parse() noexcept;
532}; // EnumRecordPrototype
533#endif // DOXYGEN
534
535}} // namespace [alib::enums]
536
constexpr const TChar * Terminate() const
Definition tastring.inl:821
constexpr bool IsEmpty() const
Definition string.hpp:383
constexpr bool IsNotEmpty() const
Definition string.hpp:389
constexpr integer Length() const
Definition string.hpp:326
TChar CharAtStart() const
Definition string.hpp:466
integer IndexOfAny(const TString &needles, integer startIdx=0) const
Definition string.hpp:1090
integer IndexOfOrLength(TChar needle) const
Definition string.hpp:972
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)
TString< TChar > ConsumeToken(TChar separator=',', lang::Inclusion includeSeparator=lang::Inclusion::Include)
#define A_CHAR(STR)
#define ALIB_API
Definition alib.hpp:639
#define ALIB_ASSERT_ERROR(cond,...)
Definition alib.hpp:1271
#define ALIB_DBG(...)
Definition alib.hpp:390
HashMap< MonoAllocator, EnumRecordKey, const void *, EnumRecordKey::Hash, EnumRecordKey::EqualTo > ENUM_RECORD_MAP
Global directory to find enum records.
Definition records.cpp:35
ALIB_API void setEnumRecord(const std::type_info &rtti, integer integral, const void *record)
Definition records.cpp:50
ALIB_API const void * getEnumRecord(const std::type_info &rtti, integer integral)
Definition records.cpp:59
HashMap< MonoAllocator, EnumRecordKey, const void *, EnumRecordKey::Hash, EnumRecordKey::EqualTo > & getInternalRecordMap()
Definition records.cpp:77
void Bootstrap()
Definition records.cpp:306
void Shutdown()
Definition records.cpp:297
@ 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/subcomponents.
@ 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.
ALIB_API MonoAllocator GLOBAL_ALLOCATOR
Definition alib.cpp:69
constexpr CString DEFAULT_WHITESPACES
A zero-terminated string of default whitespace characters.
Definition cstring.hpp:600
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>.
constexpr CString NEW_LINE
A zero-terminated string containing the new-line character sequence.
Definition cstring.hpp:580
monomem::TMonoAllocator< lang::HeapAllocator > MonoAllocator
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:273
String EnumElementName
The name of the enum element.
Definition records.hpp:660
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
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 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 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)
EnumRecordPrototype() noexcept=default
ALIB_API void Parse() noexcept
static void Bootstrap(TEnum element, TArgs &&... args) noexcept
Compare functor for this key type.
Hash functor for this key type.