ALib C++ Library
Library Version: 2511 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 /// Constructor.
301 /// @param formatterClassName The name of the derived class. Used to generate error messages
302 /// including a link into the online documentation. (Therefore
303 /// has to be the exact name.
304 FormatterStdImpl( const String& formatterClassName );
305
306 //################################################################################################
307 // Implementation of abstract interface of parent class Formatter
308 //################################################################################################
309 protected:
310
311 /// Implemented abstract format method which invokes a set of new abstract methods
312 /// as described in the main documentation of this class.
313 ///
314 /// @param targetString An AString that takes the result.
315 /// @param formatString The format string.
316 /// @param arguments The objects to convert.
317 /// @param argOffset The first object in \p{arguments} to use.
318 ///
319 /// @return The number of args consumed.
321 virtual int format( AString& targetString,
322 const String& formatString,
323 const BoxesMA& arguments,
324 int argOffset ) override;
325
326
327 //################################################################################################
328 // Introduction of new, partly abstract methods to be implemented (or optionally overwritten)
329 // by descendents.
330 //################################################################################################
331 protected:
332
333 /// Abstract method to search the next index of an argument placeholder in the remaining
334 /// substring (field #parser) of the format string.
335 ///
336 /// @return The index found, \c -1 if not found.
338
339 /// Overridable method to clean and reset the fields representing the current placeholder
340 /// attributes (those with name prefix \c pha) before parsing them.
341 ///
342 /// The default implementation sets all pha-fields as documented per field.
343 /// \note
344 /// Derived classes (aka the specific formatter classes) are to invoke this (parent)
345 /// implementation first and then to make some own adjustments to meet the defaults that
346 /// apply to the formatting specification implemented by the derived class and - if this
347 /// applies - also to reset extended attributes of the derived formatter type.
348 virtual void resetPlaceholder();
349
350
351 /// Abstract method to parse the format definition at the start of string
352 /// #parser and set the placeholder attributes accordingly.<br>
353 /// Field \alib{format::FormatterStdImpl::PlaceholderAttributes;FormatSpec}
354 /// might be set by this method to portion of the placeholder format string.
355 /// If so, methods #writeCustomFormat and #parseStdFormatSpec are used to then parse
356 /// this portion of the placeholder string.
357 ///
358 /// @return \c true on success, \c false on errors.
359 virtual bool parsePlaceholder() =0;
360
361 /// Virtual method that may write an argument using a custom method/format.
362 /// The default implementation checks if object
363 /// \alib{format::FormatterStdImpl::PlaceholderAttributes;Arg} supports an own format specifier
364 /// by disposing about box-function \alib{format;FFormat}.
365 /// If so, the function is invoked with passing
366 /// \alib{format::FormatterStdImpl::PlaceholderAttributes;FormatSpec}, the result of the
367 /// formatting is written directly into the #targetString and \c true is returned.
368 /// The latter causes method #format (which invokes this method) to continue with the next
369 /// replacement field.<br>
370 /// If \c false is returned, method #format continues the field processing by invoking
371 /// #parseStdFormatSpec, #checkStdFieldAgainstArgument and #writeStdArgument.
372 ///
373 /// @return \c true if \alib{format::FormatterStdImpl::PlaceholderAttributes;Arg}
374 /// was written, \c false otherwise.
375 virtual bool writeCustomFormat();
376
377 /// Abstract method to parse the format specification for standard types (those that
378 /// are not processed by #writeCustomFormat). This method may be left empty
379 /// (just return constant \c true) if method #parsePlaceholder will never sets
380 /// field \alib{format::FormatterStdImpl::PlaceholderAttributes;FormatSpec}.
381 ///
382 /// @return \c true on success, \c false on errors.
383 virtual bool parseStdFormatSpec() =0;
384
385 /// Virtual method invoked after #parseStdFormatSpec and before #writeStdArgument().
386 /// The default implementation checks the settings of placeholder attribute values
387 /// (fields with prefix \c pha), which were set by #parsePlaceholder and optionally by
388 /// #parseStdFormatSpec, against the type of the argument given.
389 ///
390 /// If type and format information is missing in the format string, reasonable default
391 /// values are set depending on the type of the argument.
392 ///
393 /// @throws
394 /// If the argument type contradicts the replacement field type, exception
395 /// \alib{format::FMTExceptions;IncompatibleTypeCode} is thrown.
396 ///
397 /// @return \c true if OK, \c false if replacement should be aborted.
398 virtual bool checkStdFieldAgainstArgument();
399
400 /// Virtual method to write the argument. The default implementation should be sufficient
401 /// for most derived formatter implementations, but of course can be overridden and extended.
402 virtual void writeStdArgument();
403
404 /// Virtual method to do pre- and post- processing of the field written.
405 /// Pre-processing could, for example, be adding tabulator spaces, letter case conversions,
406 ///
407 /// A negative given index \p{startIdx} indicates the pre-processing phase.
408 /// If \p{target} is given, this indicates an "intermediate phase": The argument has been
409 /// written, but no alignment or cutting has been done, yet. This phase should usually
410 /// be ignored, but is, for example, important for search and replacement actions.
411 /// If a field has a custom format implementation (e.g., time and date values), then
412 /// the intermediate phase is never called.
413 ///
414 /// \note
415 /// The reason why this method is \b not implemented as two different ones is that
416 /// derived classes might do some more complicated parsing of parts of the placeholder
417 /// string in this method. In this case, the parsing is needed to be implemented only
418 /// once, while the finally parsed commands are only conditionally executed depending
419 /// if executed as pre or post phase.
420 ///
421 /// @param startIdx If \c -1 pre-processing is indicated, otherwise post-processing and
422 /// the index of the start of the field written in #targetString is given.
423 /// @param target The target string, only if different from field #targetString, which
424 /// indicates intermediate phase.
425 /// @return \c false, if the placeholder should be skipped (nothing is written for it).
426 /// \c true otherwise.
427 virtual bool preAndPostProcess( integer startIdx,
428 AString* target = nullptr ) {
429 (void) startIdx;
430 (void) target;
431 return true;
432 }
433
434 /// Helper method (overridable) that usually is invoked by the implementation of
435 /// #parsePlaceholder when an argument index is read from the format string,
436 ///
437 /// If this does not happen, method #format will invoke this method providing \c -1 for
438 /// value of parameter \p{pos} to automatically choose the next argument.
439 ///
440 /// Consequently, this method sets the fields
441 /// \alib{format::FormatterStdImpl::PlaceholderAttributes;Arg} and
442 /// \alib{format::FormatterStdImpl::PlaceholderAttributes;ArgIdx}.
443 /// For auto-values, it increments #nextAutoIdx.
444 /// Finally, this method is responsible for the correct book-keeping of #argsConsumed.
445 ///
446 /// @param pos The index of the argument.
447 /// If \c -1 is given, the index is auto-incremented using field #nextAutoIdx.
448 /// @return \c true on success, \c false on errors.
449 virtual bool setArgument( int pos );
450
451 /// Implementations of this abstract virtual method need to copy the given amount of
452 /// characters from sting #parser to \b AString #targetString. With that
453 /// "escaped" placeholder field characters (for example, these are \c "{{" in python style
454 /// or \c "%%" in JAVA style) as well as other escape sequences defined with the format are
455 /// to be replaced with this method.
456 ///
457 /// @param length The number of characters to write.
458 virtual void writeStringPortion( integer length ) =0;
459};
460
461} // namespace [alib::format]
462
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:503
#define ALIB_ENUMS_ASSIGN_RECORD(TEnum, TRecord)
#define ALIB_EXPORT
Definition alib.inl:497
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:1149
boxing::TBoxes< MonoAllocator > BoxesMA
Type alias in namespace alib.
Definition boxes.inl:193
characters::character character
Type alias in namespace alib.
strings::TSubstring< character > Substring
Type alias in namespace alib.