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<utf16_t
>((chr >> 10) & 0x3ff);
91 str[1] = 0xdc00 +
static_cast<utf16_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 bool islbreak(_In_ T chr)
116 return chr ==
'\n' || chr ==
'\r';
128 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 bool isspace(_In_ T chr)
146 return chr ==
' ' || chr ==
'\t' || chr ==
'\n' || chr ==
'\r' || chr ==
'\v' || chr ==
'\f';
155 bool islower(_In_ T chr)
157 return 'a' <= chr && chr <=
'z';
166 bool isupper(_In_ T chr)
168 return 'A' <= chr && chr <=
'Z';
177 bool isdigit(_In_ T chr)
179 return '0' <= chr && chr <=
'9';
188 bool isalpha(_In_ T chr)
190 return islower(chr) || isupper(chr);
199 bool is7bit(_In_ T chr)
201 return '\x00' <= chr && chr <=
'\x7f';
210 inline size_t glyphlen(_In_reads_or_z_opt_(count)
const utf16_t* glyph, _In_
size_t count)
212 _Assume_(glyph || !count);
214 size_t i = count < 2 || !is_surrogate_pair(glyph) ? 1 : 2;
215 for (; i < count && iscombining(glyph[i]); ++i);
227 inline size_t glyphlen(_In_reads_or_z_opt_(count)
const utf32_t* glyph, _In_
size_t count)
229 _Assume_(glyph || !count);
232 for (; i < count && iscombining(glyph[i]); ++i);
244 inline size_t glyphrlen(_In_reads_or_z_opt_(count)
const utf16_t* str, _In_
size_t count)
246 _Assume_(count && str && str[count - 1]);
247 for (
size_t i = count; i--;) {
248 if (!iscombining(str[i]))
249 return count - (!is_low_surrogate(str[i]) || i == 0 || !is_high_surrogate(str[i - 1]) ? i : i - 1);
260 inline size_t glyphrlen(_In_reads_or_z_opt_(count)
const utf32_t* str, _In_
size_t count)
262 _Assume_(count && str && str[count - 1]);
263 for (
size_t i = count; i--;) {
264 if (!iscombining(str[i]))
265 return count - (i == 0 ? i : i - 1);
278 T tolower(_In_ T chr)
280 return isupper(chr) ? chr | 0x20 : chr;
291 T toupper(_In_ T chr)
293 return islower(chr) ? chr | ~0x20 : chr;
304 size_t strlen(_In_z_
const T* str)
308 for (i = 0; str[i]; ++i);
321 size_t strnlen(_In_reads_or_z_opt_(count)
const T* str, _In_
size_t count)
323 _Assume_(str || !count);
325 for (i = 0; i < count && str[i]; ++i);
336 template <
class T,
size_t N>
337 size_t strnlen(_In_
const T (&str)[N])
339 return strnlen(str, N);
342 constexpr auto npos{
static_cast<size_t>(-1) };
353 size_t strchr(_In_z_
const T* str, _In_ T chr)
356 for (
size_t i = 0; str[i]; ++i)
357 if (str[i] == chr)
return i;
372 _In_reads_or_z_opt_(count)
const T* str,
376 _Assume_(str || !count);
377 for (
size_t i = 0; i < count && str[i]; ++i)
378 if (str[i] == chr)
return i;
390 template <
class T,
size_t N>
392 _In_
const T (&str)[N],
395 return strnchr(str, N, chr);
413 for (
size_t i = 0; str[i]; ++i)
414 if (str[i] == chr) z = i;
429 _In_reads_or_z_opt_(count)
const T* str,
433 _Assume_(str || !count);
435 for (
size_t i = 0; i < count && str[i]; ++i)
436 if (str[i] == chr) z = i;
448 template <
class T,
size_t N>
450 _In_
const T (&str)[N],
453 return strrnchr(str, N, chr);
471 for (
size_t i = 0; str[i]; ++i)
472 if (tolower(str[i]) == chr)
return i;
489 _In_
const std::locale& locale)
492 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
493 chr = ctype.tolower(chr);
494 for (
size_t i = 0; str[i]; ++i)
495 if (ctype.tolower(str[i]) == chr)
return i;
510 _In_reads_or_z_opt_(count)
const T* str,
514 _Assume_(str || !count);
516 for (
size_t i = 0; i < count && str[i]; ++i)
517 if (tolower(str[i]) == chr)
return i;
533 _In_reads_or_z_opt_(count)
const T* str,
536 _In_
const std::locale& locale)
538 _Assume_(str || !count);
539 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
540 chr = ctype.tolower(chr);
541 for (
size_t i = 0; i < count && str[i]; ++i)
542 if (ctype.tolower(str[i]) == chr)
return i;
554 template <
class T,
size_t N>
556 _In_
const T (&str)[N],
559 return strnichr(str, N, chr);
571 template <
class T,
size_t N>
573 _In_
const T (&str)[N],
575 _In_
const std::locale& locale)
577 return strnichr(str, N, chr, locale);
596 for (
size_t i = 0; str[i]; ++i)
597 if (tolower(str[i]) == chr) z = i;
612 _In_reads_or_z_opt_(count)
const T* str,
614 _In_
const std::locale& locale)
617 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
618 chr = ctype.tolower(chr);
620 for (
size_t i = 0; str[i]; ++i)
621 if (ctype.tolower(str[i]) == chr) z = i;
636 _In_reads_or_z_opt_(count)
const T* str,
640 _Assume_(str || !count);
643 for (
size_t i = 0; i < count && str[i]; ++i)
644 if (tolower(str[i]) == chr) z = i;
660 _In_reads_or_z_opt_(count)
const T* str,
663 _In_
const std::locale& locale)
665 _Assume_(str || !count);
666 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
667 chr = ctype.tolower(chr);
669 for (
size_t i = 0; i < count && str[i]; ++i)
670 if (ctype.tolower(str[i]) == chr) z = i;
682 template <
class T,
size_t N>
684 _In_
const T (&str)[N],
687 return strrnichr(str, N, chr);
699 template <
class T,
size_t N>
701 _In_
const T (&str)[N],
703 _In_
const std::locale& locale)
705 return strrnichr(str, N, chr, locale);
756 _In_reads_or_z_opt_(count)
const T* str,
759 _Assume_(str || !count);
760 for (
size_t i = 0; i < count && str[i]; ++i)
761 if (!isspace(str[i]))
777 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
778 _In_
const std::locale& locale)
780 _Assume_(str || !count);
781 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
782 for (
size_t i = 0; i < count && str[i]; ++i)
783 if (!ctype.is(ctype.space, str[i]))
795 template <
class T,
size_t N>
796 bool isblank(_In_
const T (&str)[N])
798 return isblank(str, N);
809 template <
class T,
size_t N>
811 _In_
const T (&str)[N],
812 _In_
const std::locale& locale)
814 return isblank(str, N, locale);
843 bool is7bit(_In_reads_or_z_opt_(count)
const T* str, _In_
size_t count)
845 _Assume_(str || !count);
846 for (
size_t i = 0; i < count && str[i]; i++)
859 template <
class T,
size_t N>
860 bool is7bit(_In_
const T (&str)[N])
862 return is7bit(str, N);
873 template <
class T1,
class T2>
874 int strcmp(_In_z_
const T1* str1, _In_z_
const T2* str2)
878 size_t i; T1 a; T2 b;
879 for (i = 0; (a = str1[i]) | (b = str2[i]); ++i) {
880 if (a > b)
return +1;
881 if (a < b)
return -1;
883 if (str1[i])
return +1;
884 if (str2[i])
return -1;
897 template <
class T1,
class T2>
898 int strncmp(_In_reads_or_z_opt_(count)
const T1* str1, _In_reads_or_z_opt_(count)
const T2* str2, _In_
size_t count)
900 _Assume_(str1 || !count);
901 _Assume_(str2 || !count);
902 size_t i; T1 a; T2 b;
903 for (i = 0; i < count && ((a = str1[i]) | (b = str2[i])); ++i) {
904 if (a > b)
return +1;
905 if (a < b)
return -1;
907 if (i < count && str1[i])
return +1;
908 if (i < count && str2[i])
return -1;
922 template <
class T1,
class T2>
924 _In_reads_or_z_opt_(count1)
const T1* str1, _In_
size_t count1,
925 _In_reads_or_z_opt_(count2)
const T2* str2, _In_
size_t count2)
927 _Assume_(str1 || !count1);
928 _Assume_(str2 || !count2);
930 for (i = 0; i < count1 && i < count2; ++i) {
933 if (!a && !b)
return 0;
934 if (a > b)
return +1;
935 if (a < b)
return -1;
937 if (i < count1 && str1[i])
return +1;
938 if (i < count2 && str2[i])
return -1;
950 template <
class T1,
size_t N1,
class T2,
size_t N2>
952 _In_
const T1 (&str1)[N1],
953 _In_
const T2 (&str2)[N2])
955 return strncmp(str1, N1, str2, N2);
969 _In_reads_or_z_opt_(count1)
const utf32_t* str1, _In_
size_t count1,
970 _In_reads_or_z_opt_(count2)
const utf16_t* str2, _In_
size_t count2)
972 _Assume_(str1 || !count1);
973 _Assume_(str2 || !count2);
974 size_t i, j, j_next; utf32_t a, b;
975 for (i = 0, j = 0; i < count1 && j < count2; ++i, j = j_next) {
979 if (j + 1 >= count2 || !is_surrogate_pair(&str2[j])) {
980 b =
static_cast<utf32_t
>(str2[j]);
984 b = surrogate_pair_to_ucs4(&str2[j]);
989 if (a > b)
return +1;
990 if (a < b)
return -1;
992 if (i < count1 && str1[i])
return +1;
993 if (j < count2 && str2[j])
return -1;
1005 template <
size_t N1,
size_t N2>
1007 _In_
const utf32_t (&str1)[N1],
1008 _In_
const utf16_t (&str2)[N2])
1010 return strncmp(str1, N1, str2, N2);
1021 template <
class T1,
class T2>
1022 int strrcmp(_In_z_
const T1* str1, _In_z_
const T2* str2)
1027 _Assume_(str1 || !i);
1028 _Assume_(str2 || !j);
1029 size_t k; T1 a; T2 b;
1030 for (k = 1; i && j; k++) {
1032 if ((a = str1[i]) > (b = str2[j]))
return +1;
1033 if (a < b)
return -1;
1035 if (i && !j)
return +1;
1036 if (!i && j)
return -1;
1049 template <
class T1,
class T2>
1050 int strrncmp(_In_reads_or_z_opt_(count)
const T1* str1, _In_reads_or_z_opt_(count)
const T2* str2, _In_
size_t count)
1053 i = strnlen(str1, count),
1054 j = strnlen(str2, count);
1055 _Assume_(str1 || !i);
1056 _Assume_(str2 || !j);
1057 size_t k; T1 a; T2 b;
1058 for (k = 1; i && j; k++) {
1060 if ((a = str1[i]) > (b = str2[j]))
return +1;
1061 if (a < b)
return -1;
1063 if (i && !j)
return +1;
1064 if (!i && j)
return -1;
1078 template <
class T1,
class T2>
1080 _In_reads_or_z_opt_(count1)
const T1* str1, _In_
size_t count1,
1081 _In_reads_or_z_opt_(count2)
const T2* str2, _In_
size_t count2)
1084 i = strnlen(str1, count1),
1085 j = strnlen(str2, count2);
1086 _Assume_(str1 || !i);
1087 _Assume_(str2 || !j);
1088 size_t k; T1 a; T2 b;
1089 for (k = 1; i && j; k++) {
1091 if ((a = str1[i]) > (b = str2[j]))
return +1;
1092 if (a < b)
return -1;
1094 if (i && !j)
return +1;
1095 if (!i && j)
return -1;
1107 template <
class T1,
size_t N1,
class T2,
size_t N2>
1109 _In_
const T1 (&str1)[N1],
1110 _In_
const T2 (&str2)[N2])
1112 return strrncmp(str1, N1, str2, N2);
1123 template <
class T1,
class T2>
1124 int stricmp(_In_z_
const T1* str1, _In_z_
const T2* str2)
1129 for (i = 0; ; ++i) {
1130 auto a = tolower(str1[i]);
1131 auto b = tolower(str2[i]);
1132 if (!a && !b)
return 0;
1133 if (a > b)
return +1;
1134 if (a < b)
return -1;
1147 template <
class T1,
class T2>
1148 int stricmp(_In_z_
const T1* str1, _In_z_
const T2* str2, _In_
const std::locale& locale)
1153 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
1154 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
1156 auto a = ctype1.tolower(str1[i]);
1157 auto b = ctype2.tolower(str2[i]);
1158 if (!a && !b)
return 0;
1159 if (a > b)
return +1;
1160 if (a < b)
return -1;
1162 if (str1[i])
return +1;
1163 if (str2[i])
return -1;
1176 template <
class T1,
class T2>
1177 int strnicmp(_In_reads_or_z_opt_(count)
const T1* str1, _In_reads_or_z_opt_(count)
const T2* str2, _In_
size_t count)
1179 _Assume_(str1 || !count);
1180 _Assume_(str2 || !count);
1182 for (i = 0; i < count; ++i) {
1183 auto a = tolower(str1[i]);
1184 auto b = tolower(str2[i]);
1185 if (!a && !b)
return 0;
1186 if (a > b)
return +1;
1187 if (a < b)
return -1;
1189 if (i < count && str1[i])
return +1;
1190 if (i < count && str2[i])
return -1;
1204 template <
class T1,
class T2>
1205 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)
1207 _Assume_(str1 || !count);
1208 _Assume_(str2 || !count);
1210 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
1211 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
1212 for (i = 0; i < count; ++i) {
1213 auto a = ctype1.tolower(str1[i]);
1214 auto b = ctype2.tolower(str2[i]);
1215 if (!a && !b)
return 0;
1216 if (a > b)
return +1;
1217 if (a < b)
return -1;
1219 if (i < count && str1[i])
return +1;
1220 if (i < count && str2[i])
return -1;
1234 template <
class T1,
class T2>
1236 _In_reads_or_z_opt_(count1)
const T1* str1, _In_
size_t count1,
1237 _In_reads_or_z_opt_(count2)
const T2* str2, _In_
size_t count2)
1239 _Assume_(str1 || !count1);
1240 _Assume_(str2 || !count2);
1242 for (i = 0; i < count1 && i < count2; ++i) {
1243 auto a = tolower(str1[i]);
1244 auto b = tolower(str2[i]);
1245 if (!a && !b)
return 0;
1246 if (a > b)
return +1;
1247 if (a < b)
return -1;
1249 if (i < count1 && str1[i])
return +1;
1250 if (i < count2 && str2[i])
return -1;
1265 template <
class T1,
class T2>
1267 _In_reads_or_z_opt_(count1)
const T1* str1, _In_
size_t count1,
1268 _In_reads_or_z_opt_(count2)
const T2* str2, _In_
size_t count2,
1269 _In_
const std::locale& locale)
1271 _Assume_(str1 || !count1);
1272 _Assume_(str2 || !count2);
1274 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
1275 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
1276 for (i = 0; i < count1 && i < count2; ++i) {
1277 auto a = ctype1.tolower(str1[i]);
1278 auto b = ctype2.tolower(str2[i]);
1279 if (!a && !b)
return 0;
1280 if (a > b)
return +1;
1281 if (a < b)
return -1;
1283 if (i < count1 && str1[i])
return +1;
1284 if (i < count2 && str2[i])
return -1;
1296 template <
class T1,
size_t N1,
class T2,
size_t N2>
1298 _In_
const T1 (&str1)[N1],
1299 _In_
const T2 (&str2)[N2])
1301 strnicmp(str1, N1, str2, N2);
1313 template <
class T1,
size_t N1,
class T2,
size_t N2>
1315 _In_
const T1 (&str1)[N1],
1316 _In_
const T2 (&str2)[N2],
1317 _In_
const std::locale& locale)
1319 strnicmp(str1, N1, str2, N2, locale);
1333 _In_z_
const T* str1,
1334 _In_z_
const T* str2,
1335 _In_
const std::locale& locale)
1339 auto& collate = std::use_facet<std::collate<T>>(locale);
1340 return collate.compare(str1, str1 + strlen(str1), str2, str2 + strlen(str2));
1356 _In_reads_or_z_opt_(count1)
const T* str1, _In_
size_t count1,
1357 _In_reads_or_z_opt_(count2)
const T* str2, _In_
size_t count2,
1358 _In_
const std::locale& locale)
1360 _Assume_(str1 || !count1);
1361 _Assume_(str2 || !count2);
1362 auto& collate = std::use_facet<std::collate<T>>(locale);
1363 return collate.compare(str1, str1 + count1, str2, str2 + count2);
1375 template <
class T,
size_t N1,
size_t N2>
1377 _In_
const T (&str1)[N1],
1378 _In_
const T (&str2)[N2],
1379 _In_
const std::locale& locale)
1381 return strncoll(str1, N1, str2, N2, locale);
1392 template <
class T1,
class T2>
1394 _In_z_
const T1* str,
1395 _In_z_
const T2* sample)
1399 for (
size_t offset = 0;; ++offset) {
1400 for (
size_t i = offset, j = 0;; ++i, ++j) {
1405 if (str[i] != sample[j])
1420 template <
class T1,
class T2>
1422 _In_reads_or_z_opt_(count)
const T1* str, _In_
size_t count,
1423 _In_z_
const T2* sample)
1425 _Assume_(str || !count);
1427 for (
size_t offset = 0;; ++offset) {
1428 for (
size_t i = offset, j = 0;; ++i, ++j) {
1431 if (i >= count || !str[i])
1433 if (str[i] != sample[j])
1447 template <
class T1,
size_t N1,
class T2>
1449 _In_
const T1 (&str)[N1],
1450 _In_z_
const T2* sample)
1452 return strnstr(str, N1, sample);
1463 template <
class T1,
class T2>
1465 _In_z_
const T1* str,
1466 _In_z_
const T2* sample)
1470 for (
size_t offset = 0;; ++offset) {
1471 for (
size_t i = offset, j = 0;; ++i, ++j) {
1476 if (tolower(str[i]) != tolower(sample[j]))
1491 template <
class T1,
class T2>
1493 _In_z_
const T1* str,
1494 _In_z_
const T2* sample,
1495 _In_
const std::locale& locale)
1499 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
1500 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
1501 for (
size_t offset = 0;; ++offset) {
1502 for (
size_t i = offset, j = 0;; ++i, ++j) {
1507 if (ctype1.tolower(str[i]) != ctype2.tolower(sample[j]))
1522 template <
class T1,
class T2>
1524 _In_reads_or_z_opt_(count)
const T1* str,
1526 _In_z_
const T2* sample)
1528 _Assume_(str || !count);
1530 for (
size_t offset = 0;; ++offset) {
1531 for (
size_t i = offset, j = 0;; ++i, ++j) {
1534 if (i >= count || !str[i])
1536 if (tolower(str[i]) != tolower(sample[j]))
1552 template <
class T1,
class T2>
1554 _In_reads_or_z_opt_(count)
const T1* str,
1556 _In_z_
const T2* sample,
1557 _In_
const std::locale& locale)
1559 _Assume_(str || !count);
1561 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
1562 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
1563 for (
size_t offset = 0;; ++offset) {
1564 for (
size_t i = offset, j = 0;; ++i, ++j) {
1567 if (i >= count || !str[i])
1569 if (ctype1.tolower(str[i]) != ctype2.tolower(sample[j]))
1583 template <
class T1,
size_t N1,
class T2>
1585 _In_
const T1 (&str)[N1],
1586 _In_z_
const T2* sample)
1588 return strnistr(str, N1, sample);
1600 template <
class T1,
size_t N1,
class T2>
1602 _In_
const T1 (&str)[N1],
1603 _In_z_
const T2* sample,
1604 _In_
const std::locale& locale)
1606 return strnistr(str, N1, sample, locale);
1617 template <
class T1,
class T2>
1619 _Out_writes_z_(_String_length_(src) + 1) T1* dst,
1620 _In_z_
const T2* src)
1624 for (
size_t i = 0; ; ++i) {
1625 if ((dst[i] =
static_cast<T1
>(src[i])) == 0)
1639 template <
class T1,
class T2>
1641 _Out_writes_(count) _Post_maybez_ T1* dst,
1642 _In_reads_or_z_opt_(count)
const T2* src, _In_
size_t count)
1644 _Assume_(dst || !count);
1645 _Assume_(src || !count);
1646 for (
size_t i = 0; ; ++i) {
1649 if ((dst[i] =
static_cast<T1
>(src[i])) == 0)
1664 template <
class T1,
class T2>
1666 _Out_writes_(count_dst) _Post_maybez_ T1* dst, _In_
size_t count_dst,
1667 _In_reads_or_z_opt_(count_src)
const T2* src, _In_
size_t count_src)
1669 _Assume_(dst || !count_dst);
1670 _Assume_(src || !count_src);
1671 for (
size_t i = 0; ; ++i)
1675 if (i >= count_src) {
1679 if ((dst[i] =
static_cast<T1
>(src[i])) == 0)
1692 template <
class T1,
size_t N1,
class T2,
size_t N2>
1694 _Out_ _Post_maybez_ T1 (&dst)[N1],
1695 _In_
const T2 (&src)[N2])
1697 return strncpy(dst, N1, src, N2);
1708 template <
class T1,
class T2>
1710 _In_z_ _Out_writes_z_(_String_length_(dst) + _String_length_(src) + 1) T1* dst,
1711 _In_z_
const T2* src)
1715 for (
size_t i = 0, j = stdex::strlen<T1>(dst); ; ++i, ++j) {
1716 if ((dst[j] =
static_cast<T1
>(src[i])) == 0)
1730 template <
class T1,
class T2>
1733 _In_reads_or_z_opt_(count)
const T2* src, _In_
size_t count)
1735 _Assume_(dst || !count);
1736 _Assume_(src || !count);
1737 for (
size_t i = 0, j = stdex::strlen<T1>(dst); ; ++i, ++j) {
1740 if ((dst[j] =
static_cast<T1
>(src[i])) == 0)
1755 template <
class T1,
class T2>
1757 _Out_writes_(count_dst) _Post_maybez_ T1* dst, _In_
size_t count_dst,
1758 _In_reads_or_z_opt_(count_src)
const T2* src, _In_
size_t count_src)
1760 _Assume_(dst || !count_dst);
1761 _Assume_(src || !count_src);
1762 for (
size_t i = 0, j = stdex::strnlen<T1>(dst, count_dst); ; ++i, ++j)
1766 if (i >= count_src) {
1770 if ((dst[j] =
static_cast<T1
>(src[i])) == 0)
1786 _Check_return_ _Ret_maybenull_z_ T* strdup(_In_opt_z_
const T* str)
1788 if (!str) _Unlikely_
1790 size_t count = strlen(str) + 1;
1791 T* dst =
new T[count];
1792 strncpy(dst, count, str, SIZE_MAX);
1809 _In_reads_or_z_opt_(count)
const T* str,
1812 T* dst =
new T[count];
1813 strncpy(dst, count, str, SIZE_MAX);
1827 template <
class T,
size_t N>
1828 _Check_return_ _Ret_maybenull_z_ T* strndup(_In_
const T (&str)[N])
1830 return strndup(str, N);
1843 size_t crlf2nl(_Out_writes_z_(_String_length_(src) + 1) T* dst, _In_z_
const T* src)
1848 for (i = j = 0; src[j];) {
1849 if (src[j] !=
'\r' || src[j + 1] !=
'\n')
1850 dst[i++] = src[j++];
1866 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
1867 void crlf2nl(_Inout_ std::basic_string<T, TR, AX>& dst, _In_z_
const T* src)
1870 _Assume_(src != dst.data());
1872 dst.reserve(strlen(src));
1873 for (
size_t j = 0; src[j];) {
1874 if (src[j] !=
'\r' || src[j + 1] !=
'\n')
1888 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
1889 void crlf2nl(_Inout_ std::basic_string<T, TR, AX>& str)
1892 for (i = j = 0, n = str.size(); j < n;) {
1893 if (str[j] !=
'\r' || str[j + 1] !=
'\n')
1894 str[i++] = str[j++];
1904 template <
class T,
class T_bin>
1906 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
1907 _Out_opt_
size_t* end,
1909 _Out_ uint8_t& flags)
1911 _Assume_(str || !count);
1912 _Assume_(radix == 0 || 2 <= radix && radix <= 36);
1915 T_bin value = 0, digit,
1917 max_ui_pre1, max_ui_pre2;
1923 if (i >= count || !str[i])
goto error;
1924 if (!isspace(str[i]))
break;
1928 if (str[i] ==
'+') {
1931 if (i >= count || !str[i])
goto error;
1933 else if (str[i] ==
'-') {
1936 if (i >= count || !str[i])
goto error;
1941 if (str[i] ==
'0' && i + 1 < count && (str[i + 1] ==
'x' || str[i + 1] ==
'X')) {
1943 if (i >= count || !str[i])
goto error;
1948 if (str[i] ==
'0') {
1950 if (i >= count || !str[i])
goto error;
1951 if (str[i] ==
'x' || str[i] ==
'X') {
1954 if (i >= count || !str[i])
goto error;
1964 max_ui_pre1 = max_ui / (T_bin)radix;
1965 max_ui_pre2 = max_ui % (T_bin)radix;
1967 if (
'0' <= str[i] && str[i] <=
'9')
1968 digit = (T_bin)str[i] -
'0';
1969 else if (
'A' <= str[i] && str[i] <=
'Z')
1970 digit = (T_bin)str[i] -
'A' +
'\x0a';
1971 else if (
'a' <= str[i] && str[i] <=
'z')
1972 digit = (T_bin)str[i] -
'a' +
'\x0a';
1975 if (digit >= (T_bin)radix)
1978 if (value < max_ui_pre1 ||
1979 (value == max_ui_pre1 && digit <= max_ui_pre2))
1980 value = value * (T_bin)radix + digit;
1987 if (i >= count || !str[i])
2007 template <
class T,
class T_bin>
2009 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
2010 _Out_opt_
size_t* end,
2016 switch (
sizeof(T_bin)) {
2018 value = (T_bin)strtoint<T, uint8_t>(str, count, end, radix, flags);
2019 if ((flags & 0x01) && (value & 0x80)) {
2023 return (flags & 0x02) ?
2024 (flags & 0x01) ? (T_bin)0x80 : (T_bin)0x7f :
2025 (flags & 0x01) ? -value : value;
2028 value = (T_bin)strtoint<T, uint16_t>(str, count, end, radix, flags);
2029 if ((flags & 0x01) && (value & 0x8000)) {
2033 return (flags & 0x02) ?
2034 (flags & 0x01) ? (T_bin)0x8000 : (T_bin)0x7fff :
2035 (flags & 0x01) ? -value : value;
2038 value = (T_bin)strtoint<T, uint32_t>(str, count, end, radix, flags);
2039 if ((flags & 0x01) && (value & 0x80000000)) {
2043 return (flags & 0x02) ?
2044 (flags & 0x01) ? (T_bin)0x80000000 : (T_bin)0x7fffffff :
2045 (flags & 0x01) ? -value : value;
2048 value = (T_bin)strtoint<T, uint64_t>(str, count, end, radix, flags);
2049 if ((flags & 0x01) && (value & 0x8000000000000000)) {
2053 return (flags & 0x02) ?
2054 (flags & 0x01) ? (T_bin)0x8000000000000000 : (T_bin)0x7fffffffffffffff :
2055 (flags & 0x01) ? -value : value;
2058 throw std::invalid_argument(
"Unsupported bit length");
2071 template <
class T,
size_t N,
class T_bin>
2073 _In_
const T (&str)[N],
2074 _Out_opt_
size_t* end,
2077 return strtoint<T, T_bin>(str, N, end, radix);
2090 template <
class T,
class T_bin>
2092 _In_reads_or_z_opt_(count)
const T* str,
2094 _Out_opt_
size_t* end,
2100 switch (
sizeof(T_bin)) {
2101 case 1: value = (T_bin)strtoint<T, uint8_t>(str, count, end, radix, flags);
break;
2102 case 2: value = (T_bin)strtoint<T, uint16_t>(str, count, end, radix, flags);
break;
2103 case 4: value = (T_bin)strtoint<T, uint32_t>(str, count, end, radix, flags);
break;
2104 case 8: value = (T_bin)strtoint<T, uint64_t>(str, count, end, radix, flags);
break;
2105 default:
throw std::invalid_argument(
"Unsupported bit length");
2108 return (flags & 0x02) ?
2109 (flags & 0x01) ? (T_bin)0 : (T_bin)-1 :
2110 (flags & 0x01) ? ~value : value;
2122 template <
class T,
size_t N,
class T_bin>
2124 _In_
const T (&str)[N],
2125 _Out_opt_
size_t* end,
2128 return strtouint<T, T_bin>(str, N, end, radix);
2143 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
2144 _Out_opt_
size_t* end,
2147 return strtoint<T, int32_t>(str, count, end, radix);
2159 template <
class T,
size_t N>
2161 _In_
const T (&str)[N],
2162 _Out_opt_
size_t* end,
2165 return strto32<T>(str, N, end, radix);
2180 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
2181 _Out_opt_
size_t* end,
2184 return strtoint<T, int64_t>(str, count, end, radix);
2196 template <
class T,
size_t N>
2198 _In_
const T (&str)[N],
2199 _Out_opt_
size_t* end,
2202 return strto64<T>(str, N, end, radix);
2218 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
2219 _Out_opt_
size_t* end,
2222#if defined(_WIN64) || defined(__LP64__)
2223 return static_cast<ptrdiff_t
>(strto64(str, count, end, radix));
2225 return static_cast<ptrdiff_t
>(strto32(str, count, end, radix));
2239 template <
class T,
size_t N>
2241 _In_
const T (&str)[N],
2242 _Out_opt_
size_t* end,
2245 return strtoi<T>(str, N, end, radix);
2260 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
2261 _Out_opt_
size_t* end,
2264 return strtouint<T, uint32_t>(str, count, end, radix);
2276 template <
class T,
size_t N>
2278 _In_
const T (&str)[N],
2279 _Out_opt_
size_t* end,
2282 return strtou32(str, N, end, radix);
2297 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
2298 _Out_opt_
size_t* end,
2301 return strtouint<T, uint64_t>(str, count, end, radix);
2313 template <
class T,
size_t N>
2315 _In_
const T (&str)[N],
2316 _Out_opt_
size_t* end,
2319 return strtou64<T>(str, N, end, radix);
2335 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
2336 _Out_opt_
size_t* end,
2339#if defined(_WIN64) || defined(__LP64__)
2340 return static_cast<size_t>(strtou64(str, count, end, radix));
2342 return static_cast<size_t>(strtou32(str, count, end, radix));
2356 template <
class T,
size_t N>
2358 _In_
const T (&str)[N],
2359 _Out_opt_
size_t* end,
2362 return strtoui<T>(str, N, end, radix);
2375 inline double strtod(
2376 _In_reads_or_z_opt_(count)
const char* str, _In_
size_t count,
2377 _Out_opt_
size_t* end,
2378 _In_opt_ locale_t locale)
2380 count = strnlen(str, count);
2381 _Assume_(str || !count);
2382 std::string tmp(str, count);
2386 r = _strtod_l(tmp.c_str(), &_end, locale);
2388 r = strtod_l(tmp.c_str(), &_end, locale);
2390 if (end) *end = (size_t)(_end - tmp.c_str());
2404 inline double strtod(
2405 _In_reads_or_z_opt_(count)
const wchar_t* str, _In_
size_t count,
2406 _Out_opt_
size_t* end,
2407 _In_opt_ locale_t locale)
2409 count = strnlen(str, count);
2410 _Assume_(str || !count);
2411 std::wstring tmp(str, count);
2415 r = _wcstod_l(tmp.c_str(), &_end, locale);
2417 r = wcstod_l(tmp.c_str(), &_end, locale);
2419 if (end) *end = (size_t)(_end - tmp.c_str());
2424 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)
2427#pragma warning(suppress: 4996)
2428 return _vsnprintf_l(str, capacity, format, locale, arg);
2430 va_list arg_mutable;
2431 va_copy(arg_mutable, arg);
2432 return ::vsnprintf_l(str, capacity, locale, format, arg_mutable);
2436 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)
2439#pragma warning(suppress: 4996)
2440 return _vsnwprintf_l(str, capacity, format, locale, arg);
2442 va_list arg_mutable;
2443 va_copy(arg_mutable, arg);
2444 return ::vswprintf_l(str, capacity, locale, format, arg_mutable);
2459 template<
class T,
class TR,
class AX>
2460 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)
2462 T buf[1024 /
sizeof(T)];
2465 int count = vsnprintf(buf, _countof(buf), format, locale, arg);
2466 if (0 <= count &&
static_cast<size_t>(count) <= _countof(buf)) {
2468 str.append(buf,
static_cast<size_t>(count));
2469 return static_cast<size_t>(count);
2475 count = vsnprintf(NULL, 0, format, locale, arg);
2476 _Assume_(count >= 0);
2478 case EINVAL:
throw std::invalid_argument(
"invalid vsnprintf arguments");
2479 case EILSEQ:
throw std::runtime_error(
"encoding error");
2480 default:
throw std::runtime_error(
"failed to format string");
2483 size_t offset = str.size();
2484 str.resize(offset + count);
2485 if (vsnprintf(&str[offset], count + 1, format, locale, arg) != count) _Unlikely_
2486 throw std::runtime_error(
"failed to format string");
2488 size_t offset = str.size();
2489 for (
size_t capacity = 2 * 1024 /
sizeof(T);; capacity *= 2) {
2493 str.resize(offset + capacity);
2494 count = vsnprintf(&str[offset], capacity, format, locale, arg);
2495 if (0 <= count &&
static_cast<size_t>(count) <= capacity) {
2496 str.resize(offset +
static_cast<size_t>(count));
2497 return static_cast<size_t>(count);
2500 case EINVAL:
throw std::invalid_argument(
"invalid vsnprintf arguments");
2501 case EILSEQ:
throw std::runtime_error(
"encoding error");
2502 default:
throw std::runtime_error(
"failed to format string");
2506 return static_cast<size_t>(count);
2518 template<
class T,
class TR,
class AX>
2519 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, ...)
2522 va_start(arg, locale);
2523 size_t n = vappendf(str, format, locale, arg);
2536 template<
class T,
class TR,
class AX>
2537 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)
2540 vappendf(str, format, locale, arg);
2550 template<
class T,
class TR,
class AX>
2551 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, ...)
2554 va_start(arg, locale);
2555 vsprintf(str, format, locale, arg);
2568 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2569 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)
2571 std::basic_string<T, TR, AX> str;
2572 vappendf(str, format, locale, arg);
2584 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2585 std::basic_string<T, TR, AX> sprintf(_In_z_ _Printf_format_string_params_(2)
const T* format, _In_opt_ locale_t locale, ...)
2588 va_start(arg, locale);
2589 auto str = vsprintf(format, locale, arg);
2595 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)
2598 return _strftime_l(str, capacity, format, time, locale);
2600 return strftime_l(str, capacity, format, time, locale);
2604 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)
2607 return _wcsftime_l(str, capacity, format, time, locale);
2609 return wcsftime_l(str, capacity, format, time, locale);
2622 template<
class T,
class TR,
class AX>
2623 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)
2625 T buf[1024 /
sizeof(T)];
2628 size_t count = strftime(buf, _countof(buf), format, time, locale);
2631 str.append(buf, count);
2634 size_t offset = str.size();
2635 for (
size_t capacity = 2 * 1024 /
sizeof(T);; capacity *= 2) {
2637 str.resize(offset + capacity);
2638 count = strftime(&str[offset], capacity + 1, format, time, locale);
2640 str.resize(offset + count);
2654 template<
class T,
class TR,
class AX>
2655 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)
2658 strcatftime(str, format, time, locale);
2670 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2671 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)
2673 std::basic_string<T, TR, AX> str;
2674 strcatftime(str, format, time, locale);
2713 void strlwr(_Inout_updates_z_(count) T* str, _In_
size_t count)
2715 _Assume_(str || !count);
2716 for (
size_t i = 0; i < count && str[i]; ++i)
2717 str[i] = tolower(str[i]);
2728 void strlwr(_Inout_updates_z_(count) T* str, _In_
size_t count, _In_
const std::locale& locale)
2730 _Assume_(str || !count);
2731 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2732 for (
size_t i = 0; i < count && str[i]; ++i)
2733 str[i] = ctype.tolower(str[i]);
2741 template<
class T,
size_t N>
2742 void strlwr(_Inout_ T (&str)[N])
2753 template<
class T,
size_t N>
2754 void strlwr(_Inout_ T (&str)[N], _In_
const std::locale& locale)
2756 strlwr(str, N, locale);
2764 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2765 void strlwr(_Inout_ std::basic_string<T, TR, AX>& str)
2777 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2778 void strlwr(_Inout_ std::basic_string<T, TR, AX>& str, _In_
const std::locale& locale)
2780 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2782 c = ctype.tolower(c);
2820 void strupr(_Inout_updates_z_(count) T* str, _In_
size_t count)
2822 _Assume_(str || !count);
2823 for (
size_t i = 0; i < count && str[i]; ++i)
2824 str[i] = toupper(str[i]);
2835 void strupr(_Inout_updates_z_(count) T* str, _In_
size_t count, _In_
const std::locale& locale)
2837 _Assume_(str || !count);
2838 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2839 for (
size_t i = 0; i < count && str[i]; ++i)
2840 str[i] = ctype.toupper(str[i]);
2848 template<
class T,
size_t N>
2849 void strupr(_Inout_ T (&str)[N])
2851 return strupr(str, N);
2860 template<
class T,
size_t N>
2861 void strupr(_Inout_ T (&str)[N], _In_
const std::locale& locale)
2863 return strupr(str, N, locale);
2871 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2872 void strupr(_Inout_ std::basic_string<T, TR, AX>& str)
2884 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2885 void strupr(_Inout_ std::basic_string<T, TR, AX>& str, _In_
const std::locale& locale)
2887 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2889 c = ctype.toupper(c);
2902 _Inout_z_count_(count) T* str, _In_
size_t count)
2904 for (
size_t i = 0;; ++i) {
2906 if (count) str[0] = 0;
2913 if (!isspace(str[i])) {
2915 return strnlen(str, count);
2916 size_t n = count != SIZE_MAX ? strncpy(str, str + i, count - i) : strcpy(str, str + i);
2934 _Inout_z_count_(count) T* str, _In_
size_t count,
2935 _In_
const std::locale& locale)
2937 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2938 for (
size_t i = 0;; ++i) {
2940 if (count) str[0] = 0;
2947 if (!ctype.is(ctype.space, str[i])) {
2949 return strnlen(str, count);
2950 size_t n = count != SIZE_MAX ? strncpy(str, str + i, count - i) : strcpy(str, str + i);
2962 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2963 void ltrim(_Inout_ std::basic_string<T, TR, AX>& s)
2970 [&](_In_ T ch) { return !isspace(ch); }));
2979 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2980 void ltrim(_Inout_ std::basic_string<T, TR, AX>& s, _In_
const std::locale& locale)
2982 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2988 [&](_In_ T ch) { return !ctype.is(ctype.space, ch); }));
3001 _Inout_z_count_(count) T* str, _In_
size_t count)
3003 for (
size_t i = 0, j = 0;;) {
3004 if (i >= count || !str[i]) {
3005 if (j < count) str[j] = 0;
3008 if (!isspace(str[i]))
3026 _Inout_z_count_(count) T* str, _In_
size_t count,
3027 _In_
const std::locale& locale)
3029 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
3030 for (
size_t i = 0, j = 0;;) {
3031 if (i >= count || !str[i]) {
3032 if (j < count) str[j] = 0;
3035 if (!ctype.is(ctype.space, str[i]))
3047 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
3048 void rtrim(_Inout_ std::basic_string<T, TR, AX>& s)
3054 [&](_In_ T ch) { return !isspace(ch); }).base(),
3064 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
3065 void rtrim(_Inout_ std::basic_string<T, TR, AX>& s, _In_
const std::locale& locale)
3067 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
3072 [&](_In_ T ch) { return !ctype.is(ctype.space, ch); }).base(),
3086 _Inout_z_count_(count) T* str, _In_
size_t count)
3088 return ltrim(str, rtrim(str, count));
3102 _Inout_z_count_(count) T* str, _In_
size_t count,
3103 _In_
const std::locale& locale)
3105 return ltrim(str, rtrim(str, count, locale), locale);
3113 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
3114 void trim(_Inout_ std::basic_string<T, TR, AX>& s)
3116 auto nonspace = [&](_In_ T ch) {
return !isspace(ch); };
3137 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
3138 void trim(_Inout_ std::basic_string<T, TR, AX>& s, _In_
const std::locale& locale)
3140 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
3141 auto nonspace = [&](_In_ T ch) {
return !ctype.is(ctype.space, ch); };