ALib C++ Library
Library Version: 2402 R1
Documentation generated by doxygen
Loading...
Searching...
No Matches
formatter.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
10#define HPP_ALIB_LANG_FORMAT_FORMATTER 1
11
12#if !defined(HPP_ALIB_LANG_FORMAT_FWDS)
14#endif
15
17
18#if ALIB_THREADS
19 #if !defined (HPP_ALIB_THREADS_THREADLOCK)
21 #endif
22#endif
23
24
25#if !defined(HPP_ALIB_STRINGS_NUMBERFORMAT)
27#endif
28
29#if !defined (HPP_ALIB_STRINGS_SUBSTRING)
31#endif
32
33#if ALIB_THREADS
34 #if !defined (HPP_ALIB_THREADS_THREADLOCK)
36 #endif
37#else
38 #if !defined (HPP_ALIB_LANG_OWNER)
39 #include "alib/lang/owner.hpp"
40 #endif
41#endif
42
43namespace alib { namespace lang::format {
44
45/** ************************************************************************************************
46 * This is an abstract base class to implement an \alib string formatter. A string formatter
47 * uses a "format string" to transform arguments into formatted text. The format string defines
48 * how the arguments are transformed by offering a "placeholder syntax".
49 *
50 * With this information, it becomes clear that different formatter types (derived types that offer
51 * a concrete placeholder syntax) all can have the same interface methods.
52 * This class defines this abstract interface.
53 *
54 * Built-in formatters, provided by module \alib_basecamp and derived from this class, are
55 * \alib{lang::format;FormatterPythonStyle;FormatterPythonStyle} and
56 * \alib{lang::format;FormatterJavaStyle;FormatterJavaStyle}.
57 *
58 * ## Friends ##
59 * class \alib{lang::basecamp::BaseCamp}.
60 **************************************************************************************************/
63 : public threads::ThreadLock
64#endif
65{
66 #if !defined(ALIB_DOX)
68 #endif
69
71
72 // #############################################################################################
73 // Internal fields
74 // #############################################################################################
75 protected:
76 /** A list of boxes. This is reset with every new invocation of variadic template method
77 * #Format */
79
80 /** A buffer used for conversion of the next argument, if it is not of string type. */
82
84
85 // #############################################################################################
86 // public fields
87 // #############################################################################################
88 public:
89 /**
90 * Stores default attributes for formatting numbers.
91 * Likewise #AlternativeNumberFormat, it usually is not used directly for formatting by
92 * descendants.
93 * Instead, at the beginning of parsing a next placeholder field, values are copied to
94 * a local copy. During the parsing process, values are then modified only in this local
95 * copy, probably taken from #AlternativeNumberFormat.
96 *
97 * This object is to be initialized in the constructor (of descendants) once to meet the
98 * formatting defaults of the corresponding specification.
99 * If after construction, attribute values of this object are changed, such changes are
100 * applied to all number formatting.
101 */
103
104 /**
105 * This number format is used to store alternative attributes. Likewise #DefaultNumberFormat,
106 * it is never used directly for formatting.
107 * Instead when processing the placeholder syntax, alternatives get copied from either this
108 * object or from #DefaultNumberFormat.
109 *
110 * This object is initialized in the constructor (of descendants) once to meet the
111 * formatting defaults of the corresponding specification.
112 *
113 * With the implementations of this class provided with \alib, not all fields in this object
114 * are used. The fields used are:
115 * <p>
116 * - Locale-specific versions of floating point separators:
117 * - \alib{strings;TNumberFormat::DecimalPointChar;NumberFormat::DecimalPointChar}
118 * - \alib{strings;TNumberFormat::ThousandsGroupChar;NumberFormat::ThousandsGroupChar}
119 *
120 * These are retrieved according to the current locale once in the constructor. To
121 * change the locale, these fields can be changed.
122 *
123 * - Lower case versions of floating point literals:
124 * - \alib{strings;TNumberFormat::ExponentSeparator;NumberFormat::ExponentSeparator}
125 * - \alib{strings;TNumberFormat::INFLiteral;NumberFormat::INFLiteral}
126 * - \alib{strings;TNumberFormat::NANLiteral;NumberFormat::NANLiteral}
127 *
128 * - Lower case versions of prefix literals that indicate the base of integral values:
129 * - \alib{strings;TNumberFormat::BinLiteralPrefix;BinLiteralPrefix}
130 * - \alib{strings;TNumberFormat::HexLiteralPrefix;HexLiteralPrefix}
131 * - \alib{strings;TNumberFormat::OctLiteralPrefix;OctLiteralPrefix}
132 */
134
135 /**
136 * An optional, next formatter. If set, this formatter will be invoked for a format string
137 * that does not contain recognized placeholders.
138 * \attention
139 * This field is public and not further maintained by this class. Setting the field lies
140 * completely in the responsibility of the user. E.g. cyclic settings must be avoided.
141 * Also, object life-cycle management is completely up to the user.
142 */
143 std::shared_ptr<Formatter> Next;
144
145 // #############################################################################################
146 // Constructor/destructor/ThreadLock overrides
147 // #############################################################################################
148 public:
149
150 /** ****************************************************************************************
151 * Destructs an object of this class.
152 * Note that concatenated formatters are not deleted automatically.
153 ******************************************************************************************/
154 virtual ~Formatter()
155 {}
156
157 /** ****************************************************************************************
158 * Overrides (non-virtual) \alib{threads;ThreadLock::Acquire}.
159 *
160 * This method checks if this was the first acquisition and if so, invokes method
161 * #reset. Therefore, a series of formatting calls may be performed without resetting
162 * the internal state, by acquiring the object once prior to the series of invocations
163 * and releasing it afterwards.
164 *
165 * Furthermore, this method invokes itself on potentially attached formatter #Next
166 * (recursion).
167 *
168 * This method is inherently called by convenience method #Format that accepts variadic
169 * arguments and hence no explicit invocation is needed in this case.
170 *
171 * Acquiring this formatter is mandatory with overloaded methods #FormatArgs.
172 *
173 * Multiple (nested) acquirements by the same execution thread are allowed.
174 * A corresponding amount of invocations to #Release have to be made.
175 *
176 * \note
177 * In the debug-compilation of an application, this method accepts the parameters,
178 * providing information about the caller. In the release version these parameters do not
179 * exist. Therefore use macro #ALIB_CALLER_PRUNED to provide the parameters:
180 *
181 * sample.Acquire( ALIB_CALLER_PRUNED );
182 *
183 * @param dbgFile Caller information. Available only with debug builds.
184 * @param dbgLine Caller information. Available only with debug builds.
185 * @param dbgFunc Caller information. Available only with debug builds.
186 * @return An internally allocated container of boxes that may be used to collect
187 * formatter arguments.
188 ******************************************************************************************/
189 #if ALIB_DEBUG
190 ALIB_API Boxes& Acquire( const NCString& dbgFile, int dbgLine, const NCString& dbgFunc );
191 #else
193 #endif
194
195 /** ****************************************************************************************
196 * Overrides (non-virtual) \alib{threads;ThreadLock::Release}, which is called.
197 * In addition, the method is called on potentially attached formatter #Next (recursion).
198 ******************************************************************************************/
199 ALIB_API void Release();
200
201#if !ALIB_THREADS || defined(ALIB_DOX)
202 /** ****************************************************************************************
203 * Returns the number of acquirements of this formatter.
204 *
205 * \note
206 * Usually this method is inherited from base clas \alib{threads;ThreadLock} and
207 * therefore not defined. However, in the absence of module \alib_threads in an
208 * \alibdist, this method is re-implemented with this type.
209 *
210 * @return The number of (recursive) acquirements.
211 ******************************************************************************************/
213 {
214 return cntAcquirements;
215 }
216#endif //!ALIB_THREADS
217
218 // #############################################################################################
219 // Interface
220 // #############################################################################################
221
222 /** ****************************************************************************************
223 * Variadic template method that accepts a target \b %AString and a list of arguments.
224 *
225 * This is a convenience method to allow single-line format invocations. No calls to
226 * methods #Acquire and #Release are needed to be performed.
227 *
228 * \note
229 * This method uses <c>static_assert</c> to disallow the invocation with one
230 * variadic argument of type \alib{boxing;Boxes} or a derived type.
231 * This is to ensure that for these box containers, the more efficient method #FormatArgs
232 * is used.
233 *
234 * @tparam TArgs Variadic template type list.
235 * @param target An AString that takes the result.
236 * @param args The variadic list of arguments to be used with formatters.
237 * @return A reference to this formatter to allow concatenated operations.
238 ******************************************************************************************/
239 template <typename... TArgs>
240 Formatter& Format( AString& target, TArgs&&... args )
241 {
242 // assert that this method is not used with Boxes containers.
243 // Those are to be processed with FormatArgs
244 constexpr bool Argument_has_type_Boxes=
245 (sizeof...(TArgs) == 1)
246 && ATMP_ISOF( ATMP_RCVR( std::tuple_element<0 ALIB_COMMA std::tuple<TArgs...>> ),
247 Boxes);
248 static_assert( !Argument_has_type_Boxes,
249 "To pass a container of type Boxes to a formatter, use method FormatArgs." );
251
252 // create argument objects using implicit constructor invocation
253 boxes.clear();
254 boxes.Add( std::forward<TArgs>( args )... );
255
256 // invoke format
257 formatLoop( target, boxes );
258 return *this;
259 }
260
261 /** ****************************************************************************************
262 * Formats the internal list of arguments that iis returned when acquiring access to this
263 * formatter with #Acquire.
264 *
265 * This method may be more efficient than using inlined variadic method \b Format
266 * and should be preferred if:
267 * - Format arguments can not be collected in a single invocation, for example if those
268 * are to be collected in a loop.
269 * - Multiple format operations (invocations of this method) are to be performed in a row.
270 * In this case, only a single call to #Acquire and #Release is to be performed.
271 *
272 * @param target An AString that takes the result.
273 * @return A reference to this formatter to allow concatenated operations.
274 *******************************************************************************************/
277 {
279 "FMT", "Formatter not acquired." ) )
280 return formatLoop( target, boxes );
281 }
282
283
284 /** ****************************************************************************************
285 * Same as Format(AString&) but allows to specify an external list of arguments instead of
286 * the internally allocated object, which is returned by method #Acquire.
287 *
288 * @param args The arguments to be used with formatters.
289 * @param target An AString that takes the result.
290 * @return A reference to this formatter to allow concatenated operations.
291 *******************************************************************************************/
292 Formatter& FormatArgs( AString& target, const Boxes& args )
293 {
295 "FMT", "Formatter not acquired." ) )
296 return formatLoop( target, args );
297 }
298
299
300 /** ****************************************************************************************
301 * Clones and returns a copy of this formatter.
302 *
303 * If a formatter is attached to field \alib{lang::format;Formatter::Next}, it is
304 * cloned as well.
305 *
306 * @returns An object of the same (derived) type and the same custom settings.
307 ******************************************************************************************/
308 virtual Formatter* Clone() = 0;
309
310 /** ****************************************************************************************
311 * Clones the settings from the given formatter.
312 * @param reference The formatter to copy settings from.
313 ******************************************************************************************/
315 virtual void CloneSettings( Formatter& reference );
316
317 // #############################################################################################
318 // Static Interface methods (default formatter)
319 // #############################################################################################
320 protected:
321 /**
322 * A static singleton instance which is received with #GetDefault.
323 */
326
327 public:
328 /** ****************************************************************************************
329 * Returns the default formatter object. With the module initialization (method
330 * \alib{lang::basecamp;BaseCamp::bootstrap}), an object of type
331 * \alib{lang::format;FormatterPythonStyle;FormatterPythonStyle} is created and a second
332 *
333 * one of type \alib{lang::format;FormatterJavaStyle;FormatterJavaStyle} is appended.
334 * Those formatters will be deleted with \alib{lang::basecamp;BaseCamp::shutdown},
335 * respectively when a different default formatter is set (see #ReplaceDefault)
336 * and no other shared pointer of the original one exists.
337 *
338 * @return A shared pointer containing the default formatter.
339 ******************************************************************************************/
340 static
342 {
343 return defaultFormatter;
344 }
345
346 /** ****************************************************************************************
347 * Same as #GetDefault, also acquires the formatter before it is returned.
348 * the reference.
349 *
350 * @param dbgFile Caller information. Available only with debug builds.
351 * @param dbgLine Caller information. Available only with debug builds.
352 * @param dbgFunc Caller information. Available only with debug builds.
353 * @return A shared pointer containing the default formatter, already acquired.
354 ******************************************************************************************/
355 #if ALIB_DEBUG
356 static
358 int dbgLine,
359 const NCString& dbgFunc )
360 {
361 defaultFormatter->Acquire( dbgFile, dbgLine, dbgFunc );
362 return defaultFormatter;
363 }
364 #else
365 static
367 {
368 defaultFormatter->Acquire();
369 return defaultFormatter;
370 }
371 #endif
372
373 /** ****************************************************************************************
374 * Replaces the formatter currently defined as the default formatter.
375 *
376 * \see
377 * Static methods #GetDefault and #AcquireDefault.
378 * @param newFormatter The replacement formatter.
379 ******************************************************************************************/
381 void ReplaceDefault( Formatter* newFormatter );
382
383 // #############################################################################################
384 // Protected methods
385 // #############################################################################################
386 protected:
387 /** ****************************************************************************************
388 * Virtual method which is invoked with each invocation of #Format.
389 * The default implementation does nothing.
390 ******************************************************************************************/
391 virtual void initializeFormat() {}
392
393 /** ****************************************************************************************
394 * Virtual method to used to reset internal states. This method is invoked only with
395 * the first \ref Acquire "acquisition" of a formatter. This way, reset of internal states
396 * can be suppressed over a series of format calls by acquiring the formatter explicitly
397 * prior to the series.
398 *
399 * As a sample, derived type
400 * \alib{lang::format;FormatterPythonStyle;FormatterPythonStyle} clears its auto-tab
401 * and auto-width positions.
402 *
403 *
404 * The default implementation does nothing.
405 ******************************************************************************************/
406 virtual void reset() {}
407
408
409 /** ****************************************************************************************
410 * The abstract format method that needs to be implemented by descendants.
411 * Note that parameter \p{startIdx} and the demanded return value together comprise the
412 * possibility to use more than one formatter in parallel and to perform multiple format
413 * operations on suitable argument lists. This demands the implementation of this method to
414 * \b not copy the format string to the \p{target} in the case that no 'escape sequence'
415 * was found. For further information, see the general documentation of this class.
416 *
417 * @param target The %AString that takes the result.
418 * @param formatString The format string.
419 * @param args The objects to be used with formatters.
420 * @param startArgument The first object in \p{args} to convert.
421 *
422 * @return The number of args consumed.
423 ******************************************************************************************/
424 virtual int format( AString& target,
425 const String& formatString,
426 const Boxes& args,
427 int startArgument ) = 0;
428
429 /** ****************************************************************************************
430 * The format loop implementation. Searches format strings in \p{args} and tests
431 * if \c this or #Next is capable of processing it.
432 *
433 * @param target An AString that takes the result.
434 * @param args The objects to be used with formatters.
435 * @return A reference to this formatter to allow concatenated operations.
436 ******************************************************************************************/
438 Formatter& formatLoop( AString& target, const Boxes& args );
439};
440
441} // namespace alib[:: lang::format]
442
443
444} // namespace [alib]
445
446
447#endif // HPP_ALIB_LANG_FORMAT_FORMATTER
Formatter & FormatArgs(AString &target, const Boxes &args)
ALIB_API void ReplaceDefault(Formatter *newFormatter)
static ALIB_API SPFormatter defaultFormatter
virtual int format(AString &target, const String &formatString, const Boxes &args, int startArgument)=0
ALIB_API Formatter & FormatArgs(AString &target)
virtual ALIB_API void CloneSettings(Formatter &reference)
ALIB_API Boxes & Acquire(const NCString &dbgFile, int dbgLine, const NCString &dbgFunc)
ALIB_API void Release()
defined(ALIB_DOX)
Definition formatter.cpp:70
Formatter & Format(AString &target, TArgs &&... args)
ALIB_THREADS.
std::shared_ptr< Formatter > Next
ALIB_API Formatter & formatLoop(AString &target, const Boxes &args)
Definition formatter.cpp:83
virtual Formatter * Clone()=0
static SPFormatter GetDefault()
static SPFormatter AcquireDefault(const NCString &dbgFile, int dbgLine, const NCString &dbgFunc)
#define ALIB_IFN_THREADS(...)
Definition alib.hpp:304
#define ALIB_ASSERT_MODULE(modulename)
Definition alib.hpp:190
#define ALIB_IF_THREADS(...)
Definition alib.hpp:303
#define ATMP_ISOF( T, TBase)
Definition tmp.hpp:33
#define ALIB_API
Definition alib.hpp:538
#define ATMP_RCVR( T)
Definition tmp.hpp:41
#define ALIB_ASSERT_ERROR(cond,...)
Definition alib.hpp:984
#define ALIB_LOCK
#define ALIB_DBG_PREVENT_RECURSIVE_METHOD_CALLS_MEMBER_DECL
Definition owner.hpp:119
#define ALIB_COMMA
Definition alib.hpp:825
#define ALIB_THREADS
Definition alib.hpp:180
Definition alib.cpp:57
std::shared_ptr< lang::format::Formatter > SPFormatter