ALib C++ Library
Library Version: 2511 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 integer nLen= needle.Length();
84 if( nLen == 0 )
85 return startIdx;
86 ALIB_ASSERT_ERROR( startIdx >= 0 && startIdx <= length, "STRINGS",
87 "Illegal start index given: 0 <= {} < {}.", startIdx, length )
88 ALIB_ASSERT_ERROR( endIdx <= length -nLen + 1 , "STRINGS",
89 "Illegal end index given: {} > {}.", endIdx, length -nLen + 1 )
90 const TChar* buf= buffer + startIdx;
91 const TChar* bufEnd= buffer + endIdx;
92 const TChar* nBuf= needle.Buffer();
93 const TChar* nBufEnd= nBuf + nLen;
94
95 while ( buf < bufEnd ) {
96 const TChar* b= buf;
97 const TChar* n= nBuf;
98 while ( characters::Equal<TChar,TSensitivity>(*b++, *n++ ) )
99 if( n == nBufEnd )
100 return buf - buffer;
101 ++buf;
102 }
103 return -1;
104}
105
106template<typename TChar>
107requires alib::characters::IsCharacter<TChar>
108integer TString<TChar>::IndexOfSegmentEnd( TChar opener, TChar closer, integer idx ) const {
109 int openCnt= 1;
110 while( idx < length ) {
111 if( buffer[idx] == opener ) ++openCnt;
112 if( buffer[idx] == closer && --openCnt == 0 )
113 break;
114
115 ++idx;
116 }
117
118 return openCnt == 0 ? idx : -openCnt;
119}
120
121//##################################################################################################
122// ParseXXX()
123//##################################################################################################
124template<typename TChar>
125requires alib::characters::IsCharacter<TChar>
126uint64_t TString<TChar>::ParseDecDigits( integer startIdx, integer* newIdx )
127 const {
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 indexPointer= newIdx;
135 *indexPointer= startIdx;
136 }
137
138 return detail::ParseDecDigits<TChar>( *this, *indexPointer );
139}
140
141
142template<typename TChar>
143requires alib::characters::IsCharacter<TChar>
144int64_t TString<TChar>::ParseInt( integer startIdx, TNumberFormat<TChar>* numberFormat, integer* newIdx )
145 const {
146 // we need an index pointer reference. So if none was given in parameter newIdx
147 // then we just use parameter startIdx!
148 integer* indexPointer;
149 if ( newIdx == nullptr )
150 indexPointer= &startIdx;
151 else {
152 indexPointer= newIdx;
153 *indexPointer= startIdx;
154 }
155
156 return detail::ParseInt( *this, *indexPointer, numberFormat == nullptr ? TNumberFormat<TChar>::Computational
157 : *numberFormat );
158}
159
160template<typename TChar>
161requires alib::characters::IsCharacter<TChar>
162uint64_t TString<TChar>::ParseDec( integer startIdx, TNumberFormat<TChar>* numberFormat, integer* newIdx )
163 const {
164 // we need an index pointer reference. So if none was given in parameter newIdx
165 // then we just use parameter startIdx!
166 integer* indexPointer;
167 if ( newIdx == nullptr )
168 indexPointer= &startIdx;
169 else {
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>
179requires alib::characters::IsCharacter<TChar>
180uint64_t TString<TChar>::ParseBin( integer startIdx, TNumberFormat<TChar>* numberFormat, integer* newIdx )
181 const {
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 indexPointer= newIdx;
189 *indexPointer= startIdx;
190 }
191
192 return detail::ParseBin( *this, *indexPointer, numberFormat == nullptr ? TNumberFormat<TChar>::Computational
193 : *numberFormat );
194}
195
196template<typename TChar>
197requires alib::characters::IsCharacter<TChar>
198uint64_t TString<TChar>::ParseHex( integer startIdx, TNumberFormat<TChar>* numberFormat, integer* newIdx )
199 const {
200 // we need an index pointer reference. So if none was given in parameter newIdx
201 // then we just use parameter startIdx!
202 integer* indexPointer;
203 if ( newIdx == nullptr )
204 indexPointer= &startIdx;
205 else {
206 indexPointer= newIdx;
207 *indexPointer= startIdx;
208 }
209
210 return detail::ParseHex( *this, *indexPointer, numberFormat == nullptr ? TNumberFormat<TChar>::Computational
211 : *numberFormat );
212}
213
214template<typename TChar>
215requires alib::characters::IsCharacter<TChar>
216uint64_t TString<TChar>::ParseOct( integer startIdx, TNumberFormat<TChar>* numberFormat, integer* newIdx )
217 const {
218 // we need an index pointer reference. So if none was given in parameter newIdx
219 // then we just use parameter startIdx!
220 integer* indexPointer;
221 if ( newIdx == nullptr )
222 indexPointer= &startIdx;
223 else {
224 indexPointer= newIdx;
225 *indexPointer= startIdx;
226 }
227
228 return detail::ParseOct( *this, *indexPointer, numberFormat == nullptr ? TNumberFormat<TChar>::Computational
229 : *numberFormat );
230}
231
232template<typename TChar>
233requires alib::characters::IsCharacter<TChar>
234double TString<TChar>::ParseFloat( integer startIdx, TNumberFormat<TChar>* numberFormat, integer* newIdx )
235 const {
236 // we need an index pointer reference. So if none was given in parameter newIdx
237 // then we just use parameter startIdx!
238 integer* indexPointer;
239 if ( newIdx == nullptr )
240 indexPointer= &startIdx;
241 else {
242 indexPointer= newIdx;
243 *indexPointer= startIdx;
244 }
245
246 return detail::ParseFloat( *this, *indexPointer, numberFormat == nullptr ? TNumberFormat<TChar>::Computational
247 : *numberFormat );
248}
249
250
251//##################################################################################################
252// NString
253//##################################################################################################
254template<>
256 if ( length == 0 )
257 return 0;
258
259 const nchar* cs= buffer;
260
261 //---------------------------------------- Windows Version ---------------------------------------
262 #if defined( _WIN32 )
263
264 int conversionSize= MultiByteToWideChar( CP_UTF8, 0, cs, int( length ), nullptr, 0 );
265
266 // check for errors
267 #if ALIB_DEBUG
268 if ( conversionSize == 0 ) {
269 // not enough space?
270 int error= GetLastError();
271
272 NString128 msg( "AString: Conversion to wide character string failed (Error: " );
273 if ( error == ERROR_INSUFFICIENT_BUFFER ) msg._( "ERROR_INSUFFICIENT_BUFFER." );
274 else if ( error == ERROR_INVALID_FLAGS ) msg._( "ERROR_INVALID_FLAGS." );
275 else if ( error == ERROR_INVALID_PARAMETER ) msg._( "ERROR_INVALID_PARAMETER" );
276 else if ( error == ERROR_NO_UNICODE_TRANSLATION ) msg._( "ERROR_NO_UNICODE_TRANSLATION" );
277 else msg._( error );
278 msg._(')');
279
280 ALIB_WARNING( "STRINGS", msg )
281 return length;
282 }
283
284 if( conversionSize > length ) {
285 ALIB_ERROR( "STRINGS", "MBCS to WCS conversion failed. Conversion length=",
286 conversionSize );
287 return length;
288 }
289 #endif
290
291 return conversionSize;
292
293 //-------------------------------------- __GLIBCXX__ Version -------------------------------------
294 #elif defined (__GLIBCXX__) || defined(_LIBCPP_VERSION) || defined(__APPLE__) || defined(__ANDROID_NDK__)
295
296 size_t conversionSize= mbsnrtowcs( nullptr, &cs, size_t(length), 0, nullptr );
297 if ( conversionSize == size_t(-1) ) {
298 ALIB_WARNING( "STRINGS", "MBCS to WCS conversion failed. Illegal MBC sequence. "
299 "Probably UTF-8 is not set in locale" )
300 return length;
301 }
302
303 ALIB_ASSERT_ERROR( conversionSize <= size_t( length ), "STRINGS",
304 "MBCS to WCS conversion failed. Conversion length=", conversionSize )
305
306 return integer(conversionSize);
307
308 #else
309
310 #pragma message ("Unknown Platform in file: " __FILE__ )
311 return length;
312
313 #endif
314}
315
318template integer TString<nchar>::IndexOfSegmentEnd( nchar opener, nchar closer, integer idx ) const;
319template uint64_t TString<nchar>::ParseDecDigits( integer, integer* ) const;
320template int64_t TString<nchar>::ParseInt ( integer, TNumberFormat<nchar>* , integer* ) const;
321template uint64_t TString<nchar>::ParseDec ( integer, TNumberFormat<nchar>* , integer* ) const;
322template uint64_t TString<nchar>::ParseBin ( integer, TNumberFormat<nchar>* , integer* ) const;
323template uint64_t TString<nchar>::ParseHex ( integer, TNumberFormat<nchar>* , integer* ) const;
324template uint64_t TString<nchar>::ParseOct ( integer, TNumberFormat<nchar>* , integer* ) const;
326
327
328//##################################################################################################
329// WString
330//##################################################################################################
333template integer TString<wchar>::IndexOfSegmentEnd( wchar opener, wchar closer , integer idx ) const;
334template uint64_t TString<wchar>::ParseDecDigits( integer, integer* ) const;
335template int64_t TString<wchar>::ParseInt ( integer, TNumberFormat<wchar>* , integer* ) const;
336template uint64_t TString<wchar>::ParseDec ( integer, TNumberFormat<wchar>* , integer* ) const;
337template uint64_t TString<wchar>::ParseBin ( integer, TNumberFormat<wchar>* , integer* ) const;
338template uint64_t TString<wchar>::ParseHex ( integer, TNumberFormat<wchar>* , integer* ) const;
339template uint64_t TString<wchar>::ParseOct ( integer, TNumberFormat<wchar>* , integer* ) const;
341
342//##################################################################################################
343// XString
344//##################################################################################################
345template<>
347 if ( length == 0 )
348 return 0;
349
350 const xchar* src= buffer;
351 const xchar* srcEnd= buffer + length;
352 integer result= 0;
353#if ALIB_SIZEOF_WCHAR_T == 4
354
355 // convert UTF16 to UTF32
356 while (src < srcEnd) {
357 const char32_t uc = static_cast<char32_t>( *src++ );
358 if ((uc - 0xd800) >= 2048) // not surrogate
359 ++result;
360 else {
361 ALIB_ASSERT_ERROR( src < srcEnd // has one more?
362 && ((uc & 0xfffffc00) == 0xd800) // is low?
363 && ((char32_t(*src++) & 0xfffffc00) == 0xdc00), // is high?
364 "STRINGS", "Error decoding UTF16" )
365
366 ++result;
367 ++src;
368 } }
369
370#else
371
372 // convert UTF32 to UTF16
373 while (src < srcEnd) {
374 uinteger uc= *src++;
375 ALIB_ASSERT_ERROR( uc < 0xd800
376 || ( uc >= 0xe000 && uc <= 0x10ffff ), "STRINGS",
377 "Illegal unicode 32 bit codepoint" )
378
379 if( uc < 0x10000 )
380 ++result;
381 else {
382 uc-= 0x10000;
383 result+= 2;
384 } }
385
386#endif
387
388 return result;
389}
390
393template integer TString<xchar>::IndexOfSegmentEnd( xchar opener, xchar closer ,integer ) const;
394template uint64_t TString<xchar>::ParseDecDigits( integer, integer* ) const;
395template int64_t TString<xchar>::ParseInt ( integer, TNumberFormat<xchar>* , integer* ) const;
396template uint64_t TString<xchar>::ParseDec ( integer, TNumberFormat<xchar>* , integer* ) const;
397template uint64_t TString<xchar>::ParseBin ( integer, TNumberFormat<xchar>* , integer* ) const;
398template uint64_t TString<xchar>::ParseHex ( integer, TNumberFormat<xchar>* , integer* ) const;
399template uint64_t TString<xchar>::ParseOct ( integer, TNumberFormat<xchar>* , integer* ) const;
401
402//##################################################################################################
403// Hashcode
404//##################################################################################################
405template<typename TChar>
406requires alib::characters::IsCharacter<TChar>
407std::size_t TString<TChar>::Hashcode() const
408{
409 return std::hash<std::basic_string_view<TChar>>()(
410 std::basic_string_view<TChar>( Buffer(), size_t( Length() ) ) );
411}
412
413
414template std::size_t TString<nchar>::Hashcode () const;
415template std::size_t TString<wchar>::Hashcode () const;
416template std::size_t TString<xchar>::Hashcode () const;
417
418template<typename TChar>
419requires alib::characters::IsCharacter<TChar>
420std::size_t TString<TChar>::HashcodeIgnoreCase() const {
421 std::size_t result= 68460391ul * ( size_t(length) + 1 );
422
423 auto* begin= buffer;
424 auto* end = buffer + length;
425 while( begin != end )
426 result = 199ul * result + std::size_t( ToUpper<TChar>( *begin++ ) );
427
428 return result;
429}
430template std::size_t TString<nchar>::HashcodeIgnoreCase() const;
431template std::size_t TString<wchar>::HashcodeIgnoreCase() const;
432template std::size_t TString<xchar>::HashcodeIgnoreCase() const;
433
434//##################################################################################################
435// debug methods
436//##################################################################################################
437#if ALIB_DEBUG_STRINGS
438template void TString<nchar>::dbgCheck() const;
439template void TString<wchar>::dbgCheck() const;
440template void TString<xchar>::dbgCheck() const;
441#endif
442
443
444#endif // DOXYGEN
445
446} // namespace alib[::strings]
447} // namespace [alib]
ALIB_DLL uint64_t ParseDec(integer startIdx=0, TNumberFormat< TChar > *numberFormat=nullptr, integer *newIdx=nullptr) const
constexpr integer Length() const
Definition string.inl:316
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:1064
#define ALIB_WARNING(domain,...)
Definition alib.inl:1063
#define ALIB_ERROR(domain,...)
Definition alib.inl:1062
#define ALIB_ASSERT_ERROR(cond, domain,...)
Definition alib.inl:1066
integer Length(const TChar *cstring)
Definition functions.inl:89
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