Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
Characters/CString/Utilities.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#include <limits>
5#include <locale>
6
8
9namespace Stroika::Foundation::Characters::CString {
10
11 /*
12 ********************************************************************************
13 ********************************** Length **************************************
14 ********************************************************************************
15 */
16 template <IPossibleCharacterRepresentation T>
17 inline size_t Length (const T* p)
18 {
20 if constexpr (sizeof (T) == 1) {
21 return ::strlen (reinterpret_cast<const char*> (p));
22 }
23 else if constexpr (sizeof (T) == sizeof (wchar_t)) {
24 return ::wcslen (reinterpret_cast<const wchar_t*> (p));
25 }
26 else {
27 const T* i = p;
28 while (*i++ != '\0')
29 ;
30 Assert (i > p);
31 return i - p - 1;
32 }
33 }
34
35 /*
36 ********************************************************************************
37 *************************************** Equals *********************************
38 ********************************************************************************
39 */
40 template <>
41 inline bool Equals (const char* lhs, const char* rhs)
42 {
43 RequireNotNull (lhs);
44 RequireNotNull (rhs);
45 return ::strcmp (lhs, rhs) == 0;
46 }
47 template <>
48 inline bool Equals (const char8_t* lhs, const char8_t* rhs)
49 {
50 RequireNotNull (lhs);
51 RequireNotNull (rhs);
52 return ::strcmp (reinterpret_cast<const char*> (lhs), reinterpret_cast<const char*> (rhs)) == 0;
53 }
54 template <>
55 inline bool Equals (const char16_t* lhs, const char16_t* rhs)
56 {
57 RequireNotNull (lhs);
58 RequireNotNull (rhs);
59 const char16_t* li = lhs;
60 const char16_t* ri = rhs;
61 while (*li == *ri) {
62 if (*li == '\0') {
63 return true;
64 }
65 ++li;
66 ++ri;
67 }
68 return false;
69 }
70 template <>
71 inline bool Equals (const char32_t* lhs, const char32_t* rhs)
72 {
73 RequireNotNull (lhs);
74 RequireNotNull (rhs);
75 const char32_t* li = lhs;
76 const char32_t* ri = rhs;
77 while (*li == *ri) {
78 if (*li == '\0') {
79 return true;
80 }
81 ++li;
82 ++ri;
83 }
84 return false;
85 }
86 template <>
87 inline bool Equals (const wchar_t* lhs, const wchar_t* rhs)
88 {
89 RequireNotNull (lhs);
90 RequireNotNull (rhs);
91 return ::wcscmp (lhs, rhs) == 0;
92 }
93
94 /*
95 ********************************************************************************
96 *************************************** Copy ***********************************
97 ********************************************************************************
98 */
99 template <typename T>
100 void Copy (T* dest, size_t nEltsInDest, const T* src)
101 {
102 // Only provide template specializations - but this variant so we get syntax error compiling instead of
103 // link error if someone calls with other types...
104 void* fail;
105 dest = fail;
106 }
107 template <>
108 inline void Copy (char* dest, size_t nEltsInDest, const char* src)
109 {
110 RequireNotNull (dest);
111 RequireNotNull (src);
112 Require (nEltsInDest >= 1);
113 char* destEnd = dest + nEltsInDest;
114 char* di = dest;
115 const char* si = src;
116 while ((*di++ = *si++) != '\0') {
117 Assert (di <= destEnd);
118 if (di == destEnd) {
119 *(di - 1) = '\0';
120 break;
121 }
122 }
123 Ensure (Length (dest) < nEltsInDest);
124 }
125 template <>
126 inline void Copy (wchar_t* dest, size_t nEltsInDest, const wchar_t* src)
127 {
128 RequireNotNull (dest);
129 RequireNotNull (src);
130 Require (nEltsInDest >= 1);
131 wchar_t* destEnd = dest + nEltsInDest;
132 wchar_t* di = dest;
133 const wchar_t* si = src;
134 while ((*di++ = *si++) != '\0') {
135 Assert (di <= destEnd);
136 if (di == destEnd) {
137 *(di - 1) = '\0';
138 break;
139 }
140 }
141 Ensure (Length (dest) < nEltsInDest);
142 }
143
144 /*
145 ********************************************************************************
146 *************************************** Cat ************************************
147 ********************************************************************************
148 */
149 template <typename T>
150 void Cat (T* dest, size_t nEltsInDest, const T* src)
151 {
152 // Only provide template specializations - but this variant so we get syntax error compiling instead of
153 // link error if someone calls with other types...
154 void* fail;
155 dest = fail;
156 }
157 template <>
158 inline void Cat (char* dest, size_t nEltsInDest, const char* src)
159 {
160 RequireNotNull (dest);
161 RequireNotNull (src);
162 Require (nEltsInDest >= 1);
163 char* destEnd = dest + nEltsInDest;
164 char* di = dest + strlen (dest);
165 const char* si = src;
166 while ((*di++ = *si++) != '\0') {
167 Assert (di <= destEnd);
168 if (di == destEnd) {
169 *(di - 1) = '\0';
170 break;
171 }
172 }
173 Ensure (Length (dest) < nEltsInDest);
174 }
175 template <>
176 inline void Cat (wchar_t* dest, size_t nEltsInDest, const wchar_t* src)
177 {
178 RequireNotNull (dest);
179 RequireNotNull (src);
180 Require (nEltsInDest >= 1);
181 wchar_t* destEnd = dest + nEltsInDest;
182 wchar_t* di = dest + ::wcslen (dest);
183 const wchar_t* si = src;
184 while ((*di++ = *si++) != '\0') {
185 Assert (di <= destEnd);
186 if (di == destEnd) {
187 *(di - 1) = '\0';
188 break;
189 }
190 }
191 Ensure (Length (dest) < nEltsInDest);
192 }
193
194 /*
195 ********************************************************************************
196 ************************** LTrim/RTrim/Trim ************************************
197 ********************************************************************************
198 */
199 template <typename TCHAR>
200 basic_string<TCHAR> LTrim (const basic_string<TCHAR>& text)
201 {
202 locale loc1; // default locale
203 const ctype<TCHAR>& ct = use_facet<ctype<TCHAR>> (loc1);
204 typename basic_string<TCHAR>::const_iterator i = text.begin ();
205 for (; i != text.end () and ct.is (ctype<TCHAR>::space, *i); ++i)
206 ;
207 return basic_string<TCHAR> (i, text.end ());
208 }
209 template <typename TCHAR>
210 basic_string<TCHAR> RTrim (const basic_string<TCHAR>& text)
211 {
212 locale loc1; // default locale
213 const ctype<TCHAR>& ct = use_facet<ctype<TCHAR>> (loc1);
214 typename basic_string<TCHAR>::const_iterator i = text.end ();
215 for (; i != text.begin () and ct.is (ctype<TCHAR>::space, *(i - 1)); --i)
216 ;
217 return basic_string<TCHAR> (text.begin (), i);
218 }
219 template <typename TCHAR>
220 inline basic_string<TCHAR> Trim (const basic_string<TCHAR>& text)
221 {
222 return LTrim (RTrim (text));
223 }
224
225 /*
226 ********************************************************************************
227 ******************************* String2Int *************************************
228 ********************************************************************************
229 */
230 namespace Private_ {
231 long long int String2Int_ (const string& s);
232 long long int String2Int_ (const char* s);
233 long long int String2Int_ (const wchar_t* s);
234 long long int String2Int_ (const wstring& s);
235 unsigned long long int String2UInt_ (const string& s);
236 unsigned long long int String2UInt_ (const char* s);
237 unsigned long long int String2UInt_ (const wchar_t* s);
238 unsigned long long int String2UInt_ (const wstring& s);
239 inline long long int String2Int_ (const char* s)
240 {
241 return String2Int_ (string{s});
242 }
243 inline long long int String2Int_ (const wchar_t* s)
244 {
245 return String2Int_ (wstring (s));
246 }
247 inline unsigned long long int String2UInt_ (const char* s)
248 {
249 return String2UInt_ (string{s});
250 }
251 inline unsigned long long int String2UInt_ (const wchar_t* s)
252 {
253 return String2UInt_ (wstring{s});
254 }
256 template <typename T, typename STRING_ARG>
257 T String2IntOrUInt_ (STRING_ARG s)
258 {
259 if (numeric_limits<T>::is_signed) {
260 long long int l = String2Int_ (s);
261 if (l <= numeric_limits<T>::min ()) {
262 return numeric_limits<T>::min ();
263 }
264 if (l >= numeric_limits<T>::max ()) {
265 return numeric_limits<T>::max ();
266 }
267 return static_cast<T> (l);
268 }
269 else {
270 unsigned long long int l = String2UInt_ (s);
271 if (l >= numeric_limits<T>::max ()) {
272 return numeric_limits<T>::max ();
273 }
274 return static_cast<T> (l);
275 }
276 }
277 }
278 DISABLE_COMPILER_MSC_WARNING_END (4018)
279
280 template <typename T>
281 inline T String2Int (const string& s)
282 {
283 return Private_::String2IntOrUInt_<T, const string&> (s);
284 }
285 template <typename T>
286 inline T String2Int (const wchar_t* s)
287 {
288 return Private_::String2IntOrUInt_<T, const wchar_t*> (s);
289 }
290 template <typename T>
291 inline T String2Int (const wstring& s)
292 {
293 return Private_::String2IntOrUInt_<T, const wstring&> (s);
294 }
295}
#define RequireNotNull(p)
Definition Assertions.h:347
void Cat(T *dest, size_t nEltsInDest, const T *src2Append)
Safe variant of strncat() - which always NUL-terminates the string. DIFFERNT arguments however,...
basic_string< TCHAR > LTrim(const basic_string< TCHAR > &text)
size_t Length(const T *p)
Measure the length of the argument c-string (NUL-terminated string).
void Copy(T *dest, size_t nEltsInDest, const T *src)
Safe variant of strncpy() - which always NUL-terminates the string.
bool Equals(const T *lhs, const T *rhs)
strcmp or wsccmp() as appropriate == 0