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;
57 using locale = std::unique_ptr<__crt_locale_pointers, free_locale_delete>;
58#elif defined(__APPLE__)
59 using locale = std::unique_ptr<struct _xlocale, free_locale_delete>;
61 using locale = std::unique_ptr<struct __locale_struct, free_locale_delete>;
68 static locale locale_C(_create_locale(LC_ALL,
"C"));
69#elif defined(__APPLE__)
70 static locale locale_C(newlocale(LC_ALL_MASK,
"C", LC_GLOBAL_LOCALE));
79 typedef wchar_t utf16_t;
81 typedef char16_t utf16_t;
89 inline bool is_high_surrogate(_In_ utf16_t chr)
91 return 0xd800 < chr && chr < 0xdc00;
99 inline bool is_low_surrogate(_In_ utf16_t chr)
101 return 0xdc00 < chr && chr < 0xe000;
109 inline bool is_surrogate_pair(_In_reads_(2)
const utf16_t* str)
111 return is_high_surrogate(str[0]) && is_low_surrogate(str[1]);
119 inline char32_t surrogate_pair_to_ucs4(_In_reads_(2)
const utf16_t* str)
121 assert(is_surrogate_pair(str));
123 ((
char32_t)(str[0] - 0xd800) << 10) +
124 (char32_t)(str[1] - 0xdc00) +
133 inline void ucs4_to_surrogate_pair(_Out_writes_(2) utf16_t* str, _In_
char32_t chr)
135 assert(chr >= 0x10000);
137 str[0] = 0xd800 + (char32_t)((chr >> 10) & 0x3ff);
138 str[1] = 0xdc00 + (char32_t)(chr & 0x3ff);
146 inline bool iscombining(_In_
char32_t chr)
149 (0x0300 <= chr && chr < 0x0370) ||
150 (0x1dc0 <= chr && chr < 0x1e00) ||
151 (0x20d0 <= chr && chr < 0x2100) ||
152 (0xfe20 <= chr && chr < 0xfe30);
161 inline size_t islbreak(_In_ T chr)
163 return chr ==
'\n' || chr ==
'\r';
173 inline size_t islbreak(_In_reads_or_z_opt_(count)
const T* chr, _In_
size_t count)
175 _Analysis_assume_(chr || !count);
176 if (count >= 2 && ((chr[0] ==
'\r' && chr[1] ==
'\n') || (chr[0] ==
'\n' && chr[1] ==
'\r')))
178 if (count > 1 && (chr[0] ==
'\n' || chr[0] ==
'\r'))
189 inline size_t glyphlen(_In_reads_or_z_opt_(count)
const wchar_t* glyph, _In_
size_t count)
191 _Analysis_assume_(glyph || !count);
194 size_t i = count < 2 || !is_surrogate_pair(glyph) ? 1 : 2;
198 for (; i < count && iscombining(glyph[i]); ++i);
212 inline size_t strlen(_In_z_
const T* str)
216 for (i = 0; str[i]; ++i);
229 inline size_t strnlen(_In_reads_or_z_opt_(count)
const T* str, _In_
size_t count)
231 assert(str || !count);
233 for (i = 0; i < count && str[i]; ++i);
237 constexpr auto npos{
static_cast<size_t>(-1) };
248 inline size_t strchr(_In_z_
const T* str, _In_ T chr)
251 for (
size_t i = 0; str[i]; ++i)
252 if (str[i] == chr)
return i;
266 inline size_t strnchr(
267 _In_reads_or_z_opt_(count)
const T* str,
271 assert(str || !count);
272 for (
size_t i = 0; i < count && str[i]; ++i)
273 if (str[i] == chr)
return i;
287 inline size_t strrnchr(
288 _In_reads_or_z_opt_(count)
const T* str,
292 assert(str || !count);
294 for (
size_t i = 0; i < count && str[i]; ++i)
295 if (str[i] == chr) z = i;
309 inline size_t strnichr(
310 _In_reads_or_z_opt_(count)
const T* str,
313 _In_
const std::locale& locale)
315 assert(str || !count);
316 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
317 chr = ctype.tolower(chr);
318 for (
size_t i = 0; i < count && str[i]; ++i)
319 if (ctype.tolower(str[i]) == chr)
return i;
333 inline size_t strrnichr(
334 _In_reads_or_z_opt_(count)
const T* str,
337 _In_
const std::locale& locale)
339 assert(str || !count);
340 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
341 chr = ctype.tolower(chr);
343 for (
size_t i = 0; i < count && str[i]; ++i)
344 if (ctype.tolower(str[i]) == chr) z = i;
358 template <
class T1,
class T2>
360 _In_reads_or_z_opt_(count1)
const T1* str1, _In_
size_t count1,
361 _In_reads_or_z_opt_(count2)
const T2* str2, _In_
size_t count2)
363 assert(str1 || !count1);
364 assert(str2 || !count2);
365 size_t i; T1 a; T2 b;
366 for (i = 0; i < count1 && i < count2 && ((a = str1[i]) | (b = str2[i])); ++i) {
367 if (a > b)
return +1;
368 if (a < b)
return -1;
370 if (i < count1 && str1[i])
return +1;
371 if (i < count2 && str2[i])
return -1;
387 _In_reads_or_z_opt_(count1)
const T* str1, _In_
size_t count1,
388 _In_reads_or_z_opt_(count2)
const T* str2, _In_
size_t count2,
389 _In_
const std::locale& locale)
391 assert(str1 || !count1);
392 assert(str2 || !count2);
393 auto& collate = std::use_facet<std::collate<T>>(locale);
394 return collate.compare(str1, str1 + count1, str2, str2 + count2);
407 template <
class T1,
class T2>
409 _In_reads_or_z_opt_(count1)
const T1* str1, _In_
size_t count1,
410 _In_reads_or_z_opt_(count2)
const T2* str2, _In_
size_t count2,
411 _In_
const std::locale& locale)
413 assert(str1 || !count1);
414 assert(str2 || !count2);
415 size_t i; T1 a; T2 b;
416 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
417 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
418 for (i = 0; i < count1 && i < count2 && ((a = ctype1.tolower(str1[i])) | (b = ctype2.tolower(str2[i]))); i++) {
419 if (a > b)
return +1;
420 if (a < b)
return -1;
422 if (i < count1 && str1[i])
return +1;
423 if (i < count2 && str2[i])
return -1;
435 template <
class T1,
class T2>
436 inline size_t strstr(
437 _In_z_
const T1* str,
438 _In_z_
const T2* sample)
442 for (
size_t offset = 0;; ++offset) {
443 for (
size_t i = offset, j = 0;; ++i, ++j) {
448 if (str[i] != sample[j])
463 template <
class T1,
class T2>
464 inline size_t strnstr(
465 _In_reads_or_z_opt_(count)
const T1* str,
467 _In_z_
const T2* sample)
469 assert(str || !count);
471 for (
size_t offset = 0;; ++offset) {
472 for (
size_t i = offset, j = 0;; ++i, ++j) {
475 if (i >= count || !str[i])
477 if (str[i] != sample[j])
491 template <
class T1,
class T2>
492 inline size_t stristr(
493 _In_z_
const T1* str,
494 _In_z_
const T2* sample,
495 _In_
const std::locale& locale)
499 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
500 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
501 for (
size_t offset = 0;; ++offset) {
502 for (
size_t i = offset, j = 0;; ++i, ++j) {
507 if (ctype1.tolower(str[i]) != ctype2.tolower(sample[j]))
522 template <
class T1,
class T2>
523 inline size_t strnistr(
524 _In_reads_or_z_opt_(count)
const T1* str,
526 _In_z_
const T2* sample,
527 _In_
const std::locale& locale)
529 assert(str || !count);
531 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
532 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
533 for (
size_t offset = 0;; ++offset) {
534 for (
size_t i = offset, j = 0;; ++i, ++j) {
537 if (i >= count || !str[i])
539 if (ctype1.tolower(str[i]) != ctype2.tolower(sample[j]))
553 template <
class T1,
class T2>
554 inline size_t strcpy(
555 _Out_writes_z_(_String_length_(src) + 1) T1* dst,
556 _In_z_
const T2* src)
559 for (
size_t i = 0; ; ++i) {
560 if ((dst[i] = src[i]) == 0)
574 template <
class T1,
class T2>
575 inline size_t strncpy(
576 _Out_writes_(count) _Post_maybez_ T1* dst,
577 _In_reads_or_z_opt_(count)
const T2* src, _In_
size_t count)
579 assert(dst && src || !count);
580 for (
size_t i = 0; ; ++i) {
583 if ((dst[i] = src[i]) == 0)
598 template <
class T1,
class T2>
599 inline size_t strncpy(
600 _Out_writes_(count_dst) _Post_maybez_ T1* dst, _In_
size_t count_dst,
601 _In_reads_or_z_opt_(count_src)
const T2* src, _In_
size_t count_src)
603 assert(dst || !count_dst);
604 assert(src || !count_src);
605 for (
size_t i = 0; ; ++i)
613 if ((dst[i] = src[i]) == 0)
626 template <
class T1,
class T2>
627 inline size_t strcat(
628 _In_z_ _Out_writes_z_(_String_length_(dst) + _String_length_(src) + 1) T1* dst,
629 _In_z_
const T2* src)
632 for (
size_t i = 0, j = stdex::strlen<T1>(dst); ; ++i, ++j) {
633 if ((dst[j] = src[i]) == 0)
647 template <
class T1,
class T2>
648 inline size_t strncat(
649 _Out_writes_(count) _Post_maybez_ T1* dst,
650 _In_reads_or_z_opt_(count)
const T2* src, _In_
size_t count)
652 assert(dst && src || !count);
653 for (
size_t i = 0, j = stdex::strlen<T1>(dst); ; ++i, ++j) {
656 if ((dst[j] = src[i]) == 0)
671 template <
class T1,
class T2>
672 inline size_t strncat(
673 _Out_writes_(count_dst) _Post_maybez_ T1* dst, _In_
size_t count_dst,
674 _In_reads_or_z_opt_(count_src)
const T2* src, _In_
size_t count_src)
676 assert(dst || !count_dst);
677 assert(src || !count_src);
678 for (
size_t i = 0, j = stdex::strnlen<T1>(dst, count_dst); ; ++i, ++j)
686 if ((dst[j] = src[i]) == 0)
702 inline _Check_return_ _Ret_maybenull_z_ T* strdup(_In_opt_z_
const T* str)
706 size_t count = strlen(str) + 1;
707 T* dst =
new T[count];
708 strncpy(dst, count, str, SIZE_MAX);
724 inline _Ret_z_ T* strndup(
725 _In_reads_or_z_opt_(count)
const T* str,
728 T* dst =
new T[count];
729 strncpy(dst, count, str, SIZE_MAX);
743 inline size_t crlf2nl(_Out_writes_z_(strlen(src)) T* dst, _In_z_
const T* src)
748 for (i = j = 0; src[j];) {
749 if (src[j] !=
'\r' || src[j + 1] !=
'\n')
761 template <
class T,
class T_bin>
762 inline T_bin strtoint(
763 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
764 _Out_opt_
size_t* end,
766 _Out_ uint8_t& flags)
768 assert(str || !count);
769 assert(radix == 0 || 2 <= radix && radix <= 36);
772 T_bin value = 0, digit,
774 max_ui_pre1, max_ui_pre2;
780 if (i >= count || !str[i])
goto error;
781 if (!isspace(str[i]))
break;
788 if (i >= count || !str[i])
goto error;
790 else if (str[i] ==
'-') {
793 if (i >= count || !str[i])
goto error;
798 if (str[i] ==
'0' && i + 1 < count && (str[i + 1] ==
'x' || str[i + 1] ==
'X')) {
800 if (i >= count || !str[i])
goto error;
807 if (i >= count || !str[i])
goto error;
808 if (str[i] ==
'x' || str[i] ==
'X') {
811 if (i >= count || !str[i])
goto error;
821 max_ui_pre1 = max_ui / (T_bin)radix;
822 max_ui_pre2 = max_ui % (T_bin)radix;
824 if (
'0' <= str[i] && str[i] <=
'9')
825 digit = (T_bin)str[i] -
'0';
826 else if (
'A' <= str[i] && str[i] <=
'Z')
827 digit = (T_bin)str[i] -
'A' +
'\x0a';
828 else if (
'a' <= str[i] && str[i] <=
'z')
829 digit = (T_bin)str[i] -
'a' +
'\x0a';
832 if (digit >= (T_bin)radix)
835 if (value < max_ui_pre1 ||
836 (value == max_ui_pre1 && digit <= max_ui_pre2))
837 value = value * (T_bin)radix + digit;
844 if (i >= count || !str[i])
864 template <
class T,
class T_bin>
866 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
867 _Out_opt_
size_t* end,
873 switch (
sizeof(T_bin)) {
875 value = (T_bin)strtoint<T, uint8_t>(str, count, end, radix, flags);
876 if ((flags & 0x01) && (value & 0x80)) {
880 return (flags & 0x02) ?
881 (flags & 0x01) ? (T_bin)0x80 : (T_bin)0x7f :
882 (flags & 0x01) ? -value : value;
885 value = (T_bin)strtoint<T, uint16_t>(str, count, end, radix, flags);
886 if ((flags & 0x01) && (value & 0x8000)) {
890 return (flags & 0x02) ?
891 (flags & 0x01) ? (T_bin)0x8000 : (T_bin)0x7fff :
892 (flags & 0x01) ? -value : value;
895 value = (T_bin)strtoint<T, uint32_t>(str, count, end, radix, flags);
896 if ((flags & 0x01) && (value & 0x80000000)) {
900 return (flags & 0x02) ?
901 (flags & 0x01) ? (T_bin)0x80000000 : (T_bin)0x7fffffff :
902 (flags & 0x01) ? -value : value;
905 value = (T_bin)strtoint<T, uint64_t>(str, count, end, radix, flags);
906 if ((flags & 0x01) && (value & 0x8000000000000000)) {
910 return (flags & 0x02) ?
911 (flags & 0x01) ? (T_bin)0x8000000000000000 : (T_bin)0x7fffffffffffffff :
912 (flags & 0x01) ? -value : value;
915 throw std::invalid_argument(
"Unsupported bit length");
929 template <
class T,
class T_bin>
930 inline T_bin strtouint(
931 _In_reads_or_z_opt_(count)
const T* str,
933 _Out_opt_
size_t* end,
939 switch (
sizeof(T_bin)) {
940 case 1: value = (T_bin)strtoint<T, uint8_t>(str, count, end, radix, flags);
break;
941 case 2: value = (T_bin)strtoint<T, uint16_t>(str, count, end, radix, flags);
break;
942 case 4: value = (T_bin)strtoint<T, uint32_t>(str, count, end, radix, flags);
break;
943 case 8: value = (T_bin)strtoint<T, uint64_t>(str, count, end, radix, flags);
break;
944 default:
throw std::invalid_argument(
"Unsupported bit length");
947 return (flags & 0x02) ?
948 (flags & 0x01) ? (T_bin)0 : (T_bin)-1 :
949 (flags & 0x01) ? ~value : value;
963 inline int32_t strto32(
964 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
965 _Out_opt_
size_t* end,
968 return strtoint<T, int32_t>(str, count, end, radix);
982 inline int64_t strto64(
983 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
984 _Out_opt_
size_t* end,
987 return strtoint<T, int64_t>(str, count, end, radix);
1002 inline intptr_t strtoi(
1003 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
1004 _Out_opt_
size_t* end,
1007#if defined(_WIN64) || defined(__LP64__)
1008 return (intptr_t)strto64(str, count, end, radix);
1010 return (intptr_t)strto32(str, count, end, radix);
1025 inline uint32_t strtou32(
1026 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
1027 _Out_opt_
size_t* end,
1030 return strtouint<T, uint32_t>(str, count, end, radix);
1044 inline uint64_t strtou64(
1045 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
1046 _Out_opt_
size_t* end,
1049 return strtouint<T, uint64_t>(str, count, end, radix);
1064 inline size_t strtoui(
1065 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
1066 _Out_opt_
size_t* end,
1069#if defined(_WIN64) || defined(__LP64__)
1070 return (
size_t)strtou64(str, count, end, radix);
1072 return (
size_t)strtou32(str, count, end, radix);
1077 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)
1082#pragma warning(suppress: 4996)
1083 r = _vsnprintf_l(str, capacity, format, locale, arg);
1085 r = ::vsnprintf(str, capacity, format, arg);
1087 if (r == -1 && strnlen(str, capacity) == capacity) {
1089 capacity += std::max<size_t>(capacity / 8, 0x80);
1090 if (capacity > INT_MAX)
1091 throw std::invalid_argument(
"string too big");
1092 return (
int)capacity;
1097 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)
1103#pragma warning(suppress: 4996)
1104 r = _vsnwprintf_l(str, capacity, format, locale, arg);
1106 r = vswprintf(str, capacity, format, arg);
1108 if (r == -1 && strnlen(str, capacity) == capacity) {
1110 capacity += std::max<size_t>(capacity / 8, 0x80);
1111 if (capacity > INT_MAX)
1112 throw std::invalid_argument(
"string too big");
1113 return (
int)capacity;
1127 template<
class _Elem,
class _Traits,
class _Ax>
1128 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)
1130 _Elem buf[1024/
sizeof(_Elem)];
1133 int count = vsnprintf(buf, _countof(buf) - 1, format, locale, arg);
1136 str.append(buf, count);
1138 for (
size_t capacity = 2*1024/
sizeof(_Elem);; capacity *= 2) {
1140 auto buf_dyn = std::make_unique<_Elem[]>(capacity);
1141 count = vsnprintf(buf_dyn.get(), capacity - 1, format, locale, arg);
1143 str.append(buf_dyn.get(), count);
1157 template<
class _Elem,
class _Traits,
class _Ax>
1158 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, ...)
1161 va_start(arg, locale);
1162 vappendf(str, format, locale, arg);
1174 template<
class _Elem,
class _Traits,
class _Ax>
1175 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)
1178 vappendf(str, format, locale, arg);
1188 template<
class _Elem,
class _Traits,
class _Ax>
1189 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, ...)
1192 va_start(arg, locale);
1193 vsprintf(str, format, locale, arg);
1206 template<
class _Elem,
class _Traits = std::
char_traits<_Elem>,
class _Ax = std::allocator<_Elem>>
1207 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)
1209 std::basic_string<_Elem, _Traits, _Ax> str;
1210 vappendf(str, format, locale, arg);
1222 template<
class _Elem,
class _Traits = std::
char_traits<_Elem>,
class _Ax = std::allocator<_Elem>>
1223 inline std::basic_string<_Elem, _Traits, _Ax> sprintf(_In_z_ _Printf_format_string_params_(2)
const _Elem *format, _In_opt_ locale_t locale, ...)
1226 va_start(arg, locale);
1227 auto str = vsprintf(format, locale, arg);
Deleter for unique_ptr using free_locale.
Definition string.hpp:39
void operator()(locale_t locale) const
Delete a pointer.
Definition string.hpp:43