ALib C++ Library
Library Version: 2412 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
string.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 !DOXYGEN
12# if ALIB_DEBUG
14# endif
15#endif // !DOXYGEN
16
17using namespace alib::characters;
18
19namespace alib {
20
21//==================================================================================================
22/// This is the reference documentation of sub-namespace \c strings of the \aliblink, which
23/// holds types of library module \alib_strings_nl.
24///
25/// Extensive documentation for this module is provided with
26/// \ref alib_mod_strings "ALib Module Strings - Programmer's Manual".
27//==================================================================================================
28namespace strings {
29
30#if !DOXYGEN
31
32
33// #################################################################################################
34// dbgCheck()
35// #################################################################################################
36#if ALIB_DEBUG_STRINGS
37
38namespace {
39 bool astringCheckReported= false;
40}
41
42template<typename TChar>
43void TString<TChar>::dbgCheck() const
44{
45 // write to the console once that we are debugging AString
46 if ( !astringCheckReported )
47 {
48 astringCheckReported= true;
49 ALIB_MESSAGE( "STRINGS", "ALIB_DEBUG_STRINGS is enabled")
50 }
51
52 ALIB_ASSERT_ERROR( length == 0 || buffer != nullptr, "STRINGS",
53 "Nulled string has a length of ", int(length) )
54
56 for (integer i= length -1 ; i >= 0 ; --i)
57 if ( buffer[i] == '\0' )
58 {
59 ALIB_ERROR( "STRINGS", "Found termination character '\\0' in buffer. Index=", int(i) )
60 break;
61 }
63}
64
65#endif
66
67
68// #################################################################################################
69// indexOf...()
70// #################################################################################################
71template<typename TChar>
72template<lang::Case TSensitivity>
73integer TString<TChar>::indexOfString( const TString<TChar>& needle,
74 integer startIdx, integer endIdx ) const
75{
76 integer nLen= needle.Length();
77 if( nLen == 0 )
78 return startIdx;
79 ALIB_ASSERT_ERROR( startIdx >= 0 && startIdx <= length, "STRINGS", "Illegal start index given." )
80 ALIB_ASSERT_ERROR( endIdx <= length -nLen + 1 , "STRINGS", "Illegal end index given." )
82 const TChar* buf= buffer + startIdx;
83 const TChar* bufEnd= buffer + endIdx;
84 const TChar* nBuf= needle.Buffer();
85 const TChar* nBufEnd= nBuf + nLen;
86
87 while ( buf < bufEnd )
88 {
89 const TChar* b= buf;
90 const TChar* n= nBuf;
91 while ( characters::Equal<TChar,TSensitivity>(*b++, *n++ ) )
92 if( n == nBufEnd )
93 return buf - buffer;
94 ++buf;
95 }
96 return -1;
98}
99
100template<typename TChar>
101integer TString<TChar>::IndexOfSegmentEnd( TChar opener, TChar closer, integer idx ) const
102{
103 int openCnt= 1;
104 while( idx < length )
105 {
107 if( buffer[idx] == opener ) ++openCnt;
108 if( buffer[idx] == closer && --openCnt == 0 )
109 break;
110
111 ++idx;
113 }
114
115 return openCnt == 0 ? idx : -openCnt;
116}
117
118// #################################################################################################
119// ParseXXX()
120// #################################################################################################
121template<typename TChar>
122uint64_t TString<TChar>::ParseDecDigits( integer startIdx, integer* newIdx )
123const
124{
125 // we need an index pointer reference. So if none was given in parameter newIdx
126 // then we just use parameter startIdx!
127 integer* indexPointer;
128 if ( newIdx == nullptr )
129 indexPointer= &startIdx;
130 else
131 {
132 indexPointer= newIdx;
133 *indexPointer= startIdx;
134 }
135
136 return detail::ParseDecDigits<TChar>( *this, *indexPointer );
137}
138
139
140template<typename TChar>
141int64_t TString<TChar>::ParseInt( integer startIdx, TNumberFormat<TChar>* numberFormat, integer* newIdx )
142const
143{
144 // we need an index pointer reference. So if none was given in parameter newIdx
145 // then we just use parameter startIdx!
146 integer* indexPointer;
147 if ( newIdx == nullptr )
148 indexPointer= &startIdx;
149 else
150 {
151 indexPointer= newIdx;
152 *indexPointer= startIdx;
153 }
154
155 return detail::ParseInt( *this, *indexPointer, numberFormat == nullptr ? TNumberFormat<TChar>::Computational
156 : *numberFormat );
157}
158
159template<typename TChar>
160uint64_t TString<TChar>::ParseDec( integer startIdx, TNumberFormat<TChar>* numberFormat, integer* newIdx )
161const
162{
163 // we need an index pointer reference. So if none was given in parameter newIdx
164 // then we just use parameter startIdx!
165 integer* indexPointer;
166 if ( newIdx == nullptr )
167 indexPointer= &startIdx;
168 else
169 {
170 indexPointer= newIdx;
171 *indexPointer= startIdx;
172 }
173
174 return detail::ParseDec( *this, *indexPointer, numberFormat == nullptr ? TNumberFormat<TChar>::Computational
175 : *numberFormat );
176}
177
178template<typename TChar>
179uint64_t TString<TChar>::ParseBin( integer startIdx, TNumberFormat<TChar>* numberFormat, integer* newIdx )
180const
181{
182 // we need an index pointer reference. So if none was given in parameter newIdx
183 // then we just use parameter startIdx!
184 integer* indexPointer;
185 if ( newIdx == nullptr )
186 indexPointer= &startIdx;
187 else
188 {
189 indexPointer= newIdx;
190 *indexPointer= startIdx;
191 }
192
193 return detail::ParseBin( *this, *indexPointer, numberFormat == nullptr ? TNumberFormat<TChar>::Computational
194 : *numberFormat );
195}
196
197template<typename TChar>
198uint64_t TString<TChar>::ParseHex( integer startIdx, TNumberFormat<TChar>* numberFormat, integer* newIdx )
199const
200{
201 // we need an index pointer reference. So if none was given in parameter newIdx
202 // then we just use parameter startIdx!
203 integer* indexPointer;
204 if ( newIdx == nullptr )
205 indexPointer= &startIdx;
206 else
207 {
208 indexPointer= newIdx;
209 *indexPointer= startIdx;
210 }
211
212 return detail::ParseHex( *this, *indexPointer, numberFormat == nullptr ? TNumberFormat<TChar>::Computational
213 : *numberFormat );
214}
215
216template<typename TChar>
217uint64_t TString<TChar>::ParseOct( integer startIdx, TNumberFormat<TChar>* numberFormat, integer* newIdx )
218const
219{
220 // we need an index pointer reference. So if none was given in parameter newIdx
221 // then we just use parameter startIdx!
222 integer* indexPointer;
223 if ( newIdx == nullptr )
224 indexPointer= &startIdx;
225 else
226 {
227 indexPointer= newIdx;
228 *indexPointer= startIdx;
229 }
230
231 return detail::ParseOct( *this, *indexPointer, numberFormat == nullptr ? TNumberFormat<TChar>::Computational
232 : *numberFormat );
233}
234
235template<typename TChar>
236double TString<TChar>::ParseFloat( integer startIdx, TNumberFormat<TChar>* numberFormat, integer* newIdx )
237const
238{
239 // we need an index pointer reference. So if none was given in parameter newIdx
240 // then we just use parameter startIdx!
241 integer* indexPointer;
242 if ( newIdx == nullptr )
243 indexPointer= &startIdx;
244 else
245 {
246 indexPointer= newIdx;
247 *indexPointer= startIdx;
248 }
249
250 return detail::ParseFloat( *this, *indexPointer, numberFormat == nullptr ? TNumberFormat<TChar>::Computational
251 : *numberFormat );
252}
253
254
255// #################################################################################################
256// NString
257// #################################################################################################
258template<>
260{
261 if ( length == 0 )
262 return 0;
263
264 const nchar* cs= buffer;
265
266 //--------- Windows Version ----------
267 #if defined( _WIN32 )
268
269 int conversionSize= MultiByteToWideChar( CP_UTF8, 0, cs, static_cast<int>( length ), nullptr, 0 );
270
271 // check for errors
272 #if ALIB_DEBUG
273 if ( conversionSize == 0 )
274 {
275 // not enough space?
276 int error= GetLastError();
277
278 NString128 msg( "AString: Conversion to wide character string failed (Error: " );
279 if ( error == ERROR_INSUFFICIENT_BUFFER ) msg._( "ERROR_INSUFFICIENT_BUFFER." );
280 else if ( error == ERROR_INVALID_FLAGS ) msg._( "ERROR_INVALID_FLAGS." );
281 else if ( error == ERROR_INVALID_PARAMETER ) msg._( "ERROR_INVALID_PARAMETER" );
282 else if ( error == ERROR_NO_UNICODE_TRANSLATION ) msg._( "ERROR_NO_UNICODE_TRANSLATION" );
283 else msg._( error );
284 msg._(')');
285
286 ALIB_WARNING( msg )
287 return length;
288 }
289
290 if( conversionSize > length )
291 {
292 ALIB_ERROR( "STRINGS", "MBCS to WCS conversion failed. Conversion length=", conversionSize );
293 return length;
294 }
295 #endif
296
297 return conversionSize;
298
299 //--------- __GLIBCXX__ Version ---------
300 #elif defined (__GLIBCXX__) || defined(__APPLE__) || defined(__ANDROID_NDK__)
301
302 size_t conversionSize= mbsnrtowcs( nullptr, &cs, size_t(length), 0, nullptr );
303 if ( conversionSize == size_t(-1) )
304 {
305 ALIB_WARNING( "STRINGS", "MBCS to WCS conversion failed. Illegal MBC sequence. Probably UTF-8 is not set in locale" )
306 return length;
307 }
308
309 ALIB_ASSERT_ERROR( conversionSize <= size_t( length ), "STRINGS",
310 NString128( "MBCS to WCS conversion failed. Conversion length=")
311 << conversionSize )
312
313 return static_cast<integer>(conversionSize);
314
315 #else
316
317 #pragma message ("Unknown Platform in file: " __FILE__ )
318 return length;
319
320 #endif
321}
322
325template integer TString<nchar>::IndexOfSegmentEnd( nchar opener, nchar closer, integer idx ) const;
326template uint64_t TString<nchar>::ParseDecDigits( integer, integer* ) const;
327template int64_t TString<nchar>::ParseInt ( integer, TNumberFormat<nchar>* , integer* ) const;
328template uint64_t TString<nchar>::ParseDec ( integer, TNumberFormat<nchar>* , integer* ) const;
329template uint64_t TString<nchar>::ParseBin ( integer, TNumberFormat<nchar>* , integer* ) const;
330template uint64_t TString<nchar>::ParseHex ( integer, TNumberFormat<nchar>* , integer* ) const;
331template uint64_t TString<nchar>::ParseOct ( integer, TNumberFormat<nchar>* , integer* ) const;
332template double TString<nchar>::ParseFloat ( integer, TNumberFormat<nchar>* , integer* ) const;
333
334
335// #################################################################################################
336// WString
337// #################################################################################################
340template integer TString<wchar>::IndexOfSegmentEnd( wchar opener, wchar closer , integer idx ) const;
341template uint64_t TString<wchar>::ParseDecDigits( integer, integer* ) const;
342template int64_t TString<wchar>::ParseInt ( integer, TNumberFormat<wchar>* , integer* ) const;
343template uint64_t TString<wchar>::ParseDec ( integer, TNumberFormat<wchar>* , integer* ) const;
344template uint64_t TString<wchar>::ParseBin ( integer, TNumberFormat<wchar>* , integer* ) const;
345template uint64_t TString<wchar>::ParseHex ( integer, TNumberFormat<wchar>* , integer* ) const;
346template uint64_t TString<wchar>::ParseOct ( integer, TNumberFormat<wchar>* , integer* ) const;
347template double TString<wchar>::ParseFloat ( integer, TNumberFormat<wchar>* , integer* ) const;
348
349// #################################################################################################
350// XString
351// #################################################################################################
352template<>
354{
355 if ( length == 0 )
356 return 0;
357
359 const xchar* src= buffer;
360 const xchar* srcEnd= buffer + length;
361 integer result= 0;
362#if ALIB_SIZEOF_WCHAR_T == 4
363
364 // convert UTF16 to UTF32
365 while (src < srcEnd)
366 {
367 const char32_t uc = static_cast<char32_t>( *src++ );
368 if ((uc - 0xd800) >= 2048) // not surrogate
369 ++result;
370 else
371 {
373 ALIB_ASSERT_ERROR( src < srcEnd // has one more?
374 && ((uc & 0xfffffc00) == 0xd800) // is low?
375 && ((static_cast<char32_t>( *src++ ) & 0xfffffc00) == 0xdc00), // is high?
376 "STRINGS", "Error decoding UTF16" )
377
378 ++result;
379 ++src;
381 }
382 }
383
384#else
385
386 // convert UTF32 to UTF16
387 while (src < srcEnd)
388 {
389 uinteger uc= *src++;
390 ALIB_ASSERT_ERROR( uc < 0xd800
391 || ( uc >= 0xe000 && uc <= 0x10ffff ), "STRINGS",
392 "Illegal unicode 32 bit codepoint" )
393
394 if( uc < 0x10000 )
395 ++result;
396 else
397 {
398 uc-= 0x10000;
399 result+= 2;
400 }
401 }
402
403#endif
404
405 return result;
406}
407
410template integer TString<xchar>::IndexOfSegmentEnd( xchar opener, xchar closer ,integer ) const;
411template uint64_t TString<xchar>::ParseDecDigits( integer, integer* ) const;
412template int64_t TString<xchar>::ParseInt ( integer, TNumberFormat<xchar>* , integer* ) const;
413template uint64_t TString<xchar>::ParseDec ( integer, TNumberFormat<xchar>* , integer* ) const;
414template uint64_t TString<xchar>::ParseBin ( integer, TNumberFormat<xchar>* , integer* ) const;
415template uint64_t TString<xchar>::ParseHex ( integer, TNumberFormat<xchar>* , integer* ) const;
416template uint64_t TString<xchar>::ParseOct ( integer, TNumberFormat<xchar>* , integer* ) const;
417template double TString<xchar>::ParseFloat ( integer, TNumberFormat<xchar>* , integer* ) const;
418
419// #################################################################################################
420// Hashcode
421// #################################################################################################
422template<typename TChar>
423std::size_t TString<TChar>::Hashcode() const
424{
425 return std::hash<std::basic_string_view<TChar>>()(
426 std::basic_string_view<TChar>( Buffer(), size_t( Length() ) ) );
427}
428
429
430template std::size_t TString<nchar>::Hashcode () const;
431template std::size_t TString<wchar>::Hashcode () const;
432template std::size_t TString<xchar>::Hashcode () const;
433
434template<typename TChar>
435std::size_t TString<TChar>::HashcodeIgnoreCase() const
436{
437 std::size_t result= 68460391ul * ( size_t(length) + 1 );
438
439 auto* begin= buffer;
440 auto* end = buffer + length;
441 while( begin != end )
442 result = 199ul * result + std::size_t( ToUpper<TChar>( *begin++ ) );
443
444 return result;
445}
446template std::size_t TString<nchar>::HashcodeIgnoreCase() const;
447template std::size_t TString<wchar>::HashcodeIgnoreCase() const;
448template std::size_t TString<xchar>::HashcodeIgnoreCase() const;
449
450// #################################################################################################
451// debug methods
452// #################################################################################################
453#if ALIB_DEBUG_STRINGS
454template void TString<nchar>::dbgCheck() const;
455template void TString<wchar>::dbgCheck() const;
456template void TString<xchar>::dbgCheck() const;
457#endif
458
459
460#endif // DOXYGEN
461
462} // namespace alib[::strings]
463} // namespace [alib]
464
integer IndexOfSegmentEnd(TChar opener, TChar closer, integer idx) const
ALIB_API uint64_t ParseHex(integer startIdx=0, TNumberFormat< TChar > *numberFormat=nullptr, integer *newIdx=nullptr) const
ALIB_API uint64_t ParseBin(integer startIdx=0, TNumberFormat< TChar > *numberFormat=nullptr, integer *newIdx=nullptr) const
std::size_t Hashcode() const
std::size_t HashcodeIgnoreCase() const
ALIB_API uint64_t ParseDec(integer startIdx=0, TNumberFormat< TChar > *numberFormat=nullptr, integer *newIdx=nullptr) const
ALIB_API double ParseFloat(integer startIdx=0, TNumberFormat< TChar > *numberFormat=nullptr, integer *newIdx=nullptr) const
ALIB_API int64_t ParseInt(integer startIdx=0, TNumberFormat< TChar > *numberFormat=nullptr, integer *newIdx=nullptr) const
ALIB_API integer indexOfString(const TString &needle, integer startIdx, integer endIdx) const
ALIB_API uint64_t ParseOct(integer startIdx=0, TNumberFormat< TChar > *numberFormat=nullptr, integer *newIdx=nullptr) const
ALIB_API uint64_t ParseDecDigits(integer startIdx=0, integer *newIdx=nullptr) const
integer WStringLength() const
#define ALIB_WARNING(...)
Definition alib.hpp:1268
#define ALIB_MESSAGE(...)
Definition alib.hpp:1269
#define ALIB_WARNINGS_RESTORE
Definition alib.hpp:849
#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
PLATFORM_SPECIFIC xchar
TChar ToUpper(TChar c)
integer Length(const TChar *cstring)
bool Equal(TChar lhs, TRhs rhs)
PLATFORM_SPECIFIC wchar
ALIB_API uint64_t ParseOct(const TString< TChar > &src, integer &idx, const TNumberFormat< TChar > &nf)
ALIB_API int64_t ParseInt(const TString< TChar > &src, integer &idx, const TNumberFormat< TChar > &nf)
ALIB_API uint64_t ParseHex(const TString< TChar > &src, integer &idx, const TNumberFormat< TChar > &nf)
ALIB_API uint64_t ParseBin(const TString< TChar > &src, integer &idx, const TNumberFormat< TChar > &nf)
uint64_t ParseDecDigits(const TString< TChar > &src, integer &idx)
ALIB_API double ParseFloat(const TString< TChar > &src, integer &idx, const TNumberFormat< TChar > &nf)
ALIB_API uint64_t ParseDec(const TString< TChar > &src, integer &idx, const TNumberFormat< TChar > &nf)
Definition alib.cpp:69
lang::uinteger uinteger
Type alias in namespace alib.
Definition integers.hpp:276
lang::integer integer
Type alias in namespace alib.
Definition integers.hpp:273
static TNumberFormat Computational