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