ALib C++ Library
Library Version: 2412 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
tastring_ca_impl.inl
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// #################################################################################################
7#if !DOXYGEN
8
9#if !defined(HPP_ALIB_STRINGS_TASTRING_INLINING)
10# error "ALib sources with ending '.inl' must not be included from outside."
11#endif
12
13// #################################################################################################
14// #################################################################################################
15// This inlined compilation unit is to be included by compilation that specialize template
16// type "strings::TAString" in respect to its two template parameters TChar and TAllocator.
17// For this, before inclusion two preprocessor symbols have to be specified:
18// - ASTR_TCHAR_SPEC The character type
19// - ASTR_TALLOC_SPEC The allocator type
20// At the end of this header, both symbols will be set undefined, to allow a next invocation
21// with new symbols (and to enforce the right usage).
22//
23// With "tastring_ca_decl.inl", the corresponding declarations are to be made.
24// #################################################################################################
25// #################################################################################################
26
27#if !defined(ASTR_TCHAR_SPEC)
28# error "Preprocessor symbol ASTR_TCHAR_SPEC has to be given as ALIB_CHAR_TYPE_ID_XYZ before invoking this .INL"
29#endif
30#if !defined(ASTR_TALLOC_SPEC)
31# error "Preprocessor symbol ASTR_TCHAR_SPEC has to be given as ALIB_CHAR_TYPE_ID_XYZ before invoking this .INL"
32#endif
33
34
35#if ASTR_TCHAR_SPEC == ALIB_CHAR_TYPE_ID_N
36# define TCHARNAME nchar
37#elif ASTR_TCHAR_SPEC == ALIB_CHAR_TYPE_ID_W
38# define TCHARNAME wchar
39#elif ASTR_TCHAR_SPEC == ALIB_CHAR_TYPE_ID_X
40# define TCHARNAME xchar
41#else
42# error
43#endif
44
45
46
47namespace alib::strings {
48#if ALIB_DEBUG_STRINGS
50#endif
55template integer TAString<TCHARNAME, ASTR_TALLOC_SPEC>::SearchAndReplace (const TString<TCHARNAME>&,const TString<TCHARNAME>&,integer,integer,lang::Case,integer );
56template TAString<TCHARNAME, ASTR_TALLOC_SPEC>& TAString<TCHARNAME, ASTR_TALLOC_SPEC>::Trim (const TCString<TCHARNAME>& );
57template integer TAString<TCHARNAME, ASTR_TALLOC_SPEC>::TrimAt (integer,const TCString<TCHARNAME>& );
58
59
60#if ALIB_DEBUG
61template void T_Append<std::type_info , TCHARNAME, ASTR_TALLOC_SPEC>::operator()( TAString<TCHARNAME, ASTR_TALLOC_SPEC>&, const std::type_info& );
62#endif
63#if ALIB_EXT_LIB_THREADS_AVAILABLE
64template void T_Append<std::thread::id , TCHARNAME, ASTR_TALLOC_SPEC>::operator()( TAString<TCHARNAME, ASTR_TALLOC_SPEC>&, const std::thread::id& );
65#endif
66template void T_Append<lang::CallerInfo , TCHARNAME, ASTR_TALLOC_SPEC>::operator()( TAString<TCHARNAME, ASTR_TALLOC_SPEC>&, const lang::CallerInfo& );
67
68
69template void T_Append<bool , TCHARNAME, ASTR_TALLOC_SPEC>::operator()( TAString<TCHARNAME, ASTR_TALLOC_SPEC>&, bool );
70template void T_Append< int64_t , TCHARNAME, ASTR_TALLOC_SPEC>::operator()( TAString<TCHARNAME, ASTR_TALLOC_SPEC>&, int64_t );
71template void T_Append< uint64_t , TCHARNAME, ASTR_TALLOC_SPEC>::operator()( TAString<TCHARNAME, ASTR_TALLOC_SPEC>&, uint64_t );
72template void T_Append<float , TCHARNAME, ASTR_TALLOC_SPEC>::operator()( TAString<TCHARNAME, ASTR_TALLOC_SPEC>&, float );
73template void T_Append<double , TCHARNAME, ASTR_TALLOC_SPEC>::operator()( TAString<TCHARNAME, ASTR_TALLOC_SPEC>&, double );
74template void T_Append<TFormat<TCHARNAME> , TCHARNAME, ASTR_TALLOC_SPEC>::operator()( TAString<TCHARNAME, ASTR_TALLOC_SPEC>&, const TFormat<TCHARNAME>& );
75template void T_Append<TFormat<TCHARNAME>::Tab , TCHARNAME, ASTR_TALLOC_SPEC>::operator()( TAString<TCHARNAME, ASTR_TALLOC_SPEC>&, const TFormat<TCHARNAME>::Tab& );
76template void T_Append<TFormat<TCHARNAME>::Field , TCHARNAME, ASTR_TALLOC_SPEC>::operator()( TAString<TCHARNAME, ASTR_TALLOC_SPEC>&, const TFormat<TCHARNAME>::Field& );
77template void T_Append<TFormat<TCHARNAME>::Escape, TCHARNAME, ASTR_TALLOC_SPEC>::operator()( TAString<TCHARNAME, ASTR_TALLOC_SPEC>&, const TFormat<TCHARNAME>::Escape& );
78template void T_Append<TFormat<TCHARNAME>::Bin , TCHARNAME, ASTR_TALLOC_SPEC>::operator()( TAString<TCHARNAME, ASTR_TALLOC_SPEC>&, const TFormat<TCHARNAME>::Bin& );
79template void T_Append<TFormat<TCHARNAME>::Hex , TCHARNAME, ASTR_TALLOC_SPEC>::operator()( TAString<TCHARNAME, ASTR_TALLOC_SPEC>&, const TFormat<TCHARNAME>::Hex& );
80template void T_Append<TFormat<TCHARNAME>::Oct , TCHARNAME, ASTR_TALLOC_SPEC>::operator()( TAString<TCHARNAME, ASTR_TALLOC_SPEC>&, const TFormat<TCHARNAME>::Oct& );
81template void T_Append<TFormat<TCHARNAME>::Fill , TCHARNAME, ASTR_TALLOC_SPEC>::operator()( TAString<TCHARNAME, ASTR_TALLOC_SPEC>&, const TFormat<TCHARNAME>::Fill& );
82
83
84
85
86// #################################################################################################
87// #################################################################################################
88// Append methods of incompatible character width.
89// #################################################################################################
90// #################################################################################################
91
92// #################################################################################################
93// TCheck==CHK Versions
94// Checks the src parameter. Then, if src not nullptr but empty, this string is
95// ensured to be not nulled, which means a buffer is allocated if non was before.
96// Finally invokes the TCheck==NC version.
97// #################################################################################################
98#define CHECKING_VERSION_IMPLEMENTATION_OF_APPEND(TChar,TAllocator,TCharParam) \
99 template<> template<> \
100 ALIB_API \
101 TAString<TChar,TAllocator>& TAString<TChar,TAllocator>::Append<CHK> ( const TCharParam* src, integer srcLength ) \
102 { \
103 if( !src ) return *this; \
104 if ( srcLength <= 0 ) \
105 { \
106 if ( base::IsNull() ) \
107 SetBuffer( 15 ); \
108 return *this; \
109 } \
110 return Append<NC>( src, srcLength ); \
111 } \
112
113
114// We have to know what the "real" types are.
115#if ALIB_CHARACTERS_NATIVE_WCHAR
116# define REAL_WCHAR wchar
117# define REAL_XCHAR xchar
118#else
119# define REAL_WCHAR xchar
120# define REAL_XCHAR wchar
121#endif
122
125
126// #################################################################################################
127// <wchar_t>
128// #################################################################################################
129#if ( (ASTR_TCHAR_SPEC == ALIB_CHAR_TYPE_ID_W) && ALIB_CHARACTERS_NATIVE_WCHAR ) || ( (ASTR_TCHAR_SPEC == ALIB_CHAR_TYPE_ID_X) && !ALIB_CHARACTERS_NATIVE_WCHAR )
130template<> template<>
132TAString<wchar_t, ASTR_TALLOC_SPEC>& TAString<wchar_t, ASTR_TALLOC_SPEC>::Append<NC>( const char* src, integer srcLength )
133{
134 ALIB_STRING_DBG_CHK( this )
135
136 // copy loop
137 EnsureRemainingCapacity( srcLength );
138
139 //--------- Windows Version ----------
140 #if defined( _WIN32 )
141 if( srcLength == 0)
142 return *this;
143 integer conversionSize= MultiByteToWideChar( CP_UTF8, 9,
144 src, static_cast<int>( srcLength ),
145 vbuffer + length, static_cast<int>( Capacity() - length ) );
146 // check for errors
147 #if ALIB_DEBUG
148 if ( conversionSize == 0 )
149 {
150 // not enough space?
151 int error= GetLastError();
152
154 "MBCS to WCS conversion failed (Error: ",
155 ( error == ERROR_INSUFFICIENT_BUFFER ? "ERROR_INSUFFICIENT_BUFFER."
156 : error == ERROR_INVALID_FLAGS ? "ERROR_INVALID_FLAGS."
157 : error == ERROR_INVALID_PARAMETER ? "ERROR_INVALID_PARAMETER"
158 : error == ERROR_NO_UNICODE_TRANSLATION ? "ERROR_NO_UNICODE_TRANSLATION"
159 : NString64( error ).Terminate() ),
160 ")" )
161 }
162
163 ALIB_ASSERT_ERROR( conversionSize <= srcLength, "STRINGS",
164 NString128( "MBCS to WCS conversion failed. Requested length=" )._( srcLength )
165 ._( ", conversion length=" )._(conversionSize)
166 )
167 #endif
168
169 length+= conversionSize;
170 return *this;
171
172
173 //--------- __GLIBCXX__ Version ---------
174 #elif defined (__GLIBCXX__) || defined(__APPLE__) || defined(__ANDROID_NDK__)
175
176 while(srcLength > 0 )
177 {
178 integer actConversionLenght= srcLength;
179 for( int pass= 0 ; pass < 2 ; ++pass )
180 {
181
182 mbstate_t ps; memset( &ps, 0, sizeof(mbstate_t) );
183 const nchar* srcp= src;
184 size_t wcWritten= mbsnrtowcs( vbuffer + length, &srcp,
185 size_t(actConversionLenght),
186 size_t(Capacity() - length), &ps );
187
188 // single character failed?
189 if( wcWritten == static_cast<size_t >(-1) )
190 {
191 // already repeated?
192 // This can't (must not) happen! If it did, release code does infinite loop!
193 ALIB_ASSERT( pass == 0 )
194
195 // first character that failed?
196 if( srcp == src )
197 {
198 ++src;
199 --srcLength;
200 *(vbuffer + length++)= '?';
201 break; // break try loop, continue with next character
202 }
203
204 // retry those characters that succeeded
205 actConversionLenght= srcp - src;
206 continue;
207 }
208
209 length+= wcWritten;
210 src+= wcWritten;
211 srcLength-= actConversionLenght;
212 break;
213 }
214 }
215 return *this;
216
217 #else
218 #pragma message ("Unknown Platform in file: " __FILE__ )
219 return *this;
220 #endif
221}
222CHECKING_VERSION_IMPLEMENTATION_OF_APPEND(wchar_t, ASTR_TALLOC_SPEC, char )
223
224
225#if ALIB_SIZEOF_WCHAR_T == 4
226
227 template<>
228 template<>
230 TAString<wchar_t, ASTR_TALLOC_SPEC>& TAString<wchar_t, ASTR_TALLOC_SPEC>::Append<NC>( const char16_t* src, integer srcLength )
231 {
232 EnsureRemainingCapacity( srcLength );
233
234 // convert UTF16 to UTF32
235 const char16_t* srcEnd= src + srcLength;
236 while (src < srcEnd)
237 {
238 const char32_t uc = *src++;
239 if ((uc - 0xd800) >= 2048) // not surrogate
240 {
241 vbuffer[length++] = static_cast<wchar_t>(uc);
242 }
243 else
244 {
245 ALIB_ASSERT_ERROR( src < srcEnd // has one more?
246 && ((uc & 0xfffffc00) == 0xd800) // is low
247 && ((*src & 0xfffffc00) == 0xdc00), // is high
248 "STRINGS", "Error decoding UTF16" )
249
250 vbuffer[length++]= static_cast<wchar_t>( (uc << 10)
251 + ((*src++) - 0x35fdc00 ) );
252 }
253 }
254
255 return *this;
256 }
257
258 CHECKING_VERSION_IMPLEMENTATION_OF_APPEND(wchar_t, ASTR_TALLOC_SPEC, char16_t )
259#else
260
261 template<>
262 template<>
264 TAString<wchar_t, ASTR_TALLOC_SPEC>& TAString<wchar_t, ASTR_TALLOC_SPEC>::Append<NC>( const char32_t* src, integer srcLength )
265 {
266 // convert UTF32 to UTF16
267 EnsureRemainingCapacity( srcLength * 2 );
268
269 const char32_t* srcEnd= src + srcLength;
270 while (src < srcEnd)
271 {
272 uinteger uc= *src++;
273 ALIB_ASSERT_ERROR( uc < 0xd800
274 || ( uc >= 0xe000 && uc <= 0x10ffff ),
275 "STRINGS", "Illegal unicode 32 bit codepoint" )
276
277 if( uc < 0x10000 )
278 {
279 vbuffer[length++]= static_cast<wchar_t>( uc );
280 }
281 else
282 {
283 uc-= 0x10000;
284 vbuffer[length++]= static_cast<wchar_t>( ( uc >> 10 ) + 0xd800 );
285 vbuffer[length++]= static_cast<wchar_t>( ( uc & 0x3ff ) + 0xdc00 );
286 }
287 }
288
289 return *this;
290 }
291
292 CHECKING_VERSION_IMPLEMENTATION_OF_APPEND(wchar_t, ASTR_TALLOC_SPEC, char32_t )
293#endif
294
295
296#endif // #if ASTR_TCHAR_SPEC == ALIB_CHAR_TYPE_ID_W
297
298
299// #################################################################################################
300// <XCHARXX_T> (char16_t or char32_t)
301// #################################################################################################
302#if ASTR_TCHAR_SPEC == ALIB_CHAR_TYPE_ID_X
303
304#if ALIB_SIZEOF_WCHAR_T == 2
305
306 template<> template<>
308 TAString<REAL_XCHAR, ASTR_TALLOC_SPEC>& TAString<REAL_XCHAR, ASTR_TALLOC_SPEC>::Append<NC>( const wchar_t* src, integer srcLength )
309 {
310 EnsureRemainingCapacity( srcLength );
311
312 // convert UTF16 to UTF32
313 const wchar_t* srcEnd= src + srcLength;
314 while (src < srcEnd)
315 {
316 const char32_t uc = *src++;
317 if ((uc - 0xd800) >= 2048) // not surrogate
318 {
319 vbuffer[length++] = static_cast<REAL_XCHAR>(uc);
320 }
321 else
322 {
323 ALIB_ASSERT_ERROR( src < srcEnd // has one more?
324 && ((uc & 0xfffffc00) == 0xd800) // is low
325 && ((*src & 0xfffffc00) == 0xdc00), // is high
326 "STRINGS", "Error decoding UTF16" )
327
328 vbuffer[length++]= static_cast<REAL_XCHAR>( (uc << 10)
329 + ((*src++) - 0x35fdc00 ) );
330 }
331 }
332
333 return *this;
334 }
335
336#else
337
338 template<> template<>
340 TAString<REAL_XCHAR, ASTR_TALLOC_SPEC>& TAString<REAL_XCHAR, ASTR_TALLOC_SPEC>::Append<NC>( const wchar_t* src, integer srcLength )
341 {
342 // convert UTF32 to UTF16
343 EnsureRemainingCapacity( srcLength * 2 ); // can potentially double!
344
345 const wchar_t* srcEnd= src + srcLength;
346 while (src < srcEnd)
347 {
348 uinteger uc= static_cast<uinteger>( *src++ );
349 ALIB_ASSERT_ERROR( uc < 0xd800
350 || ( uc >= 0xe000 && uc <= 0x10ffff ),
351 "STRINGS", "Illegal unicode 32 bit codepoint" )
352
353 if( uc < 0x10000 )
354 {
355 vbuffer[length++]= static_cast<REAL_XCHAR>( uc );
356 }
357 else
358 {
359 uc-= 0x10000;
360 vbuffer[length++]= static_cast<REAL_XCHAR>( ( uc >> 10 ) + 0xd800 );
361 vbuffer[length++]= static_cast<REAL_XCHAR>( ( uc & 0x3ff ) + 0xdc00 );
362 }
363 }
364
365 return *this;
366 }
367#endif
368
369template<> template<>
371TAString<REAL_XCHAR, ASTR_TALLOC_SPEC>& TAString<REAL_XCHAR, ASTR_TALLOC_SPEC>::Append<NC>( const char* src, integer srcLength )
372{
373 ALIB_STRING_DBG_CHK( this )
374
375 // We are using a WAString to do the job. Not efficient, but for today, this should be all we do!
376 TLocalString<REAL_WCHAR,8192> converter;
377 converter.Append<NC>( src, srcLength );
378 return Append<NC>( converter.Buffer(), converter.Length() );
379}
380
381CHECKING_VERSION_IMPLEMENTATION_OF_APPEND(REAL_XCHAR , ASTR_TALLOC_SPEC, char )
382CHECKING_VERSION_IMPLEMENTATION_OF_APPEND(REAL_XCHAR , ASTR_TALLOC_SPEC, wchar_t )
383
384#endif //#if ASTR_TCHAR_SPEC == ALIB_CHAR_TYPE_ID_X
385
386// #################################################################################################
387// <nchar>
388// #################################################################################################
389#if ASTR_TCHAR_SPEC == ALIB_CHAR_TYPE_ID_N
390
391template<> template<>
393TAString<char, ASTR_TALLOC_SPEC>& TAString<char, ASTR_TALLOC_SPEC>::Append<NC>( const REAL_WCHAR* src, integer srcLength )
394{
395 ALIB_STRING_DBG_CHK( this )
396 ALIB_ASSERT_ERROR( src, "STRINGS", "nullptr appended to string" )
397 if( srcLength == 0 )
398 return *this;
399
400 //--------- Windows Version ---------
401 #if defined( _WIN32 )
402
403 // loop until reserved size is big enough
404 EnsureRemainingCapacity( srcLength * 2 );
405 for(;;)
406 {
407 int conversionSize= WideCharToMultiByte( CP_UTF8, 0,
408 src, static_cast<int>( srcLength),
409 TString<nchar>::vbuffer + TString<nchar>::length, static_cast<int>( Capacity() - TString<nchar>::length ),
410 NULL, NULL );
411 if ( conversionSize > 0 )
412 {
413 TString<nchar>::length+= conversionSize;
414 return *this;
415 }
416
417 // not enough space?
418 int error= GetLastError();
419 if (error == ERROR_INSUFFICIENT_BUFFER )
420 {
421 EnsureRemainingCapacity( srcLength );
422 continue;
423 }
424
425 // quit on other errors
427 "AString: Cannot convert wide character string to UTF-8. Error: ",
428 ( error == ERROR_INVALID_FLAGS ? "ERROR_INVALID_FLAGS."
429 : error == ERROR_INVALID_PARAMETER ? "ERROR_INVALID_PARAMETER"
430 : error == ERROR_NO_UNICODE_TRANSLATION ? "ERROR_NO_UNICODE_TRANSLATION"
431 : NString64(error).Terminate() )
432 )
433
434 return *this;
435 }
436
437 //--------- __GLIBCXX__ Version ---------
438 #elif defined (__GLIBCXX__) || defined(__APPLE__) || defined(__ANDROID_NDK__)
439
440 integer maxConversionSize= integer(MB_CUR_MAX) * srcLength;
441
442 mbstate_t ps;
443 EnsureRemainingCapacity( maxConversionSize );
444 memset( &ps, 0, sizeof(mbstate_t) );
445 const wchar_t* srcp= src;
446 size_t conversionSize= wcsnrtombs( TString<nchar>::vbuffer + TString<nchar>::length, &srcp, size_t(srcLength), size_t(maxConversionSize), &ps);
447 if ( conversionSize == size_t( -1 ) )
448 {
449 ALIB_WARNING( "STRINGS", "Cannot convert WCS to MBCS. Check locale settings (should be UTF-8)" )
450 return *this;
451 }
452
453 if ( conversionSize < 1 )
454 {
455 ALIB_ERROR( "STRINGS", "Error converting WCS to MBCS." )
456 return *this;
457 }
458
459 TString<nchar>::length+= conversionSize;
460 return *this;
461
462 #else
463 #pragma message ("Unknown Platform in file: " __FILE__ )
464 return *this;
465 #endif
466}
467
468template<>
469template<>
471TAString<char, ASTR_TALLOC_SPEC>& TAString<nchar, ASTR_TALLOC_SPEC>::Append<NC>( const REAL_XCHAR* src, integer srcLength )
472{
473 // convert to wchar_t and invoke wchar_t version
474 TLocalString<wchar_t,2048> converter;
476 converter.Append<NC>( src, srcLength );
477 Append<NC>( converter.Buffer(), converter.Length() );
478
479 return *this;
480}
481
482CHECKING_VERSION_IMPLEMENTATION_OF_APPEND(char , ASTR_TALLOC_SPEC, wchar )
483CHECKING_VERSION_IMPLEMENTATION_OF_APPEND(char , ASTR_TALLOC_SPEC, xchar )
484
485#endif // #if ASTR_TCHAR_SPEC == ALIB_CHAR_TYPE_ID_N
486
487
488} // namespace [alib::strings]
489
490
493#undef CHECKING_VERSION_IMPLEMENTATION_OF_APPEND
494#undef REAL_WCHAR
495#undef REAL_XCHAR
496#undef TCHARNAME
497#undef ASTR_TALLOC_SPEC
498#undef ASTR_TCHAR_SPEC
499
500#endif //if !DOXYGEN
501
ALIB_API integer SearchAndReplace(TChar needle, TChar replacement, integer startIdx=0, integer endIdx=strings::MAX_LEN)
ALIB_API void GrowBufferAtLeastBy(integer minimumGrowth)
TAString & Append(const TCharSrc *src, integer srcLength)
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 DbgDisableBufferReplacementWarning()
Definition tastring.inl:363
ALIB_API void SetBuffer(integer newCapacity)
#define ALIB_WARNING(...)
Definition alib.hpp:1268
#define ALIB_WARNINGS_RESTORE
Definition alib.hpp:849
#define ALIB_API
Definition alib.hpp:639
#define ALIB_WARNINGS_IGNORE_SIGN_CONVERSION
Definition alib.hpp:844
#define ALIB_ERROR(...)
Definition alib.hpp:1267
#define ALIB_ASSERT_ERROR(cond,...)
Definition alib.hpp:1271
#define ALIB_WARNINGS_ALLOW_UNSAFE_BUFFER_USAGE
Definition alib.hpp:760
#define ALIB_STRING_DBG_CHK(instance)
#define ALIB_ASSERT(cond)
Definition alib.hpp:1270
Case
Denotes upper and lower case character treatment.
NLocalString< 128 > NString128
Type alias name for TLocalString<nchar,128>.
lang::uinteger uinteger
Type alias in namespace alib.
Definition integers.hpp:276
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:273
void operator()(TAString< TChar > &target, const TAppendable &src)