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