ALib C++ Framework
by
Library Version: 2511 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
tastringimpl.inl
1//##################################################################################################
2// ALib C++ Framework
3//
4// Copyright 2013-2025 A-Worx GmbH, Germany
5// Published under 'Boost Software License' (a free software license, see LICENSE.txt)
6//##################################################################################################
7#if !defined(ALIB_STRINGS_TASTRING_INSTANTIATION)
8# error "ALib sources with ending '.inl' must not be included from outside."
9#endif
10
11#if !DOXYGEN
12#endif // !DOXYGEN
13
14
15
16namespace alib { namespace strings {
17
18/// \attention
19/// This is a non-existing namespace! It is exclusively defined for the
20/// \https{documentation parser,www.doxygen.nl}.
21///
22/// In this <b>"documentation namespace"</b>, you will find specializations of functor
23/// #"AppendableTraits" which in reality are implemented in parent
24/// namespace #"alib::strings" (as required by C++ language syntax).<br>
25/// The rationale for tricking the documentation to this pseude-namespace, is to twofold:
26/// On the one hand to keep namespace \b %alib::strings clean and on the other to have
27/// an overview of all specializations in one place.
28namespace APPENDABLES {}
29
30
31//##################################################################################################
32// AString::_dbgCheck()
33//##################################################################################################
34//! @cond NO_DOX
35#if ALIB_DEBUG_STRINGS
36
37template<typename TChar, typename TAllocator>
38requires alib::lang::IsAllocator<TAllocator>
40{
41 base::dbgCheck();
42
43 integer cap= Capacity();
44
45 ALIB_ASSERT_ERROR( debugLastAllocRequest == 0
46 || base::length <= debugLastAllocRequest, "STRINGS",
47 "Error: Previous allocation request was too short: {} < {} ",
48 debugLastAllocRequest, base::length )
49
50 ALIB_ASSERT_ERROR( base::length <= cap, "STRINGS",
51 "Error: Length greater than allocation size: {} > {}",
52 base::length, cap )
53
54 if( base::buffer && HasInternalBuffer() )
55 {
56 for (integer i= -16 ; i < 0 ; ++i)
57 if ( base::buffer[i] != 2 )
58 {
59 ALIB_ERROR( "STRINGS", "Magic byte not found at start of buffer." )
60 break;
61 }
62 for (integer i= 1 ; i <= 16 ; ++i)
63 if ( base::buffer[ cap + i] != 3 )
64 {
65 ALIB_ERROR( "STRINGS", "Magic byte not found at end of buffer." )
66 break;
67 }
68 }
69}
70
71#endif
72//! @endcond
73
74
75//##################################################################################################
76// Allocation
77//##################################################################################################
78template<typename TChar, typename TAllocator>
79requires alib::lang::IsAllocator<TAllocator>
81 integer actCapacity= Capacity();
82
83 ALIB_ASSERT_WARNING ( base::length + minimumGrowth > actCapacity, "STRINGS",
84 "Unnecessary invocation of Grow(): {} <= {}", base::length + minimumGrowth, actCapacity )
85
86 // first allocation? Go with given growth as size
87 if (actCapacity == 0 ) {
88 SetBuffer( minimumGrowth > 15 ? minimumGrowth : 15 );
89 #if ALIB_DEBUG_STRINGS
90 debugLastAllocRequest= minimumGrowth;
91 #endif
92
93 return;
94 }
95
96 // calc new size: in general grow by 50%
97 integer newCapacity= actCapacity + (actCapacity / 2);
98 if ( newCapacity < base::length + minimumGrowth )
99 newCapacity+= minimumGrowth;
100
101 if ( newCapacity < 15 )
102 newCapacity= 15;
103
104 SetBuffer( newCapacity );
105 #if ALIB_DEBUG_STRINGS
106 debugLastAllocRequest= actCapacity + minimumGrowth;
107 #endif
108}
109
110template<typename TChar, typename TAllocator>
113 #if ALIB_DEBUG_STRINGS
115 if(capacity > 0)
116 allocBase::GetAllocator().dbgCheckMemory( base::vbuffer - 16 ,
117 sizeof(TChar) * (size_t(capacity + 1) + 32));
118 #endif
119
120
121 ALIB_ASSERT( newCapacity >= 0, "STRINGS" )
122
123 // do nothing if life-cycle is managed by us and same size,
124 if ( capacity >= 0 && capacity == newCapacity )
125 return;
126
127 #if ALIB_DEBUG_STRINGS
128 debugLastAllocRequest= newCapacity;
129 #endif
130
131 // set uninitialized (and return)
132 if ( newCapacity == 0 ) {
134 "AString::SetBuffer(): removing an external buffer (setting string nulled). "
135 "This may not be wanted." )
136
137 if ( capacity > 0 )
138 allocBase::GetAllocator().free( base::vbuffer
140 - 16
141 #endif
142 , size_t(capacity + 1) * sizeof(TChar)
144 + 32 * sizeof(TChar)
145 #endif
146 );
147
148 capacity=
149 base::length= 0;
150 base::buffer= nullptr;
151 return;
152 }
153
154 #if ALIB_DEBUG
156 ALIB_WARNING( "STRINGS",
157 "Replacing an external buffer of size {} by an internally managed one of size {}."
158 " This may not be wanted: ", -capacity +1, newCapacity +1,
159 *this )
160 #endif
161
162 // extend or shrink an existing buffer (and return)
163 if( capacity > 0 ) {
164 size_t allocSize= size_t(newCapacity + 1) * sizeof(TChar);
165 #if !ALIB_DEBUG_STRINGS
166 base::buffer= static_cast<TChar*>(
167 allocBase::GetAllocator().reallocate( base::vbuffer,
168 size_t(capacity + 1) * sizeof(TChar),
169 allocSize,
170 alignof(TChar) ) );
171 newCapacity= integer(allocSize / sizeof(TChar)) - 1;
172 allocBase::GetAllocator().dbgAcknowledgeIncreasedAllocSize( base::vbuffer, allocSize );
173 #else
174 // add 16 characters of padding at start/end
175 allocSize+= 32 * sizeof(TChar);
176 base::buffer= static_cast<TChar*>(
177 allocBase::GetAllocator().reallocate( base::vbuffer - 16,
178 size_t(capacity + 1 + 32) * sizeof(TChar),
179 allocSize,
180 alignof(TChar) ) ) + 16;
181 newCapacity= integer(allocSize / sizeof(TChar)) - 32 -1;
182
183 // write '\3' to end ('\0'= termination byte, '\1'= untermination byte )
184 characters::Fill( base::vbuffer + newCapacity + 1 , 16, TChar('\3') );
185 allocBase::GetAllocator().dbgAcknowledgeIncreasedAllocSize( base::vbuffer - 16, allocSize );
186 #endif
187
188 capacity= newCapacity;
189 if ( base::length > capacity )
191
192 return;
193 }
194
195 // create new Buffer
196 size_t allocSize= size_t(newCapacity +1) * sizeof(TChar);
197 #if !ALIB_DEBUG_STRINGS
198 TChar* newBuffer= static_cast<TChar*>( allocBase::GetAllocator().allocate( allocSize, alignof(TChar)) );
199 newCapacity= integer(allocSize / sizeof(TChar)) - 1;
200 allocBase::GetAllocator().dbgAcknowledgeIncreasedAllocSize( newBuffer, allocSize );
201 #else
202 // add 16 characters of padding at start/end
203 allocSize+= 32 * sizeof(TChar);
204 TChar* newBuffer= static_cast<TChar*>( allocBase::GetAllocator().allocate( allocSize, alignof(TChar)) ) + 16;
205 newCapacity= integer(allocSize / sizeof(TChar)) - 32 - 1;
206
207 // write '\2' to start, '\3' to end ('\0'= termination byte, '\1'= untermination byte )
208 characters::Fill( newBuffer - 16, 16 , TChar('\2') );
209 characters::Fill( newBuffer + newCapacity + 1 , 16 , TChar('\3') );
210 allocBase::GetAllocator().dbgAcknowledgeIncreasedAllocSize( newBuffer - 16, allocSize );
211 #endif
212
213 // if we had a buffer before
214 if ( capacity != 0 ) {
215 // copy data and delete old buffer
216 characters::Copy( base::buffer, (std::min)( base::length + 1, newCapacity + 1), newBuffer );
217
218 if ( capacity > 0 )
219 allocBase::GetAllocator().free( base::vbuffer
221 - 16
222 #endif
223 , size_t(capacity + 1) * sizeof(TChar)
225 + 32* sizeof(TChar)
226 #endif
227 );
228 } else {
229 ALIB_ASSERT( base::length == 0, "STRINGS")
230 }
231
232 // set new Buffer and adjust length
233 base::buffer= newBuffer;
234 capacity= newCapacity;
235 if ( base::length > capacity )
237}
238
239
240template<typename TChar, typename TAllocator>
242void TAString<TChar, TAllocator>::SetBuffer( TChar* extBuffer, integer extBufferSize, integer extLength,
243 lang::Responsibility responsibility ) {
244 ALIB_ASSERT_ERROR( !(extBufferSize == 0 && extBuffer != nullptr)
245 && !(extBufferSize != 0 && extBuffer == nullptr) , "STRINGS",
246 "AString::SetBuffer(): Given buffer is nullptr while given alloc size is not 0 (or vice versa)")
247
248 // delete any existing
249 if ( capacity > 0 )
250 allocBase::GetAllocator().free( base::vbuffer
252 - 16
253 #endif
254 , size_t(capacity + 1) * sizeof(TChar)
256 + 32* sizeof(TChar)
257 #endif
258 );
259
260
261 // too small? treat as if a nullptr was given.
262 if ( extBufferSize < 1 ) {
263 ALIB_ERROR( "STRINGS", "allocation size < 1" )
264 extBuffer= nullptr;
265 }
266
267 // null buffer?
268 if ( (base::buffer= extBuffer) == nullptr ) {
269 #if ALIB_DEBUG_STRINGS
271 #endif
272 capacity=
273 base::length= 0;
274 return;
275 }
276
277
278 if ( extLength >= extBufferSize ) {
279 ALIB_ERROR( "STRINGS", "ext length {} >= ext allocation size {}", extLength, extBufferSize )
280 extLength= extBufferSize -1;
281 }
282
283
284 // save given buffer
285 --extBufferSize; // we count one less
286 capacity= responsibility==lang::Responsibility::Transfer ? extBufferSize
287 : -extBufferSize;
288 #if ALIB_DEBUG_STRINGS
289 debugLastAllocRequest= extBufferSize;
290 #endif
291 base::length= extLength;
292}
293
294
295
296//##################################################################################################
297// Trim
298//##################################################################################################
299template<typename TChar, typename TAllocator>
302 if ( idx < 0 )
303 return 0;
304 if ( idx >= base::length )
305 return base::length;
306
307 integer regionStart= base::template LastIndexOfAny<lang::Inclusion::Exclude, NC>( trimChars, idx ) + 1;
308 if (regionStart < 0 )
309 regionStart= 0;
310
311 integer regionEnd= TCString<TChar>(this).template IndexOfAny <lang::Inclusion::Exclude, NC>( trimChars, idx );
312 if (regionEnd < 0 )
313 regionEnd= base::length;
314
315 integer regionLength= regionEnd - regionStart;
316 if ( regionLength > 0 )
317 Delete<NC>( regionStart, regionLength );
318
319 return regionStart;
320}
321
322template<typename TChar, typename TAllocator>
325 // check
326 if (base::length == 0 || trimChars.IsEmpty() )
327 return *this;
328
329 // trim end
330 integer idx= base::template LastIndexOfAny<lang::Inclusion::Exclude, NC>( trimChars, base::length - 1 ) + 1;
331 if ( (base::length= idx) > 0 ) {
332 // trim front
333 idx= TCString<TChar>(this).template IndexOfAny<lang::Inclusion::Exclude, NC>( trimChars );
334 if ( idx > 0 )
335 Delete<NC>( 0, idx );
336 }
337
338 return *this;
339}
340
341//##################################################################################################
342// Replace()
343//##################################################################################################
344template<typename TChar, typename TAllocator>
347 TChar replacement,
348 integer startIdx,
349 integer endIdx ) {
351 if ( startIdx < 0 ) startIdx= 0;
352 else if ( startIdx >= base::length ) return 0;
353 if ( endIdx > base::length ) endIdx= base::length;
354 if ( startIdx >= endIdx ) return 0;
355
356 // replacement loop
357 TCString<TChar> thisAsCString= this;
358 integer cntReplacements= 0;
359 do
360 {
361 startIdx= thisAsCString.template IndexOfOrLength<NC>( needle, startIdx );
362 if ( startIdx == base::length )
363 break;
364 base::vbuffer[ startIdx ]= replacement;
365 ++cntReplacements;
366 }
367 while( ++startIdx < endIdx) ;
368 return cntReplacements;
369}
370
371template<typename TChar, typename TAllocator>
374 const TString<TChar>& replacement,
375 integer startIdx,
376 integer maxReplacements,
377 lang::Case sensitivity,
378 integer endIdx ) {
380
381 // check null arguments
382 if ( needle.IsEmpty() ) return 0;
383 endIdx= (std::min) (endIdx, base::length - needle.Length() + 1 );
384 if ( startIdx >= endIdx ) return 0;
385
386 integer nLen= needle.Length();
387 integer rLen= replacement.Length();
388 integer lenDiff= rLen - nLen;
389
390 // replacement loop
391 integer cntReplacements= 0;
392 while ( cntReplacements < maxReplacements && startIdx < endIdx) {
393 // search next occurrence
394 integer idx= sensitivity == lang::Case::Sensitive
395 ? TString<TChar>(*this).template IndexOf<NC, lang::Case::Sensitive>( needle, startIdx, endIdx )
396 : TString<TChar>(*this).template IndexOf<NC, lang::Case::Ignore >( needle, startIdx, endIdx );
397 if ( idx < 0 )
398 break;
399
400 // copy rest up or down
401 if ( lenDiff != 0 ) {
402 if ( lenDiff > 0 )
403 EnsureRemainingCapacity( lenDiff );
404 characters::Move( base::vbuffer + idx + nLen,
405 base::length - idx - nLen,
406 base::vbuffer + idx + nLen + lenDiff );
407 base::length+= lenDiff;
408 endIdx+= lenDiff;
409 }
410
411 // fill replacement in
412 if( rLen > 0 )
413 characters::Copy( replacement.Buffer(), rLen, base::vbuffer + idx );
414
415 // set start index to first character behind current replacement
416 startIdx= idx + rLen;
417
418 // next
419 ++cntReplacements;
420 }
421
422 // that's it
423 return cntReplacements;
424}
425
426//##################################################################################################
427// AppendableTraits<Integrals>
428//##################################################################################################
429
430template<typename TChar, typename TAllocator>
432 int64_t value ) {
433 target.EnsureRemainingCapacity(28);// 20 digits, grouping symbol, sign and what have you
434 integer length= target.Length();
435 length= detail::WriteDecSigned ( value, target.VBuffer(), length, 0, TNumberFormat<TChar>::Computational );
436 target.SetLength( length );
437}
438
439template<typename TChar, typename TAllocator>
440void AppendableTraits<uint64_t,TChar,TAllocator>::operator()( TAString<TChar,TAllocator>& target,
441 uint64_t value ) {
442 target.EnsureRemainingCapacity(28);// 20 digits, grouping symbol, sign and what have you
443 integer length= target.Length();
444 length= detail::WriteDecUnsigned ( value, target.VBuffer(), length, 0, TNumberFormat<TChar>::Computational );
445 target.SetLength( length );
446}
447
448
449template<typename TChar, typename TAllocator>
450void AppendableTraits<double,TChar,TAllocator>::operator()( TAString<TChar,TAllocator>& target,
451 double value ) {
452 target.EnsureRemainingCapacity(48); // float: 2x15 + '.' + ',' + sign + fear
453 integer length= target.Length();
454 length= detail::WriteFloat( value, target.VBuffer(), length, 0, TNumberFormat<TChar>::Computational );
455 target.SetLength( length );
456}
457
458//##################################################################################################
459// AppendableTraits<Format>
460//##################################################################################################
461
462//##################################################################################################
463// TTab()
464//##################################################################################################
465template<typename TChar, typename TAllocator>
466void AppendableTraits<TTab<TChar>, TChar,TAllocator>::operator()( TAString<TChar,TAllocator>& target,
467 const TTab<TChar>& tab) {
468 integer reference= tab.reference;
469 if (reference < 0 ) {
470 // search backwards
471 reference= target.template LastIndexOfAny<lang::Inclusion::Include>( CStringConstantsTraits<TChar>::NewLine(),
472 target.Length() -1 );
473 if ( reference < 0 )
474 reference= 0;
475 else {
476 // if new line has more than one character (windows) we have to now search the first
477 // character that is not in newline
478 reference= target.template IndexOfAny<lang::Inclusion::Exclude, NC>( CStringConstantsTraits<TChar>::NewLine(), reference );
479 if (reference < 0 )
480 reference= target.Length();
481
482 } }
483 integer length= target.Length();
484 integer qtyChars= tab.minPad > 0 ? tab.minPad : 0;
485
486 if ( tab.tabSize > 1 )
487 qtyChars+= (tab.tabSize - ( (length + qtyChars - reference) % tab.tabSize ) ) % tab.tabSize;
488
489 if ( qtyChars > 0 )
490 target.template InsertChars<NC>( tab.tabChar, qtyChars );
491}
492
493
494//##################################################################################################
495// TField()
496//##################################################################################################
497#if !ALIB_BOXING
498template<typename TChar, typename TAllocator>
499void AppendableTraits<TField<TChar>, TChar,TAllocator>::operator()(
500 TAString<TChar,TAllocator>& target, const TField<TChar>& field)
501{
502 TString<TChar> theContent= field.theContent;
503
504 integer padSize= field.fieldWidth
505 - theContent.WStringLength();
506
507 // check pad field.width
508 if (padSize <= 0 || field.alignment == lang::Alignment::Left )
509 {
510 target.template _ <NC>( theContent );
511 if (padSize > 0 ) target.template InsertChars<NC>( field.padChar, padSize );
512 return;
513 }
514
515 // align Right
516 if ( field.alignment == lang::Alignment::Right )
517 {
518 if( padSize > 0 )
519 target.template InsertChars<NC>( field.padChar, padSize );
520 target.template Append<NC>( theContent );
521 return;
522 }
523
524 // align Center
525 integer leftPadding= padSize / 2;
526 if( leftPadding > 0 )
527 target.template InsertChars<NC> ( field.padChar, leftPadding );
528 target.template Append<NC> ( theContent );
529 if( padSize > leftPadding ) target.template InsertChars<NC> ( field.padChar, padSize - leftPadding );
530}
531#endif
532
533//##################################################################################################
534// TEscape()
535//##################################################################################################
536template<typename TChar, typename TAllocator>
537void AppendableTraits<TEscape<TChar>, TChar,TAllocator>::operator()( TAString<TChar,TAllocator>& target,
538 const TEscape<TChar>& escape) {
539 if( target.AdjustRegion( const_cast<TEscape<TChar>&>(escape).startIdx,
540 const_cast<TEscape<TChar>&>(escape).length ) )
541 return;
542
543 integer regionEnd= escape.startIdx + escape.length;
544
545 //
546 // To escape sequences
547 //
548 if (escape.pSwitch == lang::Switch::On) {
549 for( integer idx= escape.startIdx; idx < regionEnd ; ++idx ) {
550 TChar c= target.CharAt(idx);
551
552 TChar resultChar= '\0';
553 switch(c) {
554 case '\\' : resultChar= '\\'; break;
555 case '\r' : resultChar= 'r' ; break;
556 case '\n' : resultChar= 'n' ; break;
557 case '\t' : resultChar= 't' ; break;
558 case '\a' : resultChar= 'a' ; break;
559 case '\b' : resultChar= 'b' ; break;
560 case '\v' : resultChar= 'v' ; break;
561 case '\f' : resultChar= 'f' ; break;
562 // case '\e' : resultChar= 'e' ; break; Not C++ standard
563 case '"' : resultChar= '"' ; break;
564
565 default : break;
566 }
567
568 if( resultChar != '\0') {
569 target.template InsertChars<NC>('\\', 1, idx);
570 target[++idx]= resultChar;
571 ++regionEnd;
572 } } }
573
574 //
575 // Un-escape escape sequences
576 //
577 else {
578 --regionEnd; // we can go 1 over it!
579 for( integer idx= escape.startIdx; idx < regionEnd ; ++idx ) {
580 TChar c= target.CharAt(idx);
581 if( c != '\\' )
582 continue;
583
584 c= target.CharAt(idx + 1);
585
586 TChar resultChar= '\0';
587 switch(c) {
588 case '\\' : resultChar= '\\'; break;
589 case 'r' : resultChar= '\r' ; break;
590 case 'n' : resultChar= '\n' ; break;
591 case 't' : resultChar= '\t' ; break;
592 case 'a' : resultChar= '\a' ; break;
593 case 'b' : resultChar= '\b' ; break;
594 case 'v' : resultChar= '\v' ; break;
595 case 'f' : resultChar= '\f' ; break;
596 // case 'e' : resultChar= '\e' ; break; Not C++ standard
597 case '"' : resultChar= '"' ; break;
598
599 default : break;
600 }
601
602 if( resultChar != '\0') {
603 target.Delete( idx, 1);
604 target[idx]= resultChar;
605 --regionEnd;
606} } } }
607
608//##################################################################################################
609// TDec Integers
610//##################################################################################################
611template<typename TChar, typename TAllocator>
612void AppendableTraits<TDec<TChar>, TChar,TAllocator>::operator()( TAString<TChar,TAllocator>& target,
613 const TDec<TChar>& fmt ) {
614 const TNumberFormat<TChar>* nf= fmt.nf;
615 if( nf == nullptr )
617
618 target.EnsureRemainingCapacity( fmt.valueType== 3 ? 48 //float: 2x15 + '.' + ',' + sign + fear
619 : 28 //int: 20 digits, grouping symbol, sign and what have you
620 );
621
622 integer length= target.Length();
623
624 length=
625 fmt.valueType == 1 ? detail::WriteDecSigned ( fmt.v.value , target.VBuffer(), length, fmt.width , *nf ) :
626 fmt.valueType == 2 ? detail::WriteDecUnsigned( uint64_t(fmt.v.value) , target.VBuffer(), length, fmt.width , *nf ) :
627 detail::WriteFloat ( fmt.v.fpValue, target.VBuffer(), length, fmt.width , *nf );
628
629 target.SetLength( length );
630}
631
632
633
634template<typename TChar, typename TAllocator>
635void AppendableTraits<TBin<TChar>, TChar,TAllocator>::operator()( TAString<TChar,TAllocator>& target,
636 const TBin<TChar>& fmt ) {
637 TNumberFormat<TChar>* nf= fmt.nf;
638 if( nf == nullptr )
640
641 target.EnsureRemainingCapacity( 80 );
642
643 integer length= target.Length();
644
645 length= detail::WriteBin( fmt.theValue, target.VBuffer(), length, fmt.theWidth, *nf );
646
647 target.SetLength( length );
648}
649
650template<typename TChar, typename TAllocator>
651void AppendableTraits<THex<TChar>, TChar,TAllocator>::operator()( TAString<TChar,TAllocator>& target,
652 const THex<TChar>& fmt ) {
653 TNumberFormat<TChar>* nf= fmt.nf;
654 if( nf == nullptr )
656
657 target.EnsureRemainingCapacity( 25 );
658
659 integer length= target.Length();
660
661 length= detail::WriteHex( fmt.theValue, target.VBuffer(), length, fmt.theWidth, *nf );
662
663 target.SetLength( length );
664}
665
666template<typename TChar, typename TAllocator>
667void AppendableTraits<TOct<TChar>, TChar,TAllocator>::operator()( TAString<TChar,TAllocator>& target,
668 const TOct<TChar>& fmt ) {
669 TNumberFormat<TChar>* nf= fmt.nf;
670 if( nf == nullptr )
672
673 target.EnsureRemainingCapacity( 30 );
674
675 integer length= target.Length();
676
677 length= detail::WriteOct( fmt.theValue, target.VBuffer(), length, fmt.theWidth, *nf );
678
679 target.SetLength( length );
680}
681
682template<typename TChar, typename TAllocator>
683void AppendableTraits<TFill<TChar>, TChar,TAllocator>::operator()( TAString<TChar,TAllocator>& target,
684 const TFill<TChar>& fmt ) {
685 if (fmt.count <= 0)
686 return;
687 target.EnsureRemainingCapacity( fmt.count );
688 characters::Fill( target.VBuffer() + target.Length(), fmt.count, fmt.fillChar );
689 target.SetLength( target.Length() + fmt.count );
690}
691
692//##################################################################################################
693// ALIB_DEBUG: std::type_info, lang::CallerInfo
694//##################################################################################################
695#if ALIB_DEBUG
696template<typename TChar, typename TAllocator>
698 const std::type_info& type ) {
699 lang::DbgTypeDemangler dmg(type);
700 NString typeName(dmg.Get());
701 NString2K result;
702
703 integer nameStart= 0;
704 bool startedWithDoubleColon= false;
705 for (integer i = 0; i < typeName.Length(); ++i) {
706 // MSVC adds struct/class/union
707 if(typeName.Substring(i, 7).Equals("struct ")) i+= 7;
708 if(typeName.Substring(i, 6).Equals("class " )) i+= 6;
709 if(typeName.Substring(i, 6).Equals("union " )) i+= 6;
710
711 char c = typeName.CharAt<NC>(i);
712 if (c==':') {
713 ALIB_ASSERT(typeName.CharAt<NC>(i+1) == ':', "STRINGS")
714 nameStart= i+2;
715 ++i;
716 continue;
717 }
718 if (!(isalnum(c) || c=='_') || i == typeName.Length() - 1) { // (c=='<' || c=='>' || c==',' || c=='(')
719 if (startedWithDoubleColon)
720 result << "::";
721 result << typeName.Substring(nameStart, i-nameStart+1);
722 nameStart= i+1;
723 startedWithDoubleColon= typeName.CharAt(nameStart) == ':';
724
725 // remove C++20 Module name
726 if (c == '@') {
727 result.DeleteEnd<NC>(1);
728 while ( ++i < typeName.Length()) {
729 c= typeName.CharAt<NC>(i);
730 if (!(isalnum(c) || c == '_' || c == '.')) {
731 nameStart= i;
732 --i;
733 break;
734 } } } } }
735
736 // some ABIs add a disambiguation-space, others don't (for example, some MacOS compiler)
737 // Thus we remove the space to have a unique behavior (and have the unit tests succeed).
738 result.SearchAndReplace("> >", ">>");
739 target << result;
740}
741#endif
742
743#if ALIB_EXT_LIB_THREADS_AVAILABLE
744template<typename TChar, typename TAllocator>
747 const std::thread::id& threadID ) {
748 #if ALIB_EXT_LIB_THREADS_AVAILABLE
749 size_t nativeIDWidth;
750 uint64_t nativeID;
751 if constexpr ( sizeof(std::thread::id) == sizeof(uint16_t) ) { nativeID= *reinterpret_cast<const uint16_t*>(&threadID); nativeIDWidth= 4; }
752 else if constexpr ( sizeof(std::thread::id) == sizeof(uint32_t) ) { nativeID= *reinterpret_cast<const uint32_t*>(&threadID); nativeIDWidth= 8; }
753 else { nativeID= *reinterpret_cast<const uint64_t*>(&threadID); nativeIDWidth=16; }
754 if (lang::IsNotNull(threadID) )
755 #if !ALIB_SINGLE_THREADED
756 {
757 integer length= target.Length();
758 Thread* thread= Thread::Get(threadID);
759 target << thread->GetName()
760 << '(' << thread->GetID()
761 << ",0x" << THex<TChar>(nativeID, int(nativeIDWidth)) <<')';
762 target.InsertChars( ' ', 30 + length - target.Length() );
763 }
764 #else
765 target << "TID=0x" << THex<TChar>(nativeID, int(nativeIDWidth) );
766 #endif
767 else
768 target << "<NULL>";
769
770 #endif
771}
772#endif
773
774template<typename TChar, typename TAllocator>
777 const lang::CallerInfo& ci ) {
778 NString2K nbuf;
779 nbuf << "[@ ";
780 if (ci.File) nbuf << ci.File << ':' << ci.Line;
781 else nbuf << "<NULL>";
782 #if ALIB_DEBUG
783 nbuf << " from '";
784 if (ci.TypeInfo) nbuf << *ci.TypeInfo << "::";
785 if(ci.Func) nbuf << ci.Func << "()";
786 else nbuf << "<NULL>";
787 nbuf << '\'';
788 #endif
789 #if ALIB_EXT_LIB_THREADS_AVAILABLE
790 nbuf << " by '"<< ci.ThreadID << '\'';
791 #endif
792 nbuf << ']';
793
794 target << nbuf;
795}
796
797
798template<typename TChar, typename TAllocator>
801 time::DateTime::Duration pSrc ) {
802 using Duration= DateTime::Duration;
803 Duration src= pSrc;
804 auto nanos= src.InNanoseconds();
805 if( nanos == 0 ) {
806 target << DT_UNITS[size_t(DayTimeUnits::TS_ZERO)];
807 return;
808 }
809
810 if( nanos < 0 ) {
811 target << A_CHAR("- ");
812 src= Duration() - src;
813 }
814
816 nf.FractionalPartWidth= 2;
817 int64_t v= src.InAbsoluteDays();
818 if( v >= 10 ) {
819 target << TDec<TChar>( src.InDays(), &nf ) << DT_UNITS[size_t(DayTimeUnits::DayPlural)];
820 return;
821 }
822
823 if( v > 0 ) {
824 target << v << ( v != 1 ? DT_UNITS[size_t(DayTimeUnits::DayPlural)]
825 : DT_UNITS[size_t(DayTimeUnits::DaySingular)] );
826
827 Duration cpy= src - ( Duration::FromAbsoluteDays(v) );
828
829 target << ' ' << TDec<TChar>( cpy.InHours(), &nf ) << DT_UNITS[size_t(DayTimeUnits::HourPlural)];
830 return;
831 }
832
833 v= src.InAbsoluteHours();
834 if( v > 0 ) {
835 target << v << ( v != 1 ? DT_UNITS[size_t(DayTimeUnits::HourPlural)]
836 : DT_UNITS[size_t(DayTimeUnits::HourSingular)] );
837
838 Duration cpy= src - ( Duration::FromAbsoluteHours(v) );
839
840 auto minutes= cpy.InAbsoluteMinutes();
841 target << ' ' << minutes << (minutes!= 1 ? DT_UNITS[size_t(DayTimeUnits::MinPlural)]
842 : DT_UNITS[size_t(DayTimeUnits::MinSingular)] );
843 return;
844 }
845
846 v= src.InAbsoluteMinutes();
847 if( v > 0 ) {
848 target << v << ( v != 1 ? DT_UNITS[size_t(DayTimeUnits::MinPlural)]
849 : DT_UNITS[size_t(DayTimeUnits::MinSingular)] );
850
851 Duration cpy= src - ( Duration::FromAbsoluteMinutes(v) );
852
853 auto seconds= cpy.InAbsoluteSeconds();
854 target << ' ' << seconds << (seconds!= 1 ? DT_UNITS[size_t(DayTimeUnits::SecPlural)]
855 : DT_UNITS[size_t(DayTimeUnits::SecSingular)] );
856 return;
857 }
858
859 v= src.InAbsoluteSeconds();
860 if( v > 0 ) {
861 target << TDec<TChar>( src.InSeconds(), &nf ) << DT_UNITS[size_t(DayTimeUnits::SecPlural)];
862 return;
863 }
864
865 nf.DecMinimumFieldWidth= 3;
866
867 auto val= src.InAbsoluteMilliseconds();
868 if( val >= 1 ) {
869 target << TDec<TChar>(val,&nf) << ( val!= 1 ?DT_UNITS[size_t(DayTimeUnits::MlSecPlural)]
870 :DT_UNITS[size_t(DayTimeUnits::MlSecSingular)]);
871 return;
872 }
873
874 val= src.InAbsoluteMicroseconds();
875 if( val >= 1 ) {
876 target << TDec<TChar>(val,&nf) << ( val!= 1 ?DT_UNITS[size_t(DayTimeUnits::McSecPlural)]
877 :DT_UNITS[size_t(DayTimeUnits::McSecSingular)]);
878 return;
879 }
880
881 val= src.InNanoseconds();
882 target << TDec<TChar>(val,&nf) << ( val!= 1 ?DT_UNITS[size_t(DayTimeUnits::NSecPlural)]
883 :DT_UNITS[size_t(DayTimeUnits::NSecSingular)] );
884 return;
885}
886
887template<typename TChar, typename TAllocator>
889 TAString<TChar,TAllocator>& target, time::Ticks::Duration src ) {
890 // simply convert the ticks-duration to a DateTime duration and use its append function
892 target, time::DateTime::Duration::FromNanoseconds( src.InNanoseconds() ));
893}
894
895
896}} // namespace [alib::strings]
#define A_CHAR(STR)
Definition alib.inl:1325
#define ALIB_ASSERT(cond, domain)
Definition alib.inl:1143
#define ALIB_WARNING(domain,...)
Definition alib.inl:1141
#define ALIB_ASSERT_WARNING(cond, domain,...)
Definition alib.inl:1145
#define ALIB_ERROR(domain,...)
Definition alib.inl:1140
#define ALIB_ASSERT_ERROR(cond, domain,...)
Definition alib.inl:1144
#define ALIB_DEBUG_STRINGS
Definition alib.inl:56
integer TrimAt(integer idx, const TCString< TChar > &trimChars=CStringConstantsTraits< TChar >::DefaultWhitespaces())
TAString & Delete(integer regionStart, integer regionLength=MAX_LEN)
integer SearchAndReplace(TChar needle, TChar replacement, integer startIdx=0, integer endIdx=strings::MAX_LEN)
bool dbgWarnWhenExternalBufferIsReplaced
Definition tastring.inl:227
constexpr TAString(TAllocator &pAllocator, TChar *extBuffer, integer extBufferSize)
Definition tastring.inl:264
void SetBuffer(integer newCapacity)
integer Capacity() const
Definition tastring.inl:588
TChar * VBuffer() const
Definition tastring.inl:637
void GrowBufferAtLeastBy(integer minimumGrowth)
TAString & Append(const TCharSrc *src, integer srcLength)
Definition tastring.inl:788
TAString & Trim(const TCString< TChar > &trimChars=CStringConstantsTraits< TChar >::DefaultWhitespaces())
void EnsureRemainingCapacity(integer spaceNeeded)
Definition tastring.inl:561
void SetLength(integer newLength)
Definition tastring.inl:699
constexpr integer Length() const
Definition string.inl:304
constexpr bool IsEmpty() const
Definition string.inl:353
const TChar * buffer
Definition string.inl:134
integer IndexOf(TChar needle, integer startIdx=0) const
Definition string.inl:803
integer IndexOfAny(const TString &needles, integer startIdx=0) const
Definition string.inl:961
constexpr const TChar * Buffer() const
Definition string.inl:299
integer WStringLength() const
constexpr TString() noexcept=default
integer IndexOfOrLength(TChar needle) const
Definition string.inl:863
integer LastIndexOfAny(const TString &needles, integer startIdx=MAX_LEN) const
Definition string.inl:1001
static Thread * Get(std::thread::id nativeID)
Definition thread.cpp:314
void typeName(const detail::VTable *vtable, AString &result)
void Copy(const TChar *src, integer length, TChar *dest)
void Move(const TChar *src, integer length, TChar *dest)
void Fill(TChar *dest, integer length, TChar value)
@ Right
Chooses right alignment.
@ Left
Chooses left alignment.
@ On
Switch it on, switched on, etc.
Case
Denotes upper and lower case character treatment.
constexpr bool IsNotNull(const T &t)
Definition tmp.inl:55
@ Transfer
Transfers responsibility to the receiving party.
String DT_UNITS[size_t(DayTimeUnits::SIZE_OF_UNITS)]
This is a detail namespace of module ALib Strings.
integer WriteHex(uint64_t value, TChar *buffer, integer idx, int minWidth, const TNumberFormat< TChar > &nf)
integer WriteDecUnsigned(uint64_t value, TChar *buffer, integer idx, int minWidth, const TNumberFormat< TChar > &nf)
integer WriteDecSigned(int64_t value, TChar *buffer, integer idx, int minWidth, const TNumberFormat< TChar > &nf)
integer WriteOct(uint64_t value, TChar *buffer, integer idx, int minWidth, const TNumberFormat< TChar > &nf)
integer WriteBin(uint64_t value, TChar *buffer, integer idx, int minWidth, const TNumberFormat< TChar > &nf)
integer WriteFloat(double value, TChar *buffer, integer idx, int minWidth, const TNumberFormat< TChar > &nf)
strings::TString< nchar > NString
Type alias in namespace alib.
Definition string.inl:2181
threads::Thread Thread
Type alias in namespace alib.
Definition thread.inl:387
lang::integer integer
Type alias in namespace alib.
Definition integers.inl:149
NLocalString< 2048 > NString2K
Type alias name for #"TLocalString;TLocalString<nchar,2048>".
#define ALIB_STRING_DBG_CHK(instance)
TAllocator & GetAllocator() const noexcept
void operator()(TAString< TChar > &target, const TAppendable &src)
static constexpr CString< TChar > NewLine
Definition cstring.inl:464
static TNumberFormat Computational
static TNumberFormat Global