20 using locale_t = _locale_t;
22 inline locale_t create_locale(_In_
int category, _In_z_
const char* locale) {
return _create_locale(category, locale); }
23 inline locale_t create_locale(_In_
int category, _In_z_
const wchar_t* locale) {
return _wcreate_locale(category, locale); }
24 inline void free_locale(_In_opt_ _locale_t locale) { _free_locale(locale); }
26 using locale_t = ::locale_t;
46 using locale = std::unique_ptr<__crt_locale_pointers, free_locale_delete>;
51 static locale locale_C(_create_locale(LC_ALL,
"C"));
57 typedef wchar_t utf16_t;
59 typedef char16_t utf16_t;
67 inline bool is_high_surrogate(_In_ utf16_t chr)
69 return 0xd800 < chr && chr < 0xdc00;
77 inline bool is_low_surrogate(_In_ utf16_t chr)
79 return 0xdc00 < chr && chr < 0xe000;
87 inline bool is_surrogate_pair(_In_reads_(2)
const utf16_t* str)
89 return is_high_surrogate(str[0]) && is_low_surrogate(str[1]);
97 inline char32_t surrogate_pair_to_ucs4(_In_reads_(2)
const utf16_t* str)
99 assert(is_surrogate_pair(str));
101 ((
char32_t)(str[0] - 0xd800) << 10) +
102 (char32_t)(str[1] - 0xdc00) +
111 inline void ucs4_to_surrogate_pair(_Out_writes_(2) utf16_t* str, _In_
char32_t chr)
113 assert(chr >= 0x10000);
115 str[0] = 0xd800 + (char32_t)((chr >> 10) & 0x3ff);
116 str[1] = 0xdc00 + (char32_t)(chr & 0x3ff);
124 inline bool iscombining(_In_
char32_t chr)
127 0x0300 <= chr && chr < 0x0370 ||
128 0x1dc0 <= chr && chr < 0x1e00 ||
129 0x20d0 <= chr && chr < 0x2100 ||
130 0xfe20 <= chr && chr < 0xfe30;
139 inline size_t islbreak(_In_ T chr)
141 return chr ==
'\n' || chr ==
'\r';
151 inline size_t islbreak(_In_reads_or_z_opt_(count)
const T* chr, _In_
size_t count)
153 _Analysis_assume_(chr || !count);
154 if (count >= 2 && (chr[0] ==
'\r' && chr[1] ==
'\n' || chr[0] ==
'\n' && chr[1] ==
'\r'))
156 if (count > 1 && (chr[0] ==
'\n' || chr[0] ==
'\r'))
167 inline size_t glyphlen(_In_reads_or_z_opt_(count)
const wchar_t* glyph, _In_
size_t count)
169 _Analysis_assume_(glyph || !count);
172 size_t i = count < 2 || !is_surrogate_pair(glyph) ? 1 : 2;
176 for (; i < count && iscombining(glyph[i]); ++i);
190 inline size_t strlen(_In_z_
const T* str)
194 for (i = 0; str[i]; ++i);
207 inline size_t strnlen(_In_reads_or_z_opt_(count)
const T* str, _In_
size_t count)
209 assert(str || !count);
211 for (i = 0; i < count && str[i]; ++i);
215 constexpr auto npos{
static_cast<size_t>(-1) };
226 inline size_t strchr(_In_z_
const T* str, _In_ T chr)
229 for (
size_t i = 0; str[i]; ++i)
230 if (str[i] == chr)
return i;
244 inline size_t strnchr(
245 _In_reads_or_z_opt_(count)
const T* str,
249 assert(str || !count);
250 for (
size_t i = 0; i < count && str[i]; ++i)
251 if (str[i] == chr)
return i;
265 inline size_t strrnchr(
266 _In_reads_or_z_opt_(count)
const T* str,
270 assert(str || !count);
272 for (
size_t i = 0; i < count && str[i]; ++i)
273 if (str[i] == chr) z = i;
287 inline size_t strnichr(
288 _In_reads_or_z_opt_(count)
const T* str,
291 _In_
const std::locale& locale)
293 assert(str || !count);
294 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
295 chr = ctype.tolower(chr);
296 for (
size_t i = 0; i < count && str[i]; ++i)
297 if (ctype.tolower(str[i]) == chr)
return i;
311 inline size_t strrnichr(
312 _In_reads_or_z_opt_(count)
const T* str,
315 _In_
const std::locale& locale)
317 assert(str || !count);
318 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
319 chr = ctype.tolower(chr);
321 for (
size_t i = 0; i < count && str[i]; ++i)
322 if (ctype.tolower(str[i]) == chr) z = i;
336 template <
class T1,
class T2>
338 _In_reads_or_z_opt_(count1)
const T1* str1, _In_
size_t count1,
339 _In_reads_or_z_opt_(count2)
const T2* str2, _In_
size_t count2)
341 assert(str1 || !count1);
342 assert(str2 || !count2);
343 size_t i; T1 a; T2 b;
344 for (i = 0; i < count1 && i < count2 && ((a = str1[i]) | (b = str2[i])); ++i) {
345 if (a > b)
return +1;
346 if (a < b)
return -1;
348 if (i < count1 && str1[i])
return +1;
349 if (i < count2 && str2[i])
return -1;
365 _In_reads_or_z_opt_(count1)
const T* str1, _In_
size_t count1,
366 _In_reads_or_z_opt_(count2)
const T* str2, _In_
size_t count2,
367 _In_
const std::locale& locale)
369 assert(str1 || !count1);
370 assert(str2 || !count2);
371 auto& collate = std::use_facet<std::collate<T>>(locale);
372 return collate.compare(str1, str1 + count1, str2, str2 + count2);
385 template <
class T1,
class T2>
387 _In_reads_or_z_opt_(count1)
const T1* str1, _In_
size_t count1,
388 _In_reads_or_z_opt_(count2)
const T2* str2, _In_
size_t count2,
389 _In_
const std::locale& locale)
391 assert(str1 || !count1);
392 assert(str2 || !count2);
393 size_t i; T1 a; T2 b;
394 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
395 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
396 for (i = 0; i < count1 && i < count2 && ((a = ctype1.tolower(str1[i])) | (b = ctype2.tolower(str2[i]))); i++) {
397 if (a > b)
return +1;
398 if (a < b)
return -1;
400 if (i < count1 && str1[i])
return +1;
401 if (i < count2 && str2[i])
return -1;
413 template <
class T1,
class T2>
414 inline size_t strstr(
415 _In_z_
const T1* str,
416 _In_z_
const T2* sample)
420 for (
size_t offset = 0;; ++offset) {
421 for (
size_t i = offset, j = 0;; ++i, ++j) {
426 if (str[i] != sample[j])
441 template <
class T1,
class T2>
442 inline size_t strnstr(
443 _In_reads_or_z_opt_(count)
const T1* str,
445 _In_z_
const T2* sample)
447 assert(str || !count);
449 for (
size_t offset = 0;; ++offset) {
450 for (
size_t i = offset, j = 0;; ++i, ++j) {
453 if (i >= count || !str[i])
455 if (str[i] != sample[j])
469 template <
class T1,
class T2>
470 inline size_t stristr(
471 _In_z_
const T1* str,
472 _In_z_
const T2* sample,
473 _In_
const std::locale& locale)
477 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
478 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
479 for (
size_t offset = 0;; ++offset) {
480 for (
size_t i = offset, j = 0;; ++i, ++j) {
485 if (ctype1.tolower(str[i]) != ctype2.tolower(sample[j]))
500 template <
class T1,
class T2>
501 inline size_t strnistr(
502 _In_reads_or_z_opt_(count)
const T1* str,
504 _In_z_
const T2* sample,
505 _In_
const std::locale& locale)
507 assert(str || !count);
509 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
510 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
511 for (
size_t offset = 0;; ++offset) {
512 for (
size_t i = offset, j = 0;; ++i, ++j) {
515 if (i >= count || !str[i])
517 if (ctype1.tolower(str[i]) != ctype2.tolower(sample[j]))
531 template <
class T1,
class T2>
532 inline size_t strcpy(
533 _Out_writes_z_(_String_length_(src) + 1) T1* dst,
534 _In_z_
const T2* src)
537 for (
size_t i = 0; ; ++i) {
538 if ((dst[i] = src[i]) == 0)
552 template <
class T1,
class T2>
553 inline size_t strncpy(
554 _Out_writes_(count) _Post_maybez_ T1* dst,
555 _In_reads_or_z_opt_(count)
const T2* src, _In_
size_t count)
557 assert(dst && src || !count);
558 for (
size_t i = 0; ; ++i) {
561 if ((dst[i] = src[i]) == 0)
576 template <
class T1,
class T2>
577 inline size_t strncpy(
578 _Out_writes_(count_dst) _Post_maybez_ T1* dst, _In_
size_t count_dst,
579 _In_reads_or_z_opt_(count_src)
const T2* src, _In_
size_t count_src)
581 assert(dst || !count_dst);
582 assert(src || !count_src);
583 for (
size_t i = 0; ; ++i)
591 if ((dst[i] = src[i]) == 0)
604 template <
class T1,
class T2>
605 inline size_t strcat(
606 _In_z_ _Out_writes_z_(_String_length_(dst) + _String_length_(src) + 1) T1* dst,
607 _In_z_
const T2* src)
610 for (
size_t i = 0, j = stdex::strlen<T1>(dst); ; ++i, ++j) {
611 if ((dst[j] = src[i]) == 0)
625 template <
class T1,
class T2>
626 inline size_t strncat(
627 _Out_writes_(count) _Post_maybez_ T1* dst,
628 _In_reads_or_z_opt_(count)
const T2* src, _In_
size_t count)
630 assert(dst && src || !count);
631 for (
size_t i = 0, j = stdex::strlen<T1>(dst); ; ++i, ++j) {
634 if ((dst[j] = src[i]) == 0)
649 template <
class T1,
class T2>
650 inline size_t strncat(
651 _Out_writes_(count_dst) _Post_maybez_ T1* dst, _In_
size_t count_dst,
652 _In_reads_or_z_opt_(count_src)
const T2* src, _In_
size_t count_src)
654 assert(dst || !count_dst);
655 assert(src || !count_src);
656 for (
size_t i = 0, j = stdex::strnlen<T1>(dst, count_dst); ; ++i, ++j)
664 if ((dst[j] = src[i]) == 0)
680 inline _Check_return_ _Ret_maybenull_z_ T* strdup(_In_opt_z_
const T* str)
684 size_t count = strlen(str) + 1;
685 T* dst =
new T[count];
686 strncpy(dst, count, str, SIZE_MAX);
702 inline _Ret_z_ T* strndup(
703 _In_reads_or_z_opt_(count)
const T* str,
706 T* dst =
new T[count];
707 strncpy(dst, count, str, SIZE_MAX);
721 inline size_t crlf2nl(_Out_writes_z_(strlen(src)) T* dst, _In_z_
const T* src)
726 for (i = j = 0; src[j];) {
727 if (src[j] !=
'\r' || src[j + 1] !=
'\n')
739 template <
class T,
class T_bin>
740 inline T_bin strtoint(
741 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
742 _Out_opt_
size_t* end,
744 _Out_ uint8_t& flags)
746 assert(str || !count);
747 assert(radix == 0 || 2 <= radix && radix <= 36);
750 T_bin value = 0, digit,
752 max_ui_pre1, max_ui_pre2;
758 if (i >= count || !str[i])
goto error;
759 if (!isspace(str[i]))
break;
766 if (i >= count || !str[i])
goto error;
768 else if (str[i] ==
'-') {
771 if (i >= count || !str[i])
goto error;
776 if (str[i] ==
'0' && i + 1 < count && (str[i + 1] ==
'x' || str[i + 1] ==
'X')) {
778 if (i >= count || !str[i])
goto error;
785 if (i >= count || !str[i])
goto error;
786 if (str[i] ==
'x' || str[i] ==
'X') {
789 if (i >= count || !str[i])
goto error;
799 max_ui_pre1 = max_ui / (T_bin)radix;
800 max_ui_pre2 = max_ui % (T_bin)radix;
802 if (
'0' <= str[i] && str[i] <=
'9')
803 digit = (T_bin)str[i] -
'0';
804 else if (
'A' <= str[i] && str[i] <=
'Z')
805 digit = (T_bin)str[i] -
'A' +
'\x0a';
806 else if (
'a' <= str[i] && str[i] <=
'z')
807 digit = (T_bin)str[i] -
'a' +
'\x0a';
810 if (digit >= (T_bin)radix)
813 if (value < max_ui_pre1 ||
814 value == max_ui_pre1 && digit <= max_ui_pre2)
815 value = value * (T_bin)radix + digit;
822 if (i >= count || !str[i])
842 template <
class T,
class T_bin>
844 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
845 _Out_opt_
size_t* end,
851 switch (
sizeof(T_bin)) {
853 value = (T_bin)strtoint<T, uint8_t>(str, count, end, radix, flags);
854 if ((flags & 0x01) && (value & 0x80)) {
858 return (flags & 0x02) ?
859 (flags & 0x01) ? (T_bin)0x80 : (T_bin)0x7f :
860 (flags & 0x01) ? -value : value;
863 value = (T_bin)strtoint<T, uint16_t>(str, count, end, radix, flags);
864 if ((flags & 0x01) && (value & 0x8000)) {
868 return (flags & 0x02) ?
869 (flags & 0x01) ? (T_bin)0x8000 : (T_bin)0x7fff :
870 (flags & 0x01) ? -value : value;
873 value = (T_bin)strtoint<T, uint32_t>(str, count, end, radix, flags);
874 if ((flags & 0x01) && (value & 0x80000000)) {
878 return (flags & 0x02) ?
879 (flags & 0x01) ? (T_bin)0x80000000 : (T_bin)0x7fffffff :
880 (flags & 0x01) ? -value : value;
883 value = (T_bin)strtoint<T, uint64_t>(str, count, end, radix, flags);
884 if ((flags & 0x01) && (value & 0x8000000000000000)) {
888 return (flags & 0x02) ?
889 (flags & 0x01) ? (T_bin)0x8000000000000000 : (T_bin)0x7fffffffffffffff :
890 (flags & 0x01) ? -value : value;
893 throw std::invalid_argument(
"Unsupported bit length");
907 template <
class T,
class T_bin>
908 inline T_bin strtouint(
909 _In_reads_or_z_opt_(count)
const T* str,
911 _Out_opt_
size_t* end,
917 switch (
sizeof(T_bin)) {
918 case 1: value = (T_bin)strtoint<T, uint8_t>(str, count, end, radix, flags);
break;
919 case 2: value = (T_bin)strtoint<T, uint16_t>(str, count, end, radix, flags);
break;
920 case 4: value = (T_bin)strtoint<T, uint32_t>(str, count, end, radix, flags);
break;
921 case 8: value = (T_bin)strtoint<T, uint64_t>(str, count, end, radix, flags);
break;
922 default:
throw std::invalid_argument(
"Unsupported bit length");
925 return (flags & 0x02) ?
926 (flags & 0x01) ? (T_bin)0 : (T_bin)-1 :
927 (flags & 0x01) ? ~value : value;
941 inline int32_t strto32(
942 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
943 _Out_opt_
size_t* end,
946 return strtoint<T, int32_t>(str, count, end, radix);
960 inline int64_t strto64(
961 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
962 _Out_opt_
size_t* end,
965 return strtoint<T, int64_t>(str, count, end, radix);
980 inline intptr_t strtoi(
981 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
982 _Out_opt_
size_t* end,
985#if defined(_WIN64) || defined(__LP64__)
986 return (intptr_t)strto64(str, count, end, radix);
988 return (intptr_t)strto32(str, count, end, radix);
1003 inline uint32_t strtou32(
1004 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
1005 _Out_opt_
size_t* end,
1008 return strtouint<T, uint32_t>(str, count, end, radix);
1022 inline uint64_t strtou64(
1023 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
1024 _Out_opt_
size_t* end,
1027 return strtouint<T, uint64_t>(str, count, end, radix);
1042 inline size_t strtoui(
1043 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
1044 _Out_opt_
size_t* end,
1047#if defined(_WIN64) || defined(__LP64__)
1048 return (
size_t)strtou64(str, count, end, radix);
1050 return (
size_t)strtou32(str, count, end, radix);
1055 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)
1060#pragma warning(suppress: 4996)
1061 r = _vsnprintf_l(str, capacity, format, locale, arg);
1063 r = vsnprintf(str, capacity, format, arg);
1065 if (r == -1 && strnlen(str, capacity) == capacity) {
1067 capacity += std::max<size_t>(capacity / 8, 0x80);
1068 if (capacity > INT_MAX)
1069 throw std::invalid_argument(
"string too big");
1070 return (
int)capacity;
1075 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)
1081#pragma warning(suppress: 4996)
1082 r = _vsnwprintf_l(str, capacity, format, locale, arg);
1084 r = vswprintf(str, capacity, format, arg);
1086 if (r == -1 && strnlen(str, capacity) == capacity) {
1088 capacity += std::max<size_t>(capacity / 8, 0x80);
1089 if (capacity > INT_MAX)
1090 throw std::invalid_argument(
"string too big");
1091 return (
int)capacity;
1105 template<
class _Elem,
class _Traits,
class _Ax>
1106 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)
1108 _Elem buf[1024/
sizeof(_Elem)];
1111 int count = vsnprintf(buf, _countof(buf) - 1, format, locale, arg);
1114 str.append(buf, count);
1116 for (
size_t capacity = 2*1024/
sizeof(_Elem);; capacity *= 2) {
1118 auto buf_dyn = std::make_unique<_Elem[]>(capacity);
1119 count = vsnprintf(buf_dyn.get(), capacity - 1, format, locale, arg);
1121 str.append(buf_dyn.get(), count);
1135 template<
class _Elem,
class _Traits,
class _Ax>
1136 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, ...)
1139 va_start(arg, locale);
1140 vappendf(str, format, locale, arg);
1152 template<
class _Elem,
class _Traits,
class _Ax>
1153 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)
1156 vappendf(str, format, locale, arg);
1166 template<
class _Elem,
class _Traits,
class _Ax>
1167 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, ...)
1170 va_start(arg, locale);
1171 vsprintf(str, format, locale, arg);
1184 template<
class _Elem,
class _Traits = std::
char_traits<_Elem>,
class _Ax = std::allocator<_Elem>>
1185 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)
1187 std::basic_string<_Elem, _Traits, _Ax> str;
1188 vappendf(str, format, locale, arg);
1200 template<
class _Elem,
class _Traits = std::
char_traits<_Elem>,
class _Ax = std::allocator<_Elem>>
1201 inline std::basic_string<_Elem, _Traits, _Ax> sprintf(_In_z_ _Printf_format_string_params_(2)
const _Elem *format, _In_opt_ locale_t locale, ...)
1204 va_start(arg, locale);
1205 auto str = vsprintf(format, locale, arg);
Deleter for unique_ptr using free_locale.
Definition string.hpp:33
void operator()(locale_t locale) const
Delete a pointer.
Definition string.hpp:37