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);
929 size_t i; T1 a; T2 b;
930 for (i = 0; i < count1 && i < count2 && ((a = str1[i]) | (b = str2[i])); ++i) {
931 if (a > b)
return +1;
932 if (a < b)
return -1;
934 if (i < count1 && str1[i])
return +1;
935 if (i < count2 && str2[i])
return -1;
947 template <
class T1,
size_t N1,
class T2,
size_t N2>
949 _In_
const T1 (&str1)[N1],
950 _In_
const T2 (&str2)[N2])
952 return strncmp(str1, N1, str2, N2);
966 _In_reads_or_z_opt_(count1)
const utf32_t* str1, _In_
size_t count1,
967 _In_reads_or_z_opt_(count2)
const utf16_t* str2, _In_
size_t count2)
969 _Assume_(str1 || !count1);
970 _Assume_(str2 || !count2);
971 size_t i, j, j_next; utf32_t a, b;
972 for (i = 0, j = 0; i < count1 && j < count2; ++i, j = j_next) {
976 if (j + 1 >= count2 || !is_surrogate_pair(&str2[j])) {
977 b =
static_cast<utf32_t
>(str2[j]);
981 b = surrogate_pair_to_ucs4(&str2[j]);
986 if (a > b)
return +1;
987 if (a < b)
return -1;
989 if (i < count1 && str1[i])
return +1;
990 if (j < count2 && str2[j])
return -1;
1002 template <
size_t N1,
size_t N2>
1004 _In_
const utf32_t (&str1)[N1],
1005 _In_
const utf16_t (&str2)[N2])
1007 return strncmp(str1, N1, str2, N2);
1018 template <
class T1,
class T2>
1019 int strrcmp(_In_z_
const T1* str1, _In_z_
const T2* str2)
1024 _Assume_(str1 || !i);
1025 _Assume_(str2 || !j);
1026 size_t k; T1 a; T2 b;
1027 for (k = 1; i && j; k++) {
1029 if ((a = str1[i]) > (b = str2[j]))
return +1;
1030 if (a < b)
return -1;
1032 if (i && !j)
return +1;
1033 if (!i && j)
return -1;
1046 template <
class T1,
class T2>
1047 int strrncmp(_In_reads_or_z_opt_(count)
const T1* str1, _In_reads_or_z_opt_(count)
const T2* str2, _In_
size_t count)
1050 i = strnlen(str1, count),
1051 j = strnlen(str2, count);
1052 _Assume_(str1 || !i);
1053 _Assume_(str2 || !j);
1054 size_t k; T1 a; T2 b;
1055 for (k = 1; i && j; k++) {
1057 if ((a = str1[i]) > (b = str2[j]))
return +1;
1058 if (a < b)
return -1;
1060 if (i && !j)
return +1;
1061 if (!i && j)
return -1;
1075 template <
class T1,
class T2>
1077 _In_reads_or_z_opt_(count1)
const T1* str1, _In_
size_t count1,
1078 _In_reads_or_z_opt_(count2)
const T2* str2, _In_
size_t count2)
1081 i = strnlen(str1, count1),
1082 j = strnlen(str2, count2);
1083 _Assume_(str1 || !i);
1084 _Assume_(str2 || !j);
1085 size_t k; T1 a; T2 b;
1086 for (k = 1; i && j; k++) {
1088 if ((a = str1[i]) > (b = str2[j]))
return +1;
1089 if (a < b)
return -1;
1091 if (i && !j)
return +1;
1092 if (!i && j)
return -1;
1104 template <
class T1,
size_t N1,
class T2,
size_t N2>
1106 _In_
const T1 (&str1)[N1],
1107 _In_
const T2 (&str2)[N2])
1109 return strrncmp(str1, N1, str2, N2);
1120 template <
class T1,
class T2>
1121 int stricmp(_In_z_
const T1* str1, _In_z_
const T2* str2)
1125 size_t i; T1 a; T2 b;
1126 for (i = 0; (a = tolower(str1[i])) | (b = tolower(str2[i])); ++i) {
1127 if (a > b)
return +1;
1128 if (a < b)
return -1;
1130 if (str1[i])
return +1;
1131 if (str2[i])
return -1;
1144 template <
class T1,
class T2>
1145 int stricmp(_In_z_
const T1* str1, _In_z_
const T2* str2, _In_
const std::locale& locale)
1149 size_t i; T1 a; T2 b;
1150 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
1151 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
1152 for (i = 0; (a = ctype1.tolower(str1[i])) | (b = ctype2.tolower(str2[i])); ++i) {
1153 if (a > b)
return +1;
1154 if (a < b)
return -1;
1156 if (str1[i])
return +1;
1157 if (str2[i])
return -1;
1170 template <
class T1,
class T2>
1171 int strnicmp(_In_reads_or_z_opt_(count)
const T1* str1, _In_reads_or_z_opt_(count)
const T2* str2, _In_
size_t count)
1173 _Assume_(str1 || !count);
1174 _Assume_(str2 || !count);
1175 size_t i; T1 a; T2 b;
1176 for (i = 0; i < count && ((a = tolower(str1[i])) | (b = tolower(str2[i]))); ++i) {
1177 if (a > b)
return +1;
1178 if (a < b)
return -1;
1180 if (i < count && str1[i])
return +1;
1181 if (i < count && str2[i])
return -1;
1195 template <
class T1,
class T2>
1196 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)
1198 _Assume_(str1 || !count);
1199 _Assume_(str2 || !count);
1200 size_t i; T1 a; T2 b;
1201 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
1202 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
1203 for (i = 0; i < count && ((a = ctype1.tolower(str1[i])) | (b = ctype2.tolower(str2[i]))); ++i) {
1204 if (a > b)
return +1;
1205 if (a < b)
return -1;
1207 if (i < count && str1[i])
return +1;
1208 if (i < count && str2[i])
return -1;
1222 template <
class T1,
class T2>
1224 _In_reads_or_z_opt_(count1)
const T1* str1, _In_
size_t count1,
1225 _In_reads_or_z_opt_(count2)
const T2* str2, _In_
size_t count2)
1227 _Assume_(str1 || !count1);
1228 _Assume_(str2 || !count2);
1229 size_t i; T1 a; T2 b;
1230 for (i = 0; i < count1 && i < count2 && ((a = tolower(str1[i])) | (b = tolower(str2[i]))); ++i) {
1231 if (a > b)
return +1;
1232 if (a < b)
return -1;
1234 if (i < count1 && str1[i])
return +1;
1235 if (i < count2 && str2[i])
return -1;
1250 template <
class T1,
class T2>
1252 _In_reads_or_z_opt_(count1)
const T1* str1, _In_
size_t count1,
1253 _In_reads_or_z_opt_(count2)
const T2* str2, _In_
size_t count2,
1254 _In_
const std::locale& locale)
1256 _Assume_(str1 || !count1);
1257 _Assume_(str2 || !count2);
1258 size_t i; T1 a; T2 b;
1259 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
1260 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
1261 for (i = 0; i < count1 && i < count2 && ((a = ctype1.tolower(str1[i])) | (b = ctype2.tolower(str2[i]))); ++i) {
1262 if (a > b)
return +1;
1263 if (a < b)
return -1;
1265 if (i < count1 && str1[i])
return +1;
1266 if (i < count2 && str2[i])
return -1;
1278 template <
class T1,
size_t N1,
class T2,
size_t N2>
1280 _In_
const T1 (&str1)[N1],
1281 _In_
const T2 (&str2)[N2])
1283 strnicmp(str1, N1, str2, N2);
1295 template <
class T1,
size_t N1,
class T2,
size_t N2>
1297 _In_
const T1 (&str1)[N1],
1298 _In_
const T2 (&str2)[N2],
1299 _In_
const std::locale& locale)
1301 strnicmp(str1, N1, str2, N2, locale);
1315 _In_z_
const T* str1,
1316 _In_z_
const T* str2,
1317 _In_
const std::locale& locale)
1321 auto& collate = std::use_facet<std::collate<T>>(locale);
1322 return collate.compare(str1, str1 + strlen(str1), str2, str2 + strlen(str2));
1338 _In_reads_or_z_opt_(count1)
const T* str1, _In_
size_t count1,
1339 _In_reads_or_z_opt_(count2)
const T* str2, _In_
size_t count2,
1340 _In_
const std::locale& locale)
1342 _Assume_(str1 || !count1);
1343 _Assume_(str2 || !count2);
1344 auto& collate = std::use_facet<std::collate<T>>(locale);
1345 return collate.compare(str1, str1 + count1, str2, str2 + count2);
1357 template <
class T,
size_t N1,
size_t N2>
1359 _In_
const T (&str1)[N1],
1360 _In_
const T (&str2)[N2],
1361 _In_
const std::locale& locale)
1363 return strncoll(str1, N1, str2, N2, locale);
1374 template <
class T1,
class T2>
1376 _In_z_
const T1* str,
1377 _In_z_
const T2* sample)
1381 for (
size_t offset = 0;; ++offset) {
1382 for (
size_t i = offset, j = 0;; ++i, ++j) {
1387 if (str[i] != sample[j])
1402 template <
class T1,
class T2>
1404 _In_reads_or_z_opt_(count)
const T1* str, _In_
size_t count,
1405 _In_z_
const T2* sample)
1407 _Assume_(str || !count);
1409 for (
size_t offset = 0;; ++offset) {
1410 for (
size_t i = offset, j = 0;; ++i, ++j) {
1413 if (i >= count || !str[i])
1415 if (str[i] != sample[j])
1429 template <
class T1,
size_t N1,
class T2>
1431 _In_
const T1 (&str)[N1],
1432 _In_z_
const T2* sample)
1434 return strnstr(str, N1, sample);
1445 template <
class T1,
class T2>
1447 _In_z_
const T1* str,
1448 _In_z_
const T2* sample)
1452 for (
size_t offset = 0;; ++offset) {
1453 for (
size_t i = offset, j = 0;; ++i, ++j) {
1458 if (tolower(str[i]) != tolower(sample[j]))
1473 template <
class T1,
class T2>
1475 _In_z_
const T1* str,
1476 _In_z_
const T2* sample,
1477 _In_
const std::locale& locale)
1481 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
1482 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
1483 for (
size_t offset = 0;; ++offset) {
1484 for (
size_t i = offset, j = 0;; ++i, ++j) {
1489 if (ctype1.tolower(str[i]) != ctype2.tolower(sample[j]))
1504 template <
class T1,
class T2>
1506 _In_reads_or_z_opt_(count)
const T1* str,
1508 _In_z_
const T2* sample)
1510 _Assume_(str || !count);
1512 for (
size_t offset = 0;; ++offset) {
1513 for (
size_t i = offset, j = 0;; ++i, ++j) {
1516 if (i >= count || !str[i])
1518 if (tolower(str[i]) != tolower(sample[j]))
1534 template <
class T1,
class T2>
1536 _In_reads_or_z_opt_(count)
const T1* str,
1538 _In_z_
const T2* sample,
1539 _In_
const std::locale& locale)
1541 _Assume_(str || !count);
1543 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
1544 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
1545 for (
size_t offset = 0;; ++offset) {
1546 for (
size_t i = offset, j = 0;; ++i, ++j) {
1549 if (i >= count || !str[i])
1551 if (ctype1.tolower(str[i]) != ctype2.tolower(sample[j]))
1565 template <
class T1,
size_t N1,
class T2>
1567 _In_
const T1 (&str)[N1],
1568 _In_z_
const T2* sample)
1570 return strnistr(str, N1, sample);
1582 template <
class T1,
size_t N1,
class T2>
1584 _In_
const T1 (&str)[N1],
1585 _In_z_
const T2* sample,
1586 _In_
const std::locale& locale)
1588 return strnistr(str, N1, sample, locale);
1599 template <
class T1,
class T2>
1601 _Out_writes_z_(_String_length_(src) + 1) T1* dst,
1602 _In_z_
const T2* src)
1606 for (
size_t i = 0; ; ++i) {
1607 if ((dst[i] =
static_cast<T1
>(src[i])) == 0)
1621 template <
class T1,
class T2>
1623 _Out_writes_(count) _Post_maybez_ T1* dst,
1624 _In_reads_or_z_opt_(count)
const T2* src, _In_
size_t count)
1626 _Assume_(dst || !count);
1627 _Assume_(src || !count);
1628 for (
size_t i = 0; ; ++i) {
1631 if ((dst[i] =
static_cast<T1
>(src[i])) == 0)
1646 template <
class T1,
class T2>
1648 _Out_writes_(count_dst) _Post_maybez_ T1* dst, _In_
size_t count_dst,
1649 _In_reads_or_z_opt_(count_src)
const T2* src, _In_
size_t count_src)
1651 _Assume_(dst || !count_dst);
1652 _Assume_(src || !count_src);
1653 for (
size_t i = 0; ; ++i)
1657 if (i >= count_src) {
1661 if ((dst[i] =
static_cast<T1
>(src[i])) == 0)
1674 template <
class T1,
size_t N1,
class T2,
size_t N2>
1676 _Out_ _Post_maybez_ T1 (&dst)[N1],
1677 _In_
const T2 (&src)[N2])
1679 return strncpy(dst, N1, src, N2);
1690 template <
class T1,
class T2>
1692 _In_z_ _Out_writes_z_(_String_length_(dst) + _String_length_(src) + 1) T1* dst,
1693 _In_z_
const T2* src)
1697 for (
size_t i = 0, j = stdex::strlen<T1>(dst); ; ++i, ++j) {
1698 if ((dst[j] =
static_cast<T1
>(src[i])) == 0)
1712 template <
class T1,
class T2>
1715 _In_reads_or_z_opt_(count)
const T2* src, _In_
size_t count)
1717 _Assume_(dst || !count);
1718 _Assume_(src || !count);
1719 for (
size_t i = 0, j = stdex::strlen<T1>(dst); ; ++i, ++j) {
1722 if ((dst[j] =
static_cast<T1
>(src[i])) == 0)
1737 template <
class T1,
class T2>
1739 _Out_writes_(count_dst) _Post_maybez_ T1* dst, _In_
size_t count_dst,
1740 _In_reads_or_z_opt_(count_src)
const T2* src, _In_
size_t count_src)
1742 _Assume_(dst || !count_dst);
1743 _Assume_(src || !count_src);
1744 for (
size_t i = 0, j = stdex::strnlen<T1>(dst, count_dst); ; ++i, ++j)
1748 if (i >= count_src) {
1752 if ((dst[j] =
static_cast<T1
>(src[i])) == 0)
1768 _Check_return_ _Ret_maybenull_z_ T* strdup(_In_opt_z_
const T* str)
1770 if (!str) _Unlikely_
1772 size_t count = strlen(str) + 1;
1773 T* dst =
new T[count];
1774 strncpy(dst, count, str, SIZE_MAX);
1791 _In_reads_or_z_opt_(count)
const T* str,
1794 T* dst =
new T[count];
1795 strncpy(dst, count, str, SIZE_MAX);
1809 template <
class T,
size_t N>
1810 _Check_return_ _Ret_maybenull_z_ T* strndup(_In_
const T (&str)[N])
1812 return strndup(str, N);
1825 size_t crlf2nl(_Out_writes_z_(_String_length_(src) + 1) T* dst, _In_z_
const T* src)
1830 for (i = j = 0; src[j];) {
1831 if (src[j] !=
'\r' || src[j + 1] !=
'\n')
1832 dst[i++] = src[j++];
1848 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
1849 void crlf2nl(_Inout_ std::basic_string<T, TR, AX>& dst, _In_z_
const T* src)
1852 _Assume_(src != dst.data());
1854 dst.reserve(strlen(src));
1855 for (
size_t j = 0; src[j];) {
1856 if (src[j] !=
'\r' || src[j + 1] !=
'\n')
1870 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
1871 void crlf2nl(_Inout_ std::basic_string<T, TR, AX>& str)
1874 for (i = j = 0, n = str.size(); j < n;) {
1875 if (str[j] !=
'\r' || str[j + 1] !=
'\n')
1876 str[i++] = str[j++];
1886 template <
class T,
class T_bin>
1888 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
1889 _Out_opt_
size_t* end,
1891 _Out_ uint8_t& flags)
1893 _Assume_(str || !count);
1894 _Assume_(radix == 0 || 2 <= radix && radix <= 36);
1897 T_bin value = 0, digit,
1899 max_ui_pre1, max_ui_pre2;
1905 if (i >= count || !str[i])
goto error;
1906 if (!isspace(str[i]))
break;
1910 if (str[i] ==
'+') {
1913 if (i >= count || !str[i])
goto error;
1915 else if (str[i] ==
'-') {
1918 if (i >= count || !str[i])
goto error;
1923 if (str[i] ==
'0' && i + 1 < count && (str[i + 1] ==
'x' || str[i + 1] ==
'X')) {
1925 if (i >= count || !str[i])
goto error;
1930 if (str[i] ==
'0') {
1932 if (i >= count || !str[i])
goto error;
1933 if (str[i] ==
'x' || str[i] ==
'X') {
1936 if (i >= count || !str[i])
goto error;
1946 max_ui_pre1 = max_ui / (T_bin)radix;
1947 max_ui_pre2 = max_ui % (T_bin)radix;
1949 if (
'0' <= str[i] && str[i] <=
'9')
1950 digit = (T_bin)str[i] -
'0';
1951 else if (
'A' <= str[i] && str[i] <=
'Z')
1952 digit = (T_bin)str[i] -
'A' +
'\x0a';
1953 else if (
'a' <= str[i] && str[i] <=
'z')
1954 digit = (T_bin)str[i] -
'a' +
'\x0a';
1957 if (digit >= (T_bin)radix)
1960 if (value < max_ui_pre1 ||
1961 (value == max_ui_pre1 && digit <= max_ui_pre2))
1962 value = value * (T_bin)radix + digit;
1969 if (i >= count || !str[i])
1989 template <
class T,
class T_bin>
1991 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
1992 _Out_opt_
size_t* end,
1998 switch (
sizeof(T_bin)) {
2000 value = (T_bin)strtoint<T, uint8_t>(str, count, end, radix, flags);
2001 if ((flags & 0x01) && (value & 0x80)) {
2005 return (flags & 0x02) ?
2006 (flags & 0x01) ? (T_bin)0x80 : (T_bin)0x7f :
2007 (flags & 0x01) ? -value : value;
2010 value = (T_bin)strtoint<T, uint16_t>(str, count, end, radix, flags);
2011 if ((flags & 0x01) && (value & 0x8000)) {
2015 return (flags & 0x02) ?
2016 (flags & 0x01) ? (T_bin)0x8000 : (T_bin)0x7fff :
2017 (flags & 0x01) ? -value : value;
2020 value = (T_bin)strtoint<T, uint32_t>(str, count, end, radix, flags);
2021 if ((flags & 0x01) && (value & 0x80000000)) {
2025 return (flags & 0x02) ?
2026 (flags & 0x01) ? (T_bin)0x80000000 : (T_bin)0x7fffffff :
2027 (flags & 0x01) ? -value : value;
2030 value = (T_bin)strtoint<T, uint64_t>(str, count, end, radix, flags);
2031 if ((flags & 0x01) && (value & 0x8000000000000000)) {
2035 return (flags & 0x02) ?
2036 (flags & 0x01) ? (T_bin)0x8000000000000000 : (T_bin)0x7fffffffffffffff :
2037 (flags & 0x01) ? -value : value;
2040 throw std::invalid_argument(
"Unsupported bit length");
2053 template <
class T,
size_t N,
class T_bin>
2055 _In_
const T (&str)[N],
2056 _Out_opt_
size_t* end,
2059 return strtoint<T, T_bin>(str, N, end, radix);
2072 template <
class T,
class T_bin>
2074 _In_reads_or_z_opt_(count)
const T* str,
2076 _Out_opt_
size_t* end,
2082 switch (
sizeof(T_bin)) {
2083 case 1: value = (T_bin)strtoint<T, uint8_t>(str, count, end, radix, flags);
break;
2084 case 2: value = (T_bin)strtoint<T, uint16_t>(str, count, end, radix, flags);
break;
2085 case 4: value = (T_bin)strtoint<T, uint32_t>(str, count, end, radix, flags);
break;
2086 case 8: value = (T_bin)strtoint<T, uint64_t>(str, count, end, radix, flags);
break;
2087 default:
throw std::invalid_argument(
"Unsupported bit length");
2090 return (flags & 0x02) ?
2091 (flags & 0x01) ? (T_bin)0 : (T_bin)-1 :
2092 (flags & 0x01) ? ~value : value;
2104 template <
class T,
size_t N,
class T_bin>
2106 _In_
const T (&str)[N],
2107 _Out_opt_
size_t* end,
2110 return strtouint<T, T_bin>(str, N, end, radix);
2125 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
2126 _Out_opt_
size_t* end,
2129 return strtoint<T, int32_t>(str, count, end, radix);
2141 template <
class T,
size_t N>
2143 _In_
const T (&str)[N],
2144 _Out_opt_
size_t* end,
2147 return strto32<T>(str, N, end, radix);
2162 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
2163 _Out_opt_
size_t* end,
2166 return strtoint<T, int64_t>(str, count, end, radix);
2178 template <
class T,
size_t N>
2180 _In_
const T (&str)[N],
2181 _Out_opt_
size_t* end,
2184 return strto64<T>(str, N, end, radix);
2200 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
2201 _Out_opt_
size_t* end,
2204#if defined(_WIN64) || defined(__LP64__)
2205 return static_cast<ptrdiff_t
>(strto64(str, count, end, radix));
2207 return static_cast<ptrdiff_t
>(strto32(str, count, end, radix));
2221 template <
class T,
size_t N>
2223 _In_
const T (&str)[N],
2224 _Out_opt_
size_t* end,
2227 return strtoi<T>(str, N, end, radix);
2242 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
2243 _Out_opt_
size_t* end,
2246 return strtouint<T, uint32_t>(str, count, end, radix);
2258 template <
class T,
size_t N>
2260 _In_
const T (&str)[N],
2261 _Out_opt_
size_t* end,
2264 return strtou32(str, N, end, radix);
2279 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
2280 _Out_opt_
size_t* end,
2283 return strtouint<T, uint64_t>(str, count, end, radix);
2295 template <
class T,
size_t N>
2297 _In_
const T (&str)[N],
2298 _Out_opt_
size_t* end,
2301 return strtou64<T>(str, N, end, radix);
2317 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
2318 _Out_opt_
size_t* end,
2321#if defined(_WIN64) || defined(__LP64__)
2322 return static_cast<size_t>(strtou64(str, count, end, radix));
2324 return static_cast<size_t>(strtou32(str, count, end, radix));
2338 template <
class T,
size_t N>
2340 _In_
const T (&str)[N],
2341 _Out_opt_
size_t* end,
2344 return strtoui<T>(str, N, end, radix);
2357 inline double strtod(
2358 _In_reads_or_z_opt_(count)
const char* str, _In_
size_t count,
2359 _Out_opt_
size_t* end,
2360 _In_opt_ locale_t locale)
2362 count = strnlen(str, count);
2363 _Assume_(str || !count);
2364 std::string tmp(str, count);
2368 r = _strtod_l(tmp.c_str(), &_end, locale);
2370 r = strtod_l(tmp.c_str(), &_end, locale);
2372 if (end) *end = (size_t)(_end - tmp.c_str());
2386 inline double strtod(
2387 _In_reads_or_z_opt_(count)
const wchar_t* str, _In_
size_t count,
2388 _Out_opt_
size_t* end,
2389 _In_opt_ locale_t locale)
2391 count = strnlen(str, count);
2392 _Assume_(str || !count);
2393 std::wstring tmp(str, count);
2397 r = _wcstod_l(tmp.c_str(), &_end, locale);
2399 r = wcstod_l(tmp.c_str(), &_end, locale);
2401 if (end) *end = (size_t)(_end - tmp.c_str());
2406 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)
2409#pragma warning(suppress: 4996)
2410 return _vsnprintf_l(str, capacity, format, locale, arg);
2412 va_list arg_mutable;
2413 va_copy(arg_mutable, arg);
2414 return ::vsnprintf_l(str, capacity, locale, format, arg_mutable);
2418 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)
2421#pragma warning(suppress: 4996)
2422 return _vsnwprintf_l(str, capacity, format, locale, arg);
2424 va_list arg_mutable;
2425 va_copy(arg_mutable, arg);
2426 return ::vswprintf_l(str, capacity, locale, format, arg_mutable);
2441 template<
class T,
class TR,
class AX>
2442 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)
2444 T buf[1024 /
sizeof(T)];
2447 int count = vsnprintf(buf, _countof(buf), format, locale, arg);
2448 if (0 <= count &&
static_cast<size_t>(count) <= _countof(buf)) {
2450 str.append(buf,
static_cast<size_t>(count));
2451 return static_cast<size_t>(count);
2457 count = vsnprintf(NULL, 0, format, locale, arg);
2458 _Assume_(count >= 0);
2460 case EINVAL:
throw std::invalid_argument(
"invalid vsnprintf arguments");
2461 case EILSEQ:
throw std::runtime_error(
"encoding error");
2462 default:
throw std::runtime_error(
"failed to format string");
2465 size_t offset = str.size();
2466 str.resize(offset + count);
2467 if (vsnprintf(&str[offset], count + 1, format, locale, arg) != count) _Unlikely_
2468 throw std::runtime_error(
"failed to format string");
2470 size_t offset = str.size();
2471 for (
size_t capacity = 2 * 1024 /
sizeof(T);; capacity *= 2) {
2475 str.resize(offset + capacity);
2476 count = vsnprintf(&str[offset], capacity, format, locale, arg);
2477 if (0 <= count &&
static_cast<size_t>(count) <= capacity) {
2478 str.resize(offset +
static_cast<size_t>(count));
2479 return static_cast<size_t>(count);
2482 case EINVAL:
throw std::invalid_argument(
"invalid vsnprintf arguments");
2483 case EILSEQ:
throw std::runtime_error(
"encoding error");
2484 default:
throw std::runtime_error(
"failed to format string");
2488 return static_cast<size_t>(count);
2500 template<
class T,
class TR,
class AX>
2501 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, ...)
2504 va_start(arg, locale);
2505 size_t n = vappendf(str, format, locale, arg);
2518 template<
class T,
class TR,
class AX>
2519 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)
2522 vappendf(str, format, locale, arg);
2532 template<
class T,
class TR,
class AX>
2533 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, ...)
2536 va_start(arg, locale);
2537 vsprintf(str, format, locale, arg);
2550 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2551 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)
2553 std::basic_string<T, TR, AX> str;
2554 vappendf(str, format, locale, arg);
2566 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2567 std::basic_string<T, TR, AX> sprintf(_In_z_ _Printf_format_string_params_(2)
const T* format, _In_opt_ locale_t locale, ...)
2570 va_start(arg, locale);
2571 auto str = vsprintf(format, locale, arg);
2577 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)
2580 return _strftime_l(str, capacity, format, time, locale);
2582 return strftime_l(str, capacity, format, time, locale);
2586 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)
2589 return _wcsftime_l(str, capacity, format, time, locale);
2591 return wcsftime_l(str, capacity, format, time, locale);
2604 template<
class T,
class TR,
class AX>
2605 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)
2607 T buf[1024 /
sizeof(T)];
2610 size_t count = strftime(buf, _countof(buf), format, time, locale);
2613 str.append(buf, count);
2616 size_t offset = str.size();
2617 for (
size_t capacity = 2 * 1024 /
sizeof(T);; capacity *= 2) {
2619 str.resize(offset + capacity);
2620 count = strftime(&str[offset], capacity + 1, format, time, locale);
2622 str.resize(offset + count);
2636 template<
class T,
class TR,
class AX>
2637 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)
2640 strcatftime(str, format, time, locale);
2652 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2653 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)
2655 std::basic_string<T, TR, AX> str;
2656 strcatftime(str, format, time, locale);
2695 void strlwr(_Inout_updates_z_(count) T* str, _In_
size_t count)
2697 _Assume_(str || !count);
2698 for (
size_t i = 0; i < count && str[i]; ++i)
2699 str[i] = tolower(str[i]);
2710 void strlwr(_Inout_updates_z_(count) T* str, _In_
size_t count, _In_
const std::locale& locale)
2712 _Assume_(str || !count);
2713 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2714 for (
size_t i = 0; i < count && str[i]; ++i)
2715 str[i] = ctype.tolower(str[i]);
2723 template<
class T,
size_t N>
2724 void strlwr(_Inout_ T (&str)[N])
2735 template<
class T,
size_t N>
2736 void strlwr(_Inout_ T (&str)[N], _In_
const std::locale& locale)
2738 strlwr(str, N, locale);
2746 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2747 void strlwr(_Inout_ std::basic_string<T, TR, AX>& str)
2759 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2760 void strlwr(_Inout_ std::basic_string<T, TR, AX>& str, _In_
const std::locale& locale)
2762 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2764 c = ctype.tolower(c);
2802 void strupr(_Inout_updates_z_(count) T* str, _In_
size_t count)
2804 _Assume_(str || !count);
2805 for (
size_t i = 0; i < count && str[i]; ++i)
2806 str[i] = toupper(str[i]);
2817 void strupr(_Inout_updates_z_(count) T* str, _In_
size_t count, _In_
const std::locale& locale)
2819 _Assume_(str || !count);
2820 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2821 for (
size_t i = 0; i < count && str[i]; ++i)
2822 str[i] = ctype.toupper(str[i]);
2830 template<
class T,
size_t N>
2831 void strupr(_Inout_ T (&str)[N])
2833 return strupr(str, N);
2842 template<
class T,
size_t N>
2843 void strupr(_Inout_ T (&str)[N], _In_
const std::locale& locale)
2845 return strupr(str, N, locale);
2853 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2854 void strupr(_Inout_ std::basic_string<T, TR, AX>& str)
2866 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2867 void strupr(_Inout_ std::basic_string<T, TR, AX>& str, _In_
const std::locale& locale)
2869 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2871 c = ctype.toupper(c);
2884 _Inout_z_count_(count) T* str, _In_
size_t count)
2886 for (
size_t i = 0;; ++i) {
2888 if (count) str[0] = 0;
2895 if (!isspace(str[i])) {
2897 return strnlen(str, count);
2898 size_t n = count != SIZE_MAX ? strncpy(str, str + i, count - i) : strcpy(str, str + i);
2916 _Inout_z_count_(count) T* str, _In_
size_t count,
2917 _In_
const std::locale& locale)
2919 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2920 for (
size_t i = 0;; ++i) {
2922 if (count) str[0] = 0;
2929 if (!ctype.is(ctype.space, str[i])) {
2931 return strnlen(str, count);
2932 size_t n = count != SIZE_MAX ? strncpy(str, str + i, count - i) : strcpy(str, str + i);
2944 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2945 void ltrim(_Inout_ std::basic_string<T, TR, AX>& s)
2952 [&](_In_ T ch) { return !isspace(ch); }));
2961 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2962 void ltrim(_Inout_ std::basic_string<T, TR, AX>& s, _In_
const std::locale& locale)
2964 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2970 [&](_In_ T ch) { return !ctype.is(ctype.space, ch); }));
2983 _Inout_z_count_(count) T* str, _In_
size_t count)
2985 for (
size_t i = 0, j = 0;;) {
2986 if (i >= count || !str[i]) {
2987 if (j < count) str[j] = 0;
2990 if (!isspace(str[i]))
3008 _Inout_z_count_(count) T* str, _In_
size_t count,
3009 _In_
const std::locale& locale)
3011 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
3012 for (
size_t i = 0, j = 0;;) {
3013 if (i >= count || !str[i]) {
3014 if (j < count) str[j] = 0;
3017 if (!ctype.is(ctype.space, str[i]))
3029 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
3030 void rtrim(_Inout_ std::basic_string<T, TR, AX>& s)
3036 [&](_In_ T ch) { return !isspace(ch); }).base(),
3046 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
3047 void rtrim(_Inout_ std::basic_string<T, TR, AX>& s, _In_
const std::locale& locale)
3049 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
3054 [&](_In_ T ch) { return !ctype.is(ctype.space, ch); }).base(),
3068 _Inout_z_count_(count) T* str, _In_
size_t count)
3070 return ltrim(str, rtrim(str, count));
3084 _Inout_z_count_(count) T* str, _In_
size_t count,
3085 _In_
const std::locale& locale)
3087 return ltrim(str, rtrim(str, count, locale), locale);
3095 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
3096 void trim(_Inout_ std::basic_string<T, TR, AX>& s)
3098 auto nonspace = [&](_In_ T ch) {
return !isspace(ch); };
3119 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
3120 void trim(_Inout_ std::basic_string<T, TR, AX>& s, _In_
const std::locale& locale)
3122 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
3123 auto nonspace = [&](_In_ T ch) {
return !ctype.is(ctype.space, ch); };