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