ALib C++ Library
Library Version: 2402 R1
Documentation generated by doxygen
Loading...
Searching...
No Matches
formatterstdimpl.hpp
Go to the documentation of this file.
1/** ************************************************************************************************
2 * \file
3 * This header file is part of sub-namespace #alib::lang::format of module \alib_basecamp of
4 * the \aliblong.
5 *
6 * \emoji :copyright: 2013-2024 A-Worx GmbH, Germany.
7 * Published under \ref mainpage_license "Boost Software License".
8 **************************************************************************************************/
9#ifndef HPP_ALIB_LANG_FORMAT_FORMATTER_STD
10#define HPP_ALIB_LANG_FORMAT_FORMATTER_STD 1
11
12#if !defined (HPP_ALIB_LANG_FORMAT_FORMATTER)
14#endif
15
16
17namespace alib::lang::format {
18
19/** ************************************************************************************************
20 * This is a base class for \alib built-in formatters. The class implements abstract method
21 * \alib{lang::format;Formatter::format} and introduces a set of
22 * new abstract methods that have to be implemented by descendants.
23 *
24 * Derived types need to set default values for attributes in fields
25 * #DefaultNumberFormat and #AlternativeNumberFormat within their constructor once - according
26 * to defaults specified by the formatting syntax.
27 * This should not be repeated per format operation. This way users of the type are allowed
28 * to change such default setting (even if they this may the formatter deviates from the standard
29 * it implements).
30 *
31 * All values aggregated in member #placeholder, together comprise the set of formatting attributes
32 * which can be modified by placeholder semantics of the format string.
33 * Derived types might use extended attributes.
34 * Implementations provided with \alib define such extended attributes using a corresponding
35 * additional inner type.
36 *
37 * When parsing a placeholder of a format string, abstract method #parsePlaceholder
38 * may set field \alib{lang::format::FormatterStdImpl::PlaceholderAttributes;FormatSpec} to reflect
39 * a format-specific portion the placeholder string.
40 * It will be checked if the argument supports box-function \alib{lang::format;FFormat},
41 * and if so, this string is passed to the box-function.
42 * If the argument does not support the interface, method #parseStdFormatSpec is invoked to
43 * now parse this portion of the placeholder string in a default way.<br>
44 * This concept allows customized format specifications for custom argument types! As an example,
45 * a format specification for date/time argument types may support a custom format string
46 * like \c "yyyy-MM-dd HH:mm:ss".
47 * \note
48 * This concept is implemented with class
49 * \alib{lang::format;FormatterPythonStyle;FormatterPythonStyle} as the
50 * "Python format mini language" supports such custom format specifications. Class
51 * \alib{lang::format;FormatterJavaStyle;FormatterJavaStyle} does \b not support
52 * this mechanism.
53 *
54 * The following describes the formatting process in detail (the implementation of method #format)
55 * and this way helps to understand what is required from the implementation of the abstract methods:
56 *
57 * 1. Method parameters are stored in fields #targetString, #formatString, #arguments and
58 * #argOffset. This way, the parameters can be accessed from any implemented method without
59 * the need of passing them as parameters once more.<br>
60 * In addition, field #parser is initialized. This \b Substring is used to parse
61 * the format string. Parsed portions will be consumed from the front of the string.
62 * Finally fields #argsConsumed and #nextAutoIdx are initialized to value \c 0.
63 *
64 * 2. <b>Start of the loop</b> to find and process placeholders in the format string.
65 *
66 * 3. Abstract method #findPlaceholder is invoked. If this fails (no further placeholder was found)
67 * parsing stops. If, and only if, a placeholder was found before, method #writeStringPortion is
68 * invoked for the rest of the string prior to exiting the function.
69 *
70 * 4. Method #writeStringPortion is invoked to write the current parser contents up to the
71 * placeholder position.
72 *
73 * 5. Method #resetPlaceholder is invoked, to reset the attributes that will be parsed in the next
74 * step. The values that are set are implementation specific and need to reflect the
75 * default formatting options if no specific options are given in the format string.
76 *
77 * 6. Abstract Method #parsePlaceholder is invoked to parse and consume tokens from string #parser
78 * and while doing this, to store the parsed format attributes in the fields with
79 * name prefix \c pha (or extended attributes of a derived formatter type).<br>
80 * If an argument (positional) index is found during parsing, then method
81 * #setArgument is to be invoked by abstract method \b %parsePlaceholder providing that index.<br>
82 * If the format syntax of the formatter contains a separated format specification string
83 * (a sub-string of the placeholder string), then the method may store such format
84 * sub-string in field
85 * \alib{lang::format::FormatterStdImpl::PlaceholderAttributes;FormatSpec}.
86 *
87 * 7. Next, it is checked if an argument was set by \b %parsePlaceholder. If not, #setArgument
88 * is invoked providing \c -1 for the index to indicate auto-indexing.
89 * \note
90 * If auto-indexing should be implemented differently than done with default method
91 * #setArgument, then a custom formatter might either override the method or,
92 * in the case no index is given in the format string, just
93 * set fields
94 * \alib{lang::format::FormatterStdImpl::PlaceholderAttributes;Arg} and
95 * \alib{lang::format::FormatterStdImpl::PlaceholderAttributes;ArgIdx}
96 * already in \b %parsePlaceholder according to its own strategy
97 *
98 * 9. Method #preAndPostProcess is invoked with parameter \p{startIdx} equalling \c -1
99 * (indicating pre-processing). This allows for example to insert tab fill-characters
100 * (tab stops) prior to writing the contents of the field.
101 *
102 * 9. Method #writeCustomFormat is invoked. This allows derived formatters to write arguments in a
103 * custom way. If the method returns \c true, the loop is continued ( &rarr; Step 4.). <br>
104 * The default implementation checks whether box-function \alib{lang::format;FFormat} is defined for
105 * \alib{lang::format::FormatterStdImpl::PlaceholderAttributes;Arg}.
106 * In this case, the interface is invoked and \c true returned.
107 *
108 * 10. Again, if a format specification was stored in
109 * \alib{lang::format::FormatterStdImpl::PlaceholderAttributes;FormatSpec}
110 * method #parseStdFormatSpec is invoked which needs to set further attributes
111 * in the \b %Placeholder object according to the standard format specification of the formatter.
112 *
113 * 11. Now, as all fields that represent formatting attributes are well set (or kept with their
114 * defaulted value), method #checkStdFieldAgainstArgument is invoked.
115 * This method is virtual but not abstract. Its default implementation checks the
116 * placeholder attributes against the provided argument type and raises an error if the
117 * argument does not fit to the placeholder format specification.
118 *
119 * 12. Method #writeStdArgument is invoked. This method is virtual but not abstract.
120 * Its default implementation writes the argument value formatted according to the attribute
121 * fields.
122 *
123 * 13. Finally #preAndPostProcess is invoked with parameter \p{startIdx} pointing to the first
124 * character in #targetString of the argument written.
125 * Here, actions like case conversion might be done on the field written.
126 *
127 * 14. End of loop ( &rarr; Step 4.)
128 **************************************************************************************************/
130{
131 // #############################################################################################
132 // Placeholder types and attributes
133 // #############################################################################################
134 protected:
135 /** Denotes the type of placeholders (respectively the values they represent). */
136 enum class PHTypes
137 {
138 NotGiven , ///< The default
139 String , ///< %String type requested.
140
141 Character, ///< Converts a given character or integer number to the corresponding
142 ///< unicode character before printing.
143
144 IntBase10, ///< Outputs a given number in base 10. The default.
145 IntBinary, ///< Outputs a given number in base 2.
146 IntOctal , ///< Outputs a given number in base 8.
147 IntHex , ///< Outputs a given number in base 16.
148
149 Float , ///< Outputs a number in floating point format.
150
151 Bool , ///< Writes "true" or "false".
152 HashCode , ///< Writes raw box data as hex.
153
154 Fill , ///< Writes \alib{lang::format::FormatterStdImpl::PlaceholderAttributes;FillChar}
155 ///< x-times. Used with python-style conversion <b>{!Fill[C]}</b>.
156 };
157
158
159 /**
160 * Collection of attributes related to the current placeholder processed.
161 * \note
162 * The members of this inner class could as well be rightful members of the outer class.
163 * One object of this inner type is created as a normal member. Hence, the only
164 * reason for gathering the fields in this inner type is readability. (It has no influence
165 * on the compilation result.)
166 *
167 */
169 {
170 /** The current Box.
171 * This is set by #parsePlaceholder if explicit indexing is used. Otherwise by #format
172 * which invokes #setArgument if #parsePlaceholder did not set it yet.
173 * Set to \c nullptr in default implementation of #resetPlaceholder. */
174 const Box* Arg;
175
176 /** The portion of the replacement field that represents the format specification.
177 * This field might be set in method #parsePlaceholder and consumed in methods
178 * #writeCustomFormat and #parseStdFormatSpec.<br>
179 * This field is \e nulled in default implementation of #resetPlaceholder. */
181
182 /** The number format object for the actual attribute. With method #resetPlaceholder values
183 * found in object #DefaultNumberFormat will be copied into this. */
185
186 /** The type of the attribute as specified in the placeholder.
187 * This is set to
188 * \ref alib::lang::format::FormatterStdImpl::PHTypes::NotGiven "PHTypes::NotGiven"
189 * in default implementation of #resetPlaceholder. */
191
192 /** The alignment of the contents within a field.
193 * This is set to \alib{lang;Alignment;Alignment} in default
194 * implementation of #resetPlaceholder. */
196
197 /** The positional index of the current
198 * \alib{lang::format::FormatterStdImpl::PlaceholderAttributes;Arg;argument}.
199 * This is set by #parsePlaceholder if explicit indexing is used. Otherwise by #format
200 * which invokes #setArgument if #parsePlaceholder did not set it yet.
201 * Set to \c -1 in default implementation of #resetPlaceholder. */
203
204 /** The index of the previous argument. Used when addressing previous argument
205 * number (eg. in Java formatting style this could be "%<$...").
206 * This is set to \alib{lang::format::FormatterStdImpl::PlaceholderAttributes;ArgIdx}
207 * in default implementation of #resetPlaceholder. */
209
210 /** The (minimum) width of the output.
211 * This is set to \c 0 in default implementation of #resetPlaceholder. */
212 int Width;
213
214
215 /** If not negative, the string representation of the argument is cut prior to
216 * applying any field operation. It could be also named "precision", hence
217 * the number of characters to show - even if the field will be wider.
218 * This is set to \c -1 in default implementation of #resetPlaceholder. */
220
221 /** This is the position in the format string where the actual type code was read from.
222 * Used for exception argument generation (FMTExceptions::IncompatibleTypeCode).
223 * If -1, the actual parse position is used. */
225
226 /** If true, an alignment was explicitly specified.
227 * This is set to \c false in default implementation of #resetPlaceholder. */
229
230 /** Forces the padding to be placed after the sign (if any) but before the digits.
231 * This is used for printing fields in the form ‘+000000120'.
232 * This alignment option is only valid for numeric types.
233 * Set to \c false in default implementation of #resetPlaceholder. */
235
236 /** Used with binary, octal, or hexadecimal output. Specifies that the output will be
237 * prefixed by strings found in fields
238 * \alib{strings;TNumberFormat::BinLiteralPrefix;BinLiteralPrefix},
239 * \alib{strings;TNumberFormat::HexLiteralPrefix;HexLiteralPrefix} or
240 * \alib{strings;TNumberFormat::OctLiteralPrefix;OctLiteralPrefix} which
241 * default to \c "0b", \c "0o" and \c "0x".
242 * Set to \c false in default implementation of #resetPlaceholder. */
244
245 /** Can be \c true for float-types. If \c true, the value is multiplied with 100 and
246 * a percentage symbol \c '\%' is printed after the value.
247 * Set to \c false in default implementation of #resetPlaceholder. */
249
250 /** The filling character for fields that are larger than their content.
251 * Method #resetPlaceholder will set this to <c>' '</c>. */
253
254 /** This is the (format specific) type code of the current format operation.
255 * Used only to display error messages. May be used differently in derived classes.
256 * Is \e nulled in default implementation of #resetPlaceholder. */
258 };
259
260 // #############################################################################################
261 // protected fields
262 // #############################################################################################
263 protected:
264 /** A string buffer, used for example, when writing aligned fields. */
266
267 /** The name of the formatter as provided in the constructor. Used for generating
268 * error messages. */
270
271 /** The format string as provided with method #Format. */
273
274 /** The current (remaining) format string. */
276
277 /** The target string as provided with method #Format. */
279
280 /** The list of arguments provided with method #Format. */
282
283 /** The length of the target string before adding the formatted contents. */
285
286 /** The offset of the first argument to use. Provided with method #Format. */
288
289 /** The number of arguments consumed by the current format string. */
291
292 /** Counter for auto-indexed arguments. */
294
295 /** If \c false the formatters specification expects argument to be numbered from
296 * <c>0..N</c>. If \c true from <c>1..N</c>. */
298
299 /** If \c false the formatters specification expects argument to be numbered from
300 * <c>0..N</c>. If \c true from <c>1..N</c>. */
302
303
304 // #############################################################################################
305 // Constructor/destructor
306 // #############################################################################################
307 public:
308 /** ****************************************************************************************
309 * Constructor.
310 * @param formatterClassName The name of the derived class. Used to generate error messages
311 * including a link into the online documentation. (Therefore
312 * has to be the exact name.
313 ******************************************************************************************/
314 FormatterStdImpl( const String& formatterClassName );
315
316
317 // #############################################################################################
318 // Implementation of abstract interface of parent class Formatter
319 // #############################################################################################
320 protected:
321
322 /** ****************************************************************************************
323 * Implemented abstract format method which invokes a set of new abstract methods
324 * as described in the main documentation of this class.
325 *
326 * @param targetString An AString that takes the result.
327 * @param formatString The format string.
328 * @param arguments The objects to convert.
329 * @param argOffset The first object in \p{arguments} to use.
330 *
331 * @return The number of args consumed.
332 ******************************************************************************************/
334 virtual int format( AString& targetString,
335 const String& formatString,
336 const Boxes& arguments,
337 int argOffset ) override;
338
339
340 // #############################################################################################
341 // Introduction of new, partly abstract methods to be implemented (or optionally overwritten)
342 // by descendents.
343 // #############################################################################################
344 protected:
345
346 /** ****************************************************************************************
347 * Abstract method to search the next index of an argument placeholder in the remaining
348 * sub-string (field #parser) of the format string.
349 *
350 * @return The index found, \c -1 if not found.
351 ******************************************************************************************/
353
354 /** ****************************************************************************************
355 * Overridable method to clean and reset the fields representing the current placeholder
356 * attributes (those with name prefix \c pha) prior to parsing them.
357 *
358 * The default implementation sets all pha-fields as documented per field.
359 * \note
360 * Derived classes (aka the specific formatter classes) are to invoke this (parent)
361 * implementation first and then to make some own adjustments to meet the defaults that
362 * apply to the formatting specification implemented by the derived class and - if this
363 * applies - also to reset extended attributes of the derived formatter type.
364 ******************************************************************************************/
365 virtual void resetPlaceholder();
366
367
368 /** ****************************************************************************************
369 * Abstract method to parse the format definition at the start of string
370 * #parser and set the placeholder attributes accordingly.<br>
371 * Field \alib{lang::format::FormatterStdImpl::PlaceholderAttributes;FormatSpec}
372 * might be set by this method to portion of the placeholder format string.
373 * If so, methods #writeCustomFormat and #parseStdFormatSpec are used to then parse
374 * this portion of the placeholder string.
375 *
376 * @return \c true on success, \c false on errors.
377 ******************************************************************************************/
378 virtual bool parsePlaceholder() = 0;
379
380 /** ****************************************************************************************
381 * Virtual method that may write an argument using a custom method/format.
382 * The default implementation checks if object
383 * \alib{lang::format::FormatterStdImpl::PlaceholderAttributes;Arg} supports an own format specifier
384 * by disposing about box-function \alib{lang::format;FFormat}.
385 * If so, the function is invoked with passing
386 * \alib{lang::format::FormatterStdImpl::PlaceholderAttributes;FormatSpec}, the result of the
387 * formatting is written directly into the #targetString and \c true is returned.
388 * The latter causes method #format (which invokes this method) to continue with the next
389 * replacement field.<br>
390 * If \c false is returned, method #format continues the field processing by invoking
391 * #parseStdFormatSpec, #checkStdFieldAgainstArgument and #writeStdArgument.
392 *
393 * @return \c true if \alib{lang::format::FormatterStdImpl::PlaceholderAttributes;Arg}
394 * was written, \c false otherwise.
395 ******************************************************************************************/
396 virtual bool writeCustomFormat();
397
398 /** ****************************************************************************************
399 * Abstract method to parse the format specification for standard types (those that
400 * are not processed by #writeCustomFormat). This method may be left empty
401 * (just return constant \c true) if method #parsePlaceholder will never sets
402 * field \alib{lang::format::FormatterStdImpl::PlaceholderAttributes;FormatSpec}.
403 *
404 * @return \c true on success, \c false on errors.
405 ******************************************************************************************/
406 virtual bool parseStdFormatSpec() = 0;
407
408 /** ****************************************************************************************
409 * Virtual method invoked after #parseStdFormatSpec and before #writeStdArgument().
410 * The default implementation checks the settings of placeholder attribute values
411 * (fields with prefix \c pha), which were set by #parsePlaceholder and optionally by
412 * #parseStdFormatSpec, against the type of the argument given.
413 *
414 * If type and format information is missing in the format string, reasonable default
415 * values are set depending on the type of the argument.
416 *
417 * @throws
418 * If the argument type contradicts the replacement field type, exception
419 * \alib{lang::format::FMTExceptions;IncompatibleTypeCode} is thrown.
420 *
421 * @return \c true if OK, \c false if replacement should be aborted.
422 ******************************************************************************************/
423 virtual bool checkStdFieldAgainstArgument();
424
425 /** ****************************************************************************************
426 * Virtual method to write the argument. The default implementation should be sufficient
427 * for most derived formatter implementations, but of-course can be overridden and extended.
428 ******************************************************************************************/
429 virtual void writeStdArgument();
430
431 /** ****************************************************************************************
432 * Virtual method to do pre- and post- processing of the field written.
433 * Pre-processing could for example be adding tabulator spaces, letter case conversions,
434 *
435 * A negative given index \p{startIdx} indicates the pre-processing phase.
436 * If \p{target} is given, this indicates an "intermediate phase": The argument has been
437 * written, but no alignment or cutting has been done, yet. This phase should usually
438 * be ignored, but is for example important for search and replacement actions.
439 * If a field has a custom format implementation (e.g. time and date values), then
440 * the intermediate phase is never called.
441 *
442 * \note
443 * The reason why this method is \b not implemented as two different ones is that
444 * derived classes might do some more complicated parsing of parts of the placeholder
445 * string in this method. In this case, the parsing is needed to be implemented only
446 * once, while the finally parsed commands are only conditionally executed depending
447 * if executed as pre or post phase.
448 *
449 * @param startIdx If \c -1 pre-processing is indicated, otherwise post-processing and
450 * the index of the start of the field written in #targetString is given.
451 * @param target The target string, only if different from field #targetString, which
452 * indicates intermediate phase.
453 * @return \c false, if the placeholder should be skipped (nothing is written for it).
454 * \c true otherwise.
455 ******************************************************************************************/
456 virtual bool preAndPostProcess( integer startIdx,
457 AString* target = nullptr )
458 {
459 (void) startIdx;
460 (void) target;
461 return true;
462 }
463
464 /** ****************************************************************************************
465 * Helper method (overridable) that usually is invoked by the implementation of
466 * #parsePlaceholder when an argument index is read from the format string,
467 *
468 * If this does not happen, method #format will invoke this method providing \c -1 for
469 * value of parameter \p{pos} to automatically choose the next argument.
470 *
471 * Consequently, this method sets the fields
472 * \alib{lang::format::FormatterStdImpl::PlaceholderAttributes;Arg} and
473 * \alib{lang::format::FormatterStdImpl::PlaceholderAttributes;ArgIdx}.
474 * For auto-values, it increments #nextAutoIdx.
475 * Finally, this method is responsible for the correct book-keeping of #argsConsumed.
476 *
477 * @param pos The index of the argument.
478 * If \c -1 is given, the index is auto-incremented using field #nextAutoIdx.
479 * @return \c true on success, \c false on errors.
480 ******************************************************************************************/
481 virtual bool setArgument( int pos );
482
483 /** ****************************************************************************************
484 * Implementations of this abstract virtual method need to copy the given amount of
485 * characters from sting #parser to \b AString #targetString. With that
486 * "escaped" placeholder field characters (for example these are \c "{{" in python style
487 * or \c "%%" in JAVA style) as well as other escape sequences defined with the format are
488 * to be replaced with this method.
489 *
490 * @param length The number of characters to write.
491 ******************************************************************************************/
492 virtual void writeStringPortion( integer length ) = 0;
493};
494
495} // namespace [alib::lang::format]
496
497#endif // HPP_ALIB_LANG_FORMAT_FORMATTER_STD
@ Float
Outputs a number in floating point format.
@ HashCode
Writes raw box data as hex.
@ IntBinary
Outputs a given number in base 2.
@ IntBase10
Outputs a given number in base 10. The default.
@ IntHex
Outputs a given number in base 16.
@ IntOctal
Outputs a given number in base 8.
virtual ALIB_API int format(AString &targetString, const String &formatString, const Boxes &arguments, int argOffset) override
virtual bool preAndPostProcess(integer startIdx, AString *target=nullptr)
virtual void writeStringPortion(integer length)=0
FormatterStdImpl(const String &formatterClassName)
#define ALIB_API
Definition alib.hpp:538
platform_specific integer
Definition integers.hpp:50
characters::character character
Type alias in namespace alib.