ALib C++ Library
Library Version: 2402 R1
Documentation generated by doxygen
Loading...
Searching...
No Matches
astring.cpp
1// #################################################################################################
2// ALib C++ Library
3//
4// Copyright 2013-2024 A-Worx GmbH, Germany
5// Published under 'Boost Software License' (a free software license, see LICENSE.txt)
6// #################################################################################################
8
9#if !defined(ALIB_DOX)
10# if !defined (HPP_ALIB_STRINGS_ASTRING)
12# endif
13
14# if !defined (HPP_ALIB_STRINGS_LOCALSTRING)
16# endif
17
18# if !defined (HPP_ALIB_STRINGS_CSTRING)
20# endif
21#endif // !defined(ALIB_DOX)
22
23#if !defined (_GLIBCXX_ALGORITHM) && !defined(_ALGORITHM_)
24# include <algorithm>
25#endif
26
27namespace alib { namespace strings {
28// ####################################################################################################
29// AString::_dbgCheck()
30// ####################################################################################################
31//! @cond NO_DOX
32#if ALIB_DEBUG_STRINGS
33
34template<typename TChar>
36{
37 TString<TChar>::dbgCheck();
38
39 integer cap= Capacity();
40
41 ALIB_ASSERT_ERROR( debugLastAllocRequest == 0
42 || TString<TChar>::length <= debugLastAllocRequest, "STRINGS",
43 "Error: Previous allocation request was too short" )
44
45 ALIB_ASSERT_ERROR( TString<TChar>::length <= cap, "STRINGS",
46 "Error: Length greater than allocation size" )
47
48 if( TString<TChar>::buffer && HasInternalBuffer() )
49 {
50 for (integer i= -16 ; i < 0 ; ++i)
51 if ( TString<TChar>::buffer[i] != 2 )
52 {
53 ALIB_ERROR( "STRINGS", "Magic byte not found at start of buffer." )
54 break;
55 }
56 for (integer i= 1 ; i <= 16 ; ++i)
57 if ( TString<TChar>::buffer[ cap + i] != 3 )
58 {
59 ALIB_ERROR( "STRINGS", "Magic byte not found at end of buffer." )
60 break;
61 }
62 }
63}
64
65#endif
66//! @endcond
67
68
69// ####################################################################################################
70// Allocation
71// ####################################################################################################
72
73template<typename TChar>
75{
76 integer actCapacity= Capacity();
77
78 ALIB_ASSERT_WARNING ( TString<TChar>::length + minimumGrowth > actCapacity,
79 "STRINGS", "Unnecessary invocation of Grow()" )
80
81 // first allocation? Go with given growth as size
82 if (actCapacity == 0 )
83 {
84 SetBuffer( minimumGrowth > 16 ? minimumGrowth : 16 );
85 #if ALIB_DEBUG_STRINGS
86 debugLastAllocRequest= minimumGrowth;
87 #endif
88
89 return;
90 }
91
92 // calc new size: in general grow by 50%
93 integer newCapacity= actCapacity + (actCapacity / 2);
94 if ( newCapacity < TString<TChar>::length + minimumGrowth )
95 newCapacity+= minimumGrowth;
96
97 if ( newCapacity < 16 )
98 newCapacity= 16;
99
100 SetBuffer( newCapacity );
101 #if ALIB_DEBUG_STRINGS
102 debugLastAllocRequest= actCapacity + minimumGrowth;
103 #endif
104}
105
106template<typename TChar>
108{
110
111 ALIB_ASSERT( newCapacity >= 0 )
112
113 // do nothing if life-cycle is managed by us and same size,
114 if ( capacity >= 0 && capacity == newCapacity )
115 return;
116
117 #if ALIB_DEBUG_STRINGS
118 debugLastAllocRequest= newCapacity;
119 #endif
120
121 // set uninitialized (and return)
122 if ( newCapacity == 0 )
123 {
124 ALIB_ASSERT_WARNING( !dbgWarnWhenExternalBufferIsReplaced || capacity >= 0, "STRINGS",
125 "AString::SetBuffer(): removing an external buffer (setting string nulled). "
126 "This may not be wanted." )
127
128 if ( capacity > 0 )
129 std::free( const_cast<void*>(reinterpret_cast<const void*>( TString<TChar>::buffer
131 - 16
132 #endif
133 )) );
134
135 capacity=
137 TString<TChar>::buffer= nullptr;
138 return;
139 }
140
141 #if ALIB_DEBUG
142 if( dbgWarnWhenExternalBufferIsReplaced && capacity < 0)
143 ALIB_WARNING( "STRINGS",
144 "AString::SetBuffer(): replacing an external buffer by an internally managed one. "
145 "This may not be wanted: ", reinterpret_cast<const char*>(Terminate()) )
146 #endif
147
148 // extend or shrink an existing buffer (and return)
149 if( capacity > 0 )
150 {
151 #if !ALIB_DEBUG_STRINGS
152 TString<TChar>::buffer= static_cast<TChar*>( std::realloc( TString<TChar>::vbuffer,
153 static_cast<size_t>(newCapacity + 1)
154 * sizeof( TChar ) ) );
155 #if ALIB_AVOID_ANALYZER_WARNINGS
157 if( newCapacity > capacity )
159 newCapacity + 1 - TString<TChar>::length
160 ,'\0' );
162 #endif
163 #else
164 // add 16 characters of padding at start/end
165 TString<TChar>::buffer= static_cast<TChar*>( std::realloc( TString<TChar>::vbuffer - 16,
166 static_cast<size_t>( newCapacity + 1 + 33 )
167 * sizeof( TChar ) ) ) + 16;
168
169 // write '\3' to end ('\0'= termination byte, '\1'= untermination byte )
170 characters::CharArray<TChar>::Fill( TString<TChar>::vbuffer + newCapacity + 1, 16, '\3' );
171 #endif
172
173 capacity= newCapacity;
174 if ( TString<TChar>::length > capacity )
175 TString<TChar>::length= capacity;
176
177 return;
178 }
179
180 // create new Buffer
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
185 characters::CharArray<TChar>::Fill( newBuffer, newCapacity + 1, '\0' );
186 #endif
187 #else
188 // add 16 characters of padding at start/end
189 TChar* newBuffer= static_cast<TChar*>( std::malloc(static_cast<size_t>( newCapacity + 1 + 32 )
190 * sizeof( TChar ) ) ) + 16;
191
192 // write '\2' to start, '\3' to end ('\0'= termination byte, '\1'= untermination byte )
193 characters::CharArray<TChar>::Fill( newBuffer - 16 , 16 , '\2');
194 characters::CharArray<TChar>::Fill( newBuffer + newCapacity + 1, 16 , '\3');
195 #endif
196
197 // if we had a buffer before
198 if ( capacity != 0 )
199 {
200 // copy data and delete old buffer
202 newBuffer );
203 if ( capacity > 0 )
204 std::free( const_cast<void*>(reinterpret_cast<const void*>( TString<TChar>::buffer
206 - 16
207 #endif
208 )) );
209
210 }
211 else
212 {
214 }
215
216 // set new Buffer and adjust length
217 TString<TChar>::buffer= newBuffer;
218 capacity= newCapacity;
219 if ( TString<TChar>::length > capacity )
220 TString<TChar>::length= capacity;
221}
222
223
224template<typename TChar>
225void TAString<TChar>::SetBuffer( TChar* extBuffer, integer extBufferSize, integer extLength,
226 lang::Responsibility responsibility )
227{
228 ALIB_ASSERT_ERROR( !(extBufferSize == 0 && extBuffer != nullptr)
229 && !(extBufferSize != 0 && extBuffer == nullptr) , "STRINGS",
230 "AString::SetBuffer(): Given buffer is nullptr while given alloc size is not 0 (or vice versa)" )
231
232 // delete any existing
233 if ( capacity > 0 )
234 std::free( const_cast<void*>(reinterpret_cast<const void*>( TString<TChar>::buffer
236 - 16
237 #endif
238 )) );
239
240 // too small? treat as if a nullptr was given.
241 if ( extBufferSize < 1 )
242 {
243 ALIB_ERROR( "STRINGS", "allocation size < 1" )
244 extBuffer= nullptr;
245 }
246
247 // null buffer?
248 if ( (TString<TChar>::buffer= extBuffer) == nullptr )
249 {
250 #if ALIB_DEBUG_STRINGS
251 debugLastAllocRequest=
252 #endif
253 capacity=
255 return;
256 }
257
258
259 if ( extLength >= extBufferSize )
260 {
261 ALIB_ERROR( "STRINGS", "ext length >= ext allocation size" )
262 extLength= extBufferSize -1;
263 }
264
265
266 // save given buffer
267 --extBufferSize; // we count one less
268 capacity= responsibility==lang::Responsibility::Transfer ? extBufferSize
269 : -extBufferSize;
270 #if ALIB_DEBUG_STRINGS
271 debugLastAllocRequest= extBufferSize;
272 #endif
273 TString<TChar>::length= extLength;
274}
275
276
277
278// #############################################################################################
279// Trim
280// #############################################################################################
281
282template<typename TChar>
284{
285 if ( idx < 0 )
286 return 0;
287 if ( idx >= TString<TChar>::length )
289
290 integer regionStart= TString<TChar>::template LastIndexOfAny<lang::Inclusion::Exclude, false>( trimChars, idx ) + 1;
291 if (regionStart < 0 )
292 regionStart= 0;
293
294 integer regionEnd= TCString<TChar>(this).template IndexOfAny <lang::Inclusion::Exclude, false>( trimChars, idx );
295 if (regionEnd < 0 )
296 regionEnd= TString<TChar>::length;
297
298 integer regionLength= regionEnd - regionStart;
299 if ( regionLength > 0 )
300 Delete<false>( regionStart, regionLength );
301
302 return regionStart;
303}
304
305template<typename TChar>
307{
308 // check
309 if (TString<TChar>::length == 0 || trimChars.IsEmpty() )
310 return *this;
311
312 // trim end
313 integer idx= TString<TChar>::template LastIndexOfAny<lang::Inclusion::Exclude, false>( trimChars, TString<TChar>::length - 1 ) + 1;
314 if ( (TString<TChar>::length= idx) > 0 )
315 {
316 // trim front
317 idx= TCString<TChar>(this).template IndexOfAny<lang::Inclusion::Exclude,false>( trimChars );
318 if ( idx > 0 )
319 Delete<false>( 0, idx );
320 }
321
322 return *this;
323}
324
325
326// #################################################################################################
327// Replace()
328// #################################################################################################
329template<typename TChar>
331 TChar replacement,
332 integer startIdx )
333{
336 if ( startIdx < 0 ) startIdx= 0;
337 else if ( startIdx >= TString<TChar>::length ) return 0;
338
339 // replacement loop
340 TCString<TChar> thisAsCString= this;
341 integer cntReplacements= 0;
342 do
343 {
344 startIdx= thisAsCString.template IndexOfOrLength<false>( needle, startIdx );
345 if ( startIdx == TString<TChar>::length )
346 break;
347 TString<TChar>::vbuffer[ startIdx ]= replacement;
348 ++cntReplacements;
349 }
350 while( ++startIdx < TString<TChar>::length ) ;
351 return cntReplacements;
353}
354
355
356template<typename TChar>
358 const TString<TChar>& replacement,
359 integer startIdx,
360 integer maxReplacements,
361 lang::Case sensitivity )
362{
364
365 // check null arguments
366 if ( needle.IsEmpty() )
367 return 0;
368
369 integer nLen= needle.Length();
370 integer rLen= replacement.Length();
371 integer lenDiff= rLen - nLen;
372
373 // replacement loop
374 integer cntReplacements= 0;
375 while ( cntReplacements < maxReplacements && startIdx < TString<TChar>::length)
376 {
378 // search next occurrence
379 integer idx= sensitivity == lang::Case::Sensitive
380 ? TString<TChar>(*this).template IndexOf<false, lang::Case::Sensitive>( needle, startIdx )
381 : TString<TChar>(*this).template IndexOf<false, lang::Case::Ignore >( needle, startIdx );
382 if ( idx < 0 )
383 break;
384
385 // copy rest up or down
386 if ( lenDiff != 0 )
387 {
388 if ( lenDiff > 0 )
389 EnsureRemainingCapacity( lenDiff );
391 TString<TChar>::length - idx - nLen,
392 TString<TChar>::vbuffer + idx + nLen + lenDiff );
393 TString<TChar>::length+= lenDiff;
394 }
395
396 // fill replacement in
397 if( rLen > 0 )
399
400 // set start index to first character behind current replacement
401 startIdx= idx + rLen;
402
403 // next
404 ++cntReplacements;
406 }
407
408 // that's it
409 return cntReplacements;
410}
411
412
413#if !defined(ALIB_DOX)
414
415#if ALIB_DEBUG_STRINGS
416template void TAString<nchar>::dbgCheck() const;
417template void TAString<wchar>::dbgCheck() const;
418template void TAString<xchar>::dbgCheck() const;
419#endif
420
421// #################################################################################################
422// #################################################################################################
423// Template instantiations
424// #################################################################################################
425// #################################################################################################
426
429template void TAString<nchar>::SetBuffer (integer);
435
437template void TAString<wchar>::SetBuffer (integer);
443
445template void TAString<xchar>::SetBuffer (integer);
452
453
454// #################################################################################################
455// #################################################################################################
456// Append methods
457// #################################################################################################
458// #################################################################################################
459
460// NOTE:
461// The implementations of specialized "Append" methods are using the C++ native character
462// definitions. This way, the code can use external functions more efficient.
463// What we need for this, is the knowledge of the third C++ type used by ALib besides char and
464// wchar_t. It will be one of char16_t and char32_t and is defined below as CHARXX_T.
465// Depending on the compilation settings, this is either equal to wchar or xchar.
466#if ALIB_SIZEOF_WCHAR_T == 2
467# define CHARXX_T char32_t
468#else
469# define CHARXX_T char16_t
470#endif
471
472// #################################################################################################
473// TCheck==true Versions
474// Checks the src parameter. Then, if src not nullptr but empty, then this string is
475// assured to be not nulled, which means a buffer is allocated if non was before.
476// #################################################################################################
477#define CHECKING_VERSION_IMPLEMENTATION_OF_APPEND(TChar,TCharParam) \
478 template<> template<> \
479 TAString<TChar>& TAString<TChar>::Append<true> ( const TCharParam* src, integer srcLength ) \
480 { \
481 if( !src ) \
482 return *this; \
483 \
484 if ( srcLength <= 0 ) \
485 { \
486 if ( TString<TChar>::IsNull() ) \
487 SetBuffer( 15 ); \
488 return *this; \
489 } \
490 \
491 return Append<false>( src, srcLength ); \
492 } \
493
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 )
500
501#undef CHECKING_VERSION_IMPLEMENTATION_OF_APPEND
502
503
504// #################################################################################################
505// <char>
506// #################################################################################################
507template<> template<>
508TAString<char>& TAString<char>::Append<false>( const wchar_t* src, integer srcLength )
509{
511 ALIB_STRING_DBG_CHK( this )
512 ALIB_ASSERT_ERROR( src, "STRINGS", "nullptr appended to string" )
513 if( srcLength == 0 )
514 return *this;
515
516 //--------- Windows Version ---------
517 #if defined( _WIN32 )
518
519 // loop until reserved size is big enough
520 EnsureRemainingCapacity( srcLength * 2 );
521 for(;;)
522 {
523 int conversionSize= WideCharToMultiByte( CP_UTF8, 0,
524 src, static_cast<int>( srcLength),
525 TString<char>::vbuffer + TString<char>::length, static_cast<int>( Capacity() - TString<char>::length ),
526 NULL, NULL );
527 if ( conversionSize > 0 )
528 {
529 TString<char>::length+= conversionSize;
530 return *this;
531 }
532
533 // not enough space?
534 int error= GetLastError();
535 if (error == ERROR_INSUFFICIENT_BUFFER )
536 {
537 EnsureRemainingCapacity( srcLength );
538 continue;
539 }
540
541 // quit on other errors
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"
547 : NString64(error).Terminate() )
548 )
549
550 return *this;
551 }
552
553 //--------- __GLIBCXX__ Version ---------
554 #elif defined (__GLIBCXX__) || defined(__APPLE__) || defined(__ANDROID_NDK__)
555
556 integer maxConversionSize= integer(MB_CUR_MAX) * srcLength;
557
558 mbstate_t ps;
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 ) )
564 {
565 ALIB_WARNING( "STRINGS", "Cannot convert WCS to MBCS. Check locale settings (should be UTF-8)" )
566 return *this;
567 }
568
569 if ( conversionSize < 1 )
570 {
571 ALIB_ERROR( "STRINGS", "Error converting WCS to MBCS." )
572 return *this;
573 }
574
575 TString<char>::length+= conversionSize;
576 return *this;
577
578 #else
579 #pragma message ("Unknown Platform in file: " __FILE__ )
580 return *this;
581 #endif
583}
584
585template<>
586template<>
587TAString<char>& TAString<char>::Append<false>( const CHARXX_T* src, integer srcLength )
588{
589 // convert to wchar_t and invoke wchar_t version
590 TLocalString<wchar_t,2048> converter;
591 converter.DbgDisableBufferReplacementWarning();
592 converter.Append<false>( src, srcLength );
593 Append<false>( converter.Buffer(), converter.Length() );
594
595 return *this;
596}
597
598
600// #################################################################################################
601// <wchar_t>
602// #################################################################################################
603template<> template<>
604TAString<wchar_t>& TAString<wchar_t>::Append<false>( const char* src, integer srcLength )
605{
606 ALIB_STRING_DBG_CHK( this )
607
608 // copy loop
609 EnsureRemainingCapacity( srcLength );
610
611 //--------- Windows Version ----------
612 #if defined( _WIN32 )
613 if( srcLength == 0)
614 return *this;
615 integer conversionSize= MultiByteToWideChar( CP_UTF8, 9,
616 src, static_cast<int>( srcLength ),
617 vbuffer + length, static_cast<int>( Capacity() - length ) );
618 // check for errors
619 #if ALIB_DEBUG
620 if ( conversionSize == 0 )
621 {
622 // not enough space?
623 int error= GetLastError();
624
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"
631 : NString64( error ).Terminate() ),
632 ")" )
633 }
634
635 ALIB_ASSERT_ERROR( conversionSize <= srcLength, "STRINGS",
636 NString128( "MBCS to WCS conversion failed. Requested length=" )._( srcLength )
637 ._( ", conversion length=" )._(conversionSize)
638 )
639 #endif
640
641 length+= conversionSize;
642 return *this;
643
644
645 //--------- __GLIBCXX__ Version ---------
646 #elif defined (__GLIBCXX__) || defined(__APPLE__) || defined(__ANDROID_NDK__)
647
648 while(srcLength > 0 )
649 {
650 integer actConversionLenght= srcLength;
651 for( int pass= 0 ; pass < 2 ; ++pass )
652 {
653
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 );
659
660 // single character failed?
661 if( wcWritten == static_cast<size_t >(-1) )
662 {
663 // already repeated?
664 // This can't (must not) happen! If it did, release code does infinite loop!
665 ALIB_ASSERT( pass == 0 )
666
667 // first character that failed?
668 if( srcp == src )
670 ++src;
671 --srcLength;
672 *(vbuffer + length++)= '?';
673 break; // break try loop, continue with next character
674 }
675
676 // retry those characters that succeeded
677 actConversionLenght= srcp - src;
678 continue;
679 }
680
681 length+= wcWritten;
682 src+= wcWritten;
683 srcLength-= actConversionLenght;
684 break;
685 }
686 }
687 return *this;
688
689 #else
690 #pragma message ("Unknown Platform in file: " __FILE__ )
691 return *this;
692 #endif
693}
694
695
696#if ALIB_SIZEOF_WCHAR_T == 4
697
698 template<>
699 template<>
700 TAString<wchar_t>& TAString<wchar_t>::Append<false>( const CHARXX_T* src, integer srcLength )
702 EnsureRemainingCapacity( srcLength );
703
704 // convert UTF16 to UTF32
705 const CHARXX_T* srcEnd= src + srcLength;
706 while (src < srcEnd)
707 {
708 const char32_t uc = *src++;
709 if ((uc - 0xd800) >= 2048) // not surrogate
710 {
711 vbuffer[length++] = static_cast<wchar_t>(uc);
712 }
713 else
714 {
715 ALIB_ASSERT_ERROR( src < srcEnd // has one more?
716 && ((uc & 0xfffffc00) == 0xd800) // is low
717 && ((*src & 0xfffffc00) == 0xdc00), // is high
718 "STRINGS", "Error decoding UTF16" )
719
720 vbuffer[length++]= static_cast<wchar_t>( (uc << 10)
721 + ((*src++) - 0x35fdc00 ) );
722 }
723 }
724
725 return *this;
726 }
727
728#else
729
730 template<>
731 template<>
732 TAString<wchar_t>& TAString<wchar_t>::Append<false>( const CHARXX_T* src, integer srcLength )
733 {
734 // convert UTF32 to UTF16
735 EnsureRemainingCapacity( srcLength * 2 );
736
737 const CHARXX_T* srcEnd= src + srcLength;
738 while (src < srcEnd)
739 {
740 uinteger uc= *src++;
741 ALIB_ASSERT_ERROR( uc < 0xd800
742 || ( uc >= 0xe000 && uc <= 0x10ffff ),
743 "STRINGS", "Illegal unicode 32 bit codepoint" )
744
745 if( uc < 0x10000 )
746 {
747 vbuffer[length++]= static_cast<wchar_t>( uc );
748 }
749 else
750 {
751 uc-= 0x10000;
752 vbuffer[length++]= static_cast<wchar_t>( ( uc >> 10 ) + 0xd800 );
753 vbuffer[length++]= static_cast<wchar_t>( ( uc & 0x3ff ) + 0xdc00 );
754 }
755 }
756
757 return *this;
758 }
759#endif
760
761// #################################################################################################
762// <XCHARXX_T> (char16_t or char32_t)
763// #################################################################################################
764
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 )
768 {
769 EnsureRemainingCapacity( srcLength );
770
771 // convert UTF16 to UTF32
772 const wchar_t* srcEnd= src + srcLength;
773 while (src < srcEnd)
774 {
775 const char32_t uc = *src++;
776 if ((uc - 0xd800) >= 2048) // not surrogate
777 {
778 vbuffer[length++] = static_cast<CHARXX_T>(uc);
779 }
780 else
781 {
782 ALIB_ASSERT_ERROR( src < srcEnd // has one more?
783 && ((uc & 0xfffffc00) == 0xd800) // is low
784 && ((*src & 0xfffffc00) == 0xdc00), // is high
785 "STRINGS", "Error decoding UTF16" )
786
787 vbuffer[length++]= static_cast<CHARXX_T>( (uc << 10)
788 + ((*src++) - 0x35fdc00 ) );
789 }
790 }
791
792 return *this;
793 }
794
795#else
796
797 template<> template<>
798 TAString<CHARXX_T>& TAString<CHARXX_T>::Append<false>( const wchar_t* src, integer srcLength )
799 {
800 // convert UTF32 to UTF16
801 EnsureRemainingCapacity( srcLength * 2 );
802
803 const wchar_t* srcEnd= src + srcLength;
804 while (src < srcEnd)
805 {
806 uinteger uc= static_cast<uinteger>( *src++ );
807 ALIB_ASSERT_ERROR( uc < 0xd800
808 || ( uc >= 0xe000 && uc <= 0x10ffff ),
809 "STRINGS", "Illegal unicode 32 bit codepoint" )
810
811 if( uc < 0x10000 )
812 {
813 vbuffer[length++]= static_cast<CHARXX_T>( uc );
814 }
815 else
816 {
817 uc-= 0x10000;
818 vbuffer[length++]= static_cast<CHARXX_T>( ( uc >> 10 ) + 0xd800 );
819 vbuffer[length++]= static_cast<CHARXX_T>( ( uc & 0x3ff ) + 0xdc00 );
820 }
821 }
822
823 return *this;
824 }
825#endif
827
828template<> template<>
829TAString<CHARXX_T>& TAString<CHARXX_T>::Append<false>( const char* src, integer srcLength )
830{
831 ALIB_STRING_DBG_CHK( this )
832
833 // We are using a WAString to do the job. Not efficient, but for today, this should be all we do!
834 TLocalString<wchar_t,2048> converter;
835 converter.Append<false>( src, srcLength );
836 return Append<false>( converter.Buffer(), converter.Length() );
837}
838
839
840#undef CHARXX_T
841
842#endif // !defined(ALIB_DOX)
843
844
845
846}} // namespace [alib::strings]
ALIB_API integer TrimAt(integer idx, const TCString< TChar > &trimChars=TT_StringConstants< TChar >::DefaultWhitespaces())
Definition astring.cpp:283
void GrowBufferAtLeastBy(integer minimumGrowth)
Definition astring.cpp:74
ALIB_API TAString & Trim(const TCString< TChar > &trimChars=TT_StringConstants< TChar >::DefaultWhitespaces())
Definition astring.cpp:306
ALIB_API void SetBuffer(integer newCapacity)
Definition astring.cpp:107
ALIB_API integer SearchAndReplace(TChar needle, TChar replacement, integer startIdx=0)
Definition astring.cpp:330
constexpr bool IsEmpty() const
Definition string.hpp:414
const TChar * buffer
Definition string.hpp:129
constexpr integer Length() const
Definition string.hpp:357
constexpr const TChar * Buffer() const
Definition string.hpp:350
#define ALIB_WARNING(...)
Definition alib.hpp:981
#define ALIB_WARNINGS_RESTORE
Definition alib.hpp:715
#define ALIB_ERROR(...)
Definition alib.hpp:980
#define ALIB_ASSERT_ERROR(cond,...)
Definition alib.hpp:984
#define ALIB_WARNINGS_ALLOW_UNSAFE_BUFFER_USAGE
Definition alib.hpp:644
#define ALIB_ASSERT_WARNING(cond,...)
Definition alib.hpp:985
#define ALIB_STRING_DBG_CHK(instance)
#define ALIB_ASSERT(cond)
Definition alib.hpp:983
#define ALIB_DEBUG_STRINGS
Definition prepro.dox:41
@ Transfer
Transfers responsibility to the receiving party.
Definition alib.cpp:57
lang::uinteger uinteger
Type alias in namespace alib.
Definition integers.hpp:289
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.
Definition integers.hpp:286
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)