ALib C++ Library
Library Version: 2510 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
serialization.inl
Go to the documentation of this file.
1//==================================================================================================
2/// \file
3/// This header-file is part of the module \alib_enumrecords of the \aliblong.
4///
5/// \emoji :copyright: 2013-2025 A-Worx GmbH, Germany.
6/// Published under \ref mainpage_license "Boost Software License".
7//==================================================================================================
8ALIB_EXPORT namespace alib { namespace enumrecords {
9
11// #################################################################################################
12// Parsing (Consume)
13// #################################################################################################
14
15//==================================================================================================
16/// Consumes an element value of a C++ enumeration that is equipped with
17/// \ref alib_enums_records "ALib Enum Records" of type \alib{enumrecords;ERSerializable} (or of a derived
18/// type) from a given \alib{strings;TSubstring;Substring}.
19///
20/// In debug-builds, the method asserts that at least one record is defined for \p{TEnum}.
21///
22/// For more information, consult chapter
23/// \ref alib_enums_records_details_serialization "4.3.1 Serialization/Deserialization" of the
24/// Programmer's Manual of the module \alib_enumrecords_nl.
25///
26/// \note
27/// This namespace function is applicable to \alib{enumops;BitwiseTraits;bitwise enumrecords} as well.
28/// However, only one element name is parsed.
29/// To parse multiple elements (ored to one resulting enum value), use sibling function
30/// \alib{enumrecords;ParseBitwise}.
31///
32/// @tparam TEnum The enumeration type equipped with <b>ALib Enum Recorss</b>
33/// of type \alib{enumrecords;ERSerializable}.
34/// @tparam TChar The character type of the \p{input} substring.
35/// Deduced by the compiler.
36/// @tparam TSensitivity The sensitivity of the comparison.
37/// Defaults to \b Case::Sensitive.
38/// @tparam TTrimBeforeConsume Determines if the sub string should be (left-) trimmed before the
39/// consume operation. If so, in case of parsing failure, trimming is
40/// \b not restored.<br>
41/// Defaults to \b Whitespaces::Trim.
42/// @param[in,out] input The substring to parse. Passed as reference. On success, the
43/// substring will be shortened by the characters consumed. On failure
44/// only trimmed characters are consumed.
45/// @param[out] result The result enum element given as reference.
46/// @return \c true if an enum element was successfuly recognized, \c false otherwise.
47///
48/// ### Module Dependencies ###
49/// This method is only available if the module \alib_strings is included in the \alibbuild.
50//==================================================================================================
51template<typename TEnum,
52 typename TChar,
53 lang::Case TSensitivity = lang::Case::Ignore,
54 lang::Whitespaces TTrimBeforeConsume = lang::Whitespaces::Trim >
55requires alib::enumrecords::IsSerializable<TEnum>
56bool Parse( strings::TSubstring<TChar>& input, TEnum& result )
57{
58 ALIB_ASSERT_ERROR( EnumRecords<TEnum>().begin() != EnumRecords<TEnum>().end(), "ENUMS",
59 "No Enum Records for type <{}> found.", &typeid(TEnum) )
60 if constexpr ( TTrimBeforeConsume == lang::Whitespaces::Trim )
61 input.TrimStart();
62
63 for( auto recordIt= EnumRecords<TEnum>().begin() ;
64 recordIt != EnumRecords<TEnum>().end() ; ++recordIt )
65 if ( input.template ConsumePartOf<TSensitivity>( recordIt->EnumElementName,
66 recordIt->MinimumRecognitionLength ) > 0 )
67 {
68 result= recordIt.Enum();
69 return true;
70 }
71 return false;
72}
73
74//==================================================================================================
75/// Repeatedly invokes sibling function \alib{enumrecords;Parse} until \p{delim} is not found.
76/// The enum element values are or'ed in \p{result}.
77///
78/// In debug-builds, the method asserts that at least one record is defined for \p{TEnum}.
79///
80/// \note
81/// This method is applicable only to \alib{enumops;BitwiseTraits;bitwise enumrecords} that likewise
82/// are equipped with \ref alib_enums_records "ALib Enum Records" of (derived) type
83/// \alib{enumrecords;ERSerializable}.
84///
85///
86/// @tparam TEnum The enumeration type equipped with <b>ALib Enum Records</b>
87/// of (derived) type \alib{enumrecords;ERSerializable} and furthermore with a
88/// specialization of \alib{enumops;BitwiseTraits}.
89/// @tparam TChar The character type of the \p{input} substring.
90/// Deduced by the compiler.
91/// @tparam TSensitivity The sensitivity of the comparison.
92/// Defaults to \b Case::Ignore.
93/// @tparam TTrimBeforeConsume Determines if the substring should be (left-) trimmed before and
94/// after each consume operation. If so, in case of parsing failure,
95/// trimming is \b not restored.<br>
96/// Defaults to \b Whitespaces::Trim.
97/// @tparam delimiter The delimiter character of the enum elements.<br>
98/// Defaults to <c>','</c>.
99/// @tparam keepLastDelim If \c true , the delimiter will be kept in this substring, if
100/// after the delimiter no further enum element was found.
101/// If \c false, the delimiter will be kept.<br>
102/// Defaults to \c true.
103/// @param[in,out] input The substring to parse. Passed as reference. On success, the
104/// substring will be shortened by the characters consumed. On failure
105/// only trimmed characters are consumed.
106/// @param[out] result The result enum element given as reference.
107/// @return \c true if an enum element was successfuly recognized, \c false otherwise.
108///
109/// ### Module Dependencies ###
110/// This method is only available if the module \alib_strings is included in the \alibbuild.
111//==================================================================================================
112template<typename TEnum,
113 typename TChar,
114 lang::Case TSensitivity = lang::Case::Ignore,
115 lang::Whitespaces TTrimBeforeConsume = lang::Whitespaces::Trim,
116 TChar delimiter = ',',
117 bool keepLastDelim = true >
119 && alib::enumops::IsBitwise <TEnum> )
120bool ParseBitwise( strings::TSubstring<TChar>& input, TEnum& result )
121{
122 bool mResult= false;
123 result= TEnum(0);
124 strings::TSubstring<TChar> restoreBeforeDelim;
125 if constexpr ( keepLastDelim )
126 restoreBeforeDelim= input;
127 for(;;)
128 {
129 if constexpr ( TTrimBeforeConsume == lang::Whitespaces::Trim )
130 input.TrimStart();
131 TEnum actEnum;
133 {
134 if constexpr ( keepLastDelim )
135 input= restoreBeforeDelim;
136 return mResult;
137 }
138 result|= actEnum;
139 mResult= true;
140 if constexpr ( TTrimBeforeConsume == lang::Whitespaces::Trim )
141 input.TrimStart();
142 if constexpr ( keepLastDelim )
143 restoreBeforeDelim= input;
144
145 if( !input.template ConsumeChar<TSensitivity, TTrimBeforeConsume>( delimiter ) )
146 return mResult;
147
148 }
149}
150
151//==================================================================================================
152/// Convenience method that first uses \alib{enumrecords;Parse} to try and read an element of a C++
153/// enum. If this is not successful, an enum of type \alib{lang;Bool} is tried to be read.
154/// If this is successful, depending on the value read, the \p{TEnum} values given
155/// as parameters \p{falseValue} and \p{trueValue} are assigned.
156/// Otherwise, \c false is returned.
157///
158/// In debug-builds, the method asserts that at least one record is defined for \p{TEnum}.
159///
160/// \see
161/// For more information, consult chapter \ref alib_enums_records_details_serialization of the
162/// Programmer's Manual of the module \alib_resources.
163///
164/// @tparam TEnum The enumeration type equipped with <b>ALib Enum Records</b>
165/// of (derived) type \alib{enumrecords;ERSerializable}.
166/// @tparam TChar The character type of the \p{input} substring.
167/// Deduced by the compiler.
168/// @tparam TSensitivity The sensitivity of the comparison.
169/// Defaults to \b Case::Ignore.
170/// @tparam TTrimBeforeConsume Determines if the substring should be (left-) trimmed before and
171/// after each consume operation. If so, in case of parsing failure,
172/// trimming is \b not restored.<br>
173/// Defaults to \b Whitespaces::Trim.
174/// @param trueValue The \p{TEnum} value to use in case of \c Bool::True was read.
175/// @param falseValue The \p{TEnum} value to use in case of \c Bool::False was read.
176/// @param[in,out] input The substring to parse. Passed as reference. On success, the
177/// substring will be shortened by the characters consumed. On failure
178/// only trimmed characters are consumed.
179/// @param[out] result The result enum element given as reference.
180/// @return \c true if an element of \p{TEnum} or \alib{lang;Bool} could be read,
181/// \c false otherwise.
182//==================================================================================================
183template<typename TEnum,
184 typename TChar,
185 lang::Case TSensitivity = lang::Case::Ignore,
186 lang::Whitespaces TTrimBeforeConsume = lang::Whitespaces::Trim >
189 TEnum& result,
190 TEnum falseValue,
191 TEnum trueValue )
192{
193 // first try to read a TEnum
195 return true;
196
197 // if failed, read boolean
198 lang::Bool boolEnum;
200 {
201 result= (boolEnum == lang::Bool::True) ? trueValue : falseValue;
202 return true;
203 }
204
205 // failed
206 return false;
207}
208
209}} // namespace [alib::enumrecords]
210
211
212
213// #################################################################################################
214// Writing (AppendableTraits<Enum>)
215// #################################################################################################
216
217namespace alib { namespace strings {
218
219// Faking specializations of AppendableTraits for doxygen into namespace alib::strings::APPENDABLES
220#if DOXYGEN
221 namespace APPENDABLES {
222#endif
223
224#if !ALIB_RESOURCES || DOXYGEN
225
226/// Templated specialization of functor \alib{strings;AppendableTraits} makes elements
227/// of C++ enumeration type \p{TEnum} appendable to \alib{strings;TAString;AString} instances if:
228/// - Type \p{TEnum} is equipped with \ref alib_enums_records "ALib Enum Records" of type
229/// \alib{enumrecords;ERSerializable} (or a derived type ), and if:
230/// - \b No specialization of the type trait \alib{enumops;BitwiseTraits} exists for \p{TEnum}.
231/// (For those, a different implementation of this functor is given.)
232///
233/// \note
234/// The conditions are evaluated by the compiler using keyword \c requires and concepts
235/// \alib{enumrecords;IsSerializable} and \alib{enumops;IsBitwise} to generically specialize
236/// the type trait \alib{strings;AppendableTraits} of the module \alib_strings.
237///
238/// Member \b operator() writes the name of the given enumeration value to \p{target}.
239/// As with all specializations of functor \b %AppendableTraits, the use of it is done implicitly
240/// with various interface method of class \alib{strings;TAString;AString}.
241///
242/// If furthermore, the type trait \alib{resources;ResourcedTraits} is specialized for
243/// type \p{TEnum}, and an externalized resource string exists - according to the specification
244/// described with methods \alib{resources;ResourcedType::TypeNamePrefix} and
245/// \alib{resources;ResourcedType::TypeNamePostfix} - then these resourced strings are written
246/// prior and after the enumeration element's name.
247///
248/// \par Availability
249/// For technical reasons, this functor is available with the inclusion of the header
250/// \implude{Resources}, instead of the header \implude{EnumRecords}.<br>
251/// Only in the case that the module \alib_resources is \b not included in the \alibbuild, then a
252/// reduced version which does not display a resourced enumeration type name, is defined with
253/// the module \alib_enumrecords_nl.
254///
255/// \see
256/// - Sibling specialization
257/// \alib{strings::APPENDABLES;AppendableTraits<TBitwiseEnum,TChar,TAllocator>}
258/// - \ref alib_enums_records "ALib Enum Records".
259/// - Type trait \alib{resources;ResourcedTraits}.
260/// - Corresponding convenience type \alib{resources;ResourcedType}.
261/// - Some sample code is given with documentation \ref alib_enums_records "ALib Enum Records".
262///
263/// @tparam TEnum The enumeration type of the element that is to be appended to an \b %AString.
264/// @tparam TChar The character type of the target \b %AString.
265/// @tparam TAllocator The allocator type of the target \b %AString, as prototyped with
266/// \alib{lang;Allocator}.
267template<typename TEnum, typename TChar, typename TAllocator>
268requires ( enumrecords::IsSerializable<TEnum> && !enumops::IsBitwise<TEnum> )
270{
271 //==============================================================================================
272 /// Writes the name of the given enumeration \p{element} it to \p{target}.
273 ///
274 /// If available for \p{TEnum}, the resourced name
275 /// \alib{resources;ResourcedType::TypeNamePrefix;prefix} and
276 /// \alib{resources;ResourcedType::TypeNamePostfix;postfix} are written before and after
277 /// the element's name.
278 ///
279 /// If no record exists for \p{element}, its underlying integral value is written.
280 /// In debug-builds, the method asserts that at least one record is defined for \p{TEnum}.
281 ///
282 ///
283 /// @param target The \b AString that \p{element} is to be appended to.
284 /// @param element The enumeration element to append to \p{target}.
285 //==============================================================================================
286 void operator()( TAString<TChar,TAllocator>& target, TEnum element )
287 {
288 ALIB_ASSERT_ERROR( EnumRecords<TEnum>().begin() != EnumRecords<TEnum>().end(), "ENUMS",
289 "No Enum Records for type <{}> found.", &typeid(TEnum) )
290
291 auto* record= enumrecords::TryRecord( element );
292 if( record != nullptr )
293 target << record->EnumElementName;
294 else
295 target << UnderlyingIntegral( element );
296 }
297};
298
299/// This specialization of type-traits-functor \alib{strings;AppendableTraits} makes elements of
300/// C++ enumeration type \p{TBitwiseEnum} appendable to \alib{strings;TAString;AString} instances,
301/// if
302/// - Type \p{TBitwiseEnum} is equipped with \ref alib_enums_records "ALib Enum Records" of type
303/// \alib{enumrecords;ERSerializable} (or a derived type derived from \b ERSerializable), and
304/// - \b A specialization of type trait \alib{enumops;BitwiseTraits} exists for \p{TBitwiseEnum}.
305/// (For non-bitwise types, a different implementation of this functor is given.)
306///
307/// Member \b operator() writes all value names corresponding to the bits set in \p{src},
308/// separated by delimiter character <c>','</c>.
309/// \note
310/// For technical reasons, the delimiter is not adjustable. In cases a different delimiter
311/// is to be used, it needs to be replaced in the string after the value is written.
312///
313/// If the underlying integral value of a given enum element may be become \c 0, a corresponding
314/// enum record associated to such non-bit value will be used if existent.
315///
316/// Furthermore, with bitwise type enumrecords, the defined enum records may contain entries that
317/// represent combinations of more than one integral bit. Such combination entries are supported
318/// but have to be registered with class \alib{enumrecords;EnumRecords} \b before the
319/// standard single bit entries!
320/// If combined bit values are matched, the corresponding element names that represent the
321/// single bit values will not be written.
322///
323/// As a sample, let's consider a window manager software which has a scoped enum type representing
324/// window states. Because a window might have more than one state, macro
325/// \ref ALIB_ENUMS_MAKE_BITWISE is used to specialize the type trait \alib{enumops;BitwiseTraits}.
326/// Next, macro \ref ALIB_ENUMS_ASSIGN_RECORD used to associate the type with enum record type
327/// \alib{enumrecords;ERSerializable}:
328///
329/// \snippet "DOX_ENUMS.cpp" DOX_ENUMS_BITWISE_DECLARATION
330///
331/// A window that is both, vertically and horizontally maximized, is considered to be "just"
332/// \e maximized. Therefore, during bootstrap of the software, enum records that fetch that the
333/// combination of states are defined \b before the single-state records:
334///
335/// \snippet "DOX_ENUMS.cpp" DOX_ENUMS_BITWISE_DEFINITION
336///
337/// That is all that is needed! With this setup, the following code:
338/// \snippet "DOX_ENUMS.cpp" DOX_ENUMS_BITWISE_SAMPLE
339///
340/// produces this output:
341/// \snippet "DOX_ENUMS_BITWISE_OUTPUT.txt" OUTPUT
342///
343/// If furthermore, the type trait \alib{resources;ResourcedTraits} is specialized for
344/// type \p{TBitwiseEnum} and an externalized resouce string exists - according to the
345/// specification described with the methods \alib{resources;ResourcedType::TypeNamePrefix}
346/// and /// \alib{resources;ResourcedType::TypeNamePostfix} - then these resourced strings
347/// are written prior and after the enumeration element name(s).
348///
349/// \par Availability
350/// For technical reasons, this functor is available with the inclusion of the header
351/// \implude{Resources}, instead of the header \implude{EnumRecords}.<br>
352/// Only in the case that the module \alib_resources is \b not included in the \alibbuild, then a
353/// reduced version which does not display a resourced enumeration type name, is defined with
354/// the module \alib_enumrecords_nl.
355///
356/// \see
357/// - Sibling specialization
358/// \alib{strings::APPENDABLES;AppendableTraits<TEnum,TChar,TAllocator>}
359/// - The type trait \alib{resources;ResourcedTraits}.
360/// - Corresponding convenience type \alib{resources;ResourcedType}.
361/// - Some sample code is given with documentation \ref alib_enums_records "ALib Enum Records".
362///
363/// # Reference Documentation #
364/// @tparam TBitwiseEnum The bitwise defined enumeration type.
365/// @tparam TChar The character type of the target \b %AString.
366/// @tparam TAllocator The allocator type of the target \b %AString, as prototyped with
367/// \alib{lang;Allocator}.
368template<typename TBitwiseEnum, typename TChar, typename TAllocator>
370 && alib::enumops::IsBitwise <TBitwiseEnum> )
372 //==============================================================================================
373 /// Writes a comma-separated list of element names of the bitwise defined enumeration \p{TEnum}
374 /// to \p{target}.
375 ///
376 /// In debug-builds, the method asserts that at least one record is defined for \p{TEnum}.
377 /// It is furthermore asserted that all bits contained in \p{elements} have been "covered"
378 /// by corresponding names.
379 ///
380 /// The enum records defined may aggregate several bits. Aggregations have to be defined
381 /// before records that represent the corresponding single bits (or another subset of those).
382 ///
383 /// \see
384 /// This struct's documentation for more information and a sample.
385 ///
386 /// @param target The \b AString that \p{elements} is to be appended to.
387 /// @param elements The enumeration element to append to \p{target}.
388 //==============================================================================================
389 void operator()( TAString<TChar,TAllocator>& target, TBitwiseEnum elements )
390 {
392 "ENUMS", "No Enum Records for type <{}> found.", &typeid(TBitwiseEnum) )
393
394 // check what has been covered and omit double entries
395 TBitwiseEnum covered= TBitwiseEnum(0);
396
397 // loop over entry 2 to end, check bit
398 integer len= target.Length();
399
400 for( auto recordIt= EnumRecords<TBitwiseEnum>().begin() ;
401 recordIt != EnumRecords<TBitwiseEnum>().end() ; ++recordIt )
402 {
403 // no bits are set and this entry does not contain bits, then stop here
404 if( recordIt.Integral() == 0 )
405 {
406 if( elements == TBitwiseEnum(0) )
407 {
408 target << recordIt->EnumElementName;
409 return;
410 }
411 }
412 else if( HasBits( elements, recordIt.Enum() )
413 && !HasBits( covered , recordIt.Enum() ) )
414 {
415 covered|= recordIt.Enum();
416 target << recordIt->EnumElementName << ',';
417 }
418 }
419 len= target.Length() - len;
420
421 // remove the last comma
422 if( len != 0 )
423 target.DeleteEnd( 1 );
424
425 ALIB_ASSERT_ERROR( covered == elements, "ENUMS",
426 "Not all bits have been covered while writing bitset '{}' of enumeration type <{}>."
427 " Remaining bits are '{}'.", NString128(NBin( elements )),
428 &typeid(TBitwiseEnum), NString128(NBin( covered & elements )) )
429 }
430};
431
432#endif // !ALIB_RESOURCES || DOXYGEN
433
434#if DOXYGEN
435} // namespace alib::strings[::appendables]
436#endif
437#include "ALib.Lang.CIMethods.H"
438
439}} // namespace [alib::strings]
440
441
442
TAString & DeleteEnd(integer regionLength)
constexpr integer Length() const
Definition string.inl:318
TSubstring & TrimStart(const TCString< TChar > &whiteSpaces=CStringConstantsTraits< TChar >::DefaultWhitespaces())
Definition substring.inl:76
#define ALIB_EXPORT
Definition alib.inl:488
#define ALIB_ASSERT_ERROR(cond, domain,...)
Definition alib.inl:1049
bool Parse(strings::TSubstring< TChar > &input, TEnum &result)
bool ParseBitwise(strings::TSubstring< TChar > &input, TEnum &result)
bool ParseEnumOrTypeBool(strings::TSubstring< TChar > &input, TEnum &result, TEnum falseValue, TEnum trueValue)
const RecordsTraits< TEnum >::Type * TryRecord(TEnum element)
Definition records.inl:218
Case
Denotes upper and lower case character treatment.
Whitespaces
Denotes whether a string is trimmed or not.
@ Trim
Trim whitespaces away.
NLocalString< 128 > NString128
Type alias name for TLocalString<nchar,128>.
lang::integer integer
Type alias in namespace alib.
Definition integers.inl:149
enumrecords::EnumRecords< TEnum > EnumRecords
Type alias in namespace alib.
Definition records.inl:519
strings::TBin< nchar > NBin
Type alias in namespace alib.
Definition format.inl:575
static constexpr ForwardIterator end()
Definition records.inl:419
void operator()(TAString< TChar, TAllocator > &target, TBitwiseEnum elements)
void operator()(TAString< TChar, TAllocator > &target, TEnum element)