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