10# if !defined (HPP_ALIB_STRINGS_ASTRING)
14# if !defined (HPP_ALIB_STRINGS_LOCALSTRING)
18# if !defined (HPP_ALIB_STRINGS_CSTRING)
23#if !defined (_GLIBCXX_ALGORITHM) && !defined(_ALGORITHM_)
27namespace alib {
namespace strings {
34template<
typename TChar>
37 TString<TChar>::dbgCheck();
43 "Error: Previous allocation request was too short" )
46 "Error: Length greater than allocation size" )
48 if( TString<TChar>::buffer && HasInternalBuffer() )
50 for (
integer i= -16 ; i < 0 ; ++i)
53 ALIB_ERROR(
"STRINGS",
"Magic byte not found at start of buffer." )
56 for (
integer i= 1 ; i <= 16 ; ++i)
57 if ( TString<TChar>::buffer[ cap + i] != 3 )
59 ALIB_ERROR(
"STRINGS",
"Magic byte not found at end of buffer." )
73template<
typename TChar>
76 integer actCapacity= Capacity();
79 "STRINGS",
"Unnecessary invocation of Grow()" )
82 if (actCapacity == 0 )
84 SetBuffer( minimumGrowth > 16 ? minimumGrowth : 16 );
85 #if ALIB_DEBUG_STRINGS
86 debugLastAllocRequest= minimumGrowth;
93 integer newCapacity= actCapacity + (actCapacity / 2);
95 newCapacity+= minimumGrowth;
97 if ( newCapacity < 16 )
100 SetBuffer( newCapacity );
101 #if ALIB_DEBUG_STRINGS
102 debugLastAllocRequest= actCapacity + minimumGrowth;
106template<
typename TChar>
114 if ( capacity >= 0 && capacity == newCapacity )
117 #if ALIB_DEBUG_STRINGS
118 debugLastAllocRequest= newCapacity;
122 if ( newCapacity == 0 )
125 "AString::SetBuffer(): removing an external buffer (setting string nulled). "
126 "This may not be wanted." )
142 if( dbgWarnWhenExternalBufferIsReplaced && capacity < 0)
144 "AString::SetBuffer(): replacing an external buffer by an internally managed one. "
145 "This may not be wanted: ",
reinterpret_cast<const char*
>(Terminate()) )
151 #if !ALIB_DEBUG_STRINGS
153 static_cast<size_t>(newCapacity + 1)
154 *
sizeof( TChar ) ) );
155 #if ALIB_AVOID_ANALYZER_WARNINGS
157 if( newCapacity > capacity )
166 static_cast<size_t>( newCapacity + 1 + 33 )
167 *
sizeof( TChar ) ) ) + 16;
173 capacity= newCapacity;
181 #if !ALIB_DEBUG_STRINGS
182 TChar* newBuffer=
static_cast<TChar*
>( std::malloc(
static_cast<size_t>(newCapacity + 1)
183 *
sizeof( TChar ) ) );
184 #if ALIB_AVOID_ANALYZER_WARNINGS
189 TChar* newBuffer=
static_cast<TChar*
>( std::malloc(
static_cast<size_t>( newCapacity + 1 + 32 )
190 *
sizeof( TChar ) ) ) + 16;
218 capacity= newCapacity;
224template<
typename TChar>
229 && !(extBufferSize != 0 && extBuffer ==
nullptr) ,
"STRINGS",
230 "AString::SetBuffer(): Given buffer is nullptr while given alloc size is not 0 (or vice versa)" )
241 if ( extBufferSize < 1 )
243 ALIB_ERROR(
"STRINGS",
"allocation size < 1" )
250 #if ALIB_DEBUG_STRINGS
251 debugLastAllocRequest=
259 if ( extLength >= extBufferSize )
261 ALIB_ERROR(
"STRINGS",
"ext length >= ext allocation size" )
262 extLength= extBufferSize -1;
270 #if ALIB_DEBUG_STRINGS
271 debugLastAllocRequest= extBufferSize;
282template<
typename TChar>
291 if (regionStart < 0 )
294 integer regionEnd=
TCString<TChar>(
this).template IndexOfAny <lang::Inclusion::Exclude, false>( trimChars, idx );
298 integer regionLength= regionEnd - regionStart;
299 if ( regionLength > 0 )
300 Delete<false>( regionStart, regionLength );
305template<
typename TChar>
317 idx=
TCString<TChar>(
this).template IndexOfAny<lang::Inclusion::Exclude,false>( trimChars );
319 Delete<false>( 0, idx );
329template<
typename TChar>
336 if ( startIdx < 0 ) startIdx= 0;
344 startIdx= thisAsCString.template IndexOfOrLength<false>( needle, startIdx );
351 return cntReplacements;
356template<
typename TChar>
380 ?
TString<TChar>(*this).template IndexOf<false, lang::Case::Sensitive>( needle, startIdx )
381 :
TString<TChar>(*this).template IndexOf<false, lang::Case::Ignore >( needle, startIdx );
389 EnsureRemainingCapacity( lenDiff );
401 startIdx= idx + rLen;
409 return cntReplacements;
413#if !defined(ALIB_DOX)
415#if ALIB_DEBUG_STRINGS
466#if ALIB_SIZEOF_WCHAR_T == 2
467# define CHARXX_T char32_t
469# define CHARXX_T char16_t
477#define CHECKING_VERSION_IMPLEMENTATION_OF_APPEND(TChar,TCharParam) \
478 template<> template<> \
479 TAString<TChar>& TAString<TChar>::Append<true> ( const TCharParam* src, integer srcLength ) \
484 if ( srcLength <= 0 ) \
486 if ( TString<TChar>::IsNull() ) \
491 return Append<false>( src, srcLength ); \
494 CHECKING_VERSION_IMPLEMENTATION_OF_APPEND(
char ,
wchar_t )
495 CHECKING_VERSION_IMPLEMENTATION_OF_APPEND(
char , CHARXX_T )
496 CHECKING_VERSION_IMPLEMENTATION_OF_APPEND(
wchar_t ,
char )
497 CHECKING_VERSION_IMPLEMENTATION_OF_APPEND(
wchar_t , CHARXX_T )
498 CHECKING_VERSION_IMPLEMENTATION_OF_APPEND(CHARXX_T,
char )
499 CHECKING_VERSION_IMPLEMENTATION_OF_APPEND(CHARXX_T,
wchar_t )
501#undef CHECKING_VERSION_IMPLEMENTATION_OF_APPEND
517 #if defined( _WIN32 )
520 EnsureRemainingCapacity( srcLength * 2 );
523 int conversionSize= WideCharToMultiByte( CP_UTF8, 0,
524 src,
static_cast<int>( srcLength),
527 if ( conversionSize > 0 )
534 int error= GetLastError();
535 if (error == ERROR_INSUFFICIENT_BUFFER )
537 EnsureRemainingCapacity( srcLength );
543 "AString: Cannot convert wide character string to UTF-8. Error: ",
544 ( error == ERROR_INVALID_FLAGS ?
"ERROR_INVALID_FLAGS."
545 : error == ERROR_INVALID_PARAMETER ?
"ERROR_INVALID_PARAMETER"
546 : error == ERROR_NO_UNICODE_TRANSLATION ?
"ERROR_NO_UNICODE_TRANSLATION"
554 #elif defined (__GLIBCXX__) || defined(__APPLE__) || defined(__ANDROID_NDK__)
559 EnsureRemainingCapacity( maxConversionSize );
560 memset( &ps, 0,
sizeof(mbstate_t) );
561 const wchar_t* srcp= src;
562 size_t conversionSize= wcsnrtombs( TString<char>::vbuffer +
TString<char>::length, &srcp,
static_cast<size_t>(srcLength),
static_cast<size_t>(maxConversionSize), &ps);
563 if ( conversionSize ==
static_cast<size_t>( -1 ) )
565 ALIB_WARNING(
"STRINGS",
"Cannot convert WCS to MBCS. Check locale settings (should be UTF-8)" )
569 if ( conversionSize < 1 )
571 ALIB_ERROR(
"STRINGS",
"Error converting WCS to MBCS." )
575 TString<
char>::length+= conversionSize;
579 #pragma message ("Unknown Platform in file: " __FILE__ )
587TAString<char>& TAString<char>::Append<false>(
const CHARXX_T* src,
integer srcLength )
590 TLocalString<wchar_t,2048> converter;
591 converter.DbgDisableBufferReplacementWarning();
592 converter.Append<
false>( src, srcLength );
593 Append<false>( converter.Buffer(), converter.Length() );
604TAString<wchar_t>& TAString<wchar_t>::Append<false>(
const char* src,
integer srcLength )
609 EnsureRemainingCapacity( srcLength );
612 #if defined( _WIN32 )
615 integer conversionSize= MultiByteToWideChar( CP_UTF8, 9,
616 src,
static_cast<int>( srcLength ),
617 vbuffer + length,
static_cast<int>( Capacity() - length ) );
620 if ( conversionSize == 0 )
623 int error= GetLastError();
626 "MBCS to WCS conversion failed (Error: ",
627 ( error == ERROR_INSUFFICIENT_BUFFER ?
"ERROR_INSUFFICIENT_BUFFER."
628 : error == ERROR_INVALID_FLAGS ?
"ERROR_INVALID_FLAGS."
629 : error == ERROR_INVALID_PARAMETER ?
"ERROR_INVALID_PARAMETER"
630 : error == ERROR_NO_UNICODE_TRANSLATION ?
"ERROR_NO_UNICODE_TRANSLATION"
636 NString128(
"MBCS to WCS conversion failed. Requested length=" )._( srcLength )
637 ._(
", conversion length=" )._(conversionSize)
641 length+= conversionSize;
646 #elif defined (__GLIBCXX__) || defined(__APPLE__) || defined(__ANDROID_NDK__)
648 while(srcLength > 0 )
650 integer actConversionLenght= srcLength;
651 for(
int pass= 0 ; pass < 2 ; ++pass )
654 mbstate_t ps; memset( &ps, 0,
sizeof(mbstate_t) );
655 const char* srcp= src;
656 size_t wcWritten= mbsnrtowcs( vbuffer + length, &srcp,
657 static_cast<size_t>(actConversionLenght),
658 static_cast<size_t>(Capacity() - length), &ps );
661 if( wcWritten ==
static_cast<size_t >(-1) )
672 *(vbuffer + length++)=
'?';
677 actConversionLenght= srcp - src;
683 srcLength-= actConversionLenght;
690 #pragma message ("Unknown Platform in file: " __FILE__ )
696#if ALIB_SIZEOF_WCHAR_T == 4
700 TAString<wchar_t>& TAString<wchar_t>::Append<false>(
const CHARXX_T* src,
integer srcLength )
702 EnsureRemainingCapacity( srcLength );
705 const CHARXX_T* srcEnd= src + srcLength;
708 const char32_t uc = *src++;
709 if ((uc - 0xd800) >= 2048)
711 vbuffer[length++] =
static_cast<wchar_t>(uc);
716 && ((uc & 0xfffffc00) == 0xd800)
717 && ((*src & 0xfffffc00) == 0xdc00),
718 "STRINGS",
"Error decoding UTF16" )
720 vbuffer[length++]=
static_cast<wchar_t>( (uc << 10)
721 + ((*src++) - 0x35fdc00 ) );
735 EnsureRemainingCapacity( srcLength * 2 );
737 const CHARXX_T* srcEnd= src + srcLength;
742 || ( uc >= 0xe000 && uc <= 0x10ffff ),
743 "STRINGS",
"Illegal unicode 32 bit codepoint" )
747 vbuffer[length++]=
static_cast<wchar_t>( uc );
752 vbuffer[length++]=
static_cast<wchar_t>( ( uc >> 10 ) + 0xd800 );
753 vbuffer[length++]=
static_cast<wchar_t>( ( uc & 0x3ff ) + 0xdc00 );
765#if ALIB_SIZEOF_WCHAR_T == 2
766 template<>
template<>
767 TAString<CHARXX_T>& TAString<CHARXX_T>::Append<false>(
const wchar_t* src,
integer srcLength )
769 EnsureRemainingCapacity( srcLength );
772 const wchar_t* srcEnd= src + srcLength;
775 const char32_t uc = *src++;
776 if ((uc - 0xd800) >= 2048)
778 vbuffer[length++] =
static_cast<CHARXX_T
>(uc);
783 && ((uc & 0xfffffc00) == 0xd800)
784 && ((*src & 0xfffffc00) == 0xdc00),
785 "STRINGS",
"Error decoding UTF16" )
787 vbuffer[length++]= static_cast<CHARXX_T>( (uc << 10)
788 + ((*src++) - 0x35fdc00 ) );
797 template<>
template<>
798 TAString<CHARXX_T>& TAString<CHARXX_T>::Append<false>(
const wchar_t* src,
integer srcLength )
801 EnsureRemainingCapacity( srcLength * 2 );
803 const wchar_t* srcEnd= src + srcLength;
808 || ( uc >= 0xe000 && uc <= 0x10ffff ),
809 "STRINGS",
"Illegal unicode 32 bit codepoint" )
813 vbuffer[length++]=
static_cast<CHARXX_T
>( uc );
818 vbuffer[length++]=
static_cast<CHARXX_T
>( ( uc >> 10 ) + 0xd800 );
819 vbuffer[length++]=
static_cast<CHARXX_T
>( ( uc & 0x3ff ) + 0xdc00 );
829TAString<CHARXX_T>& TAString<CHARXX_T>::Append<false>(
const char* src,
integer srcLength )
834 TLocalString<
wchar_t,2048> converter;
835 converter.Append<false>( src, srcLength );
836 return Append<false>( converter.Buffer(), converter.Length() );
ALIB_API integer TrimAt(integer idx, const TCString< TChar > &trimChars=TT_StringConstants< TChar >::DefaultWhitespaces())
void GrowBufferAtLeastBy(integer minimumGrowth)
ALIB_API TAString & Trim(const TCString< TChar > &trimChars=TT_StringConstants< TChar >::DefaultWhitespaces())
ALIB_API void SetBuffer(integer newCapacity)
ALIB_API integer SearchAndReplace(TChar needle, TChar replacement, integer startIdx=0)
constexpr bool IsEmpty() const
constexpr integer Length() const
constexpr const TChar * Buffer() const
#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
@ Transfer
Transfers responsibility to the receiving party.
lang::uinteger uinteger
Type alias in namespace alib.
NLocalString< 64 > NString64
Type alias name for TLocalString<nchar,64> .
characters::wchar wchar
Type alias in namespace alib.
characters::xchar xchar
Type alias in namespace alib.
characters::nchar nchar
Type alias in namespace alib.
lang::integer integer
Type alias in namespace alib.
static void Fill(TChar *dest, integer length, TChar value)
static void Copy(const TChar *src, integer length, TChar *dest)
static void Move(const TChar *src, integer length, TChar *dest)