libcopp 2.3.1
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
string_oprs.h
Go to the documentation of this file.
1
15#pragma once
16
17#ifndef __STDC_WANT_LIB_EXT1__
18# define __STDC_WANT_LIB_EXT1__ 1
19#endif
20
21#include <stdint.h>
22
23// Import the C++20 feature-test macros
24#ifdef __has_include
25# if __has_include(<version>)
26# include <version>
27# endif
28#elif defined(_MSC_VER) && \
29 ((defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L))
30# if _MSC_VER >= 1922
31# include <version>
32# endif
33#endif
34
35#include <algorithm>
36#include <cctype>
37#include <cstdlib>
38#include <cstring>
39#include <memory>
40#include <ostream>
41#include <string>
42#include <utility>
43
44#ifdef __cpp_lib_string_view
45# include <string_view>
46#endif
47
48#include <type_traits>
49
50#if defined(_MSC_VER) && _MSC_VER >= 1600
51# define UTIL_STRFUNC_STRCASE_CMP(l, r) _stricmp(l, r)
52# define UTIL_STRFUNC_STRNCASE_CMP(l, r, s) _strnicmp(l, r, s)
53# define UTIL_STRFUNC_STRCMP(l, r) strcmp(l, r)
54# define UTIL_STRFUNC_STRNCMP(l, r, s) strncmp(l, r, s)
55#else
56# define UTIL_STRFUNC_STRCASE_CMP(l, r) strcasecmp(l, r)
57# define UTIL_STRFUNC_STRNCASE_CMP(l, r, s) strncasecmp(l, r, s)
58# define UTIL_STRFUNC_STRCMP(l, r) strcmp(l, r)
59# define UTIL_STRFUNC_STRNCMP(l, r, s) strncmp(l, r, s)
60#endif
61
62#if (defined(_MSC_VER) && _MSC_VER >= 1600) || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) || \
63 defined(__STDC_LIB_EXT1__)
64# define UTIL_STRFUNC_SSCANF(...) sscanf_s(__VA_ARGS__)
65
66# ifdef _MSC_VER
67# define UTIL_STRFUNC_VSNPRINTF(buffer, bufsz, fmt, arg) \
68 vsnprintf_s(buffer, static_cast<size_t>(bufsz), _TRUNCATE, fmt, arg)
69# define UTIL_STRFUNC_SNPRINTF(buffer, bufsz, ...) sprintf_s(buffer, static_cast<size_t>(bufsz), __VA_ARGS__)
70# else
71# define UTIL_STRFUNC_VSNPRINTF(buffer, bufsz, fmt, arg) vsnprintf_s(buffer, static_cast<rsize_t>(bufsz), fmt, arg)
72# define UTIL_STRFUNC_SNPRINTF(buffer, bufsz, fmt, args...) \
73 snprintf_s(buffer, static_cast<rsize_t>(bufsz), fmt, ##args)
74# endif
75
76# define UTIL_STRFUNC_C11_SUPPORT 1
77#else
78# define UTIL_STRFUNC_SSCANF(...) sscanf(__VA_ARGS__)
79# define UTIL_STRFUNC_SNPRINTF(buffer, bufsz, fmt, args...) snprintf(buffer, static_cast<size_t>(bufsz), fmt, ##args)
80# define UTIL_STRFUNC_VSNPRINTF(buffer, bufsz, fmt, arg) vsnprintf(buffer, static_cast<size_t>(bufsz), fmt, arg)
81#endif
82
83namespace util {
84namespace string {
91template <class TCH = char>
92TCH tolower(TCH c) {
93 if (c >= 'A' && c <= 'Z') {
94 return static_cast<TCH>(c + static_cast<TCH>('a' - 'A'));
95 }
96
97 return c;
98}
99
106template <class TCH = char>
107TCH toupper(TCH c) {
108 if (c >= 'a' && c <= 'z') {
109 return static_cast<TCH>(c - 'a' + 'A');
110 }
111
112 return c;
113}
114
120template <class TCH>
121inline bool is_space(const TCH &c) {
122 return ' ' == c || '\t' == c || '\r' == c || '\n' == c;
123}
124
134template <class TCH>
135std::pair<const TCH *, size_t> trim(const TCH *str_begin, size_t sz, bool trim_left = true, bool trim_right = true) {
136 if (0 == sz) {
137 const TCH *str_end = str_begin;
138 while (str_end && *str_end) {
139 ++str_end;
140 }
141
142 sz = static_cast<size_t>(str_end - str_begin);
143 }
144
145 if (trim_left && str_begin) {
146 while (*str_begin && sz > 0) {
147 if (!is_space(*str_begin)) {
148 break;
149 }
150
151 --sz;
152 ++str_begin;
153 }
154 }
155
156 size_t sub_str_sz = sz;
157 if (trim_right && str_begin) {
158 while (sub_str_sz > 0) {
159 if (is_space(str_begin[sub_str_sz - 1])) {
160 --sub_str_sz;
161 } else {
162 break;
163 }
164 }
165 }
166
167 return std::make_pair(str_begin, sub_str_sz);
168}
169
175template <class TCH, class TCHE>
176void reverse(TCH *begin, TCHE end_any) {
177 TCH *end = reinterpret_cast<TCH *>(end_any);
178 if (nullptr == begin) {
179 return;
180 }
181
182 if (nullptr == end) {
183 end = begin;
184 while (*end) {
185 ++end;
186 }
187 }
188
189 if (begin >= end) {
190 return;
191 }
192
193 --end;
194 using std::swap;
195 while (begin < end) {
196 swap(*begin, *end);
197 ++begin;
198 --end;
199 }
200}
201
202template <class TCH>
203inline void reverse(TCH *begin, int end_any) {
204 reverse<TCH, TCH *>(begin, reinterpret_cast<TCH *>(static_cast<intptr_t>(end_any)));
205}
206
207template <class TCH>
208inline void reverse(TCH *begin, std::nullptr_t) {
209 reverse<TCH, TCH *>(begin, static_cast<TCH *>(nullptr));
210}
211
212template <class T>
213size_t int2str_unsigned(char *str, size_t strsz, T in) {
214 if (0 == strsz) {
215 return 0;
216 }
217
218 if (0 == in) {
219 *str = '0';
220 return 1;
221 }
222
223 size_t ret = 0;
224 while (ret < strsz && in > 0) {
225 str[ret] = static_cast<char>((in % 10) + '0');
226
227 in /= 10;
228 ++ret;
229 }
230
231 if (in > 0 && ret >= strsz) {
232 return 0;
233 }
234
235 reverse(str, str + ret);
236 return ret;
237}
238
239template <class T>
240size_t int2str_signed(char *str, size_t strsz, T in) {
241 if (0 == strsz) {
242 return 0;
243 }
244
245 if (in < 0) {
246 *str = '-';
247 size_t ret = int2str_unsigned(str + 1, strsz - 1, static_cast<typename std::make_unsigned<T>::type>(-in));
248 if (0 == ret) {
249 return 0;
250 }
251
252 return ret + 1;
253 } else {
254 return int2str_unsigned(str, strsz, static_cast<typename std::make_unsigned<T>::type>(in));
255 }
256}
257
258template <class T>
260 using value_type_s = T;
261 using value_type_u = typename std::make_unsigned<T>::type;
262
263 static inline size_t call(char *str, size_t strsz, value_type_s in) { return int2str_signed(str, strsz, in); }
264
265 static inline size_t call(char *str, size_t strsz, value_type_u in) { return int2str_unsigned(str, strsz, in); }
266};
267
275template <class T>
276inline size_t int2str(char *str, size_t strsz, const T &in) {
277 size_t ret = int2str_helper<typename std::make_signed<typename std::remove_cv<T>::type>::type>::call(str, strsz, in);
278 if (ret < strsz) {
279 str[ret] = 0;
280 }
281
282 return ret;
283}
284
291template <class T, class TCHAR>
292const TCHAR *str2int(T &out, const TCHAR *str, size_t strsz = 0) {
293 out = static_cast<T>(0);
294 if (nullptr == str || !(*str)) {
295 return str;
296 }
297
298 size_t cur = 0;
299
300 // negative
301 bool is_negative = false;
302 while ((0 == strsz || cur < strsz) && (str[cur] && str[cur] == '-')) {
303 is_negative = !is_negative;
304 ++cur;
305 }
306
307 while ((0 == strsz || cur < strsz) && (str[cur] && is_space(str[cur]))) {
308 ++cur;
309 }
310
311 if (!str[cur]) {
312 return str + cur;
313 }
314
315 if ((0 == strsz || cur + 1 < strsz) && '0' == str[cur] && 'x' == tolower(str[cur + 1])) { // hex
316 for (cur += 2; (0 == strsz || cur < strsz) && str[cur]; ++cur) {
317 char c = tolower(str[cur]);
318 if (c >= '0' && c <= '9') {
319 out = static_cast<T>(out << 4);
320 out = static_cast<T>(out + static_cast<T>(c - static_cast<char>('0')));
321 } else if (c >= 'a' && c <= 'f') {
322 out = static_cast<T>(out << 4);
323 out = static_cast<T>(out + static_cast<T>(c - static_cast<char>('a') + 10));
324 } else {
325 break;
326 }
327 }
328 } else if ((0 == strsz || cur < strsz) && '\\' == str[cur]) { // oct
329 for (++cur; (0 == strsz || cur < strsz) && (str[cur] >= '0' && str[cur] < '8'); ++cur) {
330 out = static_cast<T>(out << 3);
331 out = static_cast<T>(out + static_cast<T>(str[cur] - static_cast<char>('0')));
332 }
333 } else { // dec
334 for (; (0 == strsz || cur < strsz) && (str[cur] >= '0' && str[cur] <= '9'); ++cur) {
335 out = static_cast<T>(out * 10);
336 out = static_cast<T>(out + static_cast<T>(str[cur] - static_cast<char>('0')));
337 }
338 }
339
340 if (is_negative) {
341 out = static_cast<T>((~out) + 1);
342 }
343
344 return str + cur;
345}
346
347template <class T, class TCHAR>
348const TCHAR *str2int(T &out, const std::basic_string<TCHAR> &str) {
349 return str2int(out, str.c_str(), str.size());
350}
351
352#ifdef __cpp_lib_string_view
353template <class T, class TCHAR>
354const TCHAR *str2int(T &out, std::basic_string_view<TCHAR> str) {
355 return str2int(out, str.data(), str.size());
356}
357#endif
358
364template <class T, class TINPUT>
365inline T to_int(TINPUT &&input) {
366 T ret = 0;
367 str2int(ret, std::forward<TINPUT>(input));
368 return ret;
369}
370
377template <class TStr, class TCh>
378void hex(TStr *out, TCh c, bool upper_case = false) {
379 out[0] = static_cast<TStr>((c >> 4) & 0x0F);
380 out[1] = static_cast<TStr>(c & 0x0F);
381
382 for (int i = 0; i < 2; ++i) {
383 if (out[i] > 9) {
384 TStr base;
385 if (upper_case) {
386 base = static_cast<TStr>('A');
387 } else {
388 base = static_cast<TStr>('a');
389 }
390 base = static_cast<TStr>(base - 10);
391 out[i] = static_cast<TStr>(out[i] + base);
392 } else {
393 out[i] = static_cast<TStr>(out[i] + static_cast<TStr>('0'));
394 }
395 }
396}
397
404template <class TStr, class TCh>
405void oct(TStr *out, TCh c) {
406 out[0] = static_cast<TStr>(((c >> 6) & 0x07) + '0');
407 out[1] = static_cast<TStr>(((c >> 3) & 0x07) + '0');
408 out[2] = static_cast<TStr>((c & 0x07) + '0');
409}
410
418template <class TCh>
419void serialization(const void *src, size_t ss, TCh *out, size_t &os) {
420 const TCh *cs = reinterpret_cast<const TCh *>(src);
421 size_t i, j;
422 for (i = 0, j = 0; i < ss && j < os; ++i) {
423 if (cs[i] >= 32 && cs[i] < 127) {
424 out[j] = cs[i];
425 ++j;
426 } else if (j + 4 <= os) {
427 out[j++] = '\\';
428 oct(&out[j], cs[i]);
429 j += 3;
430 } else {
431 break;
432 }
433 }
434
435 os = j;
436}
437
444template <class Elem, class Traits>
445void serialization(const void *src, size_t ss, std::basic_ostream<Elem, Traits> &out) {
446 const Elem *cs = reinterpret_cast<const Elem *>(src);
447 size_t i;
448 for (i = 0; i < ss; ++i) {
449 if (cs[i] >= 32 && cs[i] < 127) {
450 out.put(cs[i]);
451 } else {
452 Elem tmp[4] = {'\\', 0, 0, 0};
453 oct(&tmp[1], cs[i]);
454 out.write(tmp, 4);
455 }
456 }
457}
458
466template <class TCh>
467void dumphex(const void *src, size_t ss, TCh *out, bool upper_case = false) {
468 const unsigned char *cs = reinterpret_cast<const unsigned char *>(src);
469 size_t i;
470 for (i = 0; i < ss; ++i) {
471 hex<TCh, unsigned char>(&out[i << 1], cs[i], upper_case);
472 }
473}
474
482template <class Elem, class Traits>
483void dumphex(const void *src, size_t ss, std::basic_ostream<Elem, Traits> &out, bool upper_case = false) {
484 const unsigned char *cs = reinterpret_cast<const unsigned char *>(src);
485 size_t i;
486 Elem tmp[2];
487 for (i = 0; i < ss; ++i) {
488 hex<Elem, unsigned char>(tmp, cs[i], upper_case);
489 out.write(tmp, 2);
490 }
491}
492} // namespace string
493} // namespace util
LIBCOPP_COPP_API_HEAD_ONLY void swap(LIBCOPP_COPP_NAMESPACE_ID::memory::strong_rc_ptr< T > &a, LIBCOPP_COPP_NAMESPACE_ID::memory::strong_rc_ptr< T > &b) noexcept
Support std::swap for strong_rc_ptr.
Definition rc_ptr.h:1377
size_t int2str(char *str, size_t strsz, const T &in)
整数转字符串
TCH tolower(TCH c)
字符转小写
Definition string_oprs.h:92
size_t int2str_unsigned(char *str, size_t strsz, T in)
bool is_space(const TCH &c)
是否是空白字符
void hex(TStr *out, TCh c, bool upper_case=false)
字符转十六进制表示
void dumphex(const void *src, size_t ss, TCh *out, bool upper_case=false)
字符转16进制表示
TCH toupper(TCH c)
字符转大写
void oct(TStr *out, TCh c)
字符转8进制表示
std::pair< const TCH *, size_t > trim(const TCH *str_begin, size_t sz, bool trim_left=true, bool trim_right=true)
移除两边或一边的空白字符
T to_int(TINPUT &&input)
字符串转整数
const TCHAR * str2int(T &out, const TCHAR *str, size_t strsz=0)
字符串转整数
void reverse(TCH *begin, TCHE end_any)
翻转字符串
size_t int2str_signed(char *str, size_t strsz, T in)
void serialization(const void *src, size_t ss, TCh *out, size_t &os)
字符转8进制表示
typename std::make_unsigned< T >::type value_type_u
static size_t call(char *str, size_t strsz, value_type_u in)
static size_t call(char *str, size_t strsz, value_type_s in)