ALib C++ Framework
by
Library Version: 2511 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
propertyformatter.inl
Go to the documentation of this file.
1//==================================================================================================
2/// \file
3/// This header-file is part of module \alib_format of the \aliblong.
4///
5/// \emoji :copyright: 2013-2025 A-Worx GmbH, Germany.
6/// Published under #"mainpage_license".
7//==================================================================================================
8ALIB_EXPORT namespace alib { namespace format {
9
10//==================================================================================================
11/// # Introduction # {#alib_ns_strings_propertyformatter_overview}
12///
13/// This class can be used to offer customized format strings to end users. For example, when
14/// it should be allowed to end-users to store output format strings of complex type.
15///
16/// For this, the format string definition of \alib {format;Formatter}
17/// types is extended to support identifiers,
18/// which act as placeholders for object values. The identifiers placed in the string have to match
19/// to the normal formatting placeholders in respect to their total number and value type.
20///
21/// \note
22/// In other words: This class allows not only to have custom format strings which consume a
23/// list of data objects that is hard-coded, but also to have the replacement data objects defined
24/// by the end user.
25///
26/// In the constructor of this class, a custom format string which whose syntax is based on
27/// #"alib_format_intro;standard ALib format strings" is passed.
28/// However, before using the format string, it is processed as follows:
29/// - It is searched for <em>"custom identifiers"</em> within the format string.
30/// - For each identifier found, a reference to an associated callback function is stored.
31/// - The <em>"custom identifier"</em> found is removed from the format string.
32///
33/// It could be said, that the format string given "is compiled" with the constructor of this class.
34///
35/// The only interface method #".Format" then accepts a
36/// #"alib::boxing;boxed object" of custom type that is used to collect the format string's
37/// placeholder data, by using the stored callback functions.
38///
39/// The identifiers are denoted by prefixing them with (customizable) character <c>'@'</c>.
40///
41/// A vector of objects of inner type \b IdentifierEntry needs to be defined and passed to the
42/// constructor of this class.
43/// The field #"IdentifierEntry::Name" contains the \e 'identifier' string which is removed from the
44/// format string if found. Field #"IdentifierEntry::Callback" has to point to a callback function
45/// used to retrieve the data when the identifier is found in the format string.
46///
47/// The whole approach is useful in cases where an application wants to allow a customizable output
48/// format of data objects.
49///
50/// # Sample # {#alib_ns_strings_propertyformatter_sample}
51/// Let us assume, an application uses an enumeration and a simple struct:
52/// \snippet "DOX_STRINGS.cpp" DOX_STRINGS_PROPERTY_FORMATTER_1
53///
54/// In the application's configuration file, a custom output format for objects of type \b Person
55/// should be user-defined. We document to the user that she can use Python-style or
56/// Java-style output formats - extended by the ability to place the following three identifiers in
57/// the string:
58/// - \@name
59/// - \@age
60/// - \@hobby.
61///
62/// A possible format string then would be:
63///
64/// "{@name} is aged {@age} and his/her hobby is {@hobby}"
65///
66/// \note
67/// The custom identifiers might appear anywhere in the format string. But as sampled above,
68/// placing them in directly in the formatter replacement fields, makes the string very well
69/// readable. Also, it is important to have exactly one identifier for each replacement field,
70/// which this notation of course supports well.
71///
72/// To tell this class how to retrieve the replacement values, we need to define three callback
73/// functions:
74/// \snippet "DOX_STRINGS.cpp" DOX_STRINGS_PROPERTY_FORMATTER_2
75/// It is a good idea to place the callback functions in an anonymous (sub-) namespace as they
76/// are only referred to once (in the next step).<br>
77/// As this sample is very trivial, the second parameter <c>AString&</c> is not used and named.
78/// Details on the purpose and use of this parameter is addressed
79/// #"alib_ns_strings_propertyformatter_callbacks;below".
80///
81/// As a next step, these functions need to be collected together in a "translation table".
82/// The table primarily holds a string denoting the replacement identifier and a pointer to the
83/// corresponding callback function. For convenience, the table type is provided with <c>using</c>
84/// definition #"TCallbackTable".
85///
86/// In our sample, the definition of the table looks like this:
87/// \snippet "DOX_STRINGS.cpp" DOX_STRINGS_PROPERTY_FORMATTER_3
88///
89/// This is all we need! Of course, an external declaration of our table \b PersonCallbacks
90/// should be placed somewhere in the project's header-file. With this, a code like this may now use
91/// the custom formatter strings:
92/// \snippet "DOX_STRINGS.cpp" DOX_STRINGS_PROPERTY_FORMATTER_4
93///
94/// Running the code above produces the following output:
95/// \verbinclude "DOX_STRINGS_PROPERTY_FORMATTER.txt"
96///
97/// Serializing objects in a custom format (e.g., a user could define its own \b JSon object output)
98/// should be the most obvious and frequent use case. And this is what the classes name suggests.
99/// Nevertheless, the callback methods might be more complex than just returning "properties" of
100/// objects. The next sections gives more details on the custom callbacks.
101///
102/// \I{ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * }
103/// # Callback Functions # {#alib_ns_strings_propertyformatter_callbacks}
104/// The call back function's signature is defined with <c>using</c>-statement #"TCallback" which
105/// evaluates to
106///
107/// Box (*)(const Box&, AString&)
108///
109/// The return type is #"alib::boxing::Box;Box", which allows the callback function to
110/// return objects of an arbitrary type, respectively all types that are equipped to be used
111/// with \alib formatters.
112///
113/// The first input parameter provides the data object passed to method #".Format".
114/// If the callback functions are dedicated to a property formatter that receives a certain
115/// object type (what they usually are), the custom type can be straightly unboxed.
116///
117/// \note
118/// The name of the class, as well as the sample above, indicate that the data objects are
119/// simple objects with rather simple "properties" to read. While this is the usual use case,
120/// a user of this class might pass more complex objects, or even the root object of the
121/// application to the formatter. Then, the callback function may retrieve (or calculate)
122/// any data that the application provides.
123///
124/// The second parameter is an \b AString object which optionally can be used to assemble
125/// string objects in more complex callback methods. Note, that if this string is not
126/// empty after the callback invocation, the result is copied to a string buffer allocated
127/// in the heap memory. In this case, the box object returned by the callback is ignored
128/// and instead the copy of the string is passed to the formatter. If C++ string constants
129/// (e.g <c>"true"</c> are to be returned by the callbacks, those constants do not need
130/// to be copied to the buffer, as their memory is statically allocated. In other words,
131/// the \b %AString buffer provided in the second parameter is needed to be used
132/// only in cases that a string gets assembled in the callback function!
133///
134/// \I{ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * }
135/// # Identifiers And The Escape Character '@' # {#alib_ns_strings_propertyformatter_escape}
136/// The escape character used to find custom identifiers in the format string is defined
137/// with parameter \p{ESCCharacter} of the constructor and defaults to \b '\@'.
138/// This escape character is searched in the format string. If found, the identifier is
139/// read by consuming alphabetic characters. Optionally, the end of a custom identifier can be
140/// marked with an additional escape character.
141/// Hence, the two format strings
142///
143/// "{@name}"
144/// "{@name@}"
145/// are both valid and equal.<br>
146///
147/// In case of
148/// #"FormatterPythonStyle" format strings,
149/// it is a good idea to place the identifier right inside the brackets. It just looks very intuitive.
150/// However, these versions:
151///
152/// "@name{}"
153/// "{}@name"
154/// are also valid custom format strings.
155///
156/// In case of
157/// #"FormatterJavaStyle", which uses \b '\%'
158/// as its escape character, we consider the best option to put the custom identifier in front
159/// of each \b '\%' symbol. The string of the example given above would then look like this:
160///
161/// "@name%s is aged @age%d and his/her hobby is @hobby%s"
162/// Doing it this way, the \b '\%' symbol acts as a very natural delimiter for the custom
163/// identifier.
164///
165/// Furthermore, the field #"IdentifierEntry::MinimumRecognitionLength" allows abbreviations of
166/// identifier names.
167/// It denotes the minimum number of characters to be* matched. As in the above sample a
168/// value of \c 1 is provided, each identifier of the custom format string can be abbreviated down
169/// to one character. Consequently, the following format string samples are all equal and allowed:
170///
171/// "{@name}"
172/// "{@nam}"
173/// "{@na}"
174/// "{@n}"
175///
176/// Finally, to insert the escape character itself into the format string, it has to be doubly
177/// inserted (<c>"@@"</c>).
178///
179/// \I{ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * }
180/// # Alternative # {#alib_ns_strings_propertyformatter_alternative}
181/// If \alib_expressions is compiled with the library, a utility class similar to this one
182/// is available with #"util::ExpressionFormatter".
183/// With this, complex expressions and calculations might be used instead of only having simple
184/// identifiers as replacements.
185///
186/// \I{#############################################################################################}
187/// # Reference Documentation #
188/// @throws Exception #"alib::format::FMTExceptions::UnknownPropertyInFormatString;2" \I{CLANGDUMMY}
189//==================================================================================================
191{
192 public:
193 /// The signature of the callback functions.
194 /// See #"alib_ns_strings_propertyformatter_callbacks" for more information.
195 using TCallback= Box (*)(const Box&, AString&);
196
197 /// The entry type of translation table.
199 {
200 /// The identifier string to search in the original format string.
202
203 /// The minimum characters of the identifier to read in the format string.
204 /// If less or equal to zero, abbreviations are not allowed.
206
207 /// The callback function for this identifier.
208 /// @see #"alib_ns_strings_propertyformatter_callbacks".
210 };
211
212 /// Type definition of the callback table.
213 using TCallbackTable= std::vector<IdentifierEntry>;
214
215
216 protected:
217 /// Internal type definition for the list of callback table entries collected in the
218 /// constructor by parsing the extended format string.
219 using TCallbackResultTable= std::vector<const IdentifierEntry*>;
220
221 /// The formatter (as given in the constructor).
223
224 /// The original format string. Used only for exception information.
226
227 /// The resulting format string passed to \alib formatters.
229
230 /// The callback functions to receive the format data.
232
233 public:
234
235 /// Constructor. Processes the given format string and builds internal structures
236 /// which are then used with invocations of method #".Format".
237 ///
238 /// @param customFormatString The format string as described in the class documentation.
239 /// @param propertyTable Table with property identifier names and callback functions
240 /// to retrieve the property values.
241 /// @param formatter The formatter to use. Defaults to \c nullptr which selects
242 /// the #"Formatter::DEFAULT;default formatter".
243 /// @param ESCCharacter The prefix used to search identifiers in
244 /// \p{customFormatString}.<br>
245 /// Defaults to <c>'@'</c>.
246 ///
247 /// @throws Exception #"FMTExceptions;FMTExceptions::UnknownPropertyInFormatString".
249 PropertyFormatter( const String customFormatString,
250 const TCallbackTable& propertyTable,
251 SPFormatter formatter = nullptr,
252 character ESCCharacter = '@' );
253
254 /// Writes the formatted output of the properties of the given \p{TFormattable} object
255 /// to a given \p{target} string.
256 ///
257 /// @param target The target string to write into.
258 /// @param src The custom object which is passed to the callback methods to collect
259 /// the formatter arguments.
261 void Format( AString& target, const Box& src );
262}; // class PropertyFormatter
263
264} // namespace alib[::format]
265
266/// Type alias in namespace \b alib.
268
269} // namespace [alib]
#define ALIB_DLL
Definition alib.inl:573
#define ALIB_EXPORT
Definition alib.inl:562
TCallbackResultTable callBacks
The callback functions to receive the format data.
AString formatString
The resulting format string passed to ALib formatters.
SPFormatter stdFormatter
The formatter (as given in the constructor).
PropertyFormatter(const String customFormatString, const TCallbackTable &propertyTable, SPFormatter formatter=nullptr, character ESCCharacter='@')
std::vector< IdentifierEntry > TCallbackTable
Type definition of the callback table.
Box(*)(const Box &, AString &) TCallback
AString propertyFormatString
The original format string. Used only for exception information.
void Format(AString &target, const Box &src)
std::vector< const IdentifierEntry * > TCallbackResultTable
containers::SharedPtr< format::Formatter > SPFormatter
Definition formatter.inl:42
boxing::Box Box
Type alias in namespace alib.
Definition box.inl:1135
strings::TString< character > String
Type alias in namespace alib.
Definition string.inl:2172
format::PropertyFormatter PropertyFormatter
Type alias in namespace alib.
strings::TAString< character, lang::HeapAllocator > AString
Type alias in namespace alib.
characters::character character
Type alias in namespace alib.
String Name
The identifier string to search in the original format string.