7#if !defined(ALIB_STRINGS_TASTRING_INSTANTIATION)
8# error "ALib sources with ending '.inl' must not be included from outside."
37template<
typename TChar,
typename TAllocator>
38requires alib::lang::IsAllocator<TAllocator>
46 || base::length <= debugLastAllocRequest,
"STRINGS",
47 "Error: Previous allocation request was too short: {} < {} ",
48 debugLastAllocRequest, base::length )
51 "Error: Length greater than allocation size: {} > {}",
54 if( base::buffer && HasInternalBuffer() )
56 for (
integer i= -16 ; i < 0 ; ++i)
57 if ( base::buffer[i] != 2 )
59 ALIB_ERROR(
"STRINGS",
"Magic byte not found at start of buffer." )
62 for (
integer i= 1 ; i <= 16 ; ++i)
63 if ( base::buffer[ cap + i] != 3 )
65 ALIB_ERROR(
"STRINGS",
"Magic byte not found at end of buffer." )
78template<
typename TChar,
typename TAllocator>
84 "Unnecessary invocation of Grow(): {} <= {}",
base::length + minimumGrowth, actCapacity )
87 if (actCapacity == 0 ) {
88 SetBuffer( minimumGrowth > 15 ? minimumGrowth : 15 );
89 #if ALIB_DEBUG_STRINGS
97 integer newCapacity= actCapacity + (actCapacity / 2);
99 newCapacity+= minimumGrowth;
101 if ( newCapacity < 15 )
105 #if ALIB_DEBUG_STRINGS
110template<
typename TChar,
typename TAllocator>
113 #if ALIB_DEBUG_STRINGS
117 sizeof(TChar) * (
size_t(
capacity + 1) + 32));
127 #if ALIB_DEBUG_STRINGS
132 if ( newCapacity == 0 ) {
134 "AString::SetBuffer(): removing an external buffer (setting string nulled). "
135 "This may not be wanted." )
142 ,
size_t(
capacity + 1) *
sizeof(TChar)
157 "Replacing an external buffer by an internally managed one. This may not be wanted: ",
163 size_t allocSize= size_t(newCapacity + 1) *
sizeof(TChar);
164 #if !ALIB_DEBUG_STRINGS
167 size_t(
capacity + 1) *
sizeof(TChar),
170 newCapacity=
integer(allocSize /
sizeof(TChar)) - 1;
174 allocSize+= 32 *
sizeof(TChar);
177 size_t(
capacity + 1 + 32) *
sizeof(TChar),
179 alignof(TChar) ) ) + 16;
180 newCapacity=
integer(allocSize /
sizeof(TChar)) - 32 -1;
195 size_t allocSize= size_t(newCapacity +1) *
sizeof(TChar);
196 #if !ALIB_DEBUG_STRINGS
198 newCapacity=
integer(allocSize /
sizeof(TChar)) - 1;
202 allocSize+= 32 *
sizeof(TChar);
204 newCapacity=
integer(allocSize /
sizeof(TChar)) - 32 - 1;
222 ,
size_t(
capacity + 1) *
sizeof(TChar)
239template<
typename TChar,
typename TAllocator>
244 && !(extBufferSize != 0 && extBuffer ==
nullptr) ,
"STRINGS",
245 "AString::SetBuffer(): Given buffer is nullptr while given alloc size is not 0 (or vice versa)")
253 ,
size_t(
capacity + 1) *
sizeof(TChar)
261 if ( extBufferSize < 1 ) {
262 ALIB_ERROR(
"STRINGS",
"allocation size < 1" )
268 #if ALIB_DEBUG_STRINGS
277 if ( extLength >= extBufferSize ) {
278 ALIB_ERROR(
"STRINGS",
"ext length {} >= ext allocation size {}", extLength, extBufferSize )
279 extLength= extBufferSize -1;
287 #if ALIB_DEBUG_STRINGS
298template<
typename TChar,
typename TAllocator>
307 if (regionStart < 0 )
310 integer regionEnd=
TCString<TChar>(
this).template IndexOfAny <lang::Inclusion::Exclude, NC>( trimChars, idx );
314 integer regionLength= regionEnd - regionStart;
315 if ( regionLength > 0 )
321template<
typename TChar,
typename TAllocator>
343template<
typename TChar,
typename TAllocator>
350 if ( startIdx < 0 ) startIdx= 0;
353 if ( startIdx >= endIdx )
return 0;
363 base::vbuffer[ startIdx ]= replacement;
366 while( ++startIdx < endIdx) ;
367 return cntReplacements;
370template<
typename TChar,
typename TAllocator>
381 if ( needle.
IsEmpty() )
return 0;
383 if ( startIdx >= endIdx )
return 0;
391 while ( cntReplacements < maxReplacements && startIdx < endIdx) {
400 if ( lenDiff != 0 ) {
405 base::vbuffer + idx + nLen + lenDiff );
415 startIdx= idx + rLen;
422 return cntReplacements;
429template<
typename TChar,
typename TAllocator>
438template<
typename TChar,
typename TAllocator>
448template<
typename TChar,
typename TAllocator>
451 target.EnsureRemainingCapacity(48);
452 integer length= target.Length();
454 target.SetLength( length );
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 ) {
471 target.Length() -1 );
479 reference= target.Length();
482 integer length= target.Length();
483 integer qtyChars= tab.minPad > 0 ? tab.minPad : 0;
485 if ( tab.tabSize > 1 )
486 qtyChars+= (tab.tabSize - ( (length + qtyChars - reference) % tab.tabSize ) ) % tab.tabSize;
489 target.template InsertChars<NC>( tab.tabChar, qtyChars );
497template<
typename TChar,
typename TAllocator>
503 integer padSize= field.fieldWidth
509 target.template _ <NC>( theContent );
510 if (padSize > 0 ) target.template InsertChars<NC>( field.padChar, padSize );
518 target.template InsertChars<NC>( field.padChar, padSize );
519 target.template Append<NC>( theContent );
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 );
535template<
typename TChar,
typename TAllocator>
542 integer regionEnd= escape.startIdx + escape.length;
548 for(
integer idx= escape.startIdx; idx < regionEnd ; ++idx ) {
549 TChar c= target.CharAt(idx);
551 TChar resultChar=
'\0';
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;
562 case '"' : resultChar=
'"' ;
break;
567 if( resultChar !=
'\0') {
568 target.template InsertChars<NC>(
'\\', 1, idx);
569 target[++idx]= resultChar;
578 for(
integer idx= escape.startIdx; idx < regionEnd ; ++idx ) {
579 TChar c= target.CharAt(idx);
583 c= target.CharAt(idx + 1);
585 TChar resultChar=
'\0';
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;
596 case '"' : resultChar=
'"' ;
break;
601 if( resultChar !=
'\0') {
602 target.Delete( idx, 1);
603 target[idx]= resultChar;
610template<
typename TChar,
typename TAllocator>
617 target.EnsureRemainingCapacity( fmt.valueType== 3 ? 48
625 fmt.valueType == 2 ?
detail::WriteDecUnsigned( uint64_t(fmt.v.value) , target.
VBuffer(),
length, fmt.width , *nf ) :
628 target.SetLength(
length );
633template<
typename TChar,
typename TAllocator>
640 target.EnsureRemainingCapacity( 80 );
642 integer length= target.Length();
644 length=
detail::WriteBin( fmt.theValue, target.VBuffer(), length, fmt.theWidth, *nf );
646 target.SetLength( length );
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;
656 target.EnsureRemainingCapacity( 25 );
658 integer length= target.Length();
660 length=
detail::WriteHex( fmt.theValue, target.VBuffer(), length, fmt.theWidth, *nf );
662 target.SetLength( length );
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;
672 target.EnsureRemainingCapacity( 30 );
674 integer length= target.Length();
676 length=
detail::WriteOct( fmt.theValue, target.VBuffer(), length, fmt.theWidth, *nf );
678 target.SetLength( length );
681template<
typename TChar,
typename TAllocator>
686 target.EnsureRemainingCapacity( fmt.count );
687 characters::Fill( target.VBuffer() + target.Length(), fmt.count, fmt.fillChar );
688 target.SetLength( target.Length() + fmt.count );
695template<
typename TChar,
typename TAllocator>
697 const std::type_info& type ) {
698 lang::DbgTypeDemangler dmg(type);
703 bool startedWithDoubleColon=
false;
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;
717 if (!(isalnum(c) || c==
'_') || i == typeName.Length() - 1) {
718 if (startedWithDoubleColon)
720 result <<
typeName.Substring(nameStart, i-nameStart+1);
722 startedWithDoubleColon=
typeName.CharAt(nameStart) ==
':';
726 result.DeleteEnd<NC>(1);
729 if (!(isalnum(c) || c ==
'_' || c ==
'.')) {
737 result.SearchAndReplace(
"> >",
">>");
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;
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; }
754 #if !ALIB_SINGLE_THREADED
756 integer length= target.Length();
758 target << thread->GetName()
759 <<
'(' << thread->GetID()
760 <<
",0x" <<
THex<TChar>(nativeID,
int(nativeIDWidth)) <<
')';
761 target.InsertChars(
' ', 30 + length - target.Length() );
764 target <<
"TID=0x" <<
THex<TChar>(nativeID,
int(nativeIDWidth) );
773template<
typename TChar,
typename TAllocator>
776 const lang::CallerInfo& ci ) {
779 if (ci.File) nbuf << ci.File <<
':' << ci.Line;
780 else nbuf <<
"<NULL>";
783 if (ci.TypeInfo) nbuf << *ci.TypeInfo <<
"::";
784 if(ci.Func) nbuf << ci.Func <<
"()";
785 else nbuf <<
"<NULL>";
788 #if ALIB_EXT_LIB_THREADS_AVAILABLE
789 nbuf <<
" by '"<< ci.ThreadID <<
'\'';
797template<
typename TChar,
typename TAllocator>
800 time::DateTime::Duration pSrc ) {
801 using Duration= DateTime::Duration;
803 auto nanos= src.InNanoseconds();
805 target <<
DT_UNITS[size_t(DayTimeUnits::TS_ZERO)];
811 src= Duration() - src;
815 nf.FractionalPartWidth= 2;
816 int64_t v= src.InAbsoluteDays();
818 target << TDec<TChar>( src.InDays(), &nf ) <<
DT_UNITS[size_t(DayTimeUnits::DayPlural)];
823 target << v << ( v != 1 ?
DT_UNITS[size_t(DayTimeUnits::DayPlural)]
824 :
DT_UNITS[size_t(DayTimeUnits::DaySingular)] );
826 Duration cpy= src - ( Duration::FromAbsoluteDays(v) );
828 target << ' ' << TDec<TChar>( cpy.InHours(), &nf ) <<
DT_UNITS[size_t(DayTimeUnits::HourPlural)];
832 v= src.InAbsoluteHours();
834 target << v << ( v != 1 ?
DT_UNITS[size_t(DayTimeUnits::HourPlural)]
835 :
DT_UNITS[size_t(DayTimeUnits::HourSingular)] );
837 Duration cpy= src - ( Duration::FromAbsoluteHours(v) );
839 auto minutes= cpy.InAbsoluteMinutes();
840 target <<
' ' << minutes << (minutes!= 1 ?
DT_UNITS[size_t(DayTimeUnits::MinPlural)]
841 :
DT_UNITS[size_t(DayTimeUnits::MinSingular)] );
845 v= src.InAbsoluteMinutes();
847 target << v << ( v != 1 ?
DT_UNITS[size_t(DayTimeUnits::MinPlural)]
848 :
DT_UNITS[size_t(DayTimeUnits::MinSingular)] );
850 Duration cpy= src - ( Duration::FromAbsoluteMinutes(v) );
852 auto seconds= cpy.InAbsoluteSeconds();
853 target <<
' ' << seconds << (seconds!= 1 ?
DT_UNITS[size_t(DayTimeUnits::SecPlural)]
854 :
DT_UNITS[size_t(DayTimeUnits::SecSingular)] );
858 v= src.InAbsoluteSeconds();
860 target << TDec<TChar>( src.InSeconds(), &nf ) <<
DT_UNITS[size_t(DayTimeUnits::SecPlural)];
864 nf.DecMinimumFieldWidth= 3;
866 auto val= src.InAbsoluteMilliseconds();
868 target << TDec<TChar>(val,&nf) << ( val!= 1 ?
DT_UNITS[size_t(DayTimeUnits::MlSecPlural)]
869 :
DT_UNITS[size_t(DayTimeUnits::MlSecSingular)]);
873 val= src.InAbsoluteMicroseconds();
875 target << TDec<TChar>(val,&nf) << ( val!= 1 ?
DT_UNITS[size_t(DayTimeUnits::McSecPlural)]
876 :
DT_UNITS[size_t(DayTimeUnits::McSecSingular)]);
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)] );
886template<
typename TChar,
typename TAllocator>
891 target, time::DateTime::Duration::FromNanoseconds( src.InNanoseconds() ));
TAString & Delete(integer regionStart, integer regionLength=MAX_LEN)
bool dbgWarnWhenExternalBufferIsReplaced
constexpr TAString(TAllocator &pAllocator, TChar *extBuffer, integer extBufferSize)
ALIB_DLL integer SearchAndReplace(TChar needle, TChar replacement, integer startIdx=0, integer endIdx=strings::MAX_LEN)
integer debugLastAllocRequest
ALIB_DLL void SetBuffer(integer newCapacity)
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)
ALIB_DLL void GrowBufferAtLeastBy(integer minimumGrowth)
void SetLength(integer newLength)
constexpr integer Length() const
constexpr bool IsEmpty() const
integer IndexOf(TChar needle, integer startIdx=0) const
integer IndexOfAny(const TString &needles, integer startIdx=0) const
constexpr const TChar * Buffer() const
integer WStringLength() const
constexpr TString() noexcept=default
integer IndexOfOrLength(TChar needle) const
integer LastIndexOfAny(const TString &needles, integer startIdx=MAX_LEN) const
static ALIB_DLL Thread * Get(std::thread::id nativeID)
#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_STRING_DBG_CHK(instance)
#define ALIB_DEBUG_STRINGS
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)
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.
strings::TString< nchar > NString
Type alias in namespace alib.
threads::Thread Thread
Type alias in namespace alib.
TAllocator & GetAllocator() const noexcept
void operator()(TAString< TChar > &target, const TAppendable &src)
static constexpr CString< TChar > NewLine
integer length
The length of the region to convert.
integer startIdx
The start of the region to convert.