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