26 using locale_t = _locale_t;
28 inline locale_t create_locale(_In_
int category, _In_z_
const char* locale) {
return _create_locale(category, locale); }
29 inline locale_t create_locale(_In_
int category, _In_z_
const wchar_t* locale) {
return _wcreate_locale(category, locale); }
30 inline void free_locale(_In_opt_ locale_t locale) { _free_locale(locale); }
32 using locale_t = ::locale_t;
34 inline locale_t create_locale(_In_
int category, _In_z_
const char* locale)
38 case LC_ALL : mask = LC_ALL_MASK ;
break;
39 case LC_COLLATE : mask = LC_COLLATE_MASK ;
break;
40 case LC_CTYPE : mask = LC_CTYPE_MASK ;
break;
41 case LC_MESSAGES: mask = LC_MESSAGES_MASK;
break;
42 case LC_MONETARY: mask = LC_MONETARY_MASK;
break;
43 case LC_NUMERIC : mask = LC_NUMERIC_MASK ;
break;
44 case LC_TIME : mask = LC_TIME_MASK ;
break;
46 return newlocale(mask, locale, LC_GLOBAL_LOCALE);
49 inline void free_locale(_In_opt_ locale_t locale) { freelocale(locale); }
70 using locale = std::unique_ptr<__crt_locale_pointers, free_locale_delete>;
71#elif defined(__APPLE__)
72 using locale = std::unique_ptr<struct _xlocale, free_locale_delete>;
74 using locale = std::unique_ptr<struct __locale_struct, free_locale_delete>;
80 static locale locale_C(create_locale(LC_ALL,
"C"));
86 typedef wchar_t utf16_t;
88 typedef char16_t utf16_t;
96 inline bool is_high_surrogate(_In_ utf16_t chr)
98 return 0xd800 < chr && chr < 0xdc00;
106 inline bool is_low_surrogate(_In_ utf16_t chr)
108 return 0xdc00 < chr && chr < 0xe000;
116 inline bool is_surrogate_pair(_In_reads_(2)
const utf16_t* str)
118 return is_high_surrogate(str[0]) && is_low_surrogate(str[1]);
126 inline char32_t surrogate_pair_to_ucs4(_In_reads_(2)
const utf16_t* str)
128 assert(is_surrogate_pair(str));
130 ((
char32_t)(str[0] - 0xd800) << 10) +
131 (char32_t)(str[1] - 0xdc00) +
140 inline void ucs4_to_surrogate_pair(_Out_writes_(2) utf16_t* str, _In_
char32_t chr)
142 assert(chr >= 0x10000);
144 str[0] = 0xd800 + (char32_t)((chr >> 10) & 0x3ff);
145 str[1] = 0xdc00 + (char32_t)(chr & 0x3ff);
153 inline bool iscombining(_In_
char32_t chr)
156 (0x0300 <= chr && chr < 0x0370) ||
157 (0x1dc0 <= chr && chr < 0x1e00) ||
158 (0x20d0 <= chr && chr < 0x2100) ||
159 (0xfe20 <= chr && chr < 0xfe30);
168 inline size_t islbreak(_In_ T chr)
170 return chr ==
'\n' || chr ==
'\r';
180 inline size_t islbreak(_In_reads_or_z_opt_(count)
const T* chr, _In_
size_t count)
182 _Analysis_assume_(chr || !count);
183 if (count >= 2 && ((chr[0] ==
'\r' && chr[1] ==
'\n') || (chr[0] ==
'\n' && chr[1] ==
'\r')))
185 if (count > 1 && (chr[0] ==
'\n' || chr[0] ==
'\r'))
196 inline size_t glyphlen(_In_reads_or_z_opt_(count)
const wchar_t* glyph, _In_
size_t count)
198 _Analysis_assume_(glyph || !count);
201 size_t i = count < 2 || !is_surrogate_pair(glyph) ? 1 : 2;
205 for (; i < count && iscombining(glyph[i]); ++i);
219 inline size_t strlen(_In_z_
const T* str)
223 for (i = 0; str[i]; ++i);
236 inline size_t strnlen(_In_reads_or_z_opt_(count)
const T* str, _In_
size_t count)
238 assert(str || !count);
240 for (i = 0; i < count && str[i]; ++i);
244 constexpr auto npos{
static_cast<size_t>(-1) };
255 inline size_t strchr(_In_z_
const T* str, _In_ T chr)
258 for (
size_t i = 0; str[i]; ++i)
259 if (str[i] == chr)
return i;
273 inline size_t strnchr(
274 _In_reads_or_z_opt_(count)
const T* str,
278 assert(str || !count);
279 for (
size_t i = 0; i < count && str[i]; ++i)
280 if (str[i] == chr)
return i;
294 inline size_t strrnchr(
295 _In_reads_or_z_opt_(count)
const T* str,
299 assert(str || !count);
301 for (
size_t i = 0; i < count && str[i]; ++i)
302 if (str[i] == chr) z = i;
316 inline size_t strnichr(
317 _In_reads_or_z_opt_(count)
const T* str,
320 _In_
const std::locale& locale)
322 assert(str || !count);
323 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
324 chr = ctype.tolower(chr);
325 for (
size_t i = 0; i < count && str[i]; ++i)
326 if (ctype.tolower(str[i]) == chr)
return i;
340 inline size_t strrnichr(
341 _In_reads_or_z_opt_(count)
const T* str,
344 _In_
const std::locale& locale)
346 assert(str || !count);
347 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
348 chr = ctype.tolower(chr);
350 for (
size_t i = 0; i < count && str[i]; ++i)
351 if (ctype.tolower(str[i]) == chr) z = i;
365 template <
class T1,
class T2>
367 _In_reads_or_z_opt_(count1)
const T1* str1, _In_
size_t count1,
368 _In_reads_or_z_opt_(count2)
const T2* str2, _In_
size_t count2)
370 assert(str1 || !count1);
371 assert(str2 || !count2);
372 size_t i; T1 a; T2 b;
373 for (i = 0; i < count1 && i < count2 && ((a = str1[i]) | (b = str2[i])); ++i) {
374 if (a > b)
return +1;
375 if (a < b)
return -1;
377 if (i < count1 && str1[i])
return +1;
378 if (i < count2 && str2[i])
return -1;
394 _In_reads_or_z_opt_(count1)
const T* str1, _In_
size_t count1,
395 _In_reads_or_z_opt_(count2)
const T* str2, _In_
size_t count2,
396 _In_
const std::locale& locale)
398 assert(str1 || !count1);
399 assert(str2 || !count2);
400 auto& collate = std::use_facet<std::collate<T>>(locale);
401 return collate.compare(str1, str1 + count1, str2, str2 + count2);
414 template <
class T1,
class T2>
416 _In_reads_or_z_opt_(count1)
const T1* str1, _In_
size_t count1,
417 _In_reads_or_z_opt_(count2)
const T2* str2, _In_
size_t count2,
418 _In_
const std::locale& locale)
420 assert(str1 || !count1);
421 assert(str2 || !count2);
422 size_t i; T1 a; T2 b;
423 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
424 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
425 for (i = 0; i < count1 && i < count2 && ((a = ctype1.tolower(str1[i])) | (b = ctype2.tolower(str2[i]))); i++) {
426 if (a > b)
return +1;
427 if (a < b)
return -1;
429 if (i < count1 && str1[i])
return +1;
430 if (i < count2 && str2[i])
return -1;
442 template <
class T1,
class T2>
443 inline size_t strstr(
444 _In_z_
const T1* str,
445 _In_z_
const T2* sample)
449 for (
size_t offset = 0;; ++offset) {
450 for (
size_t i = offset, j = 0;; ++i, ++j) {
455 if (str[i] != sample[j])
470 template <
class T1,
class T2>
471 inline size_t strnstr(
472 _In_reads_or_z_opt_(count)
const T1* str,
474 _In_z_
const T2* sample)
476 assert(str || !count);
478 for (
size_t offset = 0;; ++offset) {
479 for (
size_t i = offset, j = 0;; ++i, ++j) {
482 if (i >= count || !str[i])
484 if (str[i] != sample[j])
498 template <
class T1,
class T2>
499 inline size_t stristr(
500 _In_z_
const T1* str,
501 _In_z_
const T2* sample,
502 _In_
const std::locale& locale)
506 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
507 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
508 for (
size_t offset = 0;; ++offset) {
509 for (
size_t i = offset, j = 0;; ++i, ++j) {
514 if (ctype1.tolower(str[i]) != ctype2.tolower(sample[j]))
529 template <
class T1,
class T2>
530 inline size_t strnistr(
531 _In_reads_or_z_opt_(count)
const T1* str,
533 _In_z_
const T2* sample,
534 _In_
const std::locale& locale)
536 assert(str || !count);
538 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
539 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
540 for (
size_t offset = 0;; ++offset) {
541 for (
size_t i = offset, j = 0;; ++i, ++j) {
544 if (i >= count || !str[i])
546 if (ctype1.tolower(str[i]) != ctype2.tolower(sample[j]))
560 template <
class T1,
class T2>
561 inline size_t strcpy(
562 _Out_writes_z_(_String_length_(src) + 1) T1* dst,
563 _In_z_
const T2* src)
566 for (
size_t i = 0; ; ++i) {
567 if ((dst[i] = src[i]) == 0)
581 template <
class T1,
class T2>
582 inline size_t strncpy(
583 _Out_writes_(count) _Post_maybez_ T1* dst,
584 _In_reads_or_z_opt_(count)
const T2* src, _In_
size_t count)
586 assert(dst && src || !count);
587 for (
size_t i = 0; ; ++i) {
590 if ((dst[i] = src[i]) == 0)
605 template <
class T1,
class T2>
606 inline size_t strncpy(
607 _Out_writes_(count_dst) _Post_maybez_ T1* dst, _In_
size_t count_dst,
608 _In_reads_or_z_opt_(count_src)
const T2* src, _In_
size_t count_src)
610 assert(dst || !count_dst);
611 assert(src || !count_src);
612 for (
size_t i = 0; ; ++i)
620 if ((dst[i] = src[i]) == 0)
633 template <
class T1,
class T2>
634 inline size_t strcat(
635 _In_z_ _Out_writes_z_(_String_length_(dst) + _String_length_(src) + 1) T1* dst,
636 _In_z_
const T2* src)
639 for (
size_t i = 0, j = stdex::strlen<T1>(dst); ; ++i, ++j) {
640 if ((dst[j] = src[i]) == 0)
654 template <
class T1,
class T2>
655 inline size_t strncat(
656 _Out_writes_(count) _Post_maybez_ T1* dst,
657 _In_reads_or_z_opt_(count)
const T2* src, _In_
size_t count)
659 assert(dst && src || !count);
660 for (
size_t i = 0, j = stdex::strlen<T1>(dst); ; ++i, ++j) {
663 if ((dst[j] = src[i]) == 0)
678 template <
class T1,
class T2>
679 inline size_t strncat(
680 _Out_writes_(count_dst) _Post_maybez_ T1* dst, _In_
size_t count_dst,
681 _In_reads_or_z_opt_(count_src)
const T2* src, _In_
size_t count_src)
683 assert(dst || !count_dst);
684 assert(src || !count_src);
685 for (
size_t i = 0, j = stdex::strnlen<T1>(dst, count_dst); ; ++i, ++j)
693 if ((dst[j] = src[i]) == 0)
709 inline _Check_return_ _Ret_maybenull_z_ T* strdup(_In_opt_z_
const T* str)
713 size_t count = strlen(str) + 1;
714 T* dst =
new T[count];
715 strncpy(dst, count, str, SIZE_MAX);
731 inline _Ret_z_ T* strndup(
732 _In_reads_or_z_opt_(count)
const T* str,
735 T* dst =
new T[count];
736 strncpy(dst, count, str, SIZE_MAX);
750 inline size_t crlf2nl(_Out_writes_z_(strlen(src)) T* dst, _In_z_
const T* src)
755 for (i = j = 0; src[j];) {
756 if (src[j] !=
'\r' || src[j + 1] !=
'\n')
768 template <
class T,
class T_bin>
769 inline T_bin strtoint(
770 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
771 _Out_opt_
size_t* end,
773 _Out_ uint8_t& flags)
775 assert(str || !count);
776 assert(radix == 0 || 2 <= radix && radix <= 36);
779 T_bin value = 0, digit,
781 max_ui_pre1, max_ui_pre2;
787 if (i >= count || !str[i])
goto error;
788 if (!isspace(str[i]))
break;
795 if (i >= count || !str[i])
goto error;
797 else if (str[i] ==
'-') {
800 if (i >= count || !str[i])
goto error;
805 if (str[i] ==
'0' && i + 1 < count && (str[i + 1] ==
'x' || str[i + 1] ==
'X')) {
807 if (i >= count || !str[i])
goto error;
814 if (i >= count || !str[i])
goto error;
815 if (str[i] ==
'x' || str[i] ==
'X') {
818 if (i >= count || !str[i])
goto error;
828 max_ui_pre1 = max_ui / (T_bin)radix;
829 max_ui_pre2 = max_ui % (T_bin)radix;
831 if (
'0' <= str[i] && str[i] <=
'9')
832 digit = (T_bin)str[i] -
'0';
833 else if (
'A' <= str[i] && str[i] <=
'Z')
834 digit = (T_bin)str[i] -
'A' +
'\x0a';
835 else if (
'a' <= str[i] && str[i] <=
'z')
836 digit = (T_bin)str[i] -
'a' +
'\x0a';
839 if (digit >= (T_bin)radix)
842 if (value < max_ui_pre1 ||
843 (value == max_ui_pre1 && digit <= max_ui_pre2))
844 value = value * (T_bin)radix + digit;
851 if (i >= count || !str[i])
871 template <
class T,
class T_bin>
873 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
874 _Out_opt_
size_t* end,
880 switch (
sizeof(T_bin)) {
882 value = (T_bin)strtoint<T, uint8_t>(str, count, end, radix, flags);
883 if ((flags & 0x01) && (value & 0x80)) {
887 return (flags & 0x02) ?
888 (flags & 0x01) ? (T_bin)0x80 : (T_bin)0x7f :
889 (flags & 0x01) ? -value : value;
892 value = (T_bin)strtoint<T, uint16_t>(str, count, end, radix, flags);
893 if ((flags & 0x01) && (value & 0x8000)) {
897 return (flags & 0x02) ?
898 (flags & 0x01) ? (T_bin)0x8000 : (T_bin)0x7fff :
899 (flags & 0x01) ? -value : value;
902 value = (T_bin)strtoint<T, uint32_t>(str, count, end, radix, flags);
903 if ((flags & 0x01) && (value & 0x80000000)) {
907 return (flags & 0x02) ?
908 (flags & 0x01) ? (T_bin)0x80000000 : (T_bin)0x7fffffff :
909 (flags & 0x01) ? -value : value;
912 value = (T_bin)strtoint<T, uint64_t>(str, count, end, radix, flags);
913 if ((flags & 0x01) && (value & 0x8000000000000000)) {
917 return (flags & 0x02) ?
918 (flags & 0x01) ? (T_bin)0x8000000000000000 : (T_bin)0x7fffffffffffffff :
919 (flags & 0x01) ? -value : value;
922 throw std::invalid_argument(
"Unsupported bit length");
936 template <
class T,
class T_bin>
937 inline T_bin strtouint(
938 _In_reads_or_z_opt_(count)
const T* str,
940 _Out_opt_
size_t* end,
946 switch (
sizeof(T_bin)) {
947 case 1: value = (T_bin)strtoint<T, uint8_t>(str, count, end, radix, flags);
break;
948 case 2: value = (T_bin)strtoint<T, uint16_t>(str, count, end, radix, flags);
break;
949 case 4: value = (T_bin)strtoint<T, uint32_t>(str, count, end, radix, flags);
break;
950 case 8: value = (T_bin)strtoint<T, uint64_t>(str, count, end, radix, flags);
break;
951 default:
throw std::invalid_argument(
"Unsupported bit length");
954 return (flags & 0x02) ?
955 (flags & 0x01) ? (T_bin)0 : (T_bin)-1 :
956 (flags & 0x01) ? ~value : value;
970 inline int32_t strto32(
971 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
972 _Out_opt_
size_t* end,
975 return strtoint<T, int32_t>(str, count, end, radix);
989 inline int64_t strto64(
990 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
991 _Out_opt_
size_t* end,
994 return strtoint<T, int64_t>(str, count, end, radix);
1009 inline intptr_t strtoi(
1010 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
1011 _Out_opt_
size_t* end,
1014#if defined(_WIN64) || defined(__LP64__)
1015 return (intptr_t)strto64(str, count, end, radix);
1017 return (intptr_t)strto32(str, count, end, radix);
1032 inline uint32_t strtou32(
1033 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
1034 _Out_opt_
size_t* end,
1037 return strtouint<T, uint32_t>(str, count, end, radix);
1051 inline uint64_t strtou64(
1052 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
1053 _Out_opt_
size_t* end,
1056 return strtouint<T, uint64_t>(str, count, end, radix);
1071 inline size_t strtoui(
1072 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
1073 _Out_opt_
size_t* end,
1076#if defined(_WIN64) || defined(__LP64__)
1077 return (
size_t)strtou64(str, count, end, radix);
1079 return (
size_t)strtou32(str, count, end, radix);
1084 inline int vsnprintf(_Out_z_cap_(capacity)
char *str, _In_
size_t capacity, _In_z_ _Printf_format_string_params_(2)
const char *format, _In_opt_ locale_t locale, _In_ va_list arg)
1089#pragma warning(suppress: 4996)
1090 r = _vsnprintf_l(str, capacity, format, locale, arg);
1092 r = ::vsnprintf(str, capacity, format, arg);
1094 if (r == -1 && strnlen(str, capacity) == capacity) {
1096 capacity += std::max<size_t>(capacity / 8, 0x80);
1097 if (capacity > INT_MAX)
1098 throw std::invalid_argument(
"string too big");
1099 return (
int)capacity;
1104 inline int vsnprintf(_Out_z_cap_(capacity)
wchar_t *str, _In_
size_t capacity, _In_z_ _Printf_format_string_params_(2)
const wchar_t *format, _In_opt_ locale_t locale, _In_ va_list arg)
1110#pragma warning(suppress: 4996)
1111 r = _vsnwprintf_l(str, capacity, format, locale, arg);
1113 r = vswprintf(str, capacity, format, arg);
1115 if (r == -1 && strnlen(str, capacity) == capacity) {
1117 capacity += std::max<size_t>(capacity / 8, 0x80);
1118 if (capacity > INT_MAX)
1119 throw std::invalid_argument(
"string too big");
1120 return (
int)capacity;
1134 template<
class _Elem,
class _Traits,
class _Ax>
1135 inline void vappendf(_Inout_ std::basic_string<_Elem, _Traits, _Ax> &str, _In_z_ _Printf_format_string_params_(2)
const _Elem *format, _In_opt_ locale_t locale, _In_ va_list arg)
1137 _Elem buf[1024/
sizeof(_Elem)];
1140 int count = vsnprintf(buf, _countof(buf) - 1, format, locale, arg);
1143 str.append(buf, count);
1145 for (
size_t capacity = 2*1024/
sizeof(_Elem);; capacity *= 2) {
1147 auto buf_dyn = std::make_unique<_Elem[]>(capacity);
1148 count = vsnprintf(buf_dyn.get(), capacity - 1, format, locale, arg);
1150 str.append(buf_dyn.get(), count);
1164 template<
class _Elem,
class _Traits,
class _Ax>
1165 inline void appendf(_Inout_ std::basic_string<_Elem, _Traits, _Ax> &str, _In_z_ _Printf_format_string_params_(2)
const _Elem *format, _In_opt_ locale_t locale, ...)
1168 va_start(arg, locale);
1169 vappendf(str, format, locale, arg);
1181 template<
class _Elem,
class _Traits,
class _Ax>
1182 inline void vsprintf(_Inout_ std::basic_string<_Elem, _Traits, _Ax> &str, _In_z_ _Printf_format_string_params_(2)
const _Elem *format, _In_opt_ locale_t locale, _In_ va_list arg)
1185 vappendf(str, format, locale, arg);
1195 template<
class _Elem,
class _Traits,
class _Ax>
1196 inline void sprintf(_Inout_ std::basic_string<_Elem, _Traits, _Ax> &str, _In_z_ _Printf_format_string_params_(2)
const _Elem *format, _In_opt_ locale_t locale, ...)
1199 va_start(arg, locale);
1200 vsprintf(str, format, locale, arg);
1213 template<
class _Elem,
class _Traits = std::
char_traits<_Elem>,
class _Ax = std::allocator<_Elem>>
1214 inline std::basic_string<_Elem, _Traits, _Ax> vsprintf(_In_z_ _Printf_format_string_params_(2)
const _Elem *format, _In_opt_ locale_t locale, _In_ va_list arg)
1216 std::basic_string<_Elem, _Traits, _Ax> str;
1217 vappendf(str, format, locale, arg);
1229 template<
class _Elem,
class _Traits = std::
char_traits<_Elem>,
class _Ax = std::allocator<_Elem>>
1230 inline std::basic_string<_Elem, _Traits, _Ax> sprintf(_In_z_ _Printf_format_string_params_(2)
const _Elem *format, _In_opt_ locale_t locale, ...)
1233 va_start(arg, locale);
1234 auto str = vsprintf(format, locale, arg);
Deleter for unique_ptr using free_locale.
Definition string.hpp:56
void operator()(locale_t locale) const
Delete a pointer.
Definition string.hpp:60