ALib C++ Library
Library Version: 2412 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
formatterstdimpl.cpp
1// #################################################################################################
2// ALib C++ Library
3//
4// Copyright 2013-2024 A-Worx GmbH, Germany
5// Published under 'Boost Software License' (a free software license, see LICENSE.txt)
6// #################################################################################################
8
9#if !DOXYGEN
12#endif // !DOXYGEN
13
14#include <cmath>
15
16
17// For code compatibility with ALox Java/C++
18// We have to use underscore as the start of the name and for this have to disable a compiler
19// warning. But this is a local code (cpp file) anyhow.
20#if defined(__clang__)
21 #pragma clang diagnostic push
22 #pragma clang diagnostic ignored "-Wreserved-id-macro"
23#endif
24
25#if defined(__clang__)
26 #pragma clang diagnostic pop
27#endif
28
29using namespace alib::strings;
30
31namespace alib::lang::format {
32
33
45
47 const String& pFormatString,
48 const BoxesMA& pArguments,
49 int pArgOffset )
50{
51 // save parameters/init state
52 targetString= &pTargetString;
53 targetStringStartLength= pTargetString.Length();
54 formatString= pFormatString;
56 arguments = &pArguments;
57 argOffset = pArgOffset;
58
59 // initialize state info
60 nextAutoIdx= 0;
61 argsConsumed= 0;
62
63 for(;;)
64 {
65 // find start of esc
66 integer escStart= findPlaceholder();
67 if ( escStart < 0 )
68 {
69 // write rest of formatString string (only if we had consumed before)
70 if( argsConsumed > 0)
72
73 return argsConsumed;
74 }
75
76 // write string before ESC code
77 writeStringPortion( escStart );
78 parser.template ConsumeChars<NC>(1);
79
80 // get and clean field attributes
82
83 // invoke abstract method for parsing the attributes
84 if ( !parsePlaceholder() )
85 return argsConsumed;
86
87 // If no position was set in the field format string, automatically use next parameter
88 if ( placeholder.ArgIdx < 0 )
89 if ( !setArgument( -1 ) )
90 return argsConsumed;
91 ALIB_ASSERT( placeholder.Arg != nullptr )
92
93
94
95 // write field
96 if( preAndPostProcess( -1 ) )
97 {
98 integer actIdx= targetString->Length();
99 if ( !writeCustomFormat() )
100 {
101 // standard format
104 return argsConsumed;
105
106 // write argument
108 }
109 preAndPostProcess( actIdx );
110 }
111 }// main loop searching next escape sequence
112}
113
114
136
137
139{
141 {
142 if( pos == 0 )
145
146 if( pos > 0 )
147 --pos;
148 }
149
150 // auto? If not, set auto to this pos + 1
151 placeholder.ArgIdx= ( pos >= 0) ? pos : nextAutoIdx++;
152
153 // store maximum value used
154 if ( argsConsumed - 1 < placeholder.ArgIdx )
156
157 // get corresponding argument
158 int argIdx= argOffset + placeholder.ArgIdx;
159 if( argIdx >= arguments->Size() )
164
165 placeholder.Arg= &(*arguments)[size_t(argIdx)];
166 return true;
167
168
169}
170
171
173{
175 placeholder.TypeCodePosition= static_cast<int>( formatString.Length() - parser.Length() - 1 );
176
177
178 // types bool and hashcode always works!
181 return true;
182
183
185 {
188
190 return true;
191
195 "floating point", placeholder.Arg->TypeID(),
197 }
198
201 #if ALIB_SIZEOF_INTEGER == 4
202 || placeholder.Arg->IsType< int64_t>()
203 || placeholder.Arg->IsType<uint64_t>()
204 #endif
205 )
206 {
216 )
217 {
218 return true;
219 }
220
221 // not found
225 "integer", placeholder.Arg->TypeID(),
227 }
228
230 {
234 return true;
235
239 "character", placeholder.Arg->TypeID(),
241 }
242
245
246 return true;
247}
248
249
251{
252
253 // write to temp buffer first, if we have a field width given
254 AString* target;
255
256 if ( placeholder.Width > 0 )
257 {
258 target= &(fieldBuffer.Reset());
259
260 // set default alignment
265 }
266 else
267 target= targetString;
268
269 // store actual target length to fix some float exceptional cases (inf, nan)
270 integer oldTargetLength= target->Length();
271
272
273 integer fieldStartIdx= target->Length();
274
275 // the main switch over the type
276 switch( placeholder.Type )
277 {
279 ALIB_ERROR( "FMT", "Internal error: this should have been handled by method checkStdFieldAgainstArgument" )
280 break;
281
282 case PHTypes::String:
284 break;
285
286 case PHTypes::Bool:
287 target->_<NC>( placeholder.Arg->Call<FIsTrue>() ? "true" : "false" );
288 break;
289
291 {
292 wchar wc= 0;
294 else if (placeholder.Arg->IsSignedIntegral ()) wc= static_cast<wchar>( placeholder.Arg->UnboxSignedIntegral () );
295 else if (placeholder.Arg->IsUnsignedIntegral()) wc= static_cast<wchar>( placeholder.Arg->UnboxUnsignedIntegral() );
296
297 if ( wc == 0)
298 wc= L'?';
299 target->_<NC>( wc );
300 }
301 break;
302
303 case PHTypes::Fill:
304 {
305 integer qty;
311 "Fill", placeholder.Arg->TypeID(),
313 target->InsertChars( placeholder.FillChar, qty );
314 }
315 break;
316
317
319 {
321 placeholder.NF.DecMinimumFieldWidth= static_cast<int8_t>( placeholder.Width );
322
323 #if ALIB_SIZEOF_INTEGER == 4
324 if( placeholder.Arg->IsType< int64_t>() ) target->_<NC>( strings::TFormat<character>( placeholder.Arg->Unbox< int64_t>(), &placeholder.NF ) );
325 else if( placeholder.Arg->IsType<uint64_t>() ) target->_<NC>( strings::TFormat<character>( placeholder.Arg->Unbox<uint64_t>(), &placeholder.NF ) );
326 else
327 #endif
330 }
331 break;
332
333
336 case PHTypes::IntHex:
338 {
339 int digits= placeholder.Width;
341 {
345 digits-= static_cast<int>((target->Length() - fieldStartIdx));
346 if( placeholder.Width > 0 && digits <= 0 )
347 {
348 target->ShortenTo( fieldStartIdx + placeholder.Width );
349 break; // stop output, no space left
350 }
351 }
352 if ( digits <= 0 )
353 {
355 digits= ALIB_SIZEOF_INTEGER * 2;
356 else if ( placeholder.Arg->IsPointer() || placeholder.Arg->IsArray() )
357 digits= static_cast<int>( placeholder.Arg->GetPlaceholderUsageLength()
360 : 2 )
361
362 );
363 else
364 digits= 0;
365 }
366
367 uint64_t value= placeholder.Type == PHTypes::HashCode
368 ? static_cast<uint64_t>( placeholder.Arg->Hashcode() )
374 #if ALIB_SIZEOF_INTEGER == 8
377 #elif ALIB_SIZEOF_INTEGER == 4
380 #endif
381
382 if( placeholder.Type == PHTypes::IntOctal) target->_<NC>( TFormat<character>::Oct( value, digits, &placeholder.NF ) );
383 else if( placeholder.Type == PHTypes::IntBinary) target->_<NC>( TFormat<character>::Bin( value, digits, &placeholder.NF ) );
384 else if( placeholder.Type == PHTypes::HashCode ) target->_<NC>( TFormat<character>::Hex( value, digits, &placeholder.NF ) );
385 else target->_<NC>( TFormat<character>::Hex( value, digits, &placeholder.NF ) );
386 }
387 break;
388
389 case PHTypes::Float:
390 {
391 // get value
393 : placeholder.Arg->IsSignedIntegral() ? static_cast<double>( placeholder.Arg->UnboxSignedIntegral() )
394 : static_cast<double>( placeholder.Arg->UnboxUnsignedIntegral() );
396 value*= 100.0;
397
399 {
400 auto classification= std::fpclassify(value);
401
402 // write sign upfront and set fill character to 0
403 if( classification != FP_NAN )
404 {
405 bool negative= std::signbit(value);
406 if( classification == FP_ZERO && negative )
407 {
408 value= 0.0;
409 negative= false;
410 }
411
412 if( negative )
413 {
414 targetString->_<NC>( '-' );
416 value= -value;
417 }
418 else if( placeholder.NF.PlusSign != '\0' )
419 {
422 }
423 placeholder.NF.PlusSign= '\0';
424
425 if ( !HasBits(placeholder.NF.Flags, NumberFormatFlags::WriteGroupChars) || placeholder.NF.ThousandsGroupChar == '\0')
427 else
428 {
429 // calculate integral part width
430 if ( placeholder.Width > 0 && !HasBits(placeholder.NF.Flags, NumberFormatFlags::ForceScientific) )
431 {
432 placeholder.NF.IntegralPartMinimumWidth= static_cast<int8_t>( placeholder.Width - 1 ); // -1 == the dot
433
436
439
440 // check
443 }
444 }
445 }
446
447 }
448
449 target->_<NC>( strings::TFormat<character>( value, &placeholder.NF ) );
450
452 target->_<NC>( '%' );
453
454
455 // if nan or inf was written, we fill with spaces
457 && ( target->IndexOf(placeholder.NF.NANLiteral, oldTargetLength) >= 0
458 || target->IndexOf(placeholder.NF.INFLiteral, oldTargetLength) >= 0 ) )
460
461 }
462 break;
463
464 default: ALIB_ERROR("Illegal switch state.") break;
465 } // switch( placeholder.Type )
466
467 // now do an 'intermediate post phase' processing
468 preAndPostProcess( fieldStartIdx, target );
469
470 // apply cutting
471 if ( placeholder.CutContent >= 0 )
472 {
473 // wchar compilation: we grant the length is the same as the number of wide characters
474 // added, although this is still not true for some unicode character combinations
475 if( std::is_same<character, wchar>::value )
476 {
477 // too much added?
478 if( target->Length() - oldTargetLength > placeholder.CutContent )
479 target->ShortenTo( oldTargetLength + placeholder.CutContent );
480 }
481 else
482 {
483 integer qtyWCharsAdded= target->Substring<NC>( oldTargetLength, target->Length() - oldTargetLength ).WStringLength();
484
485 // too much added?
486 if( qtyWCharsAdded > placeholder.CutContent )
487 {
488 // was not unicode?
489 if( qtyWCharsAdded == target->Length() - oldTargetLength )
490 target->ShortenTo( oldTargetLength + placeholder.CutContent );
491
492 // in the unicode case, it gets complicated: we have to convert to unicode and
493 // then convert a part of it back!
494 else if( qtyWCharsAdded < 256)
495 {
496 WString256 wBuf;
499 wBuf.Append<NC>( target->Buffer() + oldTargetLength, target->Length() - oldTargetLength );
501 target->ShortenTo( oldTargetLength );
502 target->Append<NC>( wBuf.Buffer(),placeholder.CutContent );
503 }
504 }
505 }
506 }
507
508
509 // if field mode, we have to append the field buffer as a field to the real target now
510 if( target == &fieldBuffer )
512
513}
514
516{
518 if( !func )
519 return false;
520
522 return true;
523}
524
525} // namespace [alib::lang::format]
526
decltype(std::declval< typename TFDecl::Signature >()(std::declval< Box & >(), std::declval< TArgs >()...)) CallDirect(typename TFDecl::Signature function, TArgs &&... args) const
Definition box.inl:1201
uinteger UnboxUnsignedIntegral() const
Definition box.inl:627
bool IsPointer() const
Definition box.inl:737
wchar UnboxCharacter() const
Definition box.inl:669
bool IsFloatingPoint() const
Definition boxing.cpp:136
TFDecl::Signature GetFunction(Reach searchScope, bool isInvocation=false) const
bool IsUnsignedIntegral() const
Definition box.inl:593
ALIB_API size_t Hashcode() const
Definition boxing.cpp:163
bool IsSignedIntegral() const
Definition box.inl:575
bool IsType() const
unsigned int GetPlaceholderUsageLength() const
Definition box.inl:879
ALIB_API double UnboxFloatingPoint() const
Definition boxing.cpp:148
decltype(std::declval< typename TFDecl::Signature >()(std::declval< Box & >(), std::declval< TArgs >()...)) Call(TArgs &&... args) const
Definition box.inl:1175
const std::type_info & TypeID() const
Definition box.inl:941
const Placeholder & Data() const
Definition box.inl:844
integer UnboxSignedIntegral() const
Definition box.inl:610
const TUnboxable Unbox() const
bool IsArray() const
Definition box.inl:712
bool IsCharacter() const
Definition box.inl:652
integer Size() const
Definition boxes.inl:176
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.
@ 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)
TAString & ShortenTo(integer newLength)
Definition tastring.inl:971
TAString & Append(const TCharSrc *src, integer srcLength)
TAString & _(const TString< TChar > &src, integer regionStart, integer regionLength=MAX_LEN)
void DbgDisableBufferReplacementWarning()
Definition tastring.inl:363
constexpr bool IsNotEmpty() const
Definition string.hpp:389
constexpr integer Length() const
Definition string.hpp:326
TString< TChar > Substring(integer regionStart, integer regionLength=MAX_LEN) const
Definition string.hpp:406
constexpr const TChar * Buffer() const
Definition string.hpp:319
#define ALIB_CALLER_NULLED
Definition alib.hpp:1173
#define A_CHAR(STR)
#define ALIB_WARNINGS_RESTORE
Definition alib.hpp:849
#define ALIB_ERROR(...)
Definition alib.hpp:1267
#define ALIB_WARNINGS_ALLOW_UNSAFE_BUFFER_USAGE
Definition alib.hpp:760
#define ALIB_ASSERT(cond)
Definition alib.hpp:1270
#define ALIB_SIZEOF_INTEGER
Definition prepro.md:26
@ ArgumentIndexOutOfBounds
Argument index greater than number of arguments available.
@ ArgumentIndexIs0
Argument index '0' not allowed.
@ IncompatibleTypeCode
Incompatible type code given argument type found.
platform_specific integer
Definition integers.hpp:43
@ Local
Denotes local reach.
@ Right
Chooses right alignment.
@ Left
Chooses left alignment.
lang::Exception Exception
Type alias in namespace alib.
characters::wchar wchar
Type alias in namespace alib.
TCString< TChar > BinLiteralPrefix
NumberFormatFlags Flags
The flag field.
TCString< TChar > OctLiteralPrefix
TCString< TChar > NANLiteral
Defines what is written and parsed for double values that represent "not a number".
TCString< TChar > HexLiteralPrefix
TCString< TChar > ExponentSeparator
TCString< TChar > INFLiteral
Defines what is written and parsed for infinite double values.
void Set(TNumberFormat *other=nullptr)
detail::UnionIntegrals Integrals
Collection of integrals of different sizes.
uint8_t UInt8
8-bit unsigned integral.
uinteger UInt
Unsigned integral of platform-dependent size.
uint16_t UInt16
16-bit unsigned integral.
uint32_t UInt32
32-bit unsigned integral. Available only if platform is not of 32-bit.
uint64_t UInt64
64-bit unsigned integral. Available only if platform is not of 64-bit.