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