7#if !defined(HPP_ALIB_STRINGS_TASTRING_INLINING)
8# error "ALib sources with ending '.inl' must not be included from outside."
19# elif ALIB_EXT_LIB_THREADS_AVAILABLE
27namespace alib {
namespace strings {
39 namespace APPENDABLES {}
48template<
typename TChar,
typename TAllocator>
56 || base::length <= debugLastAllocRequest,
"STRINGS",
57 "Error: Previous allocation request was too short" )
60 "Error: Length greater than allocation size" )
63 if( base::buffer && HasInternalBuffer() )
65 for (
integer i= -16 ; i < 0 ; ++i)
66 if ( base::buffer[i] != 2 )
68 ALIB_ERROR(
"STRINGS",
"Magic byte not found at start of buffer." )
71 for (
integer i= 1 ; i <= 16 ; ++i)
72 if ( base::buffer[ cap + i] != 3 )
74 ALIB_ERROR(
"STRINGS",
"Magic byte not found at end of buffer." )
88template<
typename TChar,
typename TAllocator>
91 integer actCapacity= Capacity();
94 "STRINGS",
"Unnecessary invocation of Grow()" )
97 if (actCapacity == 0 )
99 SetBuffer( minimumGrowth > 15 ? minimumGrowth : 15 );
100 #if ALIB_DEBUG_STRINGS
101 debugLastAllocRequest= minimumGrowth;
108 integer newCapacity= actCapacity + (actCapacity / 2);
109 if ( newCapacity < base::length + minimumGrowth )
110 newCapacity+= minimumGrowth;
112 if ( newCapacity < 15 )
115 SetBuffer( newCapacity );
116 #if ALIB_DEBUG_STRINGS
117 debugLastAllocRequest= actCapacity + minimumGrowth;
121template<
typename TChar,
typename TAllocator>
124 #if ALIB_DEBUG_STRINGS
128 allocBase::GetAllocator().dbgCheckMemory( base::vbuffer - 16 ,
129 sizeof(TChar) * (
size_t(capacity + 1) + 32));
137 if ( capacity >= 0 && capacity == newCapacity )
140 #if ALIB_DEBUG_STRINGS
141 debugLastAllocRequest= newCapacity;
145 if ( newCapacity == 0 )
148 "AString::SetBuffer(): removing an external buffer (setting string nulled). "
149 "This may not be wanted." )
153 allocBase::GetAllocator().free( base::vbuffer
157 ,
size_t(capacity + 1) *
sizeof(TChar)
165 base::buffer=
nullptr;
171 if( dbgWarnWhenExternalBufferIsReplaced && capacity < 0)
173 "AString::SetBuffer(): replacing an external buffer by an internally managed one. "
174 "This may not be wanted: ",
reinterpret_cast<const char*
>(Terminate()) )
180 size_t allocSize= size_t(newCapacity + 1) *
sizeof(TChar);
181 #if !ALIB_DEBUG_STRINGS
182 base::buffer=
static_cast<TChar*
>(
183 allocBase::GetAllocator().reallocate( base::vbuffer,
184 size_t(capacity + 1) *
sizeof(TChar),
187 newCapacity=
integer(allocSize /
sizeof(TChar)) - 1;
188 allocBase::GetAllocator().dbgAcknowledgeIncreasedAllocSize( base::vbuffer, allocSize );
192 allocSize+= 32 *
sizeof(TChar);
193 base::buffer=
static_cast<TChar*
>(
194 allocBase::GetAllocator().reallocate( base::vbuffer - 16,
195 size_t(capacity + 1 + 32) *
sizeof(TChar),
197 alignof(TChar) ) ) + 16;
198 newCapacity=
integer(allocSize /
sizeof(TChar)) - 32 -1;
202 allocBase::GetAllocator().dbgAcknowledgeIncreasedAllocSize( base::vbuffer - 16, allocSize );
206 capacity= newCapacity;
207 if ( base::length > capacity )
208 base::length= capacity;
214 size_t allocSize= size_t(newCapacity +1) *
sizeof(TChar);
215 #if !ALIB_DEBUG_STRINGS
216 TChar* newBuffer=
static_cast<TChar*
>( allocBase::GetAllocator().allocate( allocSize,
alignof(TChar)) );
217 newCapacity=
integer(allocSize /
sizeof(TChar)) - 1;
218 allocBase::GetAllocator().dbgAcknowledgeIncreasedAllocSize( newBuffer, allocSize );
222 allocSize+= 32 *
sizeof(TChar);
223 TChar* newBuffer=
static_cast<TChar*
>( allocBase::GetAllocator().allocate( allocSize,
alignof(TChar)) ) + 16;
224 newCapacity=
integer(allocSize /
sizeof(TChar)) - 32 - 1;
229 allocBase::GetAllocator().dbgAcknowledgeIncreasedAllocSize( newBuffer - 16, allocSize );
237 characters::Copy( base::buffer, (std::min)( base::length + 1, newCapacity + 1),
241 allocBase::GetAllocator().free( base::vbuffer
245 ,
size_t(capacity + 1) *
sizeof(TChar)
258 base::buffer= newBuffer;
259 capacity= newCapacity;
260 if ( base::length > capacity )
261 base::length= capacity;
265template<
typename TChar,
typename TAllocator>
270 && !(extBufferSize != 0 && extBuffer ==
nullptr) ,
"STRINGS",
271 "AString::SetBuffer(): Given buffer is nullptr while given alloc size is not 0 (or vice versa)" )
276 allocBase::GetAllocator().free( base::vbuffer
280 ,
size_t(capacity + 1) *
sizeof(TChar)
289 if ( extBufferSize < 1 )
291 ALIB_ERROR(
"STRINGS",
"allocation size < 1" )
296 if ( (base::buffer= extBuffer) ==
nullptr )
298 #if ALIB_DEBUG_STRINGS
299 debugLastAllocRequest=
307 if ( extLength >= extBufferSize )
309 ALIB_ERROR(
"STRINGS",
"ext length >= ext allocation size" )
310 extLength= extBufferSize -1;
318 #if ALIB_DEBUG_STRINGS
319 debugLastAllocRequest= extBufferSize;
321 base::length= extLength;
330template<
typename TChar,
typename TAllocator>
335 if ( idx >= base::length )
338 integer regionStart= base::template LastIndexOfAny<lang::Inclusion::Exclude, NC>( trimChars, idx ) + 1;
339 if (regionStart < 0 )
342 integer regionEnd=
TCString<TChar>(
this).template IndexOfAny <lang::Inclusion::Exclude, NC>( trimChars, idx );
344 regionEnd= base::length;
346 integer regionLength= regionEnd - regionStart;
347 if ( regionLength > 0 )
348 Delete<NC>( regionStart, regionLength );
353template<
typename TChar,
typename TAllocator>
357 if (base::length == 0 || trimChars.
IsEmpty() )
361 integer idx= base::template LastIndexOfAny<lang::Inclusion::Exclude, NC>( trimChars, base::length - 1 ) + 1;
362 if ( (base::length= idx) > 0 )
365 idx=
TCString<TChar>(
this).template IndexOfAny<lang::Inclusion::Exclude, NC>( trimChars );
367 Delete<NC>( 0, idx );
377template<
typename TChar,
typename TAllocator>
385 if ( startIdx < 0 ) startIdx= 0;
386 else if ( startIdx >= base::length )
return 0;
387 if ( endIdx > base::length ) endIdx= base::length;
388 if ( startIdx >= endIdx )
return 0;
395 startIdx= thisAsCString.template IndexOfOrLength<NC>( needle, startIdx );
396 if ( startIdx == base::length )
398 base::vbuffer[ startIdx ]= replacement;
401 while( ++startIdx < endIdx) ;
402 return cntReplacements;
407template<
typename TChar,
typename TAllocator>
418 if ( needle.
IsEmpty() )
return 0;
419 endIdx= (std::min) (endIdx, base::length - needle.
Length() + 1 );
420 if ( startIdx >= endIdx )
return 0;
428 while ( cntReplacements < maxReplacements && startIdx < endIdx)
433 ?
TString<TChar>(*this).template IndexOf<NC, lang::Case::Sensitive>( needle, startIdx, endIdx )
434 :
TString<TChar>(*this).template IndexOf<NC, lang::Case::Ignore >( needle, startIdx, endIdx );
442 EnsureRemainingCapacity( lenDiff );
444 base::length - idx - nLen,
445 base::vbuffer + idx + nLen + lenDiff );
446 base::length+= lenDiff;
455 startIdx= idx + rLen;
463 return cntReplacements;
470template<
typename TChar,
typename TAllocator>
480template<
typename TChar,
typename TAllocator>
491template<
typename TChar,
typename TAllocator>
495 target.EnsureRemainingCapacity(48);
496 integer length= target.Length();
498 target.SetLength( length );
508template<
typename TChar,
typename TAllocator>
509void T_Append<typename TFormat<TChar>::Tab, TChar,TAllocator>::operator()( TAString<TChar,TAllocator>& target,
510 const typename TFormat<TChar>::Tab& tab)
512 integer reference= tab.reference;
517 target.Length() -1 );
526 reference= target.Length();
530 integer length= target.Length();
531 integer qtyChars= tab.minPad > 0 ? tab.minPad : 0;
533 if ( tab.tabSize > 1 )
534 qtyChars+= (tab.tabSize - ( (length + qtyChars - reference) % tab.tabSize ) ) % tab.tabSize;
537 target.template InsertChars<NC>( tab.tabChar, qtyChars );
544template<
typename TChar,
typename TAllocator>
545void T_Append<typename TFormat<TChar>::Field, TChar,TAllocator>::operator()( TAString<TChar,TAllocator>& target,
546 const typename TFormat<TChar>::Field& field)
550 TString<TChar> theContent;
553 TLocalString<TChar, 256> noneStringArgBuf;
554 noneStringArgBuf.DbgDisableBufferReplacementWarning();
557 if( !field.theContent.template IsType<void>() && field.theContent.template IsType<TString<TChar>>() )
558 theContent= field.theContent.template Unbox<TString<TChar>>();
562 noneStringArgBuf << field.theContent;
563 theContent= noneStringArgBuf;
567 TString<TChar> theContent= field.theContent;
570 integer padSize= field.fieldWidth
571 - theContent.WStringLength();
576 target.template _ <NC>( theContent );
577 if (padSize > 0 ) target.template InsertChars<NC>( field.padChar, padSize );
585 target.template InsertChars<NC>( field.padChar, padSize );
586 target.template Append<NC>( theContent );
591 integer leftPadding= padSize / 2;
592 if( leftPadding > 0 )
593 target.template InsertChars<NC> ( field.padChar, leftPadding );
594 target.template Append<NC> ( theContent );
595 if( padSize > leftPadding ) target.template InsertChars<NC> ( field.padChar, padSize - leftPadding );
601template<
typename TChar,
typename TAllocator>
602void T_Append<typename TFormat<TChar>::Escape, TChar,TAllocator>::operator()( TAString<TChar,TAllocator>& target,
603 const typename TFormat<TChar>::Escape& escape)
605 if( target.AdjustRegion(
const_cast<typename TFormat<TChar>::Escape&
>(escape).startIdx,
606 const_cast<typename TFormat<TChar>::Escape&
>(escape).length ) )
609 integer regionEnd= escape.startIdx + escape.length;
616 for(
integer idx= escape.startIdx; idx < regionEnd ; ++idx )
618 TChar c= target.CharAt(idx);
620 TChar resultChar=
'\0';
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;
632 case '"' : resultChar=
'"' ;
break;
637 if( resultChar !=
'\0')
639 target.template InsertChars<NC>(
'\\', 1, idx);
640 target[++idx]= resultChar;
652 for(
integer idx= escape.startIdx; idx < regionEnd ; ++idx )
654 TChar c= target.CharAt(idx);
658 c= target.CharAt(idx + 1);
660 TChar resultChar=
'\0';
663 case '\\' : resultChar=
'\\';
break;
664 case 'r' : resultChar=
'\r' ;
break;
665 case 'n' : resultChar=
'\n' ;
break;
666 case 't' : resultChar=
'\t' ;
break;
667 case 'a' : resultChar=
'\a' ;
break;
668 case 'b' : resultChar=
'\b' ;
break;
669 case 'v' : resultChar=
'\v' ;
break;
670 case 'f' : resultChar=
'\f' ;
break;
672 case '"' : resultChar=
'"' ;
break;
677 if( resultChar !=
'\0')
679 target.Delete( idx, 1);
680 target[idx]= resultChar;
690template<
typename TChar,
typename TAllocator>
691void T_Append<TFormat<TChar>, TChar,TAllocator>::operator()( TAString<TChar,TAllocator>& target,
698 target.EnsureRemainingCapacity( fmt.valueType== 3 ? 48
702 integer length= target.Length();
706 fmt.valueType == 2 ?
detail::WriteDecUnsigned(
static_cast<uint64_t
>(fmt.v.value) , target.VBuffer(), length, fmt.width , *nf ) :
709 target.SetLength( length );
714template<
typename TChar,
typename TAllocator>
722 target.EnsureRemainingCapacity( 80 );
724 integer length= target.Length();
726 length=
detail::WriteBin( fmt.theValue, target.VBuffer(), length, fmt.theWidth, *nf );
728 target.SetLength( length );
731template<
typename TChar,
typename TAllocator>
739 target.EnsureRemainingCapacity( 25 );
741 integer length= target.Length();
743 length=
detail::WriteHex( fmt.theValue, target.VBuffer(), length, fmt.theWidth, *nf );
745 target.SetLength( length );
748template<
typename TChar,
typename TAllocator>
756 target.EnsureRemainingCapacity( 30 );
758 integer length= target.Length();
760 length=
detail::WriteOct( fmt.theValue, target.VBuffer(), length, fmt.theWidth, *nf );
762 target.SetLength( length );
765template<
typename TChar,
typename TAllocator>
771 target.EnsureRemainingCapacity( fmt.count );
773 target.SetLength( target.Length() + fmt.count );
780template<
typename TChar,
typename TAllocator>
782 const std::type_info& type )
790template<
typename TChar,
typename TAllocator>
792 const std::thread::id& threadID )
794 #if ALIB_EXT_LIB_THREADS_AVAILABLE
795 size_t nativeIDWidth;
797 if constexpr (
sizeof(std::thread::id) ==
sizeof(uint16_t) ) { nativeID= *
reinterpret_cast<const uint16_t*
>(&threadID); nativeIDWidth= 4; }
798 else if constexpr (
sizeof(std::thread::id) ==
sizeof(uint32_t) ) { nativeID= *
reinterpret_cast<const uint32_t*
>(&threadID); nativeIDWidth= 8; }
799 else { nativeID= *
reinterpret_cast<const uint64_t*
>(&threadID); nativeIDWidth=16; }
803 integer length= target.Length();
805 target << thread->GetName()
806 <<
'(' << thread->GetID()
807 <<
",0x" <<
typename TFormat<TChar>::Hex(nativeID,
int(nativeIDWidth)) <<
')';
808 target.InsertChars(
' ', 30 + length - target.Length() );
811 target <<
"TID=0x" <<
typename TFormat<TChar>::Hex(nativeID,
int(nativeIDWidth) );
819template<
typename TChar,
typename TAllocator>
821 const lang::CallerInfo& ci )
825 if (ci.File) nbuf << ci.File <<
':' << ci.Line;
826 else nbuf <<
"<NULL>";
829 if (ci.TypeInfo) lang::DbgTypeDemangler(*ci.TypeInfo).GetShort(nbuf) <<
"::";
830 if(ci.Func) nbuf << ci.Func <<
"()";
831 else nbuf <<
"<NULL>";
834 #if ALIB_EXT_LIB_THREADS_AVAILABLE
835 nbuf <<
" by '"<< ci.ThreadID <<
'\'';
ALIB_API NAString & GetShort(NAString &target)
ALIB_API integer SearchAndReplace(TChar needle, TChar replacement, integer startIdx=0, integer endIdx=strings::MAX_LEN)
ALIB_API void GrowBufferAtLeastBy(integer minimumGrowth)
ALIB_API integer TrimAt(integer idx, const TCString< TChar > &trimChars=TT_CStringConstants< TChar >::DefaultWhitespaces())
ALIB_API TAString & Trim(const TCString< TChar > &trimChars=TT_CStringConstants< TChar >::DefaultWhitespaces())
void EnsureRemainingCapacity(integer spaceNeeded)
ALIB_API void SetBuffer(integer newCapacity)
void SetLength(integer newLength)
constexpr bool IsEmpty() const
constexpr integer Length() const
constexpr const TChar * Buffer() const
static ALIB_API Thread * Get(std::thread::id nativeID)
#define ALIB_WARNING(...)
#define ALIB_WARNINGS_RESTORE
#define ALIB_ASSERT_ERROR(cond,...)
#define ALIB_WARNINGS_ALLOW_UNSAFE_BUFFER_USAGE
#define ALIB_ASSERT_WARNING(cond,...)
#define ALIB_STRING_DBG_CHK(instance)
#define ALIB_ASSERT(cond)
#define ALIB_DEBUG_STRINGS
void Move(const TChar *src, integer length, TChar *dest)
void Copy(const TChar *src, integer length, TChar *dest)
void Fill(TChar *dest, integer length, TChar value)
constexpr bool IsNotNull(const T &t)
@ On
Switch it on, switched on, etc.
Case
Denotes upper and lower case character treatment.
@ Transfer
Transfers responsibility to the receiving party.
@ Right
Chooses right alignment.
@ Left
Chooses left alignment.
ALIB_API integer WriteFloat(double value, TChar *buffer, integer idx, int minWidth, const TNumberFormat< TChar > &nf)
ALIB_API integer WriteDecUnsigned(uint64_t value, TChar *buffer, integer idx, int minWidth, const TNumberFormat< TChar > &nf)
ALIB_API integer WriteOct(uint64_t value, TChar *buffer, integer idx, int minWidth, const TNumberFormat< TChar > &nf)
ALIB_API integer WriteDecSigned(int64_t value, TChar *buffer, integer idx, int minWidth, const TNumberFormat< TChar > &nf)
ALIB_API integer WriteHex(uint64_t value, TChar *buffer, integer idx, int minWidth, const TNumberFormat< TChar > &nf)
ALIB_API integer WriteBin(uint64_t value, TChar *buffer, integer idx, int minWidth, const TNumberFormat< TChar > &nf)
threads::Thread Thread
Type alias in namespace alib.
NLocalString< 2048 > NString2K
Type alias name for TLocalString<nchar,2048>.
lang::integer integer
Type alias in namespace alib.
static constexpr CString< TChar > NewLine
void operator()(TAString< TChar > &target, const TAppendable &src)