18 using locale_t = _locale_t;
20 using locale_t = ::locale_t;
27 typedef wchar_t utf16_t;
29 typedef char16_t utf16_t;
37 inline bool is_high_surrogate(_In_ utf16_t chr)
39 return 0xd800 < chr && chr < 0xdc00;
47 inline bool is_low_surrogate(_In_ utf16_t chr)
49 return 0xdc00 < chr && chr < 0xe000;
57 inline bool is_surrogate_pair(_In_reads_(2)
const utf16_t* str)
59 return is_high_surrogate(str[0]) && is_low_surrogate(str[1]);
67 inline char32_t surrogate_pair_to_ucs4(_In_reads_(2)
const utf16_t* str)
69 assert(is_surrogate_pair(str));
71 ((
char32_t)(str[0] - 0xd800) << 10) +
72 (char32_t)(str[1] - 0xdc00) +
81 inline void ucs4_to_surrogate_pair(_Out_writes_(2) utf16_t* str, _In_
char32_t chr)
83 assert(chr >= 0x10000);
85 str[0] = 0xd800 + (char32_t)((chr >> 10) & 0x3ff);
86 str[1] = 0xdc00 + (char32_t)(chr & 0x3ff);
94 inline bool iscombining(_In_
char32_t chr)
97 0x0300 <= chr && chr < 0x0370 ||
98 0x1dc0 <= chr && chr < 0x1e00 ||
99 0x20d0 <= chr && chr < 0x2100 ||
100 0xfe20 <= chr && chr < 0xfe30;
109 inline size_t islbreak(_In_ T chr)
111 return chr ==
'\n' || chr ==
'\r';
121 inline size_t islbreak(_In_reads_or_z_opt_(count)
const T* chr, _In_
size_t count)
123 _Analysis_assume_(chr || !count);
124 if (count >= 2 && (chr[0] ==
'\r' && chr[1] ==
'\n' || chr[0] ==
'\n' && chr[1] ==
'\r'))
126 if (count > 1 && (chr[0] ==
'\n' || chr[0] ==
'\r'))
137 inline size_t glyphlen(_In_reads_or_z_opt_(count)
const wchar_t* glyph,
size_t count)
139 _Analysis_assume_(glyph || !count);
142 size_t i = count < 2 || !is_surrogate_pair(glyph) ? 1 : 2;
146 for (; i < count && iscombining(glyph[i]); ++i);
160 inline size_t strlen(_In_z_
const T* str)
164 for (i = 0; str[i]; ++i);
177 inline size_t strnlen(_In_reads_or_z_opt_(count)
const T* str, _In_
size_t count)
181 for (i = 0; i < count && str[i]; ++i);
185 constexpr auto npos{
static_cast<size_t>(-1) };
197 inline size_t strnchr(
198 _In_reads_or_z_opt_(count)
const T* str,
202 assert(str || !count);
203 for (
size_t i = 0; i < count && str[i]; ++i)
204 if (str[i] == chr)
return i;
218 inline size_t strrnchr(
219 _In_reads_or_z_opt_(count)
const T* str,
223 assert(str || !count);
225 for (
size_t i = 0; i < count && str[i]; ++i)
226 if (str[i] == chr) z = i;
240 inline size_t strnichr(
241 _In_reads_or_z_opt_(count)
const T* str,
244 _In_
const std::locale& locale)
246 assert(str || !count);
247 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
248 chr = ctype.tolower(chr);
249 for (
size_t i = 0; i < count && str[i]; ++i)
250 if (ctype.tolower(str[i]) == chr)
return i;
264 inline size_t strrnichr(
265 _In_reads_or_z_opt_(count)
const T* str,
268 _In_
const std::locale& locale)
270 assert(str || !count);
271 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
272 chr = ctype.tolower(chr);
274 for (
size_t i = 0; i < count && str[i]; ++i)
275 if (ctype.tolower(str[i]) == chr) z = i;
289 template <
class T1,
class T2>
291 _In_reads_or_z_opt_(count1)
const T1* str1, _In_
size_t count1,
292 _In_reads_or_z_opt_(count2)
const T2* str2, _In_
size_t count2)
294 assert(str1 || !count1);
295 assert(str2 || !count2);
296 size_t i; T1 a; T2 b;
297 for (i = 0; i < count1 && i < count2 && ((a = str1[i]) | (b = str2[i])); ++i) {
298 if (a > b)
return +1;
299 if (a < b)
return -1;
301 if (i < count1 && str1[i])
return +1;
302 if (i < count2 && str2[i])
return -1;
318 _In_reads_or_z_opt_(count1)
const T* str1, _In_
size_t count1,
319 _In_reads_or_z_opt_(count2)
const T* str2, _In_
size_t count2,
320 _In_
const std::locale& locale)
322 assert(str1 || !count1);
323 assert(str2 || !count2);
324 auto& collate = std::use_facet<std::collate<T>>(locale);
325 return collate.compare(str1, str1 + count1, str2, str2 + count2);
338 template <
class T1,
class T2>
340 _In_reads_or_z_opt_(count1)
const T1* str1, _In_
size_t count1,
341 _In_reads_or_z_opt_(count2)
const T2* str2, _In_
size_t count2,
342 _In_
const std::locale& locale)
344 assert(str1 || !count1);
345 assert(str2 || !count2);
346 size_t i; T1 a; T2 b;
347 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
348 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
349 for (i = 0; i < count1 && i < count2 && ((a = ctype1.tolower(str1[i])) | (b = ctype2.tolower(str2[i]))); i++) {
350 if (a > b)
return +1;
351 if (a < b)
return -1;
353 if (i < count1 && str1[i])
return +1;
354 if (i < count2 && str2[i])
return -1;
367 template <
class T1,
class T2>
368 inline size_t strnstr(
369 _In_reads_or_z_opt_(count)
const T1* str,
371 _In_z_
const T2* sample)
373 assert(str || !count);
375 for (
size_t offset = 0;; ++offset) {
376 for (
size_t i = offset, j = 0;; ++i, ++j) {
379 if (i >= count || !str[i])
381 if (str[i] != sample[j])
396 template <
class T1,
class T2>
397 inline size_t strnistr(
398 _In_reads_or_z_opt_(count)
const T1* str,
400 _In_z_
const T2* sample,
401 _In_
const std::locale& locale)
403 assert(str || !count);
405 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
406 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
407 for (
size_t offset = 0;; ++offset) {
408 for (
size_t i = offset, j = 0;; ++i, ++j) {
411 if (i >= count || !str[i])
413 if (ctype1.tolower(str[i]) != ctype2.tolower(sample[j]))
428 template <
class T1,
class T2>
429 inline size_t strncpy(
430 _Out_writes_(count) _Post_maybez_ T1* dst,
431 _In_reads_or_z_opt_(count)
const T2* src, _In_
size_t count)
433 assert(dst && src || !count);
434 for (
size_t i = 0; ; ++i) {
437 if ((dst[i] = src[i]) == 0)
452 template <
class T1,
class T2>
453 inline size_t strncpy(
454 _Out_writes_(count_dst) _Post_maybez_ T1* dst, _In_
size_t count_dst,
455 _In_reads_or_z_opt_(count_src)
const T2* src, _In_
size_t count_src)
457 assert(dst || !count_dst);
458 assert(src || !count_src);
459 for (
size_t i = 0; ; ++i)
467 if ((dst[i] = src[i]) == 0)
482 inline size_t crlf2nl(_Out_writes_z_(strlen(src)) T* dst, _In_z_
const T* src)
487 for (i = j = 0; src[j];) {
488 if (src[j] !=
'\r' || src[j + 1] !=
'\n')
500 template <
class T,
class T_bin>
501 inline T_bin strtoint(
502 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
503 _Out_opt_
size_t* end,
505 _Out_ uint8_t& flags)
507 assert(str || !count);
508 assert(radix == 0 || 2 <= radix && radix <= 36);
511 T_bin value = 0, digit,
513 max_ui_pre1, max_ui_pre2;
519 if (i >= count || !str[i])
goto error;
520 if (!isspace(str[i]))
break;
527 if (i >= count || !str[i])
goto error;
529 else if (str[i] ==
'-') {
532 if (i >= count || !str[i])
goto error;
537 if (str[i] ==
'0' && i + 1 < count && (str[i + 1] ==
'x' || str[i + 1] ==
'X')) {
539 if (i >= count || !str[i])
goto error;
546 if (i >= count || !str[i])
goto error;
547 if (str[i] ==
'x' || str[i] ==
'X') {
550 if (i >= count || !str[i])
goto error;
560 max_ui_pre1 = max_ui / (T_bin)radix;
561 max_ui_pre2 = max_ui % (T_bin)radix;
563 if (
'0' <= str[i] && str[i] <=
'9')
564 digit = (T_bin)str[i] -
'0';
565 else if (
'A' <= str[i] && str[i] <=
'Z')
566 digit = (T_bin)str[i] -
'A' +
'\x0a';
567 else if (
'a' <= str[i] && str[i] <=
'z')
568 digit = (T_bin)str[i] -
'a' +
'\x0a';
571 if (digit >= (T_bin)radix)
574 if (value < max_ui_pre1 ||
575 value == max_ui_pre1 && digit <= max_ui_pre2)
576 value = value * (T_bin)radix + digit;
583 if (i >= count || !str[i])
603 template <
class T,
class T_bin>
605 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
606 _Out_opt_
size_t* end,
612 switch (
sizeof(T_bin)) {
614 value = (T_bin)strtoint<T, uint8_t>(str, count, end, radix, flags);
615 if ((flags & 0x01) && (value & 0x80)) {
619 return (flags & 0x02) ?
620 (flags & 0x01) ? (T_bin)0x80 : (T_bin)0x7f :
621 (flags & 0x01) ? -value : value;
624 value = (T_bin)strtoint<T, T_U2>(str, count, end, radix, flags);
625 if ((flags & 0x01) && (value & 0x8000)) {
629 return (flags & 0x02) ?
630 (flags & 0x01) ? (T_bin)0x8000 : (T_bin)0x7fff :
631 (flags & 0x01) ? -value : value;
634 value = (T_bin)strtoint<T, uint32_t>(str, count, end, radix, flags);
635 if ((flags & 0x01) && (value & 0x80000000)) {
639 return (flags & 0x02) ?
640 (flags & 0x01) ? (T_bin)0x80000000 : (T_bin)0x7fffffff :
641 (flags & 0x01) ? -value : value;
644 value = (T_bin)strtoint<T, uint64_t>(str, count, end, radix, flags);
645 if ((flags & 0x01) && (value & 0x8000000000000000)) {
649 return (flags & 0x02) ?
650 (flags & 0x01) ? (T_bin)0x8000000000000000 : (T_bin)0x7fffffffffffffff :
651 (flags & 0x01) ? -value : value;
654 throw std::invalid_argument(
"Unsupported bit length");
668 template <
class T,
class T_bin>
669 inline T_bin strtouint(
670 _In_reads_or_z_opt_(count)
const T* str,
672 _Out_opt_
size_t* end,
678 switch (
sizeof(T_bin)) {
679 case 1: value = (T_bin)strtoint<T, uint8_t>(str, count, end, radix, flags);
break;
680 case 2: value = (T_bin)strtoint<T, uint16_t>(str, count, end, radix, flags);
break;
681 case 4: value = (T_bin)strtoint<T, uint32_t>(str, count, end, radix, flags);
break;
682 case 8: value = (T_bin)strtoint<T, uint64_t>(str, count, end, radix, flags);
break;
683 default:
throw std::invalid_argument(
"Unsupported bit length");
686 return (flags & 0x02) ?
687 (flags & 0x01) ? (T_bin)0 : (T_bin)-1 :
688 (flags & 0x01) ? ~value : value;
702 inline int32_t strto32(
703 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
704 _Out_opt_
size_t* end,
707 return strtoint<T, int32_t>(str, count, end, radix);
721 inline int64_t strto64(
722 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
723 _Out_opt_
size_t* end,
726 return strtoint<T, int64_t>(str, count, end, radix);
741 inline intptr_t strtoi(
742 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
743 _Out_opt_
size_t* end,
746#if defined(_WIN64) || defined(__LP64__)
747 return (intptr_t)strto64(str, count, end, radix);
749 return (intptr_t)strto32(str, count, end, radix);
764 inline uint32_t strtou32(
765 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
766 _Out_opt_
size_t* end,
769 return strtouint<T, uint32_t>(str, count, end, radix);
783 inline uint64_t strtou64(
784 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
785 _Out_opt_
size_t* end,
788 return strtouint<T, uint64_t>(str, count, end, radix);
803 inline size_t strtoui(
804 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
805 _Out_opt_
size_t* end,
808#if defined(_WIN64) || defined(__LP64__)
809 return (
size_t)strtou64(str, count, end, radix);
811 return (
size_t)strtou32(str, count, end, radix);
816 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)
821#pragma warning(suppress: 4996)
822 r = _vsnprintf_l(str, capacity, format, locale, arg);
824 r = vsnprintf(str, capacity, format, arg);
826 if (r == -1 && strnlen(str, capacity) == capacity) {
828 capacity += std::max<size_t>(capacity / 8, 0x80);
829 if (capacity > INT_MAX)
830 throw std::invalid_argument(
"string too big");
831 return (
int)capacity;
836 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)
842#pragma warning(suppress: 4996)
843 r = _vsnwprintf_l(str, capacity, format, locale, arg);
845 r = vswprintf(str, capacity, format, arg);
847 if (r == -1 && strnlen(str, capacity) == capacity) {
849 capacity += std::max<size_t>(capacity / 8, 0x80);
850 if (capacity > INT_MAX)
851 throw std::invalid_argument(
"string too big");
852 return (
int)capacity;
866 template<
class _Elem,
class _Traits,
class _Ax>
867 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)
869 _Elem buf[1024/
sizeof(_Elem)];
872 int count = vsnprintf(buf, _countof(buf) - 1, format, locale, arg);
875 str.append(buf, count);
877 for (
size_t capacity = 2*1024/
sizeof(_Elem);; capacity *= 2) {
879 auto buf_dyn = std::make_unique<_Elem[]>(capacity);
880 count = vsnprintf(buf_dyn.get(), capacity - 1, format, locale, arg);
882 str.append(buf_dyn.get(), count);
896 template<
class _Elem,
class _Traits,
class _Ax>
897 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, ...)
900 va_start(arg, locale);
901 vappendf(str, format, locale, arg);
913 template<
class _Elem,
class _Traits,
class _Ax>
914 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)
917 vappendf(str, format, locale, arg);
927 template<
class _Elem,
class _Traits,
class _Ax>
928 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, ...)
931 va_start(arg, locale);
932 vsprintf(str, format, locale, arg);
945 template<
class _Elem,
class _Traits = std::
char_traits<_Elem>,
class _Ax = std::allocator<_Elem>>
946 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)
948 std::basic_string<_Elem, _Traits, _Ax> str;
949 vappendf(str, format, locale, arg);
961 template<
class _Elem,
class _Traits = std::
char_traits<_Elem>,
class _Ax = std::allocator<_Elem>>
962 inline std::basic_string<_Elem, _Traits, _Ax> sprintf(_In_z_ _Printf_format_string_params_(2)
const _Elem *format, _In_opt_ locale_t locale, ...)
965 va_start(arg, locale);
966 auto str = vsprintf(format, locale, arg);