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