31 using utf16_t = wchar_t;
32 using utf32_t = char32_t;
34 using utf16_t = char16_t;
35 using utf32_t = wchar_t;
43 inline bool is_high_surrogate(_In_ utf16_t chr)
45 return 0xd800 < chr && chr < 0xdc00;
53 inline bool is_low_surrogate(_In_ utf16_t chr)
55 return 0xdc00 < chr && chr < 0xe000;
63 inline bool is_surrogate_pair(_In_reads_(2)
const utf16_t* str)
65 return is_high_surrogate(str[0]) && is_low_surrogate(str[1]);
73 inline utf32_t surrogate_pair_to_ucs4(_In_reads_(2)
const utf16_t* str)
75 stdex_assert(is_surrogate_pair(str));
77 (
static_cast<utf32_t
>(str[0] - 0xd800) << 10) +
78 static_cast<utf32_t
>(str[1] - 0xdc00) +
87 inline void ucs4_to_surrogate_pair(_Out_writes_(2) utf16_t* str, _In_ utf32_t chr)
89 stdex_assert(chr >= 0x10000);
91 str[0] = 0xd800 +
static_cast<utf16_t
>((chr >> 10) & 0x3ff);
92 str[1] = 0xdc00 +
static_cast<utf16_t
>(chr & 0x3ff);
100 inline bool iscombining(_In_ utf32_t chr)
103 (0x0300 <= chr && chr < 0x0370) ||
104 (0x1dc0 <= chr && chr < 0x1e00) ||
105 (0x20d0 <= chr && chr < 0x2100) ||
106 (0xfe20 <= chr && chr < 0xfe30);
115 bool islbreak(_In_ T chr)
117 return chr ==
'\n' || chr ==
'\r';
129 size_t islbreak(_In_reads_or_z_opt_(count)
const T* chr, _In_
size_t count)
131 stdex_assert(chr || !count);
132 if (count >= 2 && ((chr[0] ==
'\r' && chr[1] ==
'\n') || (chr[0] ==
'\n' && chr[1] ==
'\r')))
134 if (count > 1 && (chr[0] ==
'\n' || chr[0] ==
'\r'))
145 bool isspace(_In_ T chr)
147 return chr ==
' ' || chr ==
'\t' || chr ==
'\n' || chr ==
'\r' || chr ==
'\v' || chr ==
'\f';
156 bool islower(_In_ T chr)
158 return 'a' <= chr && chr <=
'z';
167 bool isupper(_In_ T chr)
169 return 'A' <= chr && chr <=
'Z';
178 bool isdigit(_In_ T chr)
180 return '0' <= chr && chr <=
'9';
189 bool isalpha(_In_ T chr)
191 return islower(chr) || isupper(chr);
200 bool is7bit(_In_ T chr)
202 return '\x00' <= chr && chr <=
'\x7f';
211 inline size_t glyphlen(_In_reads_or_z_opt_(count)
const utf16_t* glyph, _In_
size_t count)
213 stdex_assert(glyph || !count);
215 size_t i = count < 2 || !is_surrogate_pair(glyph) ? 1 : 2;
216 for (; i < count && iscombining(glyph[i]); ++i);
228 inline size_t glyphlen(_In_reads_or_z_opt_(count)
const utf32_t* glyph, _In_
size_t count)
230 stdex_assert(glyph || !count);
233 for (; i < count && iscombining(glyph[i]); ++i);
245 inline size_t glyphrlen(_In_reads_or_z_opt_(count)
const utf16_t* str, _In_
size_t count)
247 stdex_assert(count && str && str[count - 1]);
248 for (
size_t i = count; i--;) {
249 if (!iscombining(str[i]))
250 return count - (!is_low_surrogate(str[i]) || i == 0 || !is_high_surrogate(str[i - 1]) ? i : i - 1);
261 inline size_t glyphrlen(_In_reads_or_z_opt_(count)
const utf32_t* str, _In_
size_t count)
263 stdex_assert(count && str && str[count - 1]);
264 for (
size_t i = count; i--;) {
265 if (!iscombining(str[i]))
266 return count - (i == 0 ? i : i - 1);
279 T tolower(_In_ T chr)
281 return isupper(chr) ? chr | 0x20 : chr;
292 T toupper(_In_ T chr)
294 return islower(chr) ? chr | ~0x20 : chr;
305 size_t strlen(_In_z_
const T* str)
309 for (i = 0; str[i]; ++i);
322 size_t strnlen(_In_reads_or_z_opt_(count)
const T* str, _In_
size_t count)
324 stdex_assert(str || !count);
326 for (i = 0; i < count && str[i]; ++i);
337 template <
class T,
size_t N>
338 size_t strnlen(_In_
const T (&str)[N])
340 return strnlen(str, N);
343 constexpr auto npos{
static_cast<size_t>(-1) };
354 size_t strchr(_In_z_
const T* str, _In_ T chr)
357 for (
size_t i = 0; str[i]; ++i)
358 if (str[i] == chr)
return i;
373 _In_reads_or_z_opt_(count)
const T* str,
377 stdex_assert(str || !count);
378 for (
size_t i = 0; i < count && str[i]; ++i)
379 if (str[i] == chr)
return i;
391 template <
class T,
size_t N>
393 _In_
const T (&str)[N],
396 return strnchr(str, N, chr);
414 for (
size_t i = 0; str[i]; ++i)
415 if (str[i] == chr) z = i;
430 _In_reads_or_z_opt_(count)
const T* str,
434 stdex_assert(str || !count);
436 for (
size_t i = 0; i < count && str[i]; ++i)
437 if (str[i] == chr) z = i;
449 template <
class T,
size_t N>
451 _In_
const T (&str)[N],
454 return strrnchr(str, N, chr);
472 for (
size_t i = 0; str[i]; ++i)
473 if (tolower(str[i]) == chr)
return i;
490 _In_
const std::locale& locale)
493 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
494 chr = ctype.tolower(chr);
495 for (
size_t i = 0; str[i]; ++i)
496 if (ctype.tolower(str[i]) == chr)
return i;
511 _In_reads_or_z_opt_(count)
const T* str,
515 stdex_assert(str || !count);
517 for (
size_t i = 0; i < count && str[i]; ++i)
518 if (tolower(str[i]) == chr)
return i;
534 _In_reads_or_z_opt_(count)
const T* str,
537 _In_
const std::locale& locale)
539 stdex_assert(str || !count);
540 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
541 chr = ctype.tolower(chr);
542 for (
size_t i = 0; i < count && str[i]; ++i)
543 if (ctype.tolower(str[i]) == chr)
return i;
555 template <
class T,
size_t N>
557 _In_
const T (&str)[N],
560 return strnichr(str, N, chr);
572 template <
class T,
size_t N>
574 _In_
const T (&str)[N],
576 _In_
const std::locale& locale)
578 return strnichr(str, N, chr, locale);
597 for (
size_t i = 0; str[i]; ++i)
598 if (tolower(str[i]) == chr) z = i;
613 _In_reads_or_z_opt_(count)
const T* str,
615 _In_
const std::locale& locale)
618 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
619 chr = ctype.tolower(chr);
621 for (
size_t i = 0; str[i]; ++i)
622 if (ctype.tolower(str[i]) == chr) z = i;
637 _In_reads_or_z_opt_(count)
const T* str,
641 stdex_assert(str || !count);
644 for (
size_t i = 0; i < count && str[i]; ++i)
645 if (tolower(str[i]) == chr) z = i;
661 _In_reads_or_z_opt_(count)
const T* str,
664 _In_
const std::locale& locale)
666 stdex_assert(str || !count);
667 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
668 chr = ctype.tolower(chr);
670 for (
size_t i = 0; i < count && str[i]; ++i)
671 if (ctype.tolower(str[i]) == chr) z = i;
683 template <
class T,
size_t N>
685 _In_
const T (&str)[N],
688 return strrnichr(str, N, chr);
700 template <
class T,
size_t N>
702 _In_
const T (&str)[N],
704 _In_
const std::locale& locale)
706 return strrnichr(str, N, chr, locale);
757 _In_reads_or_z_opt_(count)
const T* str,
760 stdex_assert(str || !count);
761 for (
size_t i = 0; i < count && str[i]; ++i)
762 if (!isspace(str[i]))
778 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
779 _In_
const std::locale& locale)
781 stdex_assert(str || !count);
782 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
783 for (
size_t i = 0; i < count && str[i]; ++i)
784 if (!ctype.is(ctype.space, str[i]))
796 template <
class T,
size_t N>
797 bool isblank(_In_
const T (&str)[N])
799 return isblank(str, N);
810 template <
class T,
size_t N>
812 _In_
const T (&str)[N],
813 _In_
const std::locale& locale)
815 return isblank(str, N, locale);
844 bool is7bit(_In_reads_or_z_opt_(count)
const T* str, _In_
size_t count)
846 stdex_assert(str || !count);
847 for (
size_t i = 0; i < count && str[i]; i++)
860 template <
class T,
size_t N>
861 bool is7bit(_In_
const T (&str)[N])
863 return is7bit(str, N);
874 template <
class T1,
class T2>
875 int strcmp(_In_z_
const T1* str1, _In_z_
const T2* str2)
879 size_t i; T1 a; T2 b;
880 for (i = 0; (a = str1[i]) | (b = str2[i]); ++i) {
881 if (a > b)
return +1;
882 if (a < b)
return -1;
884 if (str1[i])
return +1;
885 if (str2[i])
return -1;
898 template <
class T1,
class T2>
899 int strncmp(_In_reads_or_z_opt_(count)
const T1* str1, _In_reads_or_z_opt_(count)
const T2* str2, _In_
size_t count)
901 stdex_assert(str1 || !count);
902 stdex_assert(str2 || !count);
903 size_t i; T1 a; T2 b;
904 for (i = 0; i < count && ((a = str1[i]) | (b = str2[i])); ++i) {
905 if (a > b)
return +1;
906 if (a < b)
return -1;
908 if (i < count && str1[i])
return +1;
909 if (i < count && str2[i])
return -1;
923 template <
class T1,
class T2>
925 _In_reads_or_z_opt_(count1)
const T1* str1, _In_
size_t count1,
926 _In_reads_or_z_opt_(count2)
const T2* str2, _In_
size_t count2)
928 stdex_assert(str1 || !count1);
929 stdex_assert(str2 || !count2);
931 for (i = 0; i < count1 && i < count2; ++i) {
934 if (!a && !b)
return 0;
935 if (a > b)
return +1;
936 if (a < b)
return -1;
938 if (i < count1 && str1[i])
return +1;
939 if (i < count2 && str2[i])
return -1;
951 template <
class T1,
size_t N1,
class T2,
size_t N2>
953 _In_
const T1 (&str1)[N1],
954 _In_
const T2 (&str2)[N2])
956 return strncmp(str1, N1, str2, N2);
970 _In_reads_or_z_opt_(count1)
const utf32_t* str1, _In_
size_t count1,
971 _In_reads_or_z_opt_(count2)
const utf16_t* str2, _In_
size_t count2)
973 stdex_assert(str1 || !count1);
974 stdex_assert(str2 || !count2);
975 size_t i, j, j_next; utf32_t a, b;
976 for (i = 0, j = 0; i < count1 && j < count2; ++i, j = j_next) {
980 if (j + 1 >= count2 || !is_surrogate_pair(&str2[j])) {
981 b =
static_cast<utf32_t
>(str2[j]);
985 b = surrogate_pair_to_ucs4(&str2[j]);
990 if (a > b)
return +1;
991 if (a < b)
return -1;
993 if (i < count1 && str1[i])
return +1;
994 if (j < count2 && str2[j])
return -1;
1006 template <
size_t N1,
size_t N2>
1008 _In_
const utf32_t (&str1)[N1],
1009 _In_
const utf16_t (&str2)[N2])
1011 return strncmp(str1, N1, str2, N2);
1022 template <
class T1,
class T2>
1023 int strrcmp(_In_z_
const T1* str1, _In_z_
const T2* str2)
1028 stdex_assert(str1 || !i);
1029 stdex_assert(str2 || !j);
1030 size_t k; T1 a; T2 b;
1031 for (k = 1; i && j; k++) {
1033 if ((a = str1[i]) > (b = str2[j]))
return +1;
1034 if (a < b)
return -1;
1036 if (i && !j)
return +1;
1037 if (!i && j)
return -1;
1050 template <
class T1,
class T2>
1051 int strrncmp(_In_reads_or_z_opt_(count)
const T1* str1, _In_reads_or_z_opt_(count)
const T2* str2, _In_
size_t count)
1054 i = strnlen(str1, count),
1055 j = strnlen(str2, count);
1056 stdex_assert(str1 || !i);
1057 stdex_assert(str2 || !j);
1058 size_t k; T1 a; T2 b;
1059 for (k = 1; i && j; k++) {
1061 if ((a = str1[i]) > (b = str2[j]))
return +1;
1062 if (a < b)
return -1;
1064 if (i && !j)
return +1;
1065 if (!i && j)
return -1;
1079 template <
class T1,
class T2>
1081 _In_reads_or_z_opt_(count1)
const T1* str1, _In_
size_t count1,
1082 _In_reads_or_z_opt_(count2)
const T2* str2, _In_
size_t count2)
1085 i = strnlen(str1, count1),
1086 j = strnlen(str2, count2);
1087 stdex_assert(str1 || !i);
1088 stdex_assert(str2 || !j);
1089 size_t k; T1 a; T2 b;
1090 for (k = 1; i && j; k++) {
1092 if ((a = str1[i]) > (b = str2[j]))
return +1;
1093 if (a < b)
return -1;
1095 if (i && !j)
return +1;
1096 if (!i && j)
return -1;
1108 template <
class T1,
size_t N1,
class T2,
size_t N2>
1110 _In_
const T1 (&str1)[N1],
1111 _In_
const T2 (&str2)[N2])
1113 return strrncmp(str1, N1, str2, N2);
1124 template <
class T1,
class T2>
1125 int stricmp(_In_z_
const T1* str1, _In_z_
const T2* str2)
1130 for (i = 0; ; ++i) {
1131 auto a = tolower(str1[i]);
1132 auto b = tolower(str2[i]);
1133 if (!a && !b)
return 0;
1134 if (a > b)
return +1;
1135 if (a < b)
return -1;
1148 template <
class T1,
class T2>
1149 int stricmp(_In_z_
const T1* str1, _In_z_
const T2* str2, _In_
const std::locale& locale)
1154 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
1155 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
1157 auto a = ctype1.tolower(str1[i]);
1158 auto b = ctype2.tolower(str2[i]);
1159 if (!a && !b)
return 0;
1160 if (a > b)
return +1;
1161 if (a < b)
return -1;
1174 template <
class T1,
class T2>
1175 int strnicmp(_In_reads_or_z_opt_(count)
const T1* str1, _In_reads_or_z_opt_(count)
const T2* str2, _In_
size_t count)
1177 stdex_assert(str1 || !count);
1178 stdex_assert(str2 || !count);
1180 for (i = 0; i < count; ++i) {
1181 auto a = tolower(str1[i]);
1182 auto b = tolower(str2[i]);
1183 if (!a && !b)
return 0;
1184 if (a > b)
return +1;
1185 if (a < b)
return -1;
1187 if (i < count && str1[i])
return +1;
1188 if (i < count && str2[i])
return -1;
1202 template <
class T1,
class T2>
1203 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)
1205 stdex_assert(str1 || !count);
1206 stdex_assert(str2 || !count);
1208 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
1209 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
1210 for (i = 0; i < count; ++i) {
1211 auto a = ctype1.tolower(str1[i]);
1212 auto b = ctype2.tolower(str2[i]);
1213 if (!a && !b)
return 0;
1214 if (a > b)
return +1;
1215 if (a < b)
return -1;
1217 if (i < count && str1[i])
return +1;
1218 if (i < count && str2[i])
return -1;
1232 template <
class T1,
class T2>
1234 _In_reads_or_z_opt_(count1)
const T1* str1, _In_
size_t count1,
1235 _In_reads_or_z_opt_(count2)
const T2* str2, _In_
size_t count2)
1237 stdex_assert(str1 || !count1);
1238 stdex_assert(str2 || !count2);
1240 for (i = 0; i < count1 && i < count2; ++i) {
1241 auto a = tolower(str1[i]);
1242 auto b = tolower(str2[i]);
1243 if (!a && !b)
return 0;
1244 if (a > b)
return +1;
1245 if (a < b)
return -1;
1247 if (i < count1 && str1[i])
return +1;
1248 if (i < count2 && str2[i])
return -1;
1263 template <
class T1,
class T2>
1265 _In_reads_or_z_opt_(count1)
const T1* str1, _In_
size_t count1,
1266 _In_reads_or_z_opt_(count2)
const T2* str2, _In_
size_t count2,
1267 _In_
const std::locale& locale)
1269 stdex_assert(str1 || !count1);
1270 stdex_assert(str2 || !count2);
1272 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
1273 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
1274 for (i = 0; i < count1 && i < count2; ++i) {
1275 auto a = ctype1.tolower(str1[i]);
1276 auto b = ctype2.tolower(str2[i]);
1277 if (!a && !b)
return 0;
1278 if (a > b)
return +1;
1279 if (a < b)
return -1;
1281 if (i < count1 && str1[i])
return +1;
1282 if (i < count2 && str2[i])
return -1;
1294 template <
class T1,
size_t N1,
class T2,
size_t N2>
1296 _In_
const T1 (&str1)[N1],
1297 _In_
const T2 (&str2)[N2])
1299 strnicmp(str1, N1, str2, N2);
1311 template <
class T1,
size_t N1,
class T2,
size_t N2>
1313 _In_
const T1 (&str1)[N1],
1314 _In_
const T2 (&str2)[N2],
1315 _In_
const std::locale& locale)
1317 strnicmp(str1, N1, str2, N2, locale);
1331 _In_z_
const T* str1,
1332 _In_z_
const T* str2,
1333 _In_
const std::locale& locale)
1337 auto& collate = std::use_facet<std::collate<T>>(locale);
1338 return collate.compare(str1, str1 + strlen(str1), str2, str2 + strlen(str2));
1354 _In_reads_or_z_opt_(count1)
const T* str1, _In_
size_t count1,
1355 _In_reads_or_z_opt_(count2)
const T* str2, _In_
size_t count2,
1356 _In_
const std::locale& locale)
1358 stdex_assert(str1 || !count1);
1359 stdex_assert(str2 || !count2);
1360 auto& collate = std::use_facet<std::collate<T>>(locale);
1361 return collate.compare(str1, str1 + count1, str2, str2 + count2);
1373 template <
class T,
size_t N1,
size_t N2>
1375 _In_
const T (&str1)[N1],
1376 _In_
const T (&str2)[N2],
1377 _In_
const std::locale& locale)
1379 return strncoll(str1, N1, str2, N2, locale);
1390 template <
class T1,
class T2>
1392 _In_z_
const T1* str,
1393 _In_z_
const T2* sample)
1396 stdex_assert(sample);
1397 for (
size_t offset = 0;; ++offset) {
1398 for (
size_t i = offset, j = 0;; ++i, ++j) {
1403 if (str[i] != sample[j])
1418 template <
class T1,
class T2>
1420 _In_reads_or_z_opt_(count)
const T1* str, _In_
size_t count,
1421 _In_z_
const T2* sample)
1423 stdex_assert(str || !count);
1424 stdex_assert(sample);
1425 for (
size_t offset = 0;; ++offset) {
1426 for (
size_t i = offset, j = 0;; ++i, ++j) {
1429 if (i >= count || !str[i])
1431 if (str[i] != sample[j])
1445 template <
class T1,
size_t N1,
class T2>
1447 _In_
const T1 (&str)[N1],
1448 _In_z_
const T2* sample)
1450 return strnstr(str, N1, sample);
1461 template <
class T1,
class T2>
1463 _In_z_
const T1* str,
1464 _In_z_
const T2* sample)
1467 stdex_assert(sample);
1468 for (
size_t offset = 0;; ++offset) {
1469 for (
size_t i = offset, j = 0;; ++i, ++j) {
1474 if (tolower(str[i]) != tolower(sample[j]))
1489 template <
class T1,
class T2>
1491 _In_z_
const T1* str,
1492 _In_z_
const T2* sample,
1493 _In_
const std::locale& locale)
1496 stdex_assert(sample);
1497 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
1498 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
1499 for (
size_t offset = 0;; ++offset) {
1500 for (
size_t i = offset, j = 0;; ++i, ++j) {
1505 if (ctype1.tolower(str[i]) != ctype2.tolower(sample[j]))
1520 template <
class T1,
class T2>
1522 _In_reads_or_z_opt_(count)
const T1* str,
1524 _In_z_
const T2* sample)
1526 stdex_assert(str || !count);
1527 stdex_assert(sample);
1528 for (
size_t offset = 0;; ++offset) {
1529 for (
size_t i = offset, j = 0;; ++i, ++j) {
1532 if (i >= count || !str[i])
1534 if (tolower(str[i]) != tolower(sample[j]))
1550 template <
class T1,
class T2>
1552 _In_reads_or_z_opt_(count)
const T1* str,
1554 _In_z_
const T2* sample,
1555 _In_
const std::locale& locale)
1557 stdex_assert(str || !count);
1558 stdex_assert(sample);
1559 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
1560 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
1561 for (
size_t offset = 0;; ++offset) {
1562 for (
size_t i = offset, j = 0;; ++i, ++j) {
1565 if (i >= count || !str[i])
1567 if (ctype1.tolower(str[i]) != ctype2.tolower(sample[j]))
1581 template <
class T1,
size_t N1,
class T2>
1583 _In_
const T1 (&str)[N1],
1584 _In_z_
const T2* sample)
1586 return strnistr(str, N1, sample);
1598 template <
class T1,
size_t N1,
class T2>
1600 _In_
const T1 (&str)[N1],
1601 _In_z_
const T2* sample,
1602 _In_
const std::locale& locale)
1604 return strnistr(str, N1, sample, locale);
1615 template <
class T1,
class T2>
1617 _Out_writes_z_(_String_length_(src) + 1) T1* dst,
1618 _In_z_
const T2* src)
1622 for (
size_t i = 0; ; ++i) {
1623 if ((dst[i] =
static_cast<T1
>(src[i])) == 0)
1637 template <
class T1,
class T2>
1639 _Out_writes_(count) _Post_maybez_ T1* dst,
1640 _In_reads_or_z_opt_(count)
const T2* src, _In_
size_t count)
1642 stdex_assert(dst || !count);
1643 stdex_assert(src || !count);
1644 for (
size_t i = 0; ; ++i) {
1647 if ((dst[i] =
static_cast<T1
>(src[i])) == 0)
1662 template <
class T1,
class T2>
1664 _Out_writes_(count_dst) _Post_maybez_ T1* dst, _In_
size_t count_dst,
1665 _In_reads_or_z_opt_(count_src)
const T2* src, _In_
size_t count_src)
1667 stdex_assert(dst || !count_dst);
1668 stdex_assert(src || !count_src);
1669 for (
size_t i = 0; ; ++i)
1673 if (i >= count_src) {
1677 if ((dst[i] =
static_cast<T1
>(src[i])) == 0)
1690 template <
class T1,
size_t N1,
class T2,
size_t N2>
1692 _Out_ _Post_maybez_ T1 (&dst)[N1],
1693 _In_
const T2 (&src)[N2])
1695 return strncpy(dst, N1, src, N2);
1706 template <
class T1,
class T2>
1708 _In_z_ _Out_writes_z_(_String_length_(dst) + _String_length_(src) + 1) T1* dst,
1709 _In_z_
const T2* src)
1713 for (
size_t i = 0, j = stdex::strlen<T1>(dst); ; ++i, ++j) {
1714 if ((dst[j] =
static_cast<T1
>(src[i])) == 0)
1728 template <
class T1,
class T2>
1731 _In_reads_or_z_opt_(count)
const T2* src, _In_
size_t count)
1733 stdex_assert(dst || !count);
1734 stdex_assert(src || !count);
1735 for (
size_t i = 0, j = stdex::strlen<T1>(dst); ; ++i, ++j) {
1738 if ((dst[j] =
static_cast<T1
>(src[i])) == 0)
1753 template <
class T1,
class T2>
1755 _Out_writes_(count_dst) _Post_maybez_ T1* dst, _In_
size_t count_dst,
1756 _In_reads_or_z_opt_(count_src)
const T2* src, _In_
size_t count_src)
1758 stdex_assert(dst || !count_dst);
1759 stdex_assert(src || !count_src);
1760 for (
size_t i = 0, j = stdex::strnlen<T1>(dst, count_dst); ; ++i, ++j)
1764 if (i >= count_src) {
1768 if ((dst[j] =
static_cast<T1
>(src[i])) == 0)
1784 _Check_return_ _Ret_maybenull_z_ T* strdup(_In_opt_z_
const T* str)
1786 if (!str) _Unlikely_
1788 size_t count = strlen(str) + 1;
1789 T* dst =
new T[count];
1790 strncpy(dst, count, str, SIZE_MAX);
1807 _In_reads_or_z_opt_(count)
const T* str,
1810 T* dst =
new T[count];
1811 strncpy(dst, count, str, SIZE_MAX);
1825 template <
class T,
size_t N>
1826 _Check_return_ _Ret_maybenull_z_ T* strndup(_In_
const T (&str)[N])
1828 return strndup(str, N);
1841 size_t crlf2nl(_Out_writes_z_(_String_length_(src) + 1) T* dst, _In_z_
const T* src)
1846 for (i = j = 0; src[j];) {
1847 if (src[j] !=
'\r' || src[j + 1] !=
'\n')
1848 dst[i++] = src[j++];
1864 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
1865 void crlf2nl(_Inout_ std::basic_string<T, TR, AX>& dst, _In_z_
const T* src)
1868 stdex_assert(src != dst.data());
1870 dst.reserve(strlen(src));
1871 for (
size_t j = 0; src[j];) {
1872 if (src[j] !=
'\r' || src[j + 1] !=
'\n')
1886 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
1887 void crlf2nl(_Inout_ std::basic_string<T, TR, AX>& str)
1890 for (i = j = 0, n = str.size(); j < n;) {
1891 if (str[j] !=
'\r' || str[j + 1] !=
'\n')
1892 str[i++] = str[j++];
1902 template <
class T,
class T_bin>
1904 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
1905 _Out_opt_
size_t* end,
1907 _Out_ uint8_t& flags)
1909 stdex_assert(str || !count);
1910 stdex_assert(radix == 0 || 2 <= radix && radix <= 36);
1913 T_bin value = 0, digit,
1915 max_ui_pre1, max_ui_pre2;
1921 if (i >= count || !str[i])
goto error;
1922 if (!isspace(str[i]))
break;
1926 if (str[i] ==
'+') {
1929 if (i >= count || !str[i])
goto error;
1931 else if (str[i] ==
'-') {
1934 if (i >= count || !str[i])
goto error;
1939 if (str[i] ==
'0' && i + 1 < count && (str[i + 1] ==
'x' || str[i + 1] ==
'X')) {
1941 if (i >= count || !str[i])
goto error;
1946 if (str[i] ==
'0') {
1948 if (i >= count || !str[i])
goto error;
1949 if (str[i] ==
'x' || str[i] ==
'X') {
1952 if (i >= count || !str[i])
goto error;
1962 max_ui_pre1 = max_ui / (T_bin)radix;
1963 max_ui_pre2 = max_ui % (T_bin)radix;
1965 if (
'0' <= str[i] && str[i] <=
'9')
1966 digit = (T_bin)str[i] -
'0';
1967 else if (
'A' <= str[i] && str[i] <=
'Z')
1968 digit = (T_bin)str[i] -
'A' +
'\x0a';
1969 else if (
'a' <= str[i] && str[i] <=
'z')
1970 digit = (T_bin)str[i] -
'a' +
'\x0a';
1973 if (digit >= (T_bin)radix)
1976 if (value < max_ui_pre1 ||
1977 (value == max_ui_pre1 && digit <= max_ui_pre2))
1978 value = value * (T_bin)radix + digit;
1985 if (i >= count || !str[i])
2005 template <
class T,
class T_bin>
2007 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
2008 _Out_opt_
size_t* end,
2014 switch (
sizeof(T_bin)) {
2016 value = (T_bin)strtoint<T, uint8_t>(str, count, end, radix, flags);
2017 if ((flags & 0x01) && (value & 0x80)) {
2021 return (flags & 0x02) ?
2022 (flags & 0x01) ? (T_bin)0x80 : (T_bin)0x7f :
2023 (flags & 0x01) ? -value : value;
2026 value = (T_bin)strtoint<T, uint16_t>(str, count, end, radix, flags);
2027 if ((flags & 0x01) && (value & 0x8000)) {
2031 return (flags & 0x02) ?
2032 (flags & 0x01) ? (T_bin)0x8000 : (T_bin)0x7fff :
2033 (flags & 0x01) ? -value : value;
2036 value = (T_bin)strtoint<T, uint32_t>(str, count, end, radix, flags);
2037 if ((flags & 0x01) && (value & 0x80000000)) {
2041 return (flags & 0x02) ?
2042 (flags & 0x01) ? (T_bin)0x80000000 : (T_bin)0x7fffffff :
2043 (flags & 0x01) ? -value : value;
2046 value = (T_bin)strtoint<T, uint64_t>(str, count, end, radix, flags);
2047 if ((flags & 0x01) && (value & 0x8000000000000000)) {
2051 return (flags & 0x02) ?
2052 (flags & 0x01) ? (T_bin)0x8000000000000000 : (T_bin)0x7fffffffffffffff :
2053 (flags & 0x01) ? -value : value;
2056 throw std::invalid_argument(
"Unsupported bit length");
2069 template <
class T,
size_t N,
class T_bin>
2071 _In_
const T (&str)[N],
2072 _Out_opt_
size_t* end,
2075 return strtoint<T, T_bin>(str, N, end, radix);
2088 template <
class T,
class T_bin>
2090 _In_reads_or_z_opt_(count)
const T* str,
2092 _Out_opt_
size_t* end,
2098 switch (
sizeof(T_bin)) {
2099 case 1: value = (T_bin)strtoint<T, uint8_t>(str, count, end, radix, flags);
break;
2100 case 2: value = (T_bin)strtoint<T, uint16_t>(str, count, end, radix, flags);
break;
2101 case 4: value = (T_bin)strtoint<T, uint32_t>(str, count, end, radix, flags);
break;
2102 case 8: value = (T_bin)strtoint<T, uint64_t>(str, count, end, radix, flags);
break;
2103 default:
throw std::invalid_argument(
"Unsupported bit length");
2106 return (flags & 0x02) ?
2107 (flags & 0x01) ? (T_bin)0 : (T_bin)-1 :
2108 (flags & 0x01) ? ~value : value;
2120 template <
class T,
size_t N,
class T_bin>
2122 _In_
const T (&str)[N],
2123 _Out_opt_
size_t* end,
2126 return strtouint<T, T_bin>(str, N, end, radix);
2141 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
2142 _Out_opt_
size_t* end,
2145 return strtoint<T, int32_t>(str, count, end, radix);
2157 template <
class T,
size_t N>
2159 _In_
const T (&str)[N],
2160 _Out_opt_
size_t* end,
2163 return strto32<T>(str, N, end, radix);
2178 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
2179 _Out_opt_
size_t* end,
2182 return strtoint<T, int64_t>(str, count, end, radix);
2194 template <
class T,
size_t N>
2196 _In_
const T (&str)[N],
2197 _Out_opt_
size_t* end,
2200 return strto64<T>(str, N, end, radix);
2216 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
2217 _Out_opt_
size_t* end,
2220#if defined(_WIN64) || defined(__LP64__)
2221 return static_cast<ptrdiff_t
>(strto64(str, count, end, radix));
2223 return static_cast<ptrdiff_t
>(strto32(str, count, end, radix));
2237 template <
class T,
size_t N>
2239 _In_
const T (&str)[N],
2240 _Out_opt_
size_t* end,
2243 return strtoi<T>(str, N, end, radix);
2258 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
2259 _Out_opt_
size_t* end,
2262 return strtouint<T, uint32_t>(str, count, end, radix);
2274 template <
class T,
size_t N>
2276 _In_
const T (&str)[N],
2277 _Out_opt_
size_t* end,
2280 return strtou32(str, N, end, radix);
2295 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
2296 _Out_opt_
size_t* end,
2299 return strtouint<T, uint64_t>(str, count, end, radix);
2311 template <
class T,
size_t N>
2313 _In_
const T (&str)[N],
2314 _Out_opt_
size_t* end,
2317 return strtou64<T>(str, N, end, radix);
2333 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
2334 _Out_opt_
size_t* end,
2337#if defined(_WIN64) || defined(__LP64__)
2338 return static_cast<size_t>(strtou64(str, count, end, radix));
2340 return static_cast<size_t>(strtou32(str, count, end, radix));
2354 template <
class T,
size_t N>
2356 _In_
const T (&str)[N],
2357 _Out_opt_
size_t* end,
2360 return strtoui<T>(str, N, end, radix);
2373 inline double strtod(
2374 _In_reads_or_z_opt_(count)
const char* str, _In_
size_t count,
2375 _Out_opt_
size_t* end,
2376 _In_opt_ locale_t locale)
2378 count = strnlen(str, count);
2379 stdex_assert(str || !count);
2380 std::string tmp(str, count);
2384 r = _strtod_l(tmp.c_str(), &_end, locale);
2386 r = strtod_l(tmp.c_str(), &_end, locale);
2388 if (end) *end = (size_t)(_end - tmp.c_str());
2402 inline double strtod(
2403 _In_reads_or_z_opt_(count)
const wchar_t* str, _In_
size_t count,
2404 _Out_opt_
size_t* end,
2405 _In_opt_ locale_t locale)
2407 count = strnlen(str, count);
2408 stdex_assert(str || !count);
2409 std::wstring tmp(str, count);
2413 r = _wcstod_l(tmp.c_str(), &_end, locale);
2415 r = wcstod_l(tmp.c_str(), &_end, locale);
2417 if (end) *end = (size_t)(_end - tmp.c_str());
2422 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)
2425#pragma warning(suppress: 4996)
2426 return _vsnprintf_l(str, capacity, format, locale, arg);
2428 va_list arg_mutable;
2429 va_copy(arg_mutable, arg);
2430 return ::vsnprintf_l(str, capacity, locale, format, arg_mutable);
2434 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)
2437#pragma warning(suppress: 4996)
2438 return _vsnwprintf_l(str, capacity, format, locale, arg);
2440 va_list arg_mutable;
2441 va_copy(arg_mutable, arg);
2442 return ::vswprintf_l(str, capacity, locale, format, arg_mutable);
2457 template<
class T,
class TR,
class AX>
2458 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)
2460 T buf[1024 /
sizeof(T)];
2463 int count = vsnprintf(buf, _countof(buf), format, locale, arg);
2464 if (0 <= count &&
static_cast<size_t>(count) <= _countof(buf)) {
2466 str.append(buf,
static_cast<size_t>(count));
2467 return static_cast<size_t>(count);
2473 count = vsnprintf(NULL, 0, format, locale, arg);
2474 stdex_assert(count >= 0);
2476 case EINVAL:
throw std::invalid_argument(
"invalid vsnprintf arguments");
2477 case EILSEQ:
throw std::runtime_error(
"encoding error");
2478 default:
throw std::runtime_error(
"failed to format string");
2481 size_t offset = str.size();
2482 str.resize(offset + count);
2483 if (vsnprintf(&str[offset], count + 1, format, locale, arg) != count) _Unlikely_
2484 throw std::runtime_error(
"failed to format string");
2486 size_t offset = str.size();
2487 for (
size_t capacity = 2 * 1024 /
sizeof(T);; capacity *= 2) {
2491 str.resize(offset + capacity);
2492 count = vsnprintf(&str[offset], capacity, format, locale, arg);
2493 if (0 <= count &&
static_cast<size_t>(count) <= capacity) {
2494 str.resize(offset +
static_cast<size_t>(count));
2495 return static_cast<size_t>(count);
2498 case EINVAL:
throw std::invalid_argument(
"invalid vsnprintf arguments");
2499 case EILSEQ:
throw std::runtime_error(
"encoding error");
2500 default:
throw std::runtime_error(
"failed to format string");
2504 return static_cast<size_t>(count);
2516 template<
class T,
class TR,
class AX>
2517 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, ...)
2520 va_start(arg, locale);
2521 size_t n = vappendf(str, format, locale, arg);
2534 template<
class T,
class TR,
class AX>
2535 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)
2538 vappendf(str, format, locale, arg);
2548 template<
class T,
class TR,
class AX>
2549 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, ...)
2552 va_start(arg, locale);
2553 vsprintf(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> vsprintf(_In_z_ _Printf_format_string_params_(2)
const T* format, _In_opt_ locale_t locale, _In_ va_list arg)
2569 std::basic_string<T, TR, AX> str;
2570 vappendf(str, format, locale, arg);
2582 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2583 std::basic_string<T, TR, AX> sprintf(_In_z_ _Printf_format_string_params_(2)
const T* format, _In_opt_ locale_t locale, ...)
2586 va_start(arg, locale);
2587 auto str = vsprintf(format, locale, arg);
2593 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)
2596 return _strftime_l(str, capacity, format, time, locale);
2598 return strftime_l(str, capacity, format, time, locale);
2602 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)
2605 return _wcsftime_l(str, capacity, format, time, locale);
2607 return wcsftime_l(str, capacity, format, time, locale);
2620 template<
class T,
class TR,
class AX>
2621 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)
2623 T buf[1024 /
sizeof(T)];
2626 size_t count = strftime(buf, _countof(buf), format, time, locale);
2629 str.append(buf, count);
2632 size_t offset = str.size();
2633 for (
size_t capacity = 2 * 1024 /
sizeof(T);; capacity *= 2) {
2635 str.resize(offset + capacity);
2636 count = strftime(&str[offset], capacity + 1, format, time, locale);
2638 str.resize(offset + count);
2652 template<
class T,
class TR,
class AX>
2653 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)
2656 strcatftime(str, format, time, locale);
2668 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2669 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)
2671 std::basic_string<T, TR, AX> str;
2672 strcatftime(str, format, time, locale);
2711 void strlwr(_Inout_updates_z_(count) T* str, _In_
size_t count)
2713 stdex_assert(str || !count);
2714 for (
size_t i = 0; i < count && str[i]; ++i)
2715 str[i] = tolower(str[i]);
2726 void strlwr(_Inout_updates_z_(count) T* str, _In_
size_t count, _In_
const std::locale& locale)
2728 stdex_assert(str || !count);
2729 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2730 for (
size_t i = 0; i < count && str[i]; ++i)
2731 str[i] = ctype.tolower(str[i]);
2739 template<
class T,
size_t N>
2740 void strlwr(_Inout_ T (&str)[N])
2751 template<
class T,
size_t N>
2752 void strlwr(_Inout_ T (&str)[N], _In_
const std::locale& locale)
2754 strlwr(str, N, locale);
2762 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2763 void strlwr(_Inout_ std::basic_string<T, TR, AX>& str)
2775 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2776 void strlwr(_Inout_ std::basic_string<T, TR, AX>& str, _In_
const std::locale& locale)
2778 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2780 c = ctype.tolower(c);
2818 void strupr(_Inout_updates_z_(count) T* str, _In_
size_t count)
2820 stdex_assert(str || !count);
2821 for (
size_t i = 0; i < count && str[i]; ++i)
2822 str[i] = toupper(str[i]);
2833 void strupr(_Inout_updates_z_(count) T* str, _In_
size_t count, _In_
const std::locale& locale)
2835 stdex_assert(str || !count);
2836 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2837 for (
size_t i = 0; i < count && str[i]; ++i)
2838 str[i] = ctype.toupper(str[i]);
2846 template<
class T,
size_t N>
2847 void strupr(_Inout_ T (&str)[N])
2849 return strupr(str, N);
2858 template<
class T,
size_t N>
2859 void strupr(_Inout_ T (&str)[N], _In_
const std::locale& locale)
2861 return strupr(str, N, locale);
2869 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2870 void strupr(_Inout_ std::basic_string<T, TR, AX>& str)
2882 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2883 void strupr(_Inout_ std::basic_string<T, TR, AX>& str, _In_
const std::locale& locale)
2885 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2887 c = ctype.toupper(c);
2900 _Inout_z_count_(count) T* str, _In_
size_t count)
2902 for (
size_t i = 0;; ++i) {
2904 if (count) str[0] = 0;
2911 if (!isspace(str[i])) {
2913 return strnlen(str, count);
2914 size_t n = count != SIZE_MAX ? strncpy(str, str + i, count - i) : strcpy(str, str + i);
2932 _Inout_z_count_(count) T* str, _In_
size_t count,
2933 _In_
const std::locale& locale)
2935 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2936 for (
size_t i = 0;; ++i) {
2938 if (count) str[0] = 0;
2945 if (!ctype.is(ctype.space, str[i])) {
2947 return strnlen(str, count);
2948 size_t n = count != SIZE_MAX ? strncpy(str, str + i, count - i) : strcpy(str, str + i);
2960 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2961 void ltrim(_Inout_ std::basic_string<T, TR, AX>& s)
2968 [&](_In_ T ch) { return !isspace(ch); }));
2977 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2978 void ltrim(_Inout_ std::basic_string<T, TR, AX>& s, _In_
const std::locale& locale)
2980 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2986 [&](_In_ T ch) { return !ctype.is(ctype.space, ch); }));
2999 _Inout_z_count_(count) T* str, _In_
size_t count)
3001 for (
size_t i = 0, j = 0;;) {
3002 if (i >= count || !str[i]) {
3003 if (j < count) str[j] = 0;
3006 if (!isspace(str[i]))
3024 _Inout_z_count_(count) T* str, _In_
size_t count,
3025 _In_
const std::locale& locale)
3027 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
3028 for (
size_t i = 0, j = 0;;) {
3029 if (i >= count || !str[i]) {
3030 if (j < count) str[j] = 0;
3033 if (!ctype.is(ctype.space, str[i]))
3045 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
3046 void rtrim(_Inout_ std::basic_string<T, TR, AX>& s)
3052 [&](_In_ T ch) { return !isspace(ch); }).base(),
3062 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
3063 void rtrim(_Inout_ std::basic_string<T, TR, AX>& s, _In_
const std::locale& locale)
3065 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
3070 [&](_In_ T ch) { return !ctype.is(ctype.space, ch); }).base(),
3084 _Inout_z_count_(count) T* str, _In_
size_t count)
3086 return ltrim(str, rtrim(str, count));
3100 _Inout_z_count_(count) T* str, _In_
size_t count,
3101 _In_
const std::locale& locale)
3103 return ltrim(str, rtrim(str, count, locale), locale);
3111 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
3112 void trim(_Inout_ std::basic_string<T, TR, AX>& s)
3114 auto nonspace = [&](_In_ T ch) {
return !isspace(ch); };
3135 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
3136 void trim(_Inout_ std::basic_string<T, TR, AX>& s, _In_
const std::locale& locale)
3138 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
3139 auto nonspace = [&](_In_ T ch) {
return !ctype.is(ctype.space, ch); };