30 using utf16_t = wchar_t;
31 using utf32_t = char32_t;
33 using utf16_t = char16_t;
34 using utf32_t = wchar_t;
42 inline bool is_high_surrogate(_In_ utf16_t chr)
44 return 0xd800 < chr && chr < 0xdc00;
52 inline bool is_low_surrogate(_In_ utf16_t chr)
54 return 0xdc00 < chr && chr < 0xe000;
62 inline bool is_surrogate_pair(_In_reads_(2)
const utf16_t* str)
64 return is_high_surrogate(str[0]) && is_low_surrogate(str[1]);
72 inline utf32_t surrogate_pair_to_ucs4(_In_reads_(2)
const utf16_t* str)
74 _Assume_(is_surrogate_pair(str));
76 (
static_cast<utf32_t
>(str[0] - 0xd800) << 10) +
77 static_cast<utf32_t
>(str[1] - 0xdc00) +
86 inline void ucs4_to_surrogate_pair(_Out_writes_(2) utf16_t* str, _In_ utf32_t chr)
88 _Assume_(chr >= 0x10000);
90 str[0] = 0xd800 +
static_cast<utf32_t
>((chr >> 10) & 0x3ff);
91 str[1] = 0xdc00 +
static_cast<utf32_t
>(chr & 0x3ff);
99 inline bool iscombining(_In_ utf32_t chr)
102 (0x0300 <= chr && chr < 0x0370) ||
103 (0x1dc0 <= chr && chr < 0x1e00) ||
104 (0x20d0 <= chr && chr < 0x2100) ||
105 (0xfe20 <= chr && chr < 0xfe30);
114 inline bool islbreak(_In_ T chr)
116 return chr ==
'\n' || chr ==
'\r';
128 inline size_t islbreak(_In_reads_or_z_opt_(count)
const T* chr, _In_
size_t count)
130 _Assume_(chr || !count);
131 if (count >= 2 && ((chr[0] ==
'\r' && chr[1] ==
'\n') || (chr[0] ==
'\n' && chr[1] ==
'\r')))
133 if (count > 1 && (chr[0] ==
'\n' || chr[0] ==
'\r'))
144 inline bool isspace(_In_ T chr)
146 return chr ==
' ' || chr ==
'\t' || chr ==
'\n' || chr ==
'\r' || chr ==
'\v' || chr ==
'\f';
155 inline bool islower(_In_ T chr)
157 return 'a' <= chr && chr <=
'z';
166 inline bool isupper(_In_ T chr)
168 return 'A' <= chr && chr <=
'Z';
177 inline bool isdigit(_In_ T chr)
179 return '0' <= chr && chr <=
'9';
188 inline bool isalpha(_In_ T chr)
190 return islower(chr) || isupper(chr);
199 inline bool is7bit(_In_ T chr)
201 return '\x00' <= chr && chr <=
'\x7f';
210 inline size_t glyphlen(_In_reads_or_z_opt_(count)
const wchar_t* glyph, _In_
size_t count)
212 _Assume_(glyph || !count);
215 size_t i = count < 2 || !is_surrogate_pair(glyph) ? 1 : 2;
219 for (; i < count && iscombining(glyph[i]); ++i);
231 inline size_t glyphrlen(_In_reads_or_z_opt_(count)
const wchar_t* str, _In_
size_t count)
233 _Assume_(count && str && str[count - 1]);
234 for (
size_t i = count; i--;) {
235 if (!iscombining(str[i])) {
237 return count - (!is_low_surrogate(str[i]) || i == 0 || !is_high_surrogate(str[i - 1]) ? i : i - 1);
254 inline T tolower(_In_ T chr)
256 return isupper(chr) ? chr | 0x20 : chr;
267 inline T toupper(_In_ T chr)
269 return islower(chr) ? chr | ~0x20 : chr;
280 inline size_t strlen(_In_z_
const T* str)
284 for (i = 0; str[i]; ++i);
297 inline size_t strnlen(_In_reads_or_z_opt_(count)
const T* str, _In_
size_t count)
299 _Assume_(str || !count);
301 for (i = 0; i < count && str[i]; ++i);
312 template <
class T,
size_t N>
313 inline size_t strnlen(_In_
const T (&str)[N])
315 return strnlen(str, N);
318 constexpr auto npos{
static_cast<size_t>(-1) };
329 inline size_t strchr(_In_z_
const T* str, _In_ T chr)
332 for (
size_t i = 0; str[i]; ++i)
333 if (str[i] == chr)
return i;
347 inline size_t strnchr(
348 _In_reads_or_z_opt_(count)
const T* str,
352 _Assume_(str || !count);
353 for (
size_t i = 0; i < count && str[i]; ++i)
354 if (str[i] == chr)
return i;
366 template <
class T,
size_t N>
367 inline size_t strnchr(
368 _In_
const T (&str)[N],
371 return strnchr(str, N, chr);
383 inline size_t strrchr(
389 for (
size_t i = 0; str[i]; ++i)
390 if (str[i] == chr) z = i;
404 inline size_t strrnchr(
405 _In_reads_or_z_opt_(count)
const T* str,
409 _Assume_(str || !count);
411 for (
size_t i = 0; i < count && str[i]; ++i)
412 if (str[i] == chr) z = i;
424 template <
class T,
size_t N>
425 inline size_t strrnchr(
426 _In_
const T (&str)[N],
429 return strrnchr(str, N, chr);
441 inline size_t strichr(
447 for (
size_t i = 0; str[i]; ++i)
448 if (tolower(str[i]) == chr)
return i;
462 inline size_t strichr(
465 _In_
const std::locale& locale)
468 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
469 chr = ctype.tolower(chr);
470 for (
size_t i = 0; str[i]; ++i)
471 if (ctype.tolower(str[i]) == chr)
return i;
485 inline size_t strnichr(
486 _In_reads_or_z_opt_(count)
const T* str,
490 _Assume_(str || !count);
492 for (
size_t i = 0; i < count && str[i]; ++i)
493 if (tolower(str[i]) == chr)
return i;
508 inline size_t strnichr(
509 _In_reads_or_z_opt_(count)
const T* str,
512 _In_
const std::locale& locale)
514 _Assume_(str || !count);
515 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
516 chr = ctype.tolower(chr);
517 for (
size_t i = 0; i < count && str[i]; ++i)
518 if (ctype.tolower(str[i]) == chr)
return i;
530 template <
class T,
size_t N>
531 inline size_t strnichr(
532 _In_
const T (&str)[N],
535 return strnichr(str, N, chr);
547 template <
class T,
size_t N>
548 inline size_t strnichr(
549 _In_
const T (&str)[N],
551 _In_
const std::locale& locale)
553 return strnichr(str, N, chr, locale);
565 inline size_t strrichr(
572 for (
size_t i = 0; str[i]; ++i)
573 if (tolower(str[i]) == chr) z = i;
587 inline size_t strrichr(
588 _In_reads_or_z_opt_(count)
const T* str,
590 _In_
const std::locale& locale)
593 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
594 chr = ctype.tolower(chr);
596 for (
size_t i = 0; str[i]; ++i)
597 if (ctype.tolower(str[i]) == chr) z = i;
611 inline size_t strrnichr(
612 _In_reads_or_z_opt_(count)
const T* str,
616 _Assume_(str || !count);
619 for (
size_t i = 0; i < count && str[i]; ++i)
620 if (tolower(str[i]) == chr) z = i;
635 inline size_t strrnichr(
636 _In_reads_or_z_opt_(count)
const T* str,
639 _In_
const std::locale& locale)
641 _Assume_(str || !count);
642 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
643 chr = ctype.tolower(chr);
645 for (
size_t i = 0; i < count && str[i]; ++i)
646 if (ctype.tolower(str[i]) == chr) z = i;
658 template <
class T,
size_t N>
659 inline size_t strrnichr(
660 _In_
const T (&str)[N],
663 return strrnichr(str, N, chr);
675 template <
class T,
size_t N>
676 inline size_t strrnichr(
677 _In_
const T (&str)[N],
679 _In_
const std::locale& locale)
681 return strrnichr(str, N, chr, locale);
732 _In_reads_or_z_opt_(count)
const T* str,
735 _Assume_(str || !count);
736 for (
size_t i = 0; i < count && str[i]; ++i)
737 if (!isspace(str[i]))
753 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
754 _In_
const std::locale& locale)
756 _Assume_(str || !count);
757 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
758 for (
size_t i = 0; i < count && str[i]; ++i)
759 if (!ctype.is(ctype.space, str[i]))
771 template <
class T,
size_t N>
772 inline bool isblank(_In_
const T (&str)[N])
774 return isblank(str, N);
785 template <
class T,
size_t N>
787 _In_
const T (&str)[N],
788 _In_
const std::locale& locale)
790 return isblank(str, N, locale);
819 inline bool is7bit(_In_reads_or_z_opt_(count)
const T* str, _In_
size_t count)
821 _Assume_(str || !count);
822 for (
size_t i = 0; i < count && str[i]; i++)
835 template <
class T,
size_t N>
836 inline bool is7bit(_In_
const T (&str)[N])
838 return is7bit(str, N);
849 template <
class T1,
class T2>
850 inline int strcmp(_In_z_
const T1* str1, _In_z_
const T2* str2)
854 size_t i; T1 a; T2 b;
855 for (i = 0; (a = str1[i]) | (b = str2[i]); ++i) {
856 if (a > b)
return +1;
857 if (a < b)
return -1;
859 if (str1[i])
return +1;
860 if (str2[i])
return -1;
873 template <
class T1,
class T2>
874 inline int strncmp(_In_reads_or_z_opt_(count)
const T1* str1, _In_reads_or_z_opt_(count)
const T2* str2, _In_
size_t count)
876 _Assume_(str1 || !count);
877 _Assume_(str2 || !count);
878 size_t i; T1 a; T2 b;
879 for (i = 0; i < count && ((a = str1[i]) | (b = str2[i])); ++i) {
880 if (a > b)
return +1;
881 if (a < b)
return -1;
883 if (i < count && str1[i])
return +1;
884 if (i < count && str2[i])
return -1;
898 template <
class T1,
class T2>
900 _In_reads_or_z_opt_(count1)
const T1* str1, _In_
size_t count1,
901 _In_reads_or_z_opt_(count2)
const T2* str2, _In_
size_t count2)
903 _Assume_(str1 || !count1);
904 _Assume_(str2 || !count2);
905 size_t i; T1 a; T2 b;
906 for (i = 0; i < count1 && i < count2 && ((a = str1[i]) | (b = str2[i])); ++i) {
907 if (a > b)
return +1;
908 if (a < b)
return -1;
910 if (i < count1 && str1[i])
return +1;
911 if (i < count2 && str2[i])
return -1;
923 template <
class T1,
size_t N1,
class T2,
size_t N2>
925 _In_
const T1 (&str1)[N1],
926 _In_
const T2 (&str2)[N2])
928 return strncmp(str1, N1, str2, N2);
939 template <
class T1,
class T2>
940 inline int strrcmp(_In_z_
const T1* str1, _In_z_
const T2* str2)
945 _Assume_(str1 || !i);
946 _Assume_(str2 || !j);
947 size_t k; T1 a; T2 b;
948 for (k = 1; i && j; k++) {
950 if ((a = str1[i]) > (b = str2[j]))
return +1;
951 if (a < b)
return -1;
953 if (i && !j)
return +1;
954 if (!i && j)
return -1;
967 template <
class T1,
class T2>
968 inline int strrncmp(_In_reads_or_z_opt_(count)
const T1* str1, _In_reads_or_z_opt_(count)
const T2* str2, _In_
size_t count)
971 i = strnlen(str1, count),
972 j = strnlen(str2, count);
973 _Assume_(str1 || !i);
974 _Assume_(str2 || !j);
975 size_t k; T1 a; T2 b;
976 for (k = 1; i && j; k++) {
978 if ((a = str1[i]) > (b = str2[j]))
return +1;
979 if (a < b)
return -1;
981 if (i && !j)
return +1;
982 if (!i && j)
return -1;
996 template <
class T1,
class T2>
998 _In_reads_or_z_opt_(count1)
const T1* str1, _In_
size_t count1,
999 _In_reads_or_z_opt_(count2)
const T2* str2, _In_
size_t count2)
1002 i = strnlen(str1, count1),
1003 j = strnlen(str2, count2);
1004 _Assume_(str1 || !i);
1005 _Assume_(str2 || !j);
1006 size_t k; T1 a; T2 b;
1007 for (k = 1; i && j; k++) {
1009 if ((a = str1[i]) > (b = str2[j]))
return +1;
1010 if (a < b)
return -1;
1012 if (i && !j)
return +1;
1013 if (!i && j)
return -1;
1025 template <
class T1,
size_t N1,
class T2,
size_t N2>
1026 inline int strrncmp(
1027 _In_
const T1 (&str1)[N1],
1028 _In_
const T2 (&str2)[N2])
1030 return strrncmp(str1, N1, str2, N2);
1041 template <
class T1,
class T2>
1042 inline int stricmp(_In_z_
const T1* str1, _In_z_
const T2* str2)
1046 size_t i; T1 a; T2 b;
1047 for (i = 0; (a = tolower(str1[i])) | (b = tolower(str2[i])); ++i) {
1048 if (a > b)
return +1;
1049 if (a < b)
return -1;
1051 if (str1[i])
return +1;
1052 if (str2[i])
return -1;
1065 template <
class T1,
class T2>
1066 inline int stricmp(_In_z_
const T1* str1, _In_z_
const T2* str2, _In_
const std::locale& locale)
1070 size_t i; T1 a; T2 b;
1071 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
1072 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
1073 for (i = 0; (a = ctype1.tolower(str1[i])) | (b = ctype2.tolower(str2[i])); ++i) {
1074 if (a > b)
return +1;
1075 if (a < b)
return -1;
1077 if (str1[i])
return +1;
1078 if (str2[i])
return -1;
1091 template <
class T1,
class T2>
1092 inline int strnicmp(_In_reads_or_z_opt_(count)
const T1* str1, _In_reads_or_z_opt_(count)
const T2* str2, _In_
size_t count)
1094 _Assume_(str1 || !count);
1095 _Assume_(str2 || !count);
1096 size_t i; T1 a; T2 b;
1097 for (i = 0; i < count && ((a = tolower(str1[i])) | (b = tolower(str2[i]))); ++i) {
1098 if (a > b)
return +1;
1099 if (a < b)
return -1;
1101 if (i < count && str1[i])
return +1;
1102 if (i < count && str2[i])
return -1;
1116 template <
class T1,
class T2>
1117 inline int strnicmp(_In_reads_or_z_opt_(count)
const T1* str1, _In_reads_or_z_opt_(count)
const T2* str2, _In_
size_t count, _In_
const std::locale& locale)
1119 _Assume_(str1 || !count);
1120 _Assume_(str2 || !count);
1121 size_t i; T1 a; T2 b;
1122 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
1123 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
1124 for (i = 0; i < count && ((a = ctype1.tolower(str1[i])) | (b = ctype2.tolower(str2[i]))); ++i) {
1125 if (a > b)
return +1;
1126 if (a < b)
return -1;
1128 if (i < count && str1[i])
return +1;
1129 if (i < count && str2[i])
return -1;
1143 template <
class T1,
class T2>
1144 inline int strnicmp(
1145 _In_reads_or_z_opt_(count1)
const T1* str1, _In_
size_t count1,
1146 _In_reads_or_z_opt_(count2)
const T2* str2, _In_
size_t count2)
1148 _Assume_(str1 || !count1);
1149 _Assume_(str2 || !count2);
1150 size_t i; T1 a; T2 b;
1151 for (i = 0; i < count1 && i < count2 && ((a = tolower(str1[i])) | (b = tolower(str2[i]))); ++i) {
1152 if (a > b)
return +1;
1153 if (a < b)
return -1;
1155 if (i < count1 && str1[i])
return +1;
1156 if (i < count2 && str2[i])
return -1;
1171 template <
class T1,
class T2>
1172 inline int strnicmp(
1173 _In_reads_or_z_opt_(count1)
const T1* str1, _In_
size_t count1,
1174 _In_reads_or_z_opt_(count2)
const T2* str2, _In_
size_t count2,
1175 _In_
const std::locale& locale)
1177 _Assume_(str1 || !count1);
1178 _Assume_(str2 || !count2);
1179 size_t i; T1 a; T2 b;
1180 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
1181 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
1182 for (i = 0; i < count1 && i < count2 && ((a = ctype1.tolower(str1[i])) | (b = ctype2.tolower(str2[i]))); ++i) {
1183 if (a > b)
return +1;
1184 if (a < b)
return -1;
1186 if (i < count1 && str1[i])
return +1;
1187 if (i < count2 && str2[i])
return -1;
1199 template <
class T1,
size_t N1,
class T2,
size_t N2>
1200 inline int strnicmp(
1201 _In_
const T1 (&str1)[N1],
1202 _In_
const T2 (&str2)[N2])
1204 strnicmp(str1, N1, str2, N2);
1216 template <
class T1,
size_t N1,
class T2,
size_t N2>
1217 inline int strnicmp(
1218 _In_
const T1 (&str1)[N1],
1219 _In_
const T2 (&str2)[N2],
1220 _In_
const std::locale& locale)
1222 strnicmp(str1, N1, str2, N2, locale);
1236 _In_z_
const T* str1,
1237 _In_z_
const T* str2,
1238 _In_
const std::locale& locale)
1242 auto& collate = std::use_facet<std::collate<T>>(locale);
1243 return collate.compare(str1, str1 + strlen(str1), str2, str2 + strlen(str2));
1258 inline int strncoll(
1259 _In_reads_or_z_opt_(count1)
const T* str1, _In_
size_t count1,
1260 _In_reads_or_z_opt_(count2)
const T* str2, _In_
size_t count2,
1261 _In_
const std::locale& locale)
1263 _Assume_(str1 || !count1);
1264 _Assume_(str2 || !count2);
1265 auto& collate = std::use_facet<std::collate<T>>(locale);
1266 return collate.compare(str1, str1 + count1, str2, str2 + count2);
1278 template <
class T,
size_t N1,
size_t N2>
1279 inline int strncoll(
1280 _In_
const T (&str1)[N1],
1281 _In_
const T (&str2)[N2],
1282 _In_
const std::locale& locale)
1284 return strncoll(str1, N1, str2, N2, locale);
1295 template <
class T1,
class T2>
1296 inline size_t strstr(
1297 _In_z_
const T1* str,
1298 _In_z_
const T2* sample)
1302 for (
size_t offset = 0;; ++offset) {
1303 for (
size_t i = offset, j = 0;; ++i, ++j) {
1308 if (str[i] != sample[j])
1323 template <
class T1,
class T2>
1324 inline size_t strnstr(
1325 _In_reads_or_z_opt_(count)
const T1* str, _In_
size_t count,
1326 _In_z_
const T2* sample)
1328 _Assume_(str || !count);
1330 for (
size_t offset = 0;; ++offset) {
1331 for (
size_t i = offset, j = 0;; ++i, ++j) {
1334 if (i >= count || !str[i])
1336 if (str[i] != sample[j])
1350 template <
class T1,
size_t N1,
class T2>
1351 inline size_t strnstr(
1352 _In_
const T1 (&str)[N1],
1353 _In_z_
const T2* sample)
1355 return strnstr(str, N1, sample);
1366 template <
class T1,
class T2>
1367 inline size_t stristr(
1368 _In_z_
const T1* str,
1369 _In_z_
const T2* sample)
1373 for (
size_t offset = 0;; ++offset) {
1374 for (
size_t i = offset, j = 0;; ++i, ++j) {
1379 if (tolower(str[i]) != tolower(sample[j]))
1394 template <
class T1,
class T2>
1395 inline size_t stristr(
1396 _In_z_
const T1* str,
1397 _In_z_
const T2* sample,
1398 _In_
const std::locale& locale)
1402 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
1403 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
1404 for (
size_t offset = 0;; ++offset) {
1405 for (
size_t i = offset, j = 0;; ++i, ++j) {
1410 if (ctype1.tolower(str[i]) != ctype2.tolower(sample[j]))
1425 template <
class T1,
class T2>
1426 inline size_t strnistr(
1427 _In_reads_or_z_opt_(count)
const T1* str,
1429 _In_z_
const T2* sample)
1431 _Assume_(str || !count);
1433 for (
size_t offset = 0;; ++offset) {
1434 for (
size_t i = offset, j = 0;; ++i, ++j) {
1437 if (i >= count || !str[i])
1439 if (tolower(str[i]) != tolower(sample[j]))
1455 template <
class T1,
class T2>
1456 inline size_t strnistr(
1457 _In_reads_or_z_opt_(count)
const T1* str,
1459 _In_z_
const T2* sample,
1460 _In_
const std::locale& locale)
1462 _Assume_(str || !count);
1464 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
1465 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
1466 for (
size_t offset = 0;; ++offset) {
1467 for (
size_t i = offset, j = 0;; ++i, ++j) {
1470 if (i >= count || !str[i])
1472 if (ctype1.tolower(str[i]) != ctype2.tolower(sample[j]))
1486 template <
class T1,
size_t N1,
class T2>
1487 inline size_t strnistr(
1488 _In_
const T1 (&str)[N1],
1489 _In_z_
const T2* sample)
1491 return strnistr(str, N1, sample);
1503 template <
class T1,
size_t N1,
class T2>
1504 inline size_t strnistr(
1505 _In_
const T1 (&str)[N1],
1506 _In_z_
const T2* sample,
1507 _In_
const std::locale& locale)
1509 return strnistr(str, N1, sample, locale);
1520 template <
class T1,
class T2>
1521 inline size_t strcpy(
1522 _Out_writes_z_(_String_length_(src) + 1) T1* dst,
1523 _In_z_
const T2* src)
1527 for (
size_t i = 0; ; ++i) {
1528 if ((dst[i] =
static_cast<T1
>(src[i])) == 0)
1542 template <
class T1,
class T2>
1543 inline size_t strncpy(
1544 _Out_writes_(count) _Post_maybez_ T1* dst,
1545 _In_reads_or_z_opt_(count)
const T2* src, _In_
size_t count)
1547 _Assume_(dst || !count);
1548 _Assume_(src || !count);
1549 for (
size_t i = 0; ; ++i) {
1552 if ((dst[i] =
static_cast<T1
>(src[i])) == 0)
1567 template <
class T1,
class T2>
1568 inline size_t strncpy(
1569 _Out_writes_(count_dst) _Post_maybez_ T1* dst, _In_
size_t count_dst,
1570 _In_reads_or_z_opt_(count_src)
const T2* src, _In_
size_t count_src)
1572 _Assume_(dst || !count_dst);
1573 _Assume_(src || !count_src);
1574 for (
size_t i = 0; ; ++i)
1578 if (i >= count_src) {
1582 if ((dst[i] =
static_cast<T1
>(src[i])) == 0)
1595 template <
class T1,
size_t N1,
class T2,
size_t N2>
1596 inline size_t strncpy(
1597 _Out_ _Post_maybez_ T1 (&dst)[N1],
1598 _In_
const T2 (&src)[N2])
1600 return strncpy(dst, N1, src, N2);
1611 template <
class T1,
class T2>
1612 inline size_t strcat(
1613 _In_z_ _Out_writes_z_(_String_length_(dst) + _String_length_(src) + 1) T1* dst,
1614 _In_z_
const T2* src)
1618 for (
size_t i = 0, j = stdex::strlen<T1>(dst); ; ++i, ++j) {
1619 if ((dst[j] =
static_cast<T1
>(src[i])) == 0)
1633 template <
class T1,
class T2>
1634 inline size_t strncat(
1636 _In_reads_or_z_opt_(count)
const T2* src, _In_
size_t count)
1638 _Assume_(dst || !count);
1639 _Assume_(src || !count);
1640 for (
size_t i = 0, j = stdex::strlen<T1>(dst); ; ++i, ++j) {
1643 if ((dst[j] =
static_cast<T1
>(src[i])) == 0)
1658 template <
class T1,
class T2>
1659 inline size_t strncat(
1660 _Out_writes_(count_dst) _Post_maybez_ T1* dst, _In_
size_t count_dst,
1661 _In_reads_or_z_opt_(count_src)
const T2* src, _In_
size_t count_src)
1663 _Assume_(dst || !count_dst);
1664 _Assume_(src || !count_src);
1665 for (
size_t i = 0, j = stdex::strnlen<T1>(dst, count_dst); ; ++i, ++j)
1669 if (i >= count_src) {
1673 if ((dst[j] =
static_cast<T1
>(src[i])) == 0)
1689 inline _Check_return_ _Ret_maybenull_z_ T* strdup(_In_opt_z_
const T* str)
1691 if (!str) _Unlikely_
1693 size_t count = strlen(str) + 1;
1694 T* dst =
new T[count];
1695 strncpy(dst, count, str, SIZE_MAX);
1711 inline _Ret_z_ T* strndup(
1712 _In_reads_or_z_opt_(count)
const T* str,
1715 T* dst =
new T[count];
1716 strncpy(dst, count, str, SIZE_MAX);
1730 template <
class T,
size_t N>
1731 inline _Check_return_ _Ret_maybenull_z_ T* strndup(_In_
const T (&str)[N])
1733 return strndup(str, N);
1746 inline size_t crlf2nl(_Out_writes_z_(_String_length_(src) + 1) T* dst, _In_z_
const T* src)
1751 for (i = j = 0; src[j];) {
1752 if (src[j] !=
'\r' || src[j + 1] !=
'\n')
1753 dst[i++] = src[j++];
1769 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
1770 inline void crlf2nl(_Inout_ std::basic_string<T, TR, AX>& dst, _In_z_
const T* src)
1773 _Assume_(src != dst.data());
1775 dst.reserve(strlen(src));
1776 for (
size_t j = 0; src[j];) {
1777 if (src[j] !=
'\r' || src[j + 1] !=
'\n')
1791 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
1792 inline void crlf2nl(_Inout_ std::basic_string<T, TR, AX>& str)
1795 for (i = j = 0, n = str.size(); j < n;) {
1796 if (str[j] !=
'\r' || str[j + 1] !=
'\n')
1797 str[i++] = str[j++];
1807 template <
class T,
class T_bin>
1808 inline T_bin strtoint(
1809 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
1810 _Out_opt_
size_t* end,
1812 _Out_ uint8_t& flags)
1814 _Assume_(str || !count);
1815 _Assume_(radix == 0 || 2 <= radix && radix <= 36);
1818 T_bin value = 0, digit,
1820 max_ui_pre1, max_ui_pre2;
1826 if (i >= count || !str[i])
goto error;
1827 if (!isspace(str[i]))
break;
1831 if (str[i] ==
'+') {
1834 if (i >= count || !str[i])
goto error;
1836 else if (str[i] ==
'-') {
1839 if (i >= count || !str[i])
goto error;
1844 if (str[i] ==
'0' && i + 1 < count && (str[i + 1] ==
'x' || str[i + 1] ==
'X')) {
1846 if (i >= count || !str[i])
goto error;
1851 if (str[i] ==
'0') {
1853 if (i >= count || !str[i])
goto error;
1854 if (str[i] ==
'x' || str[i] ==
'X') {
1857 if (i >= count || !str[i])
goto error;
1867 max_ui_pre1 = max_ui / (T_bin)radix;
1868 max_ui_pre2 = max_ui % (T_bin)radix;
1870 if (
'0' <= str[i] && str[i] <=
'9')
1871 digit = (T_bin)str[i] -
'0';
1872 else if (
'A' <= str[i] && str[i] <=
'Z')
1873 digit = (T_bin)str[i] -
'A' +
'\x0a';
1874 else if (
'a' <= str[i] && str[i] <=
'z')
1875 digit = (T_bin)str[i] -
'a' +
'\x0a';
1878 if (digit >= (T_bin)radix)
1881 if (value < max_ui_pre1 ||
1882 (value == max_ui_pre1 && digit <= max_ui_pre2))
1883 value = value * (T_bin)radix + digit;
1890 if (i >= count || !str[i])
1910 template <
class T,
class T_bin>
1912 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
1913 _Out_opt_
size_t* end,
1919 switch (
sizeof(T_bin)) {
1921 value = (T_bin)strtoint<T, uint8_t>(str, count, end, radix, flags);
1922 if ((flags & 0x01) && (value & 0x80)) {
1926 return (flags & 0x02) ?
1927 (flags & 0x01) ? (T_bin)0x80 : (T_bin)0x7f :
1928 (flags & 0x01) ? -value : value;
1931 value = (T_bin)strtoint<T, uint16_t>(str, count, end, radix, flags);
1932 if ((flags & 0x01) && (value & 0x8000)) {
1936 return (flags & 0x02) ?
1937 (flags & 0x01) ? (T_bin)0x8000 : (T_bin)0x7fff :
1938 (flags & 0x01) ? -value : value;
1941 value = (T_bin)strtoint<T, uint32_t>(str, count, end, radix, flags);
1942 if ((flags & 0x01) && (value & 0x80000000)) {
1946 return (flags & 0x02) ?
1947 (flags & 0x01) ? (T_bin)0x80000000 : (T_bin)0x7fffffff :
1948 (flags & 0x01) ? -value : value;
1951 value = (T_bin)strtoint<T, uint64_t>(str, count, end, radix, flags);
1952 if ((flags & 0x01) && (value & 0x8000000000000000)) {
1956 return (flags & 0x02) ?
1957 (flags & 0x01) ? (T_bin)0x8000000000000000 : (T_bin)0x7fffffffffffffff :
1958 (flags & 0x01) ? -value : value;
1961 throw std::invalid_argument(
"Unsupported bit length");
1974 template <
class T,
size_t N,
class T_bin>
1976 _In_
const T (&str)[N],
1977 _Out_opt_
size_t* end,
1980 return strtoint<T, T_bin>(str, N, end, radix);
1993 template <
class T,
class T_bin>
1994 inline T_bin strtouint(
1995 _In_reads_or_z_opt_(count)
const T* str,
1997 _Out_opt_
size_t* end,
2003 switch (
sizeof(T_bin)) {
2004 case 1: value = (T_bin)strtoint<T, uint8_t>(str, count, end, radix, flags);
break;
2005 case 2: value = (T_bin)strtoint<T, uint16_t>(str, count, end, radix, flags);
break;
2006 case 4: value = (T_bin)strtoint<T, uint32_t>(str, count, end, radix, flags);
break;
2007 case 8: value = (T_bin)strtoint<T, uint64_t>(str, count, end, radix, flags);
break;
2008 default:
throw std::invalid_argument(
"Unsupported bit length");
2011 return (flags & 0x02) ?
2012 (flags & 0x01) ? (T_bin)0 : (T_bin)-1 :
2013 (flags & 0x01) ? ~value : value;
2025 template <
class T,
size_t N,
class T_bin>
2026 inline T_bin strtouint(
2027 _In_
const T (&str)[N],
2028 _Out_opt_
size_t* end,
2031 return strtouint<T, T_bin>(str, N, end, radix);
2045 inline int32_t strto32(
2046 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
2047 _Out_opt_
size_t* end,
2050 return strtoint<T, int32_t>(str, count, end, radix);
2062 template <
class T,
size_t N>
2063 inline int32_t strto32(
2064 _In_
const T (&str)[N],
2065 _Out_opt_
size_t* end,
2068 return strto32<T>(str, N, end, radix);
2082 inline int64_t strto64(
2083 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
2084 _Out_opt_
size_t* end,
2087 return strtoint<T, int64_t>(str, count, end, radix);
2099 template <
class T,
size_t N>
2100 inline int64_t strto64(
2101 _In_
const T (&str)[N],
2102 _Out_opt_
size_t* end,
2105 return strto64<T>(str, N, end, radix);
2120 inline ptrdiff_t strtoi(
2121 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
2122 _Out_opt_
size_t* end,
2125#if defined(_WIN64) || defined(__LP64__)
2126 return static_cast<ptrdiff_t
>(strto64(str, count, end, radix));
2128 return static_cast<ptrdiff_t
>(strto32(str, count, end, radix));
2142 template <
class T,
size_t N>
2143 inline ptrdiff_t strtoi(
2144 _In_
const T (&str)[N],
2145 _Out_opt_
size_t* end,
2148 return strtoi<T>(str, N, end, radix);
2162 inline uint32_t strtou32(
2163 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
2164 _Out_opt_
size_t* end,
2167 return strtouint<T, uint32_t>(str, count, end, radix);
2179 template <
class T,
size_t N>
2180 inline uint32_t strtou32(
2181 _In_
const T (&str)[N],
2182 _Out_opt_
size_t* end,
2185 return strtou32(str, N, end, radix);
2199 inline uint64_t strtou64(
2200 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
2201 _Out_opt_
size_t* end,
2204 return strtouint<T, uint64_t>(str, count, end, radix);
2216 template <
class T,
size_t N>
2217 inline uint64_t strtou64(
2218 _In_
const T (&str)[N],
2219 _Out_opt_
size_t* end,
2222 return strtou64<T>(str, N, end, radix);
2237 inline size_t strtoui(
2238 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
2239 _Out_opt_
size_t* end,
2242#if defined(_WIN64) || defined(__LP64__)
2243 return static_cast<size_t>(strtou64(str, count, end, radix));
2245 return static_cast<size_t>(strtou32(str, count, end, radix));
2259 template <
class T,
size_t N>
2260 inline size_t strtoui(
2261 _In_
const T (&str)[N],
2262 _Out_opt_
size_t* end,
2265 return strtoui<T>(str, N, end, radix);
2278 inline double strtod(
2279 _In_reads_or_z_opt_(count)
const char* str, _In_
size_t count,
2280 _Out_opt_
size_t* end,
2281 _In_opt_ locale_t locale)
2283 count = strnlen(str, count);
2284 _Assume_(str || !count);
2285 std::string tmp(str, count);
2289 r = _strtod_l(tmp.c_str(), &_end, locale);
2291 r = strtod_l(tmp.c_str(), &_end, locale);
2293 if (end) *end = (size_t)(_end - tmp.c_str());
2307 inline double strtod(
2308 _In_reads_or_z_opt_(count)
const wchar_t* str, _In_
size_t count,
2309 _Out_opt_
size_t* end,
2310 _In_opt_ locale_t locale)
2312 count = strnlen(str, count);
2313 _Assume_(str || !count);
2314 std::wstring tmp(str, count);
2318 r = _wcstod_l(tmp.c_str(), &_end, locale);
2320 r = wcstod_l(tmp.c_str(), &_end, locale);
2322 if (end) *end = (size_t)(_end - tmp.c_str());
2327 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)
2330#pragma warning(suppress: 4996)
2331 return _vsnprintf_l(str, capacity, format, locale, arg);
2333 va_list arg_mutable;
2334 va_copy(arg_mutable, arg);
2335 return ::vsnprintf_l(str, capacity, locale, format, arg_mutable);
2339 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)
2342#pragma warning(suppress: 4996)
2343 return _vsnwprintf_l(str, capacity, format, locale, arg);
2345 va_list arg_mutable;
2346 va_copy(arg_mutable, arg);
2347 return ::vswprintf_l(str, capacity, locale, format, arg_mutable);
2362 template<
class T,
class TR,
class AX>
2363 inline size_t vappendf(_Inout_ std::basic_string<T, TR, AX>& str, _In_z_ _Printf_format_string_params_(2)
const T* format, _In_opt_ locale_t locale, _In_ va_list arg)
2365 T buf[1024 /
sizeof(T)];
2368 int count = vsnprintf(buf, _countof(buf), format, locale, arg);
2369 if (0 <= count &&
static_cast<size_t>(count) <= _countof(buf)) {
2371 str.append(buf,
static_cast<size_t>(count));
2372 return static_cast<size_t>(count);
2378 count = vsnprintf(NULL, 0, format, locale, arg);
2379 _Assume_(count >= 0);
2381 case EINVAL:
throw std::invalid_argument(
"invalid vsnprintf arguments");
2382 case EILSEQ:
throw std::runtime_error(
"encoding error");
2383 default:
throw std::runtime_error(
"failed to format string");
2386 size_t offset = str.size();
2387 str.resize(offset + count);
2388 if (vsnprintf(&str[offset], count + 1, format, locale, arg) != count) _Unlikely_
2389 throw std::runtime_error(
"failed to format string");
2391 size_t offset = str.size();
2392 for (
size_t capacity = 2 * 1024 /
sizeof(T);; capacity *= 2) {
2396 str.resize(offset + capacity);
2397 count = vsnprintf(&str[offset], capacity, format, locale, arg);
2398 if (0 <= count &&
static_cast<size_t>(count) <= capacity) {
2399 str.resize(offset +
static_cast<size_t>(count));
2400 return static_cast<size_t>(count);
2403 case EINVAL:
throw std::invalid_argument(
"invalid vsnprintf arguments");
2404 case EILSEQ:
throw std::runtime_error(
"encoding error");
2405 default:
throw std::runtime_error(
"failed to format string");
2409 return static_cast<size_t>(count);
2421 template<
class T,
class TR,
class AX>
2422 inline size_t appendf(_Inout_ std::basic_string<T, TR, AX>& str, _In_z_ _Printf_format_string_params_(2)
const T* format, _In_opt_ locale_t locale, ...)
2425 va_start(arg, locale);
2426 size_t n = vappendf(str, format, locale, arg);
2439 template<
class T,
class TR,
class AX>
2440 inline void vsprintf(_Inout_ std::basic_string<T, TR, AX>& str, _In_z_ _Printf_format_string_params_(2)
const T* format, _In_opt_ locale_t locale, _In_ va_list arg)
2443 vappendf(str, format, locale, arg);
2453 template<
class T,
class TR,
class AX>
2454 inline void sprintf(_Inout_ std::basic_string<T, TR, AX>& str, _In_z_ _Printf_format_string_params_(2)
const T* format, _In_opt_ locale_t locale, ...)
2457 va_start(arg, locale);
2458 vsprintf(str, format, locale, arg);
2471 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2472 inline std::basic_string<T, TR, AX> vsprintf(_In_z_ _Printf_format_string_params_(2)
const T* format, _In_opt_ locale_t locale, _In_ va_list arg)
2474 std::basic_string<T, TR, AX> str;
2475 vappendf(str, format, locale, arg);
2487 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2488 inline std::basic_string<T, TR, AX> sprintf(_In_z_ _Printf_format_string_params_(2)
const T* format, _In_opt_ locale_t locale, ...)
2491 va_start(arg, locale);
2492 auto str = vsprintf(format, locale, arg);
2498 inline size_t strftime(_Out_z_cap_(capacity)
char* str, _In_
size_t capacity, _In_z_ _Printf_format_string_
const char* format, _In_
const struct tm* time, _In_opt_ locale_t locale)
2501 return _strftime_l(str, capacity, format, time, locale);
2503 return strftime_l(str, capacity, format, time, locale);
2507 inline size_t strftime(_Out_z_cap_(capacity)
wchar_t* str, _In_
size_t capacity, _In_z_ _Printf_format_string_
const wchar_t* format, _In_
const struct tm* time, _In_opt_ locale_t locale)
2510 return _wcsftime_l(str, capacity, format, time, locale);
2512 return wcsftime_l(str, capacity, format, time, locale);
2525 template<
class T,
class TR,
class AX>
2526 inline void strcatftime(_Inout_ std::basic_string<T, TR, AX>& str, _In_z_ _Printf_format_string_
const T* format, _In_
const struct tm* time, _In_opt_ locale_t locale)
2528 T buf[1024 /
sizeof(T)];
2531 size_t count = strftime(buf, _countof(buf), format, time, locale);
2534 str.append(buf, count);
2537 size_t offset = str.size();
2538 for (
size_t capacity = 2 * 1024 /
sizeof(T);; capacity *= 2) {
2540 str.resize(offset + capacity);
2541 count = strftime(&str[offset], capacity + 1, format, time, locale);
2543 str.resize(offset + count);
2557 template<
class T,
class TR,
class AX>
2558 inline void strftime(_Inout_ std::basic_string<T, TR, AX>& str, _In_z_ _Printf_format_string_
const T* format, _In_
const struct tm* time, _In_opt_ locale_t locale)
2561 strcatftime(str, format, time, locale);
2573 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2574 inline std::basic_string<T, TR, AX> strftime(_In_z_ _Printf_format_string_
const T* format, _In_
const struct tm* time, _In_opt_ locale_t locale)
2576 std::basic_string<T, TR, AX> str;
2577 strcatftime(str, format, time, locale);
2616 inline void strlwr(_Inout_updates_z_(count) T* str, _In_
size_t count)
2618 _Assume_(str || !count);
2619 for (
size_t i = 0; i < count && str[i]; ++i)
2620 str[i] = tolower(str[i]);
2631 inline void strlwr(_Inout_updates_z_(count) T* str, _In_
size_t count, _In_
const std::locale& locale)
2633 _Assume_(str || !count);
2634 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2635 for (
size_t i = 0; i < count && str[i]; ++i)
2636 str[i] = ctype.tolower(str[i]);
2644 template<
class T,
size_t N>
2645 inline void strlwr(_Inout_ T (&str)[N])
2656 template<
class T,
size_t N>
2657 inline void strlwr(_Inout_ T (&str)[N], _In_
const std::locale& locale)
2659 strlwr(str, N, locale);
2667 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2668 inline void strlwr(_Inout_ std::basic_string<T, TR, AX>& str)
2680 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2681 inline void strlwr(_Inout_ std::basic_string<T, TR, AX>& str, _In_
const std::locale& locale)
2683 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2685 c = ctype.tolower(c);
2723 inline void strupr(_Inout_updates_z_(count) T* str, _In_
size_t count)
2725 _Assume_(str || !count);
2726 for (
size_t i = 0; i < count && str[i]; ++i)
2727 str[i] = toupper(str[i]);
2738 inline void strupr(_Inout_updates_z_(count) T* str, _In_
size_t count, _In_
const std::locale& locale)
2740 _Assume_(str || !count);
2741 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2742 for (
size_t i = 0; i < count && str[i]; ++i)
2743 str[i] = ctype.toupper(str[i]);
2751 template<
class T,
size_t N>
2752 inline void strupr(_Inout_ T (&str)[N])
2754 return strupr(str, N);
2763 template<
class T,
size_t N>
2764 inline void strupr(_Inout_ T (&str)[N], _In_
const std::locale& locale)
2766 return strupr(str, N, locale);
2774 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2775 inline void strupr(_Inout_ std::basic_string<T, TR, AX>& str)
2787 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2788 inline void strupr(_Inout_ std::basic_string<T, TR, AX>& str, _In_
const std::locale& locale)
2790 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2792 c = ctype.toupper(c);
2804 inline size_t ltrim(
2805 _Inout_z_count_(count) T* str, _In_
size_t count)
2807 for (
size_t i = 0;; ++i) {
2809 if (count) str[0] = 0;
2816 if (!isspace(str[i])) {
2818 return strnlen(str, count);
2819 size_t n = count != SIZE_MAX ? strncpy(str, str + i, count - i) : strcpy(str, str + i);
2836 inline size_t ltrim(
2837 _Inout_z_count_(count) T* str, _In_
size_t count,
2838 _In_
const std::locale& locale)
2840 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2841 for (
size_t i = 0;; ++i) {
2843 if (count) str[0] = 0;
2850 if (!ctype.is(ctype.space, str[i])) {
2852 return strnlen(str, count);
2853 size_t n = count != SIZE_MAX ? strncpy(str, str + i, count - i) : strcpy(str, str + i);
2865 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2866 inline void ltrim(_Inout_ std::basic_string<T, TR, AX>& s)
2873 [&](_In_ T ch) { return !isspace(ch); }));
2882 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2883 inline void ltrim(_Inout_ std::basic_string<T, TR, AX>& s, _In_
const std::locale& locale)
2885 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2891 [&](_In_ T ch) { return !ctype.is(ctype.space, ch); }));
2903 inline size_t rtrim(
2904 _Inout_z_count_(count) T* str, _In_
size_t count)
2906 for (
size_t i = 0, j = 0;;) {
2907 if (i >= count || !str[i]) {
2908 if (j < count) str[j] = 0;
2911 if (!isspace(str[i]))
2928 inline size_t rtrim(
2929 _Inout_z_count_(count) T* str, _In_
size_t count,
2930 _In_
const std::locale& locale)
2932 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2933 for (
size_t i = 0, j = 0;;) {
2934 if (i >= count || !str[i]) {
2935 if (j < count) str[j] = 0;
2938 if (!ctype.is(ctype.space, str[i]))
2950 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2951 static inline void rtrim(_Inout_ std::basic_string<T, TR, AX>& s)
2957 [&](_In_ T ch) { return !isspace(ch); }).base(),
2967 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2968 static inline void rtrim(_Inout_ std::basic_string<T, TR, AX>& s, _In_
const std::locale& locale)
2970 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2975 [&](_In_ T ch) { return !ctype.is(ctype.space, ch); }).base(),
2989 _Inout_z_count_(count) T* str, _In_
size_t count)
2991 return ltrim(str, rtrim(str, count));
3005 _Inout_z_count_(count) T* str, _In_
size_t count,
3006 _In_
const std::locale& locale)
3008 return ltrim(str, rtrim(str, count, locale), locale);
3016 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
3017 static inline void trim(_Inout_ std::basic_string<T, TR, AX>& s)
3019 auto nonspace = [&](_In_ T ch) {
return !isspace(ch); };
3040 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
3041 static inline void trim(_Inout_ std::basic_string<T, TR, AX>& s, _In_
const std::locale& locale)
3043 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
3044 auto nonspace = [&](_In_ T ch) {
return !ctype.is(ctype.space, ch); };