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;
1163 if (str1[i])
return +1;
1164 if (str2[i])
return -1;
1177 template <
class T1,
class T2>
1178 int strnicmp(_In_reads_or_z_opt_(count)
const T1* str1, _In_reads_or_z_opt_(count)
const T2* str2, _In_
size_t count)
1180 stdex_assert(str1 || !count);
1181 stdex_assert(str2 || !count);
1183 for (i = 0; i < count; ++i) {
1184 auto a = tolower(str1[i]);
1185 auto b = tolower(str2[i]);
1186 if (!a && !b)
return 0;
1187 if (a > b)
return +1;
1188 if (a < b)
return -1;
1190 if (i < count && str1[i])
return +1;
1191 if (i < count && str2[i])
return -1;
1205 template <
class T1,
class T2>
1206 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)
1208 stdex_assert(str1 || !count);
1209 stdex_assert(str2 || !count);
1211 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
1212 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
1213 for (i = 0; i < count; ++i) {
1214 auto a = ctype1.tolower(str1[i]);
1215 auto b = ctype2.tolower(str2[i]);
1216 if (!a && !b)
return 0;
1217 if (a > b)
return +1;
1218 if (a < b)
return -1;
1220 if (i < count && str1[i])
return +1;
1221 if (i < count && str2[i])
return -1;
1235 template <
class T1,
class T2>
1237 _In_reads_or_z_opt_(count1)
const T1* str1, _In_
size_t count1,
1238 _In_reads_or_z_opt_(count2)
const T2* str2, _In_
size_t count2)
1240 stdex_assert(str1 || !count1);
1241 stdex_assert(str2 || !count2);
1243 for (i = 0; i < count1 && i < count2; ++i) {
1244 auto a = tolower(str1[i]);
1245 auto b = tolower(str2[i]);
1246 if (!a && !b)
return 0;
1247 if (a > b)
return +1;
1248 if (a < b)
return -1;
1250 if (i < count1 && str1[i])
return +1;
1251 if (i < count2 && str2[i])
return -1;
1266 template <
class T1,
class T2>
1268 _In_reads_or_z_opt_(count1)
const T1* str1, _In_
size_t count1,
1269 _In_reads_or_z_opt_(count2)
const T2* str2, _In_
size_t count2,
1270 _In_
const std::locale& locale)
1272 stdex_assert(str1 || !count1);
1273 stdex_assert(str2 || !count2);
1275 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
1276 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
1277 for (i = 0; i < count1 && i < count2; ++i) {
1278 auto a = ctype1.tolower(str1[i]);
1279 auto b = ctype2.tolower(str2[i]);
1280 if (!a && !b)
return 0;
1281 if (a > b)
return +1;
1282 if (a < b)
return -1;
1284 if (i < count1 && str1[i])
return +1;
1285 if (i < count2 && str2[i])
return -1;
1297 template <
class T1,
size_t N1,
class T2,
size_t N2>
1299 _In_
const T1 (&str1)[N1],
1300 _In_
const T2 (&str2)[N2])
1302 strnicmp(str1, N1, str2, N2);
1314 template <
class T1,
size_t N1,
class T2,
size_t N2>
1316 _In_
const T1 (&str1)[N1],
1317 _In_
const T2 (&str2)[N2],
1318 _In_
const std::locale& locale)
1320 strnicmp(str1, N1, str2, N2, locale);
1334 _In_z_
const T* str1,
1335 _In_z_
const T* str2,
1336 _In_
const std::locale& locale)
1340 auto& collate = std::use_facet<std::collate<T>>(locale);
1341 return collate.compare(str1, str1 + strlen(str1), str2, str2 + strlen(str2));
1357 _In_reads_or_z_opt_(count1)
const T* str1, _In_
size_t count1,
1358 _In_reads_or_z_opt_(count2)
const T* str2, _In_
size_t count2,
1359 _In_
const std::locale& locale)
1361 stdex_assert(str1 || !count1);
1362 stdex_assert(str2 || !count2);
1363 auto& collate = std::use_facet<std::collate<T>>(locale);
1364 return collate.compare(str1, str1 + count1, str2, str2 + count2);
1376 template <
class T,
size_t N1,
size_t N2>
1378 _In_
const T (&str1)[N1],
1379 _In_
const T (&str2)[N2],
1380 _In_
const std::locale& locale)
1382 return strncoll(str1, N1, str2, N2, locale);
1393 template <
class T1,
class T2>
1395 _In_z_
const T1* str,
1396 _In_z_
const T2* sample)
1399 stdex_assert(sample);
1400 for (
size_t offset = 0;; ++offset) {
1401 for (
size_t i = offset, j = 0;; ++i, ++j) {
1406 if (str[i] != sample[j])
1421 template <
class T1,
class T2>
1423 _In_reads_or_z_opt_(count)
const T1* str, _In_
size_t count,
1424 _In_z_
const T2* sample)
1426 stdex_assert(str || !count);
1427 stdex_assert(sample);
1428 for (
size_t offset = 0;; ++offset) {
1429 for (
size_t i = offset, j = 0;; ++i, ++j) {
1432 if (i >= count || !str[i])
1434 if (str[i] != sample[j])
1448 template <
class T1,
size_t N1,
class T2>
1450 _In_
const T1 (&str)[N1],
1451 _In_z_
const T2* sample)
1453 return strnstr(str, N1, sample);
1464 template <
class T1,
class T2>
1466 _In_z_
const T1* str,
1467 _In_z_
const T2* sample)
1470 stdex_assert(sample);
1471 for (
size_t offset = 0;; ++offset) {
1472 for (
size_t i = offset, j = 0;; ++i, ++j) {
1477 if (tolower(str[i]) != tolower(sample[j]))
1492 template <
class T1,
class T2>
1494 _In_z_
const T1* str,
1495 _In_z_
const T2* sample,
1496 _In_
const std::locale& locale)
1499 stdex_assert(sample);
1500 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
1501 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
1502 for (
size_t offset = 0;; ++offset) {
1503 for (
size_t i = offset, j = 0;; ++i, ++j) {
1508 if (ctype1.tolower(str[i]) != ctype2.tolower(sample[j]))
1523 template <
class T1,
class T2>
1525 _In_reads_or_z_opt_(count)
const T1* str,
1527 _In_z_
const T2* sample)
1529 stdex_assert(str || !count);
1530 stdex_assert(sample);
1531 for (
size_t offset = 0;; ++offset) {
1532 for (
size_t i = offset, j = 0;; ++i, ++j) {
1535 if (i >= count || !str[i])
1537 if (tolower(str[i]) != tolower(sample[j]))
1553 template <
class T1,
class T2>
1555 _In_reads_or_z_opt_(count)
const T1* str,
1557 _In_z_
const T2* sample,
1558 _In_
const std::locale& locale)
1560 stdex_assert(str || !count);
1561 stdex_assert(sample);
1562 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
1563 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
1564 for (
size_t offset = 0;; ++offset) {
1565 for (
size_t i = offset, j = 0;; ++i, ++j) {
1568 if (i >= count || !str[i])
1570 if (ctype1.tolower(str[i]) != ctype2.tolower(sample[j]))
1584 template <
class T1,
size_t N1,
class T2>
1586 _In_
const T1 (&str)[N1],
1587 _In_z_
const T2* sample)
1589 return strnistr(str, N1, sample);
1601 template <
class T1,
size_t N1,
class T2>
1603 _In_
const T1 (&str)[N1],
1604 _In_z_
const T2* sample,
1605 _In_
const std::locale& locale)
1607 return strnistr(str, N1, sample, locale);
1618 template <
class T1,
class T2>
1620 _Out_writes_z_(_String_length_(src) + 1) T1* dst,
1621 _In_z_
const T2* src)
1625 for (
size_t i = 0; ; ++i) {
1626 if ((dst[i] =
static_cast<T1
>(src[i])) == 0)
1640 template <
class T1,
class T2>
1642 _Out_writes_(count) _Post_maybez_ T1* dst,
1643 _In_reads_or_z_opt_(count)
const T2* src, _In_
size_t count)
1645 stdex_assert(dst || !count);
1646 stdex_assert(src || !count);
1647 for (
size_t i = 0; ; ++i) {
1650 if ((dst[i] =
static_cast<T1
>(src[i])) == 0)
1665 template <
class T1,
class T2>
1667 _Out_writes_(count_dst) _Post_maybez_ T1* dst, _In_
size_t count_dst,
1668 _In_reads_or_z_opt_(count_src)
const T2* src, _In_
size_t count_src)
1670 stdex_assert(dst || !count_dst);
1671 stdex_assert(src || !count_src);
1672 for (
size_t i = 0; ; ++i)
1676 if (i >= count_src) {
1680 if ((dst[i] =
static_cast<T1
>(src[i])) == 0)
1693 template <
class T1,
size_t N1,
class T2,
size_t N2>
1695 _Out_ _Post_maybez_ T1 (&dst)[N1],
1696 _In_
const T2 (&src)[N2])
1698 return strncpy(dst, N1, src, N2);
1709 template <
class T1,
class T2>
1711 _In_z_ _Out_writes_z_(_String_length_(dst) + _String_length_(src) + 1) T1* dst,
1712 _In_z_
const T2* src)
1716 for (
size_t i = 0, j = stdex::strlen<T1>(dst); ; ++i, ++j) {
1717 if ((dst[j] =
static_cast<T1
>(src[i])) == 0)
1731 template <
class T1,
class T2>
1734 _In_reads_or_z_opt_(count)
const T2* src, _In_
size_t count)
1736 stdex_assert(dst || !count);
1737 stdex_assert(src || !count);
1738 for (
size_t i = 0, j = stdex::strlen<T1>(dst); ; ++i, ++j) {
1741 if ((dst[j] =
static_cast<T1
>(src[i])) == 0)
1756 template <
class T1,
class T2>
1758 _Out_writes_(count_dst) _Post_maybez_ T1* dst, _In_
size_t count_dst,
1759 _In_reads_or_z_opt_(count_src)
const T2* src, _In_
size_t count_src)
1761 stdex_assert(dst || !count_dst);
1762 stdex_assert(src || !count_src);
1763 for (
size_t i = 0, j = stdex::strnlen<T1>(dst, count_dst); ; ++i, ++j)
1767 if (i >= count_src) {
1771 if ((dst[j] =
static_cast<T1
>(src[i])) == 0)
1787 _Check_return_ _Ret_maybenull_z_ T* strdup(_In_opt_z_
const T* str)
1789 if (!str) _Unlikely_
1791 size_t count = strlen(str) + 1;
1792 T* dst =
new T[count];
1793 strncpy(dst, count, str, SIZE_MAX);
1810 _In_reads_or_z_opt_(count)
const T* str,
1813 T* dst =
new T[count];
1814 strncpy(dst, count, str, SIZE_MAX);
1828 template <
class T,
size_t N>
1829 _Check_return_ _Ret_maybenull_z_ T* strndup(_In_
const T (&str)[N])
1831 return strndup(str, N);
1844 size_t crlf2nl(_Out_writes_z_(_String_length_(src) + 1) T* dst, _In_z_
const T* src)
1849 for (i = j = 0; src[j];) {
1850 if (src[j] !=
'\r' || src[j + 1] !=
'\n')
1851 dst[i++] = src[j++];
1867 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
1868 void crlf2nl(_Inout_ std::basic_string<T, TR, AX>& dst, _In_z_
const T* src)
1871 stdex_assert(src != dst.data());
1873 dst.reserve(strlen(src));
1874 for (
size_t j = 0; src[j];) {
1875 if (src[j] !=
'\r' || src[j + 1] !=
'\n')
1889 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
1890 void crlf2nl(_Inout_ std::basic_string<T, TR, AX>& str)
1893 for (i = j = 0, n = str.size(); j < n;) {
1894 if (str[j] !=
'\r' || str[j + 1] !=
'\n')
1895 str[i++] = str[j++];
1905 template <
class T,
class T_bin>
1907 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
1908 _Out_opt_
size_t* end,
1910 _Out_ uint8_t& flags)
1912 stdex_assert(str || !count);
1913 stdex_assert(radix == 0 || 2 <= radix && radix <= 36);
1916 T_bin value = 0, digit,
1918 max_ui_pre1, max_ui_pre2;
1924 if (i >= count || !str[i])
goto error;
1925 if (!isspace(str[i]))
break;
1929 if (str[i] ==
'+') {
1932 if (i >= count || !str[i])
goto error;
1934 else if (str[i] ==
'-') {
1937 if (i >= count || !str[i])
goto error;
1942 if (str[i] ==
'0' && i + 1 < count && (str[i + 1] ==
'x' || str[i + 1] ==
'X')) {
1944 if (i >= count || !str[i])
goto error;
1949 if (str[i] ==
'0') {
1951 if (i >= count || !str[i])
goto error;
1952 if (str[i] ==
'x' || str[i] ==
'X') {
1955 if (i >= count || !str[i])
goto error;
1965 max_ui_pre1 = max_ui / (T_bin)radix;
1966 max_ui_pre2 = max_ui % (T_bin)radix;
1968 if (
'0' <= str[i] && str[i] <=
'9')
1969 digit = (T_bin)str[i] -
'0';
1970 else if (
'A' <= str[i] && str[i] <=
'Z')
1971 digit = (T_bin)str[i] -
'A' +
'\x0a';
1972 else if (
'a' <= str[i] && str[i] <=
'z')
1973 digit = (T_bin)str[i] -
'a' +
'\x0a';
1976 if (digit >= (T_bin)radix)
1979 if (value < max_ui_pre1 ||
1980 (value == max_ui_pre1 && digit <= max_ui_pre2))
1981 value = value * (T_bin)radix + digit;
1988 if (i >= count || !str[i])
2008 template <
class T,
class T_bin>
2010 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
2011 _Out_opt_
size_t* end,
2017 switch (
sizeof(T_bin)) {
2019 value = (T_bin)strtoint<T, uint8_t>(str, count, end, radix, flags);
2020 if ((flags & 0x01) && (value & 0x80)) {
2024 return (flags & 0x02) ?
2025 (flags & 0x01) ? (T_bin)0x80 : (T_bin)0x7f :
2026 (flags & 0x01) ? -value : value;
2029 value = (T_bin)strtoint<T, uint16_t>(str, count, end, radix, flags);
2030 if ((flags & 0x01) && (value & 0x8000)) {
2034 return (flags & 0x02) ?
2035 (flags & 0x01) ? (T_bin)0x8000 : (T_bin)0x7fff :
2036 (flags & 0x01) ? -value : value;
2039 value = (T_bin)strtoint<T, uint32_t>(str, count, end, radix, flags);
2040 if ((flags & 0x01) && (value & 0x80000000)) {
2044 return (flags & 0x02) ?
2045 (flags & 0x01) ? (T_bin)0x80000000 : (T_bin)0x7fffffff :
2046 (flags & 0x01) ? -value : value;
2049 value = (T_bin)strtoint<T, uint64_t>(str, count, end, radix, flags);
2050 if ((flags & 0x01) && (value & 0x8000000000000000)) {
2054 return (flags & 0x02) ?
2055 (flags & 0x01) ? (T_bin)0x8000000000000000 : (T_bin)0x7fffffffffffffff :
2056 (flags & 0x01) ? -value : value;
2059 throw std::invalid_argument(
"Unsupported bit length");
2072 template <
class T,
size_t N,
class T_bin>
2074 _In_
const T (&str)[N],
2075 _Out_opt_
size_t* end,
2078 return strtoint<T, T_bin>(str, N, end, radix);
2091 template <
class T,
class T_bin>
2093 _In_reads_or_z_opt_(count)
const T* str,
2095 _Out_opt_
size_t* end,
2101 switch (
sizeof(T_bin)) {
2102 case 1: value = (T_bin)strtoint<T, uint8_t>(str, count, end, radix, flags);
break;
2103 case 2: value = (T_bin)strtoint<T, uint16_t>(str, count, end, radix, flags);
break;
2104 case 4: value = (T_bin)strtoint<T, uint32_t>(str, count, end, radix, flags);
break;
2105 case 8: value = (T_bin)strtoint<T, uint64_t>(str, count, end, radix, flags);
break;
2106 default:
throw std::invalid_argument(
"Unsupported bit length");
2109 return (flags & 0x02) ?
2110 (flags & 0x01) ? (T_bin)0 : (T_bin)-1 :
2111 (flags & 0x01) ? ~value : value;
2123 template <
class T,
size_t N,
class T_bin>
2125 _In_
const T (&str)[N],
2126 _Out_opt_
size_t* end,
2129 return strtouint<T, T_bin>(str, N, end, radix);
2144 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
2145 _Out_opt_
size_t* end,
2148 return strtoint<T, int32_t>(str, count, end, radix);
2160 template <
class T,
size_t N>
2162 _In_
const T (&str)[N],
2163 _Out_opt_
size_t* end,
2166 return strto32<T>(str, N, end, radix);
2181 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
2182 _Out_opt_
size_t* end,
2185 return strtoint<T, int64_t>(str, count, end, radix);
2197 template <
class T,
size_t N>
2199 _In_
const T (&str)[N],
2200 _Out_opt_
size_t* end,
2203 return strto64<T>(str, N, end, radix);
2219 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
2220 _Out_opt_
size_t* end,
2223#if defined(_WIN64) || defined(__LP64__)
2224 return static_cast<ptrdiff_t
>(strto64(str, count, end, radix));
2226 return static_cast<ptrdiff_t
>(strto32(str, count, end, radix));
2240 template <
class T,
size_t N>
2242 _In_
const T (&str)[N],
2243 _Out_opt_
size_t* end,
2246 return strtoi<T>(str, N, end, radix);
2261 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
2262 _Out_opt_
size_t* end,
2265 return strtouint<T, uint32_t>(str, count, end, radix);
2277 template <
class T,
size_t N>
2279 _In_
const T (&str)[N],
2280 _Out_opt_
size_t* end,
2283 return strtou32(str, N, end, radix);
2298 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
2299 _Out_opt_
size_t* end,
2302 return strtouint<T, uint64_t>(str, count, end, radix);
2314 template <
class T,
size_t N>
2316 _In_
const T (&str)[N],
2317 _Out_opt_
size_t* end,
2320 return strtou64<T>(str, N, end, radix);
2336 _In_reads_or_z_opt_(count)
const T* str, _In_
size_t count,
2337 _Out_opt_
size_t* end,
2340#if defined(_WIN64) || defined(__LP64__)
2341 return static_cast<size_t>(strtou64(str, count, end, radix));
2343 return static_cast<size_t>(strtou32(str, count, end, radix));
2357 template <
class T,
size_t N>
2359 _In_
const T (&str)[N],
2360 _Out_opt_
size_t* end,
2363 return strtoui<T>(str, N, end, radix);
2376 inline double strtod(
2377 _In_reads_or_z_opt_(count)
const char* str, _In_
size_t count,
2378 _Out_opt_
size_t* end,
2379 _In_opt_ locale_t locale)
2381 count = strnlen(str, count);
2382 stdex_assert(str || !count);
2383 std::string tmp(str, count);
2387 r = _strtod_l(tmp.c_str(), &_end, locale);
2389 r = strtod_l(tmp.c_str(), &_end, locale);
2391 if (end) *end = (size_t)(_end - tmp.c_str());
2405 inline double strtod(
2406 _In_reads_or_z_opt_(count)
const wchar_t* str, _In_
size_t count,
2407 _Out_opt_
size_t* end,
2408 _In_opt_ locale_t locale)
2410 count = strnlen(str, count);
2411 stdex_assert(str || !count);
2412 std::wstring tmp(str, count);
2416 r = _wcstod_l(tmp.c_str(), &_end, locale);
2418 r = wcstod_l(tmp.c_str(), &_end, locale);
2420 if (end) *end = (size_t)(_end - tmp.c_str());
2425 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)
2428#pragma warning(suppress: 4996)
2429 return _vsnprintf_l(str, capacity, format, locale, arg);
2431 va_list arg_mutable;
2432 va_copy(arg_mutable, arg);
2433 return ::vsnprintf_l(str, capacity, locale, format, arg_mutable);
2437 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)
2440#pragma warning(suppress: 4996)
2441 return _vsnwprintf_l(str, capacity, format, locale, arg);
2443 va_list arg_mutable;
2444 va_copy(arg_mutable, arg);
2445 return ::vswprintf_l(str, capacity, locale, format, arg_mutable);
2460 template<
class T,
class TR,
class AX>
2461 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)
2463 T buf[1024 /
sizeof(T)];
2466 int count = vsnprintf(buf, _countof(buf), format, locale, arg);
2467 if (0 <= count &&
static_cast<size_t>(count) <= _countof(buf)) {
2469 str.append(buf,
static_cast<size_t>(count));
2470 return static_cast<size_t>(count);
2476 count = vsnprintf(NULL, 0, format, locale, arg);
2477 stdex_assert(count >= 0);
2479 case EINVAL:
throw std::invalid_argument(
"invalid vsnprintf arguments");
2480 case EILSEQ:
throw std::runtime_error(
"encoding error");
2481 default:
throw std::runtime_error(
"failed to format string");
2484 size_t offset = str.size();
2485 str.resize(offset + count);
2486 if (vsnprintf(&str[offset], count + 1, format, locale, arg) != count) _Unlikely_
2487 throw std::runtime_error(
"failed to format string");
2489 size_t offset = str.size();
2490 for (
size_t capacity = 2 * 1024 /
sizeof(T);; capacity *= 2) {
2494 str.resize(offset + capacity);
2495 count = vsnprintf(&str[offset], capacity, format, locale, arg);
2496 if (0 <= count &&
static_cast<size_t>(count) <= capacity) {
2497 str.resize(offset +
static_cast<size_t>(count));
2498 return static_cast<size_t>(count);
2501 case EINVAL:
throw std::invalid_argument(
"invalid vsnprintf arguments");
2502 case EILSEQ:
throw std::runtime_error(
"encoding error");
2503 default:
throw std::runtime_error(
"failed to format string");
2507 return static_cast<size_t>(count);
2519 template<
class T,
class TR,
class AX>
2520 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, ...)
2523 va_start(arg, locale);
2524 size_t n = vappendf(str, format, locale, arg);
2537 template<
class T,
class TR,
class AX>
2538 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)
2541 vappendf(str, format, locale, arg);
2551 template<
class T,
class TR,
class AX>
2552 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, ...)
2555 va_start(arg, locale);
2556 vsprintf(str, format, locale, arg);
2569 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2570 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)
2572 std::basic_string<T, TR, AX> str;
2573 vappendf(str, format, locale, arg);
2585 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2586 std::basic_string<T, TR, AX> sprintf(_In_z_ _Printf_format_string_params_(2)
const T* format, _In_opt_ locale_t locale, ...)
2589 va_start(arg, locale);
2590 auto str = vsprintf(format, locale, arg);
2596 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)
2599 return _strftime_l(str, capacity, format, time, locale);
2601 return strftime_l(str, capacity, format, time, locale);
2605 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)
2608 return _wcsftime_l(str, capacity, format, time, locale);
2610 return wcsftime_l(str, capacity, format, time, locale);
2623 template<
class T,
class TR,
class AX>
2624 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)
2626 T buf[1024 /
sizeof(T)];
2629 size_t count = strftime(buf, _countof(buf), format, time, locale);
2632 str.append(buf, count);
2635 size_t offset = str.size();
2636 for (
size_t capacity = 2 * 1024 /
sizeof(T);; capacity *= 2) {
2638 str.resize(offset + capacity);
2639 count = strftime(&str[offset], capacity + 1, format, time, locale);
2641 str.resize(offset + count);
2655 template<
class T,
class TR,
class AX>
2656 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)
2659 strcatftime(str, format, time, locale);
2671 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2672 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)
2674 std::basic_string<T, TR, AX> str;
2675 strcatftime(str, format, time, locale);
2714 void strlwr(_Inout_updates_z_(count) T* str, _In_
size_t count)
2716 stdex_assert(str || !count);
2717 for (
size_t i = 0; i < count && str[i]; ++i)
2718 str[i] = tolower(str[i]);
2729 void strlwr(_Inout_updates_z_(count) T* str, _In_
size_t count, _In_
const std::locale& locale)
2731 stdex_assert(str || !count);
2732 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2733 for (
size_t i = 0; i < count && str[i]; ++i)
2734 str[i] = ctype.tolower(str[i]);
2742 template<
class T,
size_t N>
2743 void strlwr(_Inout_ T (&str)[N])
2754 template<
class T,
size_t N>
2755 void strlwr(_Inout_ T (&str)[N], _In_
const std::locale& locale)
2757 strlwr(str, N, locale);
2765 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2766 void strlwr(_Inout_ std::basic_string<T, TR, AX>& str)
2778 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2779 void strlwr(_Inout_ std::basic_string<T, TR, AX>& str, _In_
const std::locale& locale)
2781 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2783 c = ctype.tolower(c);
2821 void strupr(_Inout_updates_z_(count) T* str, _In_
size_t count)
2823 stdex_assert(str || !count);
2824 for (
size_t i = 0; i < count && str[i]; ++i)
2825 str[i] = toupper(str[i]);
2836 void strupr(_Inout_updates_z_(count) T* str, _In_
size_t count, _In_
const std::locale& locale)
2838 stdex_assert(str || !count);
2839 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2840 for (
size_t i = 0; i < count && str[i]; ++i)
2841 str[i] = ctype.toupper(str[i]);
2849 template<
class T,
size_t N>
2850 void strupr(_Inout_ T (&str)[N])
2852 return strupr(str, N);
2861 template<
class T,
size_t N>
2862 void strupr(_Inout_ T (&str)[N], _In_
const std::locale& locale)
2864 return strupr(str, N, locale);
2872 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2873 void strupr(_Inout_ std::basic_string<T, TR, AX>& str)
2885 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2886 void strupr(_Inout_ std::basic_string<T, TR, AX>& str, _In_
const std::locale& locale)
2888 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2890 c = ctype.toupper(c);
2903 _Inout_z_count_(count) T* str, _In_
size_t count)
2905 for (
size_t i = 0;; ++i) {
2907 if (count) str[0] = 0;
2914 if (!isspace(str[i])) {
2916 return strnlen(str, count);
2917 size_t n = count != SIZE_MAX ? strncpy(str, str + i, count - i) : strcpy(str, str + i);
2935 _Inout_z_count_(count) T* str, _In_
size_t count,
2936 _In_
const std::locale& locale)
2938 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2939 for (
size_t i = 0;; ++i) {
2941 if (count) str[0] = 0;
2948 if (!ctype.is(ctype.space, str[i])) {
2950 return strnlen(str, count);
2951 size_t n = count != SIZE_MAX ? strncpy(str, str + i, count - i) : strcpy(str, str + i);
2963 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2964 void ltrim(_Inout_ std::basic_string<T, TR, AX>& s)
2971 [&](_In_ T ch) { return !isspace(ch); }));
2980 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
2981 void ltrim(_Inout_ std::basic_string<T, TR, AX>& s, _In_
const std::locale& locale)
2983 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2989 [&](_In_ T ch) { return !ctype.is(ctype.space, ch); }));
3002 _Inout_z_count_(count) T* str, _In_
size_t count)
3004 for (
size_t i = 0, j = 0;;) {
3005 if (i >= count || !str[i]) {
3006 if (j < count) str[j] = 0;
3009 if (!isspace(str[i]))
3027 _Inout_z_count_(count) T* str, _In_
size_t count,
3028 _In_
const std::locale& locale)
3030 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
3031 for (
size_t i = 0, j = 0;;) {
3032 if (i >= count || !str[i]) {
3033 if (j < count) str[j] = 0;
3036 if (!ctype.is(ctype.space, str[i]))
3048 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
3049 void rtrim(_Inout_ std::basic_string<T, TR, AX>& s)
3055 [&](_In_ T ch) { return !isspace(ch); }).base(),
3065 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
3066 void rtrim(_Inout_ std::basic_string<T, TR, AX>& s, _In_
const std::locale& locale)
3068 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
3073 [&](_In_ T ch) { return !ctype.is(ctype.space, ch); }).base(),
3087 _Inout_z_count_(count) T* str, _In_
size_t count)
3089 return ltrim(str, rtrim(str, count));
3103 _Inout_z_count_(count) T* str, _In_
size_t count,
3104 _In_
const std::locale& locale)
3106 return ltrim(str, rtrim(str, count, locale), locale);
3114 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
3115 void trim(_Inout_ std::basic_string<T, TR, AX>& s)
3117 auto nonspace = [&](_In_ T ch) {
return !isspace(ch); };
3138 template<
class T,
class TR = std::
char_traits<T>,
class AX = std::allocator<T>>
3139 void trim(_Inout_ std::basic_string<T, TR, AX>& s, _In_
const std::locale& locale)
3141 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
3142 auto nonspace = [&](_In_ T ch) {
return !ctype.is(ctype.space, ch); };