20 typedef wchar_t utf16_t;
22 typedef char16_t utf16_t;
30 inline bool is_high_surrogate(_In_ utf16_t chr)
32 return 0xd800 < chr && chr < 0xdc00;
40 inline bool is_low_surrogate(_In_ utf16_t chr)
42 return 0xdc00 < chr && chr < 0xe000;
50 inline bool is_surrogate_pair(_In_reads_(2)
const utf16_t* str)
52 return is_high_surrogate(str[0]) && is_low_surrogate(str[1]);
60 inline char32_t surrogate_pair_to_ucs4(_In_reads_(2)
const utf16_t* str)
62 assert(is_surrogate_pair(str));
64 ((
char32_t)(str[0] - 0xd800) << 10) +
65 (char32_t)(str[1] - 0xdc00) +
74 inline void ucs4_to_surrogate_pair(_Out_writes_(2) utf16_t* str, _In_
char32_t chr)
76 assert(chr >= 0x10000);
78 str[0] = 0xd800 + (char32_t)((chr >> 10) & 0x3ff);
79 str[1] = 0xdc00 + (char32_t)(chr & 0x3ff);
87 inline bool iscombining(_In_
char32_t chr)
90 0x0300 <= chr && chr < 0x0370 ||
91 0x1dc0 <= chr && chr < 0x1e00 ||
92 0x20d0 <= chr && chr < 0x2100 ||
93 0xfe20 <= chr && chr < 0xfe30;
102 inline size_t islbreak(_In_ T chr)
104 return chr ==
'\n' || chr ==
'\r';
114 inline size_t islbreak(_In_reads_or_z_opt_(count)
const T* chr, _In_
size_t count)
116 _Analysis_assume_(chr || !count);
117 if (count >= 2 && (chr[0] ==
'\r' && chr[1] ==
'\n' || chr[0] ==
'\n' && chr[1] ==
'\r'))
119 if (count > 1 && (chr[0] ==
'\n' || chr[0] ==
'\r'))
130 inline size_t glyphlen(_In_reads_or_z_opt_(count)
const wchar_t* glyph,
size_t count)
132 _Analysis_assume_(glyph || !count);
135 size_t i = count < 2 || !is_surrogate_pair(glyph) ? 1 : 2;
139 for (; i < count && iscombining(glyph[i]); ++i);
153 inline size_t strlen(_In_z_
const T* str)
157 for (i = 0; str[i]; ++i);
170 inline size_t strnlen(_In_reads_or_z_opt_(count)
const T* str, _In_
size_t count)
174 for (i = 0; i < count && str[i]; ++i);
178 constexpr auto npos{
static_cast<size_t>(-1) };
190 inline size_t strnchr(
191 _In_reads_or_z_opt_(count)
const T* str,
195 assert(str || !count);
196 for (
size_t i = 0; i < count && str[i]; ++i)
197 if (str[i] == chr)
return i;
211 inline size_t strrnchr(
212 _In_reads_or_z_opt_(count)
const T* str,
216 assert(str || !count);
218 for (
size_t i = 0; i < count && str[i]; ++i)
219 if (str[i] == chr) z = i;
233 inline size_t strnichr(
234 _In_reads_or_z_opt_(count)
const T* str,
237 _In_
const std::locale& locale)
239 assert(str || !count);
240 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
241 chr = ctype.tolower(chr);
242 for (
size_t i = 0; i < count && str[i]; ++i)
243 if (ctype.tolower(str[i]) == chr)
return i;
257 inline size_t strrnichr(
258 _In_reads_or_z_opt_(count)
const T* str,
261 _In_
const std::locale& locale)
263 assert(str || !count);
264 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
265 chr = ctype.tolower(chr);
267 for (
size_t i = 0; i < count && str[i]; ++i)
268 if (ctype.tolower(str[i]) == chr) z = i;
282 template <
class T1,
class T2>
284 _In_reads_or_z_opt_(count1)
const T1* str1, _In_
size_t count1,
285 _In_reads_or_z_opt_(count2)
const T2* str2, _In_
size_t count2)
287 assert(str1 || !count1);
288 assert(str2 || !count2);
289 size_t i; T1 a; T2 b;
290 for (i = 0; i < count1 && i < count2 && ((a = str1[i]) | (b = str2[i])); ++i) {
291 if (a > b)
return +1;
292 if (a < b)
return -1;
294 if (i < count1 && str1[i])
return +1;
295 if (i < count2 && str2[i])
return -1;
311 _In_reads_or_z_opt_(count1)
const T* str1, _In_
size_t count1,
312 _In_reads_or_z_opt_(count2)
const T* str2, _In_
size_t count2,
313 _In_
const std::locale& locale)
315 assert(str1 || !count1);
316 assert(str2 || !count2);
317 auto& collate = std::use_facet<std::collate<T>>(locale);
318 return collate.compare(str1, str1 + count1, str2, str2 + count2);
331 template <
class T1,
class T2>
333 _In_reads_or_z_opt_(count1)
const T1* str1, _In_
size_t count1,
334 _In_reads_or_z_opt_(count2)
const T2* str2, _In_
size_t count2,
335 _In_
const std::locale& locale)
337 assert(str1 || !count1);
338 assert(str2 || !count2);
339 size_t i; T1 a; T2 b;
340 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
341 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
342 for (i = 0; i < count1 && i < count2 && ((a = ctype1.tolower(str1[i])) | (b = ctype2.tolower(str2[i]))); i++) {
343 if (a > b)
return +1;
344 if (a < b)
return -1;
346 if (i < count1 && str1[i])
return +1;
347 if (i < count2 && str2[i])
return -1;
360 template <
class T1,
class T2>
361 inline size_t strnstr(
362 _In_reads_or_z_opt_(count)
const T1* str,
364 _In_z_
const T2* sample)
366 assert(str || !count);
368 for (
size_t offset = 0;; ++offset) {
369 for (
size_t i = offset, j = 0;; ++i, ++j) {
372 if (i >= count || !str[i])
374 if (str[i] != sample[j])
389 template <
class T1,
class T2>
390 inline size_t strnistr(
391 _In_reads_or_z_opt_(count)
const T1* str,
393 _In_z_
const T2* sample,
394 _In_
const std::locale& locale)
396 assert(str || !count);
398 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
399 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
400 for (
size_t offset = 0;; ++offset) {
401 for (
size_t i = offset, j = 0;; ++i, ++j) {
404 if (i >= count || !str[i])
406 if (ctype1.tolower(str[i]) != ctype2.tolower(sample[j]))
421 template <
class T1,
class T2>
422 inline size_t strncpy(
423 _Out_writes_(count) _Post_maybez_ T1* dst,
424 _In_reads_or_z_opt_(count)
const T2* src, _In_
size_t count)
426 assert(dst && src || !count);
427 for (
size_t i = 0; ; ++i) {
430 if ((dst[i] = src[i]) == 0)
445 template <
class T1,
class T2>
446 inline size_t strncpy(
447 _Out_writes_(count_dst) _Post_maybez_ T1* dst, _In_
size_t count_dst,
448 _In_reads_or_z_opt_(count_src)
const T2* src, _In_
size_t count_src)
450 assert(dst || !count_dst);
451 assert(src || !count_src);
452 for (
size_t i = 0; ; ++i)
460 if ((dst[i] = src[i]) == 0)
475 inline size_t crlf2nl(_Out_writes_z_(strlen(src)) T* dst, _In_z_
const T* src)
480 for (i = j = 0; src[j];) {
481 if (src[j] !=
'\r' || src[j + 1] !=
'\n')
493 template <
class T,
class T_bin>
494 inline T_bin strtoint(
495 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
496 _Out_opt_
size_t* end,
498 _Out_ uint8_t& flags)
500 assert(str || !count);
501 assert(radix == 0 || 2 <= radix && radix <= 36);
504 T_bin value = 0, digit,
506 max_ui_pre1, max_ui_pre2;
512 if (i >= count || !str[i])
goto error;
513 if (!isspace(str[i]))
break;
520 if (i >= count || !str[i])
goto error;
522 else if (str[i] ==
'-') {
525 if (i >= count || !str[i])
goto error;
530 if (str[i] ==
'0' && i + 1 < count && (str[i + 1] ==
'x' || str[i + 1] ==
'X')) {
532 if (i >= count || !str[i])
goto error;
539 if (i >= count || !str[i])
goto error;
540 if (str[i] ==
'x' || str[i] ==
'X') {
543 if (i >= count || !str[i])
goto error;
553 max_ui_pre1 = max_ui / (T_bin)radix;
554 max_ui_pre2 = max_ui % (T_bin)radix;
556 if (
'0' <= str[i] && str[i] <=
'9')
557 digit = (T_bin)str[i] -
'0';
558 else if (
'A' <= str[i] && str[i] <=
'Z')
559 digit = (T_bin)str[i] -
'A' +
'\x0a';
560 else if (
'a' <= str[i] && str[i] <=
'z')
561 digit = (T_bin)str[i] -
'a' +
'\x0a';
564 if (digit >= (T_bin)radix)
567 if (value < max_ui_pre1 ||
568 value == max_ui_pre1 && digit <= max_ui_pre2)
569 value = value * (T_bin)radix + digit;
576 if (i >= count || !str[i])
596 template <
class T,
class T_bin>
598 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
599 _Out_opt_
size_t* end,
605 switch (
sizeof(T_bin)) {
607 value = (T_bin)strtoint<T, uint8_t>(str, count, end, radix, flags);
608 if ((flags & 0x01) && (value & 0x80)) {
612 return (flags & 0x02) ?
613 (flags & 0x01) ? (T_bin)0x80 : (T_bin)0x7f :
614 (flags & 0x01) ? -value : value;
617 value = (T_bin)strtoint<T, T_U2>(str, count, end, radix, flags);
618 if ((flags & 0x01) && (value & 0x8000)) {
622 return (flags & 0x02) ?
623 (flags & 0x01) ? (T_bin)0x8000 : (T_bin)0x7fff :
624 (flags & 0x01) ? -value : value;
627 value = (T_bin)strtoint<T, uint32_t>(str, count, end, radix, flags);
628 if ((flags & 0x01) && (value & 0x80000000)) {
632 return (flags & 0x02) ?
633 (flags & 0x01) ? (T_bin)0x80000000 : (T_bin)0x7fffffff :
634 (flags & 0x01) ? -value : value;
637 value = (T_bin)strtoint<T, uint64_t>(str, count, end, radix, flags);
638 if ((flags & 0x01) && (value & 0x8000000000000000)) {
642 return (flags & 0x02) ?
643 (flags & 0x01) ? (T_bin)0x8000000000000000 : (T_bin)0x7fffffffffffffff :
644 (flags & 0x01) ? -value : value;
647 throw std::invalid_argument(
"Unsupported bit length");
661 template <
class T,
class T_bin>
662 inline T_bin strtouint(
663 _In_reads_or_z_opt_(count)
const T* str,
665 _Out_opt_
size_t* end,
671 switch (
sizeof(T_bin)) {
672 case 1: value = (T_bin)strtoint<T, uint8_t>(str, count, end, radix, flags);
break;
673 case 2: value = (T_bin)strtoint<T, uint16_t>(str, count, end, radix, flags);
break;
674 case 4: value = (T_bin)strtoint<T, uint32_t>(str, count, end, radix, flags);
break;
675 case 8: value = (T_bin)strtoint<T, uint64_t>(str, count, end, radix, flags);
break;
676 default:
throw std::invalid_argument(
"Unsupported bit length");
679 return (flags & 0x02) ?
680 (flags & 0x01) ? (T_bin)0 : (T_bin)-1 :
681 (flags & 0x01) ? ~value : value;
695 inline int32_t strto32(
696 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
697 _Out_opt_
size_t* end,
700 return strtoint<T, int32_t>(str, count, end, radix);
714 inline int64_t strto64(
715 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
716 _Out_opt_
size_t* end,
719 return strtoint<T, int64_t>(str, count, end, radix);
734 inline intptr_t strtoi(
735 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
736 _Out_opt_
size_t* end,
739#if defined(_WIN64) || defined(__LP64__)
740 return (intptr_t)strto64(str, count, end, radix);
742 return (intptr_t)strto32(str, count, end, radix);
757 inline uint32_t strtou32(
758 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
759 _Out_opt_
size_t* end,
762 return strtouint<T, uint32_t>(str, count, end, radix);
776 inline uint64_t strtou64(
777 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
778 _Out_opt_
size_t* end,
781 return strtouint<T, uint64_t>(str, count, end, radix);
796 inline size_t strtoui(
797 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
798 _Out_opt_
size_t* end,
801#if defined(_WIN64) || defined(__LP64__)
802 return (
size_t)strtou64(str, count, end, radix);
804 return (
size_t)strtou32(str, count, end, radix);
809 inline int vsnprintf(_Out_z_cap_(capacity)
char *str, _In_
size_t capacity, _In_z_ _Printf_format_string_
const char *format, _In_ va_list arg)
812#pragma warning(suppress: 4996)
813 return _vsnprintf(str, capacity, format, arg);
815#pragma warning(suppress: 4996)
816 return ::vsnprintf(str, capacity, format, arg);
820 inline int vsnprintf(_Out_z_cap_(capacity)
wchar_t *str, _In_
size_t capacity, _In_z_ _Printf_format_string_
const wchar_t *format, _In_ va_list arg)
noexcept
822#pragma warning(suppress: 4996)
823 return _vsnwprintf(str, capacity, format, arg);
835 template<
class _Elem,
class _Traits,
class _Ax>
836 inline void vappendf(_Inout_ std::basic_string<_Elem, _Traits, _Ax> &str, _In_z_ _Printf_format_string_
const _Elem *format, _In_ va_list arg)
838 _Elem buf[1024/
sizeof(_Elem)];
841 int count = vsnprintf(buf, _countof(buf) - 1, format, arg);
844 str.append(buf, count);
846 for (
size_t capacity = 2*1024/
sizeof(_Elem);; capacity *= 2) {
848 auto buf_dyn = std::make_unique<_Elem[]>(capacity);
849 count = vsnprintf(buf_dyn.get(), capacity - 1, format, arg);
851 str.append(buf_dyn.get(), count);
864 template<
class _Elem,
class _Traits,
class _Ax>
865 inline void appendf(_Inout_ std::basic_string<_Elem, _Traits, _Ax> &str, _In_z_ _Printf_format_string_
const _Elem *format, ...)
868 va_start(arg, format);
869 vappendf(str, format, arg);
880 template<
class _Elem,
class _Traits,
class _Ax>
881 inline void vsprintf(_Inout_ std::basic_string<_Elem, _Traits, _Ax> &str, _In_z_ _Printf_format_string_
const _Elem *format, _In_ va_list arg)
884 appendf(str, format, arg);
893 template<
class _Elem,
class _Traits,
class _Ax>
894 inline void sprintf(_Inout_ std::basic_string<_Elem, _Traits, _Ax> &str, _In_z_ _Printf_format_string_
const _Elem *format, ...)
897 va_start(arg, format);
898 vsprintf(str, format, arg);