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