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