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