stdex
Additional custom or not Standard C++ covered algorithms
Loading...
Searching...
No Matches
string.hpp
1/*
2 SPDX-License-Identifier: MIT
3 Copyright © 2016-2024 Amebis
4*/
5
6#pragma once
7
8#include "assert.hpp"
9#include "compat.hpp"
10#include "locale.hpp"
11#include <ctype.h>
12#include <stdarg.h>
13#include <stdarg.h>
14#include <stdint.h>
15#include <stdio.h>
16#include <time.h>
17#ifdef __APPLE__
18#include <xlocale.h>
19#endif
20#include <algorithm>
21#include <climits>
22#include <locale>
23#include <stdexcept>
24
25namespace stdex
26{
30#ifdef _WIN32
31 using utf16_t = wchar_t;
32 using utf32_t = char32_t;
33#else
34 using utf16_t = char16_t;
35 using utf32_t = wchar_t;
36#endif
37
43 inline bool is_high_surrogate(_In_ utf16_t chr)
44 {
45 return 0xd800 <= chr && chr < 0xdc00;
46 }
47
53 inline bool is_low_surrogate(_In_ utf16_t chr)
54 {
55 return 0xdc00 <= chr && chr < 0xe000;
56 }
57
63 inline bool is_surrogate_pair(_In_reads_(2) const utf16_t* str)
64 {
65 return is_high_surrogate(str[0]) && is_low_surrogate(str[1]);
66 }
67
73 inline utf32_t surrogate_pair_to_ucs4(_In_reads_(2) const utf16_t* str)
74 {
75 stdex_assert(is_surrogate_pair(str));
76 return
77 (static_cast<utf32_t>(str[0] - 0xd800) << 10) +
78 static_cast<utf32_t>(str[1] - 0xdc00) +
79 0x10000;
80 }
81
87 inline void ucs4_to_surrogate_pair(_Out_writes_(2) utf16_t* str, _In_ utf32_t chr)
88 {
89 stdex_assert(chr >= 0x10000);
90 chr -= 0x10000;
91 str[0] = 0xd800 + static_cast<utf16_t>((chr >> 10) & 0x3ff);
92 str[1] = 0xdc00 + static_cast<utf16_t>(chr & 0x3ff);
93 }
94
100 inline bool iscombining(_In_ utf32_t chr)
101 {
102 return
103 (0x0300 <= chr && chr < 0x0370) ||
104 (0x1dc0 <= chr && chr < 0x1e00) ||
105 (0x20d0 <= chr && chr < 0x2100) ||
106 (0xfe20 <= chr && chr < 0xfe30);
107 }
108
114 template <class T>
115 bool islbreak(_In_ T chr)
116 {
117 return chr == '\n' || chr == '\r';
118 }
119
128 template <class T>
129 size_t islbreak(_In_reads_or_z_opt_(count) const T* chr, _In_ size_t count)
130 {
131 stdex_assert(chr || !count);
132 if (count >= 2 && ((chr[0] == '\r' && chr[1] == '\n') || (chr[0] == '\n' && chr[1] == '\r')))
133 return 2;
134 if (count > 1 && (chr[0] == '\n' || chr[0] == '\r'))
135 return 1;
136 return 0;
137 }
138
144 template <class T>
145 bool isspace(_In_ T chr)
146 {
147 return chr == ' ' || chr == '\t' || chr == '\n' || chr == '\r' || chr == '\v' || chr == '\f';
148 }
149
155 template <class T>
156 bool ispunct(_In_ T chr)
157 {
158 return ('!' <= chr && chr <= '/') || (':' <= chr && chr <= '@') || ('[' <= chr && chr <= '`') || ('{' <= chr && chr <= '~');
159 }
160
166 template <class T>
167 bool islower(_In_ T chr)
168 {
169 return 'a' <= chr && chr <= 'z';
170 }
171
177 template <class T>
178 bool isupper(_In_ T chr)
179 {
180 return 'A' <= chr && chr <= 'Z';
181 }
182
188 template <class T>
189 bool isdigit(_In_ T chr)
190 {
191 return '0' <= chr && chr <= '9';
192 }
193
199 template <class T>
200 bool isalpha(_In_ T chr)
201 {
202 return islower(chr) || isupper(chr);
203 }
204
210 template <class T>
211 bool is7bit(_In_ T chr)
212 {
213 return '\x00' <= chr && chr <= '\x7f';
214 }
215
222 inline size_t glyphlen(_In_reads_or_z_opt_(count) const utf16_t* glyph, _In_ size_t count)
223 {
224 stdex_assert(glyph || !count);
225 if (count) {
226 size_t i = count < 2 || !is_surrogate_pair(glyph) ? 1 : 2;
227 for (; i < count && iscombining(glyph[i]); ++i);
228 return i;
229 }
230 return 0;
231 }
232
239 inline size_t glyphlen(_In_reads_or_z_opt_(count) const utf32_t* glyph, _In_ size_t count)
240 {
241 stdex_assert(glyph || !count);
242 if (count) {
243 size_t i = 1;
244 for (; i < count && iscombining(glyph[i]); ++i);
245 return i;
246 }
247 return 0;
248 }
249
256 inline size_t glyphrlen(_In_reads_or_z_opt_(count) const utf16_t* str, _In_ size_t count)
257 {
258 stdex_assert(count && str && str[count - 1]);
259 for (size_t i = count; i--;) {
260 if (!iscombining(str[i]))
261 return count - (!is_low_surrogate(str[i]) || i == 0 || !is_high_surrogate(str[i - 1]) ? i : i - 1);
262 }
263 return count;
264 }
265
272 inline size_t glyphrlen(_In_reads_or_z_opt_(count) const utf32_t* str, _In_ size_t count)
273 {
274 stdex_assert(count && str && str[count - 1]);
275 for (size_t i = count; i--;) {
276 if (!iscombining(str[i]))
277 return count - (i == 0 ? i : i - 1);
278 }
279 return count;
280 }
281
289 template <class T>
290 T tolower(_In_ T chr)
291 {
292 return isupper(chr) ? chr | 0x20 : chr;
293 }
294
302 template <class T>
303 T toupper(_In_ T chr)
304 {
305 return islower(chr) ? chr | ~0x20 : chr;
306 }
307
315 template <class T>
316 size_t strlen(_In_z_ const T* str)
317 {
318 stdex_assert(str);
319 size_t i;
320 for (i = 0; str[i]; ++i);
321 return i;
322 }
323
332 template <class T>
333 size_t strnlen(_In_reads_or_z_opt_(count) const T* str, _In_ size_t count)
334 {
335 stdex_assert(str || !count);
336 size_t i;
337 for (i = 0; i < count && str[i]; ++i);
338 return i;
339 }
340
348 template <class T, size_t N>
349 size_t strnlen(_In_ const T (&str)[N])
350 {
351 return strnlen(str, N);
352 }
353
354 constexpr auto npos{ static_cast<size_t>(-1) };
355
364 template <class T>
365 size_t strchr(_In_z_ const T* str, _In_ T chr)
366 {
367 stdex_assert(str);
368 for (size_t i = 0; str[i]; ++i)
369 if (str[i] == chr) return i;
370 return npos;
371 }
372
382 template <class T>
383 size_t strnchr(
384 _In_reads_or_z_opt_(count) const T* str,
385 _In_ size_t count,
386 _In_ T chr)
387 {
388 stdex_assert(str || !count);
389 for (size_t i = 0; i < count && str[i]; ++i)
390 if (str[i] == chr) return i;
391 return npos;
392 }
393
402 template <class T, size_t N>
403 size_t strnchr(
404 _In_ const T (&str)[N],
405 _In_ T chr)
406 {
407 return strnchr(str, N, chr);
408 }
409
418 template <class T>
419 size_t strrchr(
420 _In_z_ const T* str,
421 _In_ T chr)
422 {
423 stdex_assert(str);
424 size_t z = npos;
425 for (size_t i = 0; str[i]; ++i)
426 if (str[i] == chr) z = i;
427 return z;
428 }
429
439 template <class T>
440 size_t strrnchr(
441 _In_reads_or_z_opt_(count) const T* str,
442 _In_ size_t count,
443 _In_ T chr)
444 {
445 stdex_assert(str || !count);
446 size_t z = npos;
447 for (size_t i = 0; i < count && str[i]; ++i)
448 if (str[i] == chr) z = i;
449 return z;
450 }
451
460 template <class T, size_t N>
461 size_t strrnchr(
462 _In_ const T (&str)[N],
463 _In_ T chr)
464 {
465 return strrnchr(str, N, chr);
466 }
467
476 template <class T>
477 size_t strichr(
478 _In_z_ const T* str,
479 _In_ T chr)
480 {
481 stdex_assert(str);
482 chr = tolower(chr);
483 for (size_t i = 0; str[i]; ++i)
484 if (tolower(str[i]) == chr) return i;
485 return npos;
486 }
487
497 template <class T>
498 size_t strichr(
499 _In_z_ const T* str,
500 _In_ T chr,
501 _In_ const std::locale& locale)
502 {
503 stdex_assert(str);
504 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
505 chr = ctype.tolower(chr);
506 for (size_t i = 0; str[i]; ++i)
507 if (ctype.tolower(str[i]) == chr) return i;
508 return npos;
509 }
510
520 template <class T>
521 size_t strnichr(
522 _In_reads_or_z_opt_(count) const T* str,
523 _In_ size_t count,
524 _In_ T chr)
525 {
526 stdex_assert(str || !count);
527 chr = tolower(chr);
528 for (size_t i = 0; i < count && str[i]; ++i)
529 if (tolower(str[i]) == chr) return i;
530 return npos;
531 }
532
543 template <class T>
544 size_t strnichr(
545 _In_reads_or_z_opt_(count) const T* str,
546 _In_ size_t count,
547 _In_ T chr,
548 _In_ const std::locale& locale)
549 {
550 stdex_assert(str || !count);
551 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
552 chr = ctype.tolower(chr);
553 for (size_t i = 0; i < count && str[i]; ++i)
554 if (ctype.tolower(str[i]) == chr) return i;
555 return npos;
556 }
557
566 template <class T, size_t N>
567 size_t strnichr(
568 _In_ const T (&str)[N],
569 _In_ T chr)
570 {
571 return strnichr(str, N, chr);
572 }
573
583 template <class T, size_t N>
584 size_t strnichr(
585 _In_ const T (&str)[N],
586 _In_ T chr,
587 _In_ const std::locale& locale)
588 {
589 return strnichr(str, N, chr, locale);
590 }
591
600 template <class T>
601 size_t strrichr(
602 _In_z_ const T* str,
603 _In_ T chr)
604 {
605 stdex_assert(str);
606 chr = tolower(chr);
607 size_t z = npos;
608 for (size_t i = 0; str[i]; ++i)
609 if (tolower(str[i]) == chr) z = i;
610 return z;
611 }
612
622 template <class T>
623 size_t strrichr(
624 _In_reads_or_z_opt_(count) const T* str,
625 _In_ T chr,
626 _In_ const std::locale& locale)
627 {
628 stdex_assert(str);
629 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
630 chr = ctype.tolower(chr);
631 size_t z = npos;
632 for (size_t i = 0; str[i]; ++i)
633 if (ctype.tolower(str[i]) == chr) z = i;
634 return z;
635 }
636
646 template <class T>
647 size_t strrnichr(
648 _In_reads_or_z_opt_(count) const T* str,
649 _In_ size_t count,
650 _In_ T chr)
651 {
652 stdex_assert(str || !count);
653 chr = tolower(chr);
654 size_t z = npos;
655 for (size_t i = 0; i < count && str[i]; ++i)
656 if (tolower(str[i]) == chr) z = i;
657 return z;
658 }
659
670 template <class T>
671 size_t strrnichr(
672 _In_reads_or_z_opt_(count) const T* str,
673 _In_ size_t count,
674 _In_ T chr,
675 _In_ const std::locale& locale)
676 {
677 stdex_assert(str || !count);
678 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
679 chr = ctype.tolower(chr);
680 size_t z = npos;
681 for (size_t i = 0; i < count && str[i]; ++i)
682 if (ctype.tolower(str[i]) == chr) z = i;
683 return z;
684 }
685
694 template <class T, size_t N>
695 size_t strrnichr(
696 _In_ const T (&str)[N],
697 _In_ T chr)
698 {
699 return strrnichr(str, N, chr);
700 }
701
711 template <class T, size_t N>
712 size_t strrnichr(
713 _In_ const T (&str)[N],
714 _In_ T chr,
715 _In_ const std::locale& locale)
716 {
717 return strrnichr(str, N, chr, locale);
718 }
719
727 //template <class T>
728 //bool isblank(_In_z_ const T* str)
729 //{
730 // stdex_assert(str);
731 // for (size_t i = 0; str[i]; ++i)
732 // if (!isspace(str[i]))
733 // return false;
734 // return true;
735 //}
736
745 //template <class T>
746 //bool isblank(
747 // _In_z_ const T* str,
748 // _In_ const std::locale& locale)
749 //{
750 // stdex_assert(str);
751 // const auto& ctype = std::use_facet<std::ctype<T>>(locale);
752 // for (size_t i = 0; str[i]; ++i)
753 // if (!ctype.is(ctype.space, str[i]))
754 // return false;
755 // return true;
756 //}
757
766 template <class T>
767 bool isblank(
768 _In_reads_or_z_opt_(count) const T* str,
769 _In_ size_t count)
770 {
771 stdex_assert(str || !count);
772 for (size_t i = 0; i < count && str[i]; ++i)
773 if (!isspace(str[i]))
774 return false;
775 return true;
776 }
777
787 template <class T>
788 bool isblank(
789 _In_reads_or_z_opt_(count) const T* str, _In_ size_t count,
790 _In_ const std::locale& locale)
791 {
792 stdex_assert(str || !count);
793 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
794 for (size_t i = 0; i < count && str[i]; ++i)
795 if (!ctype.is(ctype.space, str[i]))
796 return false;
797 return true;
798 }
799
807 template <class T, size_t N>
808 bool isblank(_In_ const T (&str)[N])
809 {
810 return isblank(str, N);
811 }
812
821 template <class T, size_t N>
822 bool isblank(
823 _In_ const T (&str)[N],
824 _In_ const std::locale& locale)
825 {
826 return isblank(str, N, locale);
827 }
828
829 // ///
830 // /// Checks if string contains all-ASCII characters
831 // ///
832 // /// \param[in] str String
833 // ///
834 // /// \return `true` if all characters are ASCII or `false` when any non-ASCII character is found in string.
835 // ///
836 // template <class T>
837 // bool is7bit(_In_z_ const T* str)
838 // {
839 // stdex_assert(str);
840 // for (size_t i = 0; str[i]; i++)
841 // if (!is7bit(str[i]))
842 // return false;
843 // return true;
844 // }
845
854 template <class T>
855 bool is7bit(_In_reads_or_z_opt_(count) const T* str, _In_ size_t count)
856 {
857 stdex_assert(str || !count);
858 for (size_t i = 0; i < count && str[i]; i++)
859 if (!is7bit(str[i]))
860 return false;
861 return true;
862 }
863
871 template <class T, size_t N>
872 bool is7bit(_In_ const T (&str)[N])
873 {
874 return is7bit(str, N);
875 }
876
885 template <class T1, class T2>
886 int strcmp(_In_z_ const T1* str1, _In_z_ const T2* str2)
887 {
888 stdex_assert(str1);
889 stdex_assert(str2);
890 size_t i; T1 a; T2 b;
891 for (i = 0; (a = str1[i]) | (b = str2[i]); ++i) {
892 if (a > b) return +1;
893 if (a < b) return -1;
894 }
895 if (str1[i]) return +1;
896 if (str2[i]) return -1;
897 return 0;
898 }
899
909 template <class T1, class T2>
910 int strncmp(_In_reads_or_z_opt_(count) const T1* str1, _In_reads_or_z_opt_(count) const T2* str2, _In_ size_t count)
911 {
912 stdex_assert(str1 || !count);
913 stdex_assert(str2 || !count);
914 size_t i; T1 a; T2 b;
915 for (i = 0; i < count && ((a = str1[i]) | (b = str2[i])); ++i) {
916 if (a > b) return +1;
917 if (a < b) return -1;
918 }
919 if (i < count && str1[i]) return +1;
920 if (i < count && str2[i]) return -1;
921 return 0;
922 }
923
934 template <class T1, class T2>
935 int strncmp(
936 _In_reads_or_z_opt_(count1) const T1* str1, _In_ size_t count1,
937 _In_reads_or_z_opt_(count2) const T2* str2, _In_ size_t count2)
938 {
939 stdex_assert(str1 || !count1);
940 stdex_assert(str2 || !count2);
941 size_t i;
942 for (i = 0; i < count1 && i < count2; ++i) {
943 auto a = str1[i];
944 auto b = str2[i];
945 if (!a && !b) return 0;
946 if (a > b) return +1;
947 if (a < b) return -1;
948 }
949 if (i < count1 && str1[i]) return +1;
950 if (i < count2 && str2[i]) return -1;
951 return 0;
952 }
953
962 template <class T1, size_t N1, class T2, size_t N2>
963 int strncmp(
964 _In_ const T1 (&str1)[N1],
965 _In_ const T2 (&str2)[N2])
966 {
967 return strncmp(str1, N1, str2, N2);
968 }
969
980 inline int strncmp(
981 _In_reads_or_z_opt_(count1) const utf32_t* str1, _In_ size_t count1,
982 _In_reads_or_z_opt_(count2) const utf16_t* str2, _In_ size_t count2)
983 {
984 stdex_assert(str1 || !count1);
985 stdex_assert(str2 || !count2);
986 size_t i, j, j_next; utf32_t a, b;
987 for (i = 0, j = 0; i < count1 && j < count2; ++i, j = j_next) {
988 a = str1[i];
989 if (!a)
990 break;
991 if (j + 1 >= count2 || !is_surrogate_pair(&str2[j])) {
992 b = static_cast<utf32_t>(str2[j]);
993 j_next = j + 1;
994 }
995 else {
996 b = surrogate_pair_to_ucs4(&str2[j]);
997 j_next = j + 2;
998 }
999 if (!b)
1000 break;
1001 if (a > b) return +1;
1002 if (a < b) return -1;
1003 }
1004 if (i < count1 && str1[i]) return +1;
1005 if (j < count2 && str2[j]) return -1;
1006 return 0;
1007 }
1008
1017 template <size_t N1, size_t N2>
1018 int strncmp(
1019 _In_ const utf32_t (&str1)[N1],
1020 _In_ const utf16_t (&str2)[N2])
1021 {
1022 return strncmp(str1, N1, str2, N2);
1023 }
1024
1033 template <class T1, class T2>
1034 int strrcmp(_In_z_ const T1* str1, _In_z_ const T2* str2)
1035 {
1036 size_t
1037 i = strlen(str1),
1038 j = strlen(str2);
1039 stdex_assert(str1 || !i);
1040 stdex_assert(str2 || !j);
1041 size_t k; T1 a; T2 b;
1042 for (k = 1; i && j; k++) {
1043 i--; j--;
1044 if ((a = str1[i]) > (b = str2[j])) return +1;
1045 if (a < b) return -1;
1046 }
1047 if (i && !j) return +1;
1048 if (!i && j) return -1;
1049 return 0;
1050 }
1051
1061 template <class T1, class T2>
1062 int strrncmp(_In_reads_or_z_opt_(count) const T1* str1, _In_reads_or_z_opt_(count) const T2* str2, _In_ size_t count)
1063 {
1064 size_t
1065 i = strnlen(str1, count),
1066 j = strnlen(str2, count);
1067 stdex_assert(str1 || !i);
1068 stdex_assert(str2 || !j);
1069 size_t k; T1 a; T2 b;
1070 for (k = 1; i && j; k++) {
1071 i--; j--;
1072 if ((a = str1[i]) > (b = str2[j])) return +1;
1073 if (a < b) return -1;
1074 }
1075 if (i && !j) return +1;
1076 if (!i && j) return -1;
1077 return 0;
1078 }
1079
1090 template <class T1, class T2>
1091 int strrncmp(
1092 _In_reads_or_z_opt_(count1) const T1* str1, _In_ size_t count1,
1093 _In_reads_or_z_opt_(count2) const T2* str2, _In_ size_t count2)
1094 {
1095 size_t
1096 i = strnlen(str1, count1),
1097 j = strnlen(str2, count2);
1098 stdex_assert(str1 || !i);
1099 stdex_assert(str2 || !j);
1100 size_t k; T1 a; T2 b;
1101 for (k = 1; i && j; k++) {
1102 i--; j--;
1103 if ((a = str1[i]) > (b = str2[j])) return +1;
1104 if (a < b) return -1;
1105 }
1106 if (i && !j) return +1;
1107 if (!i && j) return -1;
1108 return 0;
1109 }
1110
1119 template <class T1, size_t N1, class T2, size_t N2>
1120 int strrncmp(
1121 _In_ const T1 (&str1)[N1],
1122 _In_ const T2 (&str2)[N2])
1123 {
1124 return strrncmp(str1, N1, str2, N2);
1125 }
1126
1135 template <class T1, class T2>
1136 int stricmp(_In_z_ const T1* str1, _In_z_ const T2* str2)
1137 {
1138 stdex_assert(str1);
1139 stdex_assert(str2);
1140 size_t i;
1141 for (i = 0; ; ++i) {
1142 auto a = tolower(str1[i]);
1143 auto b = tolower(str2[i]);
1144 if (!a && !b) return 0;
1145 if (a > b) return +1;
1146 if (a < b) return -1;
1147 }
1148 }
1149
1159 template <class T1, class T2>
1160 int stricmp(_In_z_ const T1* str1, _In_z_ const T2* str2, _In_ const std::locale& locale)
1161 {
1162 stdex_assert(str1);
1163 stdex_assert(str2);
1164 size_t i;
1165 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
1166 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
1167 for (i = 0;; ++i) {
1168 auto a = ctype1.tolower(str1[i]);
1169 auto b = ctype2.tolower(str2[i]);
1170 if (!a && !b) return 0;
1171 if (a > b) return +1;
1172 if (a < b) return -1;
1173 }
1174 }
1175
1185 template <class T1, class T2>
1186 int strnicmp(_In_reads_or_z_opt_(count) const T1* str1, _In_reads_or_z_opt_(count) const T2* str2, _In_ size_t count)
1187 {
1188 stdex_assert(str1 || !count);
1189 stdex_assert(str2 || !count);
1190 size_t i;
1191 for (i = 0; i < count; ++i) {
1192 auto a = tolower(str1[i]);
1193 auto b = tolower(str2[i]);
1194 if (!a && !b) return 0;
1195 if (a > b) return +1;
1196 if (a < b) return -1;
1197 }
1198 if (i < count && str1[i]) return +1;
1199 if (i < count && str2[i]) return -1;
1200 return 0;
1201 }
1202
1213 template <class T1, class T2>
1214 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)
1215 {
1216 stdex_assert(str1 || !count);
1217 stdex_assert(str2 || !count);
1218 size_t i;
1219 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
1220 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
1221 for (i = 0; i < count; ++i) {
1222 auto a = ctype1.tolower(str1[i]);
1223 auto b = ctype2.tolower(str2[i]);
1224 if (!a && !b) return 0;
1225 if (a > b) return +1;
1226 if (a < b) return -1;
1227 }
1228 if (i < count && str1[i]) return +1;
1229 if (i < count && str2[i]) return -1;
1230 return 0;
1231 }
1232
1243 template <class T1, class T2>
1244 int strnicmp(
1245 _In_reads_or_z_opt_(count1) const T1* str1, _In_ size_t count1,
1246 _In_reads_or_z_opt_(count2) const T2* str2, _In_ size_t count2)
1247 {
1248 stdex_assert(str1 || !count1);
1249 stdex_assert(str2 || !count2);
1250 size_t i;
1251 for (i = 0; i < count1 && i < count2; ++i) {
1252 auto a = tolower(str1[i]);
1253 auto b = tolower(str2[i]);
1254 if (!a && !b) return 0;
1255 if (a > b) return +1;
1256 if (a < b) return -1;
1257 }
1258 if (i < count1 && str1[i]) return +1;
1259 if (i < count2 && str2[i]) return -1;
1260 return 0;
1261 }
1262
1274 template <class T1, class T2>
1275 int strnicmp(
1276 _In_reads_or_z_opt_(count1) const T1* str1, _In_ size_t count1,
1277 _In_reads_or_z_opt_(count2) const T2* str2, _In_ size_t count2,
1278 _In_ const std::locale& locale)
1279 {
1280 stdex_assert(str1 || !count1);
1281 stdex_assert(str2 || !count2);
1282 size_t i;
1283 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
1284 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
1285 for (i = 0; i < count1 && i < count2; ++i) {
1286 auto a = ctype1.tolower(str1[i]);
1287 auto b = ctype2.tolower(str2[i]);
1288 if (!a && !b) return 0;
1289 if (a > b) return +1;
1290 if (a < b) return -1;
1291 }
1292 if (i < count1 && str1[i]) return +1;
1293 if (i < count2 && str2[i]) return -1;
1294 return 0;
1295 }
1296
1305 template <class T1, size_t N1, class T2, size_t N2>
1306 int strnicmp(
1307 _In_ const T1 (&str1)[N1],
1308 _In_ const T2 (&str2)[N2])
1309 {
1310 strnicmp(str1, N1, str2, N2);
1311 }
1312
1322 template <class T1, size_t N1, class T2, size_t N2>
1323 int strnicmp(
1324 _In_ const T1 (&str1)[N1],
1325 _In_ const T2 (&str2)[N2],
1326 _In_ const std::locale& locale)
1327 {
1328 strnicmp(str1, N1, str2, N2, locale);
1329 }
1330
1340 template <class T>
1341 int strcoll(
1342 _In_z_ const T* str1,
1343 _In_z_ const T* str2,
1344 _In_ const std::locale& locale)
1345 {
1346 stdex_assert(str1);
1347 stdex_assert(str2);
1348 auto& collate = std::use_facet<std::collate<T>>(locale);
1349 return collate.compare(str1, str1 + strlen(str1), str2, str2 + strlen(str2));
1350 }
1351
1363 template <class T>
1364 int strncoll(
1365 _In_reads_or_z_opt_(count1) const T* str1, _In_ size_t count1,
1366 _In_reads_or_z_opt_(count2) const T* str2, _In_ size_t count2,
1367 _In_ const std::locale& locale)
1368 {
1369 stdex_assert(str1 || !count1);
1370 stdex_assert(str2 || !count2);
1371 auto& collate = std::use_facet<std::collate<T>>(locale);
1372 return collate.compare(str1, str1 + count1, str2, str2 + count2);
1373 }
1374
1384 template <class T, size_t N1, size_t N2>
1385 int strncoll(
1386 _In_ const T (&str1)[N1],
1387 _In_ const T (&str2)[N2],
1388 _In_ const std::locale& locale)
1389 {
1390 return strncoll(str1, N1, str2, N2, locale);
1391 }
1392
1401 template <class T1, class T2>
1402 size_t strstr(
1403 _In_z_ const T1* str,
1404 _In_z_ const T2* sample)
1405 {
1406 stdex_assert(str);
1407 stdex_assert(sample);
1408 for (size_t offset = 0;; ++offset) {
1409 for (size_t i = offset, j = 0;; ++i, ++j) {
1410 if (!sample[j])
1411 return offset;
1412 if (!str[i])
1413 return npos;
1414 if (str[i] != sample[j])
1415 break;
1416 }
1417 }
1418 }
1419
1429 template <class T1, class T2>
1430 size_t strnstr(
1431 _In_reads_or_z_opt_(count) const T1* str, _In_ size_t count,
1432 _In_z_ const T2* sample)
1433 {
1434 stdex_assert(str || !count);
1435 stdex_assert(sample);
1436 for (size_t offset = 0;; ++offset) {
1437 for (size_t i = offset, j = 0;; ++i, ++j) {
1438 if (!sample[j])
1439 return offset;
1440 if (i >= count || !str[i])
1441 return npos;
1442 if (str[i] != sample[j])
1443 break;
1444 }
1445 }
1446 }
1447
1456 template <class T1, size_t N1, class T2>
1457 size_t strnstr(
1458 _In_ const T1 (&str)[N1],
1459 _In_z_ const T2* sample)
1460 {
1461 return strnstr(str, N1, sample);
1462 }
1463
1472 template <class T1, class T2>
1473 size_t stristr(
1474 _In_z_ const T1* str,
1475 _In_z_ const T2* sample)
1476 {
1477 stdex_assert(str);
1478 stdex_assert(sample);
1479 for (size_t offset = 0;; ++offset) {
1480 for (size_t i = offset, j = 0;; ++i, ++j) {
1481 if (!sample[j])
1482 return offset;
1483 if (!str[i])
1484 return npos;
1485 if (tolower(str[i]) != tolower(sample[j]))
1486 break;
1487 }
1488 }
1489 }
1490
1500 template <class T1, class T2>
1501 size_t stristr(
1502 _In_z_ const T1* str,
1503 _In_z_ const T2* sample,
1504 _In_ const std::locale& locale)
1505 {
1506 stdex_assert(str);
1507 stdex_assert(sample);
1508 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
1509 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
1510 for (size_t offset = 0;; ++offset) {
1511 for (size_t i = offset, j = 0;; ++i, ++j) {
1512 if (!sample[j])
1513 return offset;
1514 if (!str[i])
1515 return npos;
1516 if (ctype1.tolower(str[i]) != ctype2.tolower(sample[j]))
1517 break;
1518 }
1519 }
1520 }
1521
1531 template <class T1, class T2>
1532 size_t strnistr(
1533 _In_reads_or_z_opt_(count) const T1* str,
1534 _In_ size_t count,
1535 _In_z_ const T2* sample)
1536 {
1537 stdex_assert(str || !count);
1538 stdex_assert(sample);
1539 for (size_t offset = 0;; ++offset) {
1540 for (size_t i = offset, j = 0;; ++i, ++j) {
1541 if (!sample[j])
1542 return offset;
1543 if (i >= count || !str[i])
1544 return npos;
1545 if (tolower(str[i]) != tolower(sample[j]))
1546 break;
1547 }
1548 }
1549 }
1550
1561 template <class T1, class T2>
1562 size_t strnistr(
1563 _In_reads_or_z_opt_(count) const T1* str,
1564 _In_ size_t count,
1565 _In_z_ const T2* sample,
1566 _In_ const std::locale& locale)
1567 {
1568 stdex_assert(str || !count);
1569 stdex_assert(sample);
1570 const auto& ctype1 = std::use_facet<std::ctype<T1>>(locale);
1571 const auto& ctype2 = std::use_facet<std::ctype<T2>>(locale);
1572 for (size_t offset = 0;; ++offset) {
1573 for (size_t i = offset, j = 0;; ++i, ++j) {
1574 if (!sample[j])
1575 return offset;
1576 if (i >= count || !str[i])
1577 return npos;
1578 if (ctype1.tolower(str[i]) != ctype2.tolower(sample[j]))
1579 break;
1580 }
1581 }
1582 }
1583
1592 template <class T1, size_t N1, class T2>
1593 size_t strnistr(
1594 _In_ const T1 (&str)[N1],
1595 _In_z_ const T2* sample)
1596 {
1597 return strnistr(str, N1, sample);
1598 }
1599
1609 template <class T1, size_t N1, class T2>
1610 size_t strnistr(
1611 _In_ const T1 (&str)[N1],
1612 _In_z_ const T2* sample,
1613 _In_ const std::locale& locale)
1614 {
1615 return strnistr(str, N1, sample, locale);
1616 }
1617
1626 template <class T1, class T2>
1627 size_t strcpy(
1628 _Out_writes_z_(_String_length_(src) + 1) T1* dst,
1629 _In_z_ const T2* src)
1630 {
1631 stdex_assert(dst);
1632 stdex_assert(src);
1633 for (size_t i = 0; ; ++i) {
1634 if ((dst[i] = static_cast<T1>(src[i])) == 0)
1635 return i;
1636 }
1637 }
1638
1647 inline size_t strcpy(
1648 _Out_ _Post_maybez_ utf32_t* dst,
1649 _In_z_ const utf16_t* src)
1650 {
1651 stdex_assert(dst);
1652 stdex_assert(src);
1653 for (size_t j = 0, i = 0; ; ++j, ++i) {
1654 if ((dst[j] = (is_surrogate_pair(&src[i]) ? surrogate_pair_to_ucs4(&src[i++]) : static_cast<utf32_t>(src[i]))) == 0)
1655 return j;
1656 }
1657 }
1658
1668 template <class T1, class T2>
1669 size_t strncpy(
1670 _Out_writes_(count) _Post_maybez_ T1* dst,
1671 _In_reads_or_z_opt_(count) const T2* src, _In_ size_t count)
1672 {
1673 stdex_assert(dst || !count);
1674 stdex_assert(src || !count);
1675 for (size_t i = 0; ; ++i) {
1676 if (i >= count)
1677 return i;
1678 if ((dst[i] = static_cast<T1>(src[i])) == 0)
1679 return i;
1680 }
1681 }
1682
1693 template <class T1, class T2>
1694 size_t strncpy(
1695 _Out_writes_(count_dst) _Post_maybez_ T1* dst, _In_ size_t count_dst,
1696 _In_reads_or_z_opt_(count_src) const T2* src, _In_ size_t count_src)
1697 {
1698 stdex_assert(dst || !count_dst);
1699 stdex_assert(src || !count_src);
1700 for (size_t i = 0; ; ++i)
1701 {
1702 if (i >= count_dst)
1703 return i;
1704 if (i >= count_src) {
1705 dst[i] = 0;
1706 return i;
1707 }
1708 if ((dst[i] = static_cast<T1>(src[i])) == 0)
1709 return i;
1710 }
1711 }
1712
1723 inline size_t strncpy(
1724 _Out_writes_(count_dst) _Post_maybez_ utf32_t* dst, _In_ size_t count_dst,
1725 _In_reads_or_z_opt_(count_src) const utf16_t* src, _In_ size_t count_src)
1726 {
1727 stdex_assert(dst || !count_dst);
1728 stdex_assert(src || !count_src);
1729 for (size_t j = 0, i = 0; ; ++j, ++i)
1730 {
1731 if (j >= count_dst)
1732 return j;
1733 if (i >= count_src) {
1734 dst[j] = 0;
1735 return j;
1736 }
1737 if ((dst[j] = (i + 1 < count_src && is_surrogate_pair(&src[i]) ? surrogate_pair_to_ucs4(&src[i++]) : static_cast<utf32_t>(src[i]))) == 0)
1738 return j;
1739 }
1740 }
1741
1750 template <class T1, size_t N1, class T2, size_t N2>
1751 size_t strncpy(
1752 _Out_ _Post_maybez_ T1 (&dst)[N1],
1753 _In_ const T2 (&src)[N2])
1754 {
1755 return strncpy(dst, N1, src, N2);
1756 }
1757
1766 template <class T1, class T2>
1767 size_t strcat(
1768 _In_z_ _Out_writes_z_(_String_length_(dst) + _String_length_(src) + 1) T1* dst,
1769 _In_z_ const T2* src)
1770 {
1771 stdex_assert(dst);
1772 stdex_assert(src);
1773 for (size_t i = 0, j = stdex::strlen<T1>(dst); ; ++i, ++j) {
1774 if ((dst[j] = static_cast<T1>(src[i])) == 0)
1775 return j;
1776 }
1777 }
1778
1788 template <class T1, class T2>
1789 size_t strncat(
1790 _Inout_z_ T1* dst,
1791 _In_reads_or_z_opt_(count) const T2* src, _In_ size_t count)
1792 {
1793 stdex_assert(dst || !count);
1794 stdex_assert(src || !count);
1795 for (size_t i = 0, j = stdex::strlen<T1>(dst); ; ++i, ++j) {
1796 if (i >= count)
1797 return j;
1798 if ((dst[j] = static_cast<T1>(src[i])) == 0)
1799 return j;
1800 }
1801 }
1802
1813 template <class T1, class T2>
1814 size_t strncat(
1815 _Out_writes_(count_dst) _Post_maybez_ T1* dst, _In_ size_t count_dst,
1816 _In_reads_or_z_opt_(count_src) const T2* src, _In_ size_t count_src)
1817 {
1818 stdex_assert(dst || !count_dst);
1819 stdex_assert(src || !count_src);
1820 for (size_t i = 0, j = stdex::strnlen<T1>(dst, count_dst); ; ++i, ++j)
1821 {
1822 if (j >= count_dst)
1823 return j;
1824 if (i >= count_src) {
1825 dst[j] = 0;
1826 return j;
1827 }
1828 if ((dst[j] = static_cast<T1>(src[i])) == 0)
1829 return j;
1830 }
1831 }
1832
1843 template <class T>
1844 _Check_return_ _Ret_maybenull_z_ T* strdup(_In_opt_z_ const T* str)
1845 {
1846 if (!str) _Unlikely_
1847 return nullptr;
1848 size_t count = strlen(str) + 1;
1849 T* dst = new T[count];
1850 strncpy(dst, count, str, SIZE_MAX);
1851 return dst;
1852 }
1853
1865 template <class T>
1866 _Ret_z_ T* strndup(
1867 _In_reads_or_z_opt_(count) const T* str,
1868 _In_ size_t count)
1869 {
1870 T* dst = new T[count];
1871 strncpy(dst, count, str, SIZE_MAX);
1872 return dst;
1873 }
1874
1885 template <class T, size_t N>
1886 _Check_return_ _Ret_maybenull_z_ T* strndup(_In_ const T (&str)[N])
1887 {
1888 return strndup(str, N);
1889 }
1890
1900 template <class T>
1901 size_t crlf2nl(_Out_writes_z_(_String_length_(src) + 1) T* dst, _In_z_ const T* src)
1902 {
1903 stdex_assert(dst);
1904 stdex_assert(src);
1905 size_t i, j;
1906 for (i = j = 0; src[j];) {
1907 if (src[j] != '\r' || src[j + 1] != '\n')
1908 dst[i++] = src[j++];
1909 else {
1910 dst[i++] = '\n';
1911 j += 2;
1912 }
1913 }
1914 dst[i] = 0;
1915 return i;
1916 }
1917
1924 template<class T, class TR = std::char_traits<T>, class AX = std::allocator<T>>
1925 void crlf2nl(_Inout_ std::basic_string<T, TR, AX>& dst, _In_z_ const T* src)
1926 {
1927 stdex_assert(src);
1928 stdex_assert(src != dst.data());
1929 dst.clear();
1930 dst.reserve(strlen(src));
1931 for (size_t j = 0; src[j];) {
1932 if (src[j] != '\r' || src[j + 1] != '\n')
1933 dst += src[j++];
1934 else {
1935 dst += '\n';
1936 j += 2;
1937 }
1938 }
1939 }
1940
1946 template<class T, class TR = std::char_traits<T>, class AX = std::allocator<T>>
1947 void crlf2nl(_Inout_ std::basic_string<T, TR, AX>& str)
1948 {
1949 size_t i, j, n;
1950 for (i = j = 0, n = str.size(); j < n;) {
1951 if (str[j] != '\r' || str[j + 1] != '\n')
1952 str[i++] = str[j++];
1953 else {
1954 str[i++] = '\n';
1955 j += 2;
1956 }
1957 }
1958 str.resize(i);
1959 }
1960
1962 template <class T, class T_bin>
1963 T_bin strtoint(
1964 _In_reads_or_z_opt_(count) const T* str, _In_ size_t count,
1965 _Out_opt_ size_t* end,
1966 _In_ int radix,
1967 _Out_ uint8_t& flags)
1968 {
1969 stdex_assert(str || !count);
1970 stdex_assert(radix == 0 || 2 <= radix && radix <= 36);
1971
1972 size_t i = 0;
1973 T_bin value = 0, digit,
1974 max_ui = (T_bin)-1,
1975 max_ui_pre1, max_ui_pre2;
1976
1977 flags = 0;
1978
1979 // Skip leading spaces.
1980 for (;; ++i) {
1981 if (i >= count || !str[i]) goto error;
1982 if (!isspace(str[i])) break;
1983 }
1984
1985 // Read the sign.
1986 if (str[i] == '+') {
1987 flags &= ~0x01;
1988 ++i;
1989 if (i >= count || !str[i]) goto error;
1990 }
1991 else if (str[i] == '-') {
1992 flags |= 0x01;
1993 ++i;
1994 if (i >= count || !str[i]) goto error;
1995 }
1996
1997 if (radix == 16) {
1998 // On hexadecimal, allow leading 0x.
1999 if (str[i] == '0' && i + 1 < count && (str[i + 1] == 'x' || str[i + 1] == 'X')) {
2000 i += 2;
2001 if (i >= count || !str[i]) goto error;
2002 }
2003 }
2004 else if (!radix) {
2005 // Autodetect radix.
2006 if (str[i] == '0') {
2007 ++i;
2008 if (i >= count || !str[i]) goto error;
2009 if (str[i] == 'x' || str[i] == 'X') {
2010 radix = 16;
2011 ++i;
2012 if (i >= count || !str[i]) goto error;
2013 }
2014 else
2015 radix = 8;
2016 }
2017 else
2018 radix = 10;
2019 }
2020
2021 // We have the radix.
2022 max_ui_pre1 = max_ui / (T_bin)radix;
2023 max_ui_pre2 = max_ui % (T_bin)radix;
2024 for (;;) {
2025 if ('0' <= str[i] && str[i] <= '9')
2026 digit = (T_bin)str[i] - '0';
2027 else if ('A' <= str[i] && str[i] <= 'Z')
2028 digit = (T_bin)str[i] - 'A' + '\x0a';
2029 else if ('a' <= str[i] && str[i] <= 'z')
2030 digit = (T_bin)str[i] - 'a' + '\x0a';
2031 else
2032 goto error;
2033 if (digit >= (T_bin)radix)
2034 goto error;
2035
2036 if (value < max_ui_pre1 || // Multiplication nor addition will not overflow.
2037 (value == max_ui_pre1 && digit <= max_ui_pre2)) // Small digits will not overflow.
2038 value = value * (T_bin)radix + digit;
2039 else {
2040 // Overflow!
2041 flags |= 0x02;
2042 }
2043
2044 ++i;
2045 if (i >= count || !str[i])
2046 goto error;
2047 }
2048
2049 error:
2050 if (end) *end = i;
2051 return value;
2052 }
2054
2065 template <class T, class T_bin>
2066 T_bin strtoint(
2067 _In_reads_or_z_opt_(count) const T* str, _In_ size_t count,
2068 _Out_opt_ size_t* end,
2069 _In_ int radix)
2070 {
2071 uint8_t flags;
2072 T_bin value;
2073
2074 switch (sizeof(T_bin)) {
2075 case 1:
2076 value = (T_bin)strtoint<T, uint8_t>(str, count, end, radix, flags);
2077 if ((flags & 0x01) && (value & 0x80)) {
2078 // Sign bit is 1 => overflow.
2079 flags |= 0x02;
2080 }
2081 return (flags & 0x02) ?
2082 (flags & 0x01) ? (T_bin)0x80 : (T_bin)0x7f :
2083 (flags & 0x01) ? -value : value;
2084
2085 case 2:
2086 value = (T_bin)strtoint<T, uint16_t>(str, count, end, radix, flags);
2087 if ((flags & 0x01) && (value & 0x8000)) {
2088 // Sign bit is 1 => overflow.
2089 flags |= 0x02;
2090 }
2091 return (flags & 0x02) ?
2092 (flags & 0x01) ? (T_bin)0x8000 : (T_bin)0x7fff :
2093 (flags & 0x01) ? -value : value;
2094
2095 case 4:
2096 value = (T_bin)strtoint<T, uint32_t>(str, count, end, radix, flags);
2097 if ((flags & 0x01) && (value & 0x80000000)) {
2098 // Sign bit is 1 => overflow.
2099 flags |= 0x02;
2100 }
2101 return (flags & 0x02) ?
2102 (flags & 0x01) ? (T_bin)0x80000000 : (T_bin)0x7fffffff :
2103 (flags & 0x01) ? -value : value;
2104
2105 case 8:
2106 value = (T_bin)strtoint<T, uint64_t>(str, count, end, radix, flags);
2107 if ((flags & 0x01) && (value & 0x8000000000000000)) {
2108 // Sign bit is 1 => overflow.
2109 flags |= 0x02;
2110 }
2111 return (flags & 0x02) ?
2112 (flags & 0x01) ? (T_bin)0x8000000000000000 : (T_bin)0x7fffffffffffffff :
2113 (flags & 0x01) ? -value : value;
2114
2115 default:
2116 throw std::invalid_argument("Unsupported bit length");
2117 }
2118 }
2119
2129 template <class T, size_t N, class T_bin>
2130 T_bin strtoint(
2131 _In_ const T (&str)[N],
2132 _Out_opt_ size_t* end,
2133 _In_ int radix)
2134 {
2135 return strtoint<T, T_bin>(str, N, end, radix);
2136 }
2137
2148 template <class T, class T_bin>
2149 T_bin strtouint(
2150 _In_reads_or_z_opt_(count) const T* str,
2151 _In_ size_t count,
2152 _Out_opt_ size_t* end,
2153 _In_ int radix)
2154 {
2155 uint8_t flags;
2156 T_bin value;
2157
2158 switch (sizeof(T_bin)) {
2159 case 1: value = (T_bin)strtoint<T, uint8_t>(str, count, end, radix, flags); break;
2160 case 2: value = (T_bin)strtoint<T, uint16_t>(str, count, end, radix, flags); break;
2161 case 4: value = (T_bin)strtoint<T, uint32_t>(str, count, end, radix, flags); break;
2162 case 8: value = (T_bin)strtoint<T, uint64_t>(str, count, end, radix, flags); break;
2163 default: throw std::invalid_argument("Unsupported bit length");
2164 }
2165
2166 return (flags & 0x02) ?
2167 (flags & 0x01) ? (T_bin)0 : (T_bin)-1 :
2168 (flags & 0x01) ? ~value : value;
2169 }
2170
2180 template <class T, size_t N, class T_bin>
2181 T_bin strtouint(
2182 _In_ const T (&str)[N],
2183 _Out_opt_ size_t* end,
2184 _In_ int radix)
2185 {
2186 return strtouint<T, T_bin>(str, N, end, radix);
2187 }
2188
2199 template <class T>
2200 int8_t strto8(
2201 _In_reads_or_z_opt_(count) const T* str, _In_ size_t count,
2202 _Out_opt_ size_t* end,
2203 _In_ int radix)
2204 {
2205 return strtoint<T, int8_t>(str, count, end, radix);
2206 }
2207
2217 template <class T, size_t N>
2218 int8_t strto8(
2219 _In_ const T (&str)[N],
2220 _Out_opt_ size_t* end,
2221 _In_ int radix)
2222 {
2223 return strto8<T>(str, N, end, radix);
2224 }
2225
2236 template <class T>
2237 int16_t strto16(
2238 _In_reads_or_z_opt_(count) const T* str, _In_ size_t count,
2239 _Out_opt_ size_t* end,
2240 _In_ int radix)
2241 {
2242 return strtoint<T, int16_t>(str, count, end, radix);
2243 }
2244
2254 template <class T, size_t N>
2255 int16_t strto16(
2256 _In_ const T (&str)[N],
2257 _Out_opt_ size_t* end,
2258 _In_ int radix)
2259 {
2260 return strto16<T>(str, N, end, radix);
2261 }
2262
2273 template <class T>
2274 int32_t strto32(
2275 _In_reads_or_z_opt_(count) const T* str, _In_ size_t count,
2276 _Out_opt_ size_t* end,
2277 _In_ int radix)
2278 {
2279 return strtoint<T, int32_t>(str, count, end, radix);
2280 }
2281
2291 template <class T, size_t N>
2292 int32_t strto32(
2293 _In_ const T (&str)[N],
2294 _Out_opt_ size_t* end,
2295 _In_ int radix)
2296 {
2297 return strto32<T>(str, N, end, radix);
2298 }
2299
2310 template <class T>
2311 int64_t strto64(
2312 _In_reads_or_z_opt_(count) const T* str, _In_ size_t count,
2313 _Out_opt_ size_t* end,
2314 _In_ int radix)
2315 {
2316 return strtoint<T, int64_t>(str, count, end, radix);
2317 }
2318
2328 template <class T, size_t N>
2329 int64_t strto64(
2330 _In_ const T (&str)[N],
2331 _Out_opt_ size_t* end,
2332 _In_ int radix)
2333 {
2334 return strto64<T>(str, N, end, radix);
2335 }
2336
2348 template <class T>
2349 ptrdiff_t strtoi(
2350 _In_reads_or_z_opt_(count) const T* str, _In_ size_t count,
2351 _Out_opt_ size_t* end,
2352 _In_ int radix)
2353 {
2354#if defined(_WIN64) || defined(__LP64__)
2355 return static_cast<ptrdiff_t>(strto64(str, count, end, radix));
2356#else
2357 return static_cast<ptrdiff_t>(strto32(str, count, end, radix));
2358#endif
2359 }
2360
2371 template <class T, size_t N>
2372 ptrdiff_t strtoi(
2373 _In_ const T (&str)[N],
2374 _Out_opt_ size_t* end,
2375 _In_ int radix)
2376 {
2377 return strtoi<T>(str, N, end, radix);
2378 }
2379
2390 template <class T>
2391 uint8_t strtou8(
2392 _In_reads_or_z_opt_(count) const T* str, _In_ size_t count,
2393 _Out_opt_ size_t* end,
2394 _In_ int radix)
2395 {
2396 return strtouint<T, uint8_t>(str, count, end, radix);
2397 }
2398
2408 template <class T, size_t N>
2409 uint8_t strtou8(
2410 _In_ const T (&str)[N],
2411 _Out_opt_ size_t* end,
2412 _In_ int radix)
2413 {
2414 return strtou8(str, N, end, radix);
2415 }
2416
2427 template <class T>
2428 uint16_t strtou16(
2429 _In_reads_or_z_opt_(count) const T* str, _In_ size_t count,
2430 _Out_opt_ size_t* end,
2431 _In_ int radix)
2432 {
2433 return strtouint<T, uint16_t>(str, count, end, radix);
2434 }
2435
2445 template <class T, size_t N>
2446 uint16_t strtou16(
2447 _In_ const T (&str)[N],
2448 _Out_opt_ size_t* end,
2449 _In_ int radix)
2450 {
2451 return strtou16(str, N, end, radix);
2452 }
2453
2464 template <class T>
2465 uint32_t strtou32(
2466 _In_reads_or_z_opt_(count) const T* str, _In_ size_t count,
2467 _Out_opt_ size_t* end,
2468 _In_ int radix)
2469 {
2470 return strtouint<T, uint32_t>(str, count, end, radix);
2471 }
2472
2482 template <class T, size_t N>
2483 uint32_t strtou32(
2484 _In_ const T (&str)[N],
2485 _Out_opt_ size_t* end,
2486 _In_ int radix)
2487 {
2488 return strtou32(str, N, end, radix);
2489 }
2490
2501 template <class T>
2502 uint64_t strtou64(
2503 _In_reads_or_z_opt_(count) const T* str, _In_ size_t count,
2504 _Out_opt_ size_t* end,
2505 _In_ int radix)
2506 {
2507 return strtouint<T, uint64_t>(str, count, end, radix);
2508 }
2509
2519 template <class T, size_t N>
2520 uint64_t strtou64(
2521 _In_ const T (&str)[N],
2522 _Out_opt_ size_t* end,
2523 _In_ int radix)
2524 {
2525 return strtou64<T>(str, N, end, radix);
2526 }
2527
2539 template <class T>
2540 size_t strtoui(
2541 _In_reads_or_z_opt_(count) const T* str, _In_ size_t count,
2542 _Out_opt_ size_t* end,
2543 _In_ int radix)
2544 {
2545#if defined(_WIN64) || defined(__LP64__)
2546 return static_cast<size_t>(strtou64(str, count, end, radix));
2547#else
2548 return static_cast<size_t>(strtou32(str, count, end, radix));
2549#endif
2550 }
2551
2562 template <class T, size_t N>
2563 size_t strtoui(
2564 _In_ const T (&str)[N],
2565 _Out_opt_ size_t* end,
2566 _In_ int radix)
2567 {
2568 return strtoui<T>(str, N, end, radix);
2569 }
2570
2581 inline double strtod(
2582 _In_reads_or_z_opt_(count) const char* str, _In_ size_t count,
2583 _Out_opt_ size_t* end,
2584 _In_opt_ locale_t locale)
2585 {
2586 count = strnlen(str, count);
2587 stdex_assert(str || !count);
2588 std::string tmp(str, count);
2589 char* _end;
2590 double r;
2591#if _WIN32
2592 r = _strtod_l(tmp.c_str(), &_end, locale);
2593#else
2594 r = strtod_l(tmp.c_str(), &_end, locale);
2595#endif
2596 if (end) *end = (size_t)(_end - tmp.c_str());
2597 return r;
2598 }
2599
2610 inline double strtod(
2611 _In_reads_or_z_opt_(count) const wchar_t* str, _In_ size_t count,
2612 _Out_opt_ size_t* end,
2613 _In_opt_ locale_t locale)
2614 {
2615 count = strnlen(str, count);
2616 stdex_assert(str || !count);
2617 std::wstring tmp(str, count);
2618 wchar_t* _end;
2619 double r;
2620#if _WIN32
2621 r = _wcstod_l(tmp.c_str(), &_end, locale);
2622#else
2623 r = wcstod_l(tmp.c_str(), &_end, locale);
2624#endif
2625 if (end) *end = (size_t)(_end - tmp.c_str());
2626 return r;
2627 }
2628
2630 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)
2631 {
2632#ifdef _WIN32
2633#pragma warning(suppress: 4996)
2634 return _vsnprintf_l(str, capacity, format, locale, arg);
2635#else
2636 va_list arg_mutable;
2637 va_copy(arg_mutable, arg);
2638 return ::vsnprintf_l(str, capacity, locale, format, arg_mutable);
2639#endif
2640 }
2641
2642 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)
2643 {
2644#ifdef _WIN32
2645#pragma warning(suppress: 4996)
2646 return _vsnwprintf_l(str, capacity, format, locale, arg);
2647#else
2648 va_list arg_mutable;
2649 va_copy(arg_mutable, arg);
2650 return ::vswprintf_l(str, capacity, locale, format, arg_mutable);
2651#endif
2652 }
2654
2665 template<class T, class TR, class AX>
2666 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)
2667 {
2668 T buf[1024 / sizeof(T)];
2669
2670 // Try with stack buffer first.
2671 int count = vsnprintf(buf, _countof(buf), format, locale, arg);
2672 if (0 <= count && static_cast<size_t>(count) <= _countof(buf)) {
2673 // Copy from stack.
2674 str.append(buf, static_cast<size_t>(count));
2675 return static_cast<size_t>(count);
2676 }
2677#ifdef _WIN32
2678 if (count < 0) {
2679 switch (errno) {
2680 case 0:
2681 count = vsnprintf(NULL, 0, format, locale, arg);
2682 stdex_assert(count >= 0);
2683 break;
2684 case EINVAL: throw std::invalid_argument("invalid vsnprintf arguments");
2685 case EILSEQ: throw std::runtime_error("encoding error");
2686 default: throw std::runtime_error("failed to format string");
2687 }
2688 }
2689 size_t offset = str.size();
2690 str.resize(offset + count);
2691 if (vsnprintf(&str[offset], count + 1, format, locale, arg) != count) _Unlikely_
2692 throw std::runtime_error("failed to format string");
2693#else
2694 size_t offset = str.size();
2695 for (size_t capacity = 2 * 1024 / sizeof(T);; capacity *= 2) {
2696 switch (errno) {
2697 case EOVERFLOW:
2698 // Allocate on heap and retry.
2699 str.resize(offset + capacity);
2700 count = vsnprintf(&str[offset], capacity, format, locale, arg);
2701 if (0 <= count && static_cast<size_t>(count) <= capacity) {
2702 str.resize(offset + static_cast<size_t>(count));
2703 return static_cast<size_t>(count);
2704 }
2705 break;
2706 case EINVAL: throw std::invalid_argument("invalid vsnprintf arguments");
2707 case EILSEQ: throw std::runtime_error("encoding error");
2708 default: throw std::runtime_error("failed to format string");
2709 }
2710 }
2711#endif
2712 return static_cast<size_t>(count);
2713 }
2714
2724 template<class T, class TR, class AX>
2725 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, ...)
2726 {
2727 va_list arg;
2728 va_start(arg, locale);
2729 size_t n = vappendf(str, format, locale, arg);
2730 va_end(arg);
2731 return n;
2732 }
2733
2742 template<class T, class TR, class AX>
2743 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)
2744 {
2745 str.clear();
2746 vappendf(str, format, locale, arg);
2747 }
2748
2756 template<class T, class TR, class AX>
2757 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, ...)
2758 {
2759 va_list arg;
2760 va_start(arg, locale);
2761 vsprintf(str, format, locale, arg);
2762 va_end(arg);
2763 }
2764
2774 template<class T, class TR = std::char_traits<T>, class AX = std::allocator<T>>
2775 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)
2776 {
2777 std::basic_string<T, TR, AX> str;
2778 vappendf(str, format, locale, arg);
2779 return str;
2780 }
2781
2790 template<class T, class TR = std::char_traits<T>, class AX = std::allocator<T>>
2791 std::basic_string<T, TR, AX> sprintf(_In_z_ _Printf_format_string_params_(2) const T* format, _In_opt_ locale_t locale, ...)
2792 {
2793 va_list arg;
2794 va_start(arg, locale);
2795 auto str = vsprintf(format, locale, arg);
2796 va_end(arg);
2797 return str;
2798 }
2799
2801 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)
2802 {
2803#ifdef _WIN32
2804 return _strftime_l(str, capacity, format, time, locale);
2805#else
2806 return strftime_l(str, capacity, format, time, locale);
2807#endif
2808 }
2809
2810 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)
2811 {
2812#ifdef _WIN32
2813 return _wcsftime_l(str, capacity, format, time, locale);
2814#else
2815 return wcsftime_l(str, capacity, format, time, locale);
2816#endif
2817 }
2819
2828 template<class T, class TR, class AX>
2829 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)
2830 {
2831 T buf[1024 / sizeof(T)];
2832
2833 // Try with stack buffer first.
2834 size_t count = strftime(buf, _countof(buf), format, time, locale);
2835 if (count) {
2836 // Copy from stack.
2837 str.append(buf, count);
2838 return;
2839 }
2840 size_t offset = str.size();
2841 for (size_t capacity = 2 * 1024 / sizeof(T);; capacity *= 2) {
2842 // Allocate on heap and retry.
2843 str.resize(offset + capacity);
2844 count = strftime(&str[offset], capacity + 1, format, time, locale);
2845 if (count) {
2846 str.resize(offset + count);
2847 return;
2848 }
2849 }
2850 }
2851
2860 template<class T, class TR, class AX>
2861 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)
2862 {
2863 str.clear();
2864 strcatftime(str, format, time, locale);
2865 }
2866
2876 template<class T, class TR = std::char_traits<T>, class AX = std::allocator<T>>
2877 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)
2878 {
2879 std::basic_string<T, TR, AX> str;
2880 strcatftime(str, format, time, locale);
2881 return str;
2882 }
2883
2889 //template<class T>
2890 //void strlwr(_Inout_z_ T* str)
2891 //{
2892 // stdex_assert(str);
2893 // for (size_t i = 0; str[i]; ++i)
2894 // str[i] = tolower(str[i]);
2895 //}
2896
2903 //template<class T>
2904 //void strlwr(_Inout_z_ T* str, _In_ const std::locale& locale)
2905 //{
2906 // stdex_assert(str);
2907 // const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2908 // for (size_t i = 0; str[i]; ++i)
2909 // str[i] = ctype.tolower(str[i]);
2910 //}
2911
2918 template<class T>
2919 void strlwr(_Inout_updates_z_(count) T* str, _In_ size_t count)
2920 {
2921 stdex_assert(str || !count);
2922 for (size_t i = 0; i < count && str[i]; ++i)
2923 str[i] = tolower(str[i]);
2924 }
2925
2933 template<class T>
2934 void strlwr(_Inout_updates_z_(count) T* str, _In_ size_t count, _In_ const std::locale& locale)
2935 {
2936 stdex_assert(str || !count);
2937 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2938 for (size_t i = 0; i < count && str[i]; ++i)
2939 str[i] = ctype.tolower(str[i]);
2940 }
2941
2947 template<class T, size_t N>
2948 void strlwr(_Inout_ T (&str)[N])
2949 {
2950 strlwr(str, N);
2951 }
2952
2959 template<class T, size_t N>
2960 void strlwr(_Inout_ T (&str)[N], _In_ const std::locale& locale)
2961 {
2962 strlwr(str, N, locale);
2963 }
2964
2970 template<class T, class TR = std::char_traits<T>, class AX = std::allocator<T>>
2971 void strlwr(_Inout_ std::basic_string<T, TR, AX>& str)
2972 {
2973 for (auto& c : str)
2974 c = tolower(c);
2975 }
2976
2983 template<class T, class TR = std::char_traits<T>, class AX = std::allocator<T>>
2984 void strlwr(_Inout_ std::basic_string<T, TR, AX>& str, _In_ const std::locale& locale)
2985 {
2986 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
2987 for (auto& c : str)
2988 c = ctype.tolower(c);
2989 }
2990
2996 //template<class T>
2997 //void strupr(_Inout_z_ T* str)
2998 //{
2999 // stdex_assert(str);
3000 // for (size_t i = 0; str[i]; ++i)
3001 // str[i] = toupper(str[i]);
3002 //}
3003
3010 //template<class T>
3011 //void strupr(_Inout_z_ T* str, _In_ const std::locale& locale)
3012 //{
3013 // stdex_assert(str);
3014 // const auto& ctype = std::use_facet<std::ctype<T>>(locale);
3015 // for (size_t i = 0; str[i]; ++i)
3016 // str[i] = ctype.toupper(str[i]);
3017 //}
3018
3025 template<class T>
3026 void strupr(_Inout_updates_z_(count) T* str, _In_ size_t count)
3027 {
3028 stdex_assert(str || !count);
3029 for (size_t i = 0; i < count && str[i]; ++i)
3030 str[i] = toupper(str[i]);
3031 }
3032
3040 template<class T>
3041 void strupr(_Inout_updates_z_(count) T* str, _In_ size_t count, _In_ const std::locale& locale)
3042 {
3043 stdex_assert(str || !count);
3044 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
3045 for (size_t i = 0; i < count && str[i]; ++i)
3046 str[i] = ctype.toupper(str[i]);
3047 }
3048
3054 template<class T, size_t N>
3055 void strupr(_Inout_ T (&str)[N])
3056 {
3057 return strupr(str, N);
3058 }
3059
3066 template<class T, size_t N>
3067 void strupr(_Inout_ T (&str)[N], _In_ const std::locale& locale)
3068 {
3069 return strupr(str, N, locale);
3070 }
3071
3077 template<class T, class TR = std::char_traits<T>, class AX = std::allocator<T>>
3078 void strupr(_Inout_ std::basic_string<T, TR, AX>& str)
3079 {
3080 for (auto& c : str)
3081 c = toupper(c);
3082 }
3083
3090 template<class T, class TR = std::char_traits<T>, class AX = std::allocator<T>>
3091 void strupr(_Inout_ std::basic_string<T, TR, AX>& str, _In_ const std::locale& locale)
3092 {
3093 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
3094 for (auto& c : str)
3095 c = ctype.toupper(c);
3096 }
3097
3106 template<class T>
3107 size_t ltrim(
3108 _Inout_z_count_(count) T* str, _In_ size_t count)
3109 {
3110 for (size_t i = 0;; ++i) {
3111 if (i >= count) {
3112 if (count) str[0] = 0;
3113 return 0;
3114 }
3115 if (!str[i]) {
3116 str[0] = 0;
3117 return 0;
3118 }
3119 if (!isspace(str[i])) {
3120 if (!i)
3121 return strnlen(str, count);
3122 size_t n = count != SIZE_MAX ? strncpy(str, str + i, count - i) : strcpy(str, str + i);
3123 str[n] = 0;
3124 return n;
3125 }
3126 }
3127 }
3128
3138 template<class T>
3139 size_t ltrim(
3140 _Inout_z_count_(count) T* str, _In_ size_t count,
3141 _In_ const std::locale& locale)
3142 {
3143 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
3144 for (size_t i = 0;; ++i) {
3145 if (i >= count) {
3146 if (count) str[0] = 0;
3147 return 0;
3148 }
3149 if (!str[i]) {
3150 str[0] = 0;
3151 return 0;
3152 }
3153 if (!ctype.is(ctype.space, str[i])) {
3154 if (!i)
3155 return strnlen(str, count);
3156 size_t n = count != SIZE_MAX ? strncpy(str, str + i, count - i) : strcpy(str, str + i);
3157 str[n] = 0;
3158 return n;
3159 }
3160 }
3161 }
3162
3168 template<class T, class TR = std::char_traits<T>, class AX = std::allocator<T>>
3169 void ltrim(_Inout_ std::basic_string<T, TR, AX>& s)
3170 {
3171 s.erase(
3172 s.begin(),
3173 std::find_if(
3174 s.begin(),
3175 s.end(),
3176 [&](_In_ T ch) { return !isspace(ch); }));
3177 }
3178
3185 template<class T, class TR = std::char_traits<T>, class AX = std::allocator<T>>
3186 void ltrim(_Inout_ std::basic_string<T, TR, AX>& s, _In_ const std::locale& locale)
3187 {
3188 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
3189 s.erase(
3190 s.begin(),
3191 std::find_if(
3192 s.begin(),
3193 s.end(),
3194 [&](_In_ T ch) { return !ctype.is(ctype.space, ch); }));
3195 }
3196
3205 template<class T>
3206 size_t rtrim(
3207 _Inout_z_count_(count) T* str, _In_ size_t count)
3208 {
3209 for (size_t i = 0, j = 0;;) {
3210 if (i >= count || !str[i]) {
3211 if (j < count) str[j] = 0;
3212 return j;
3213 }
3214 if (!isspace(str[i]))
3215 j = ++i;
3216 else
3217 ++i;
3218 }
3219 }
3220
3230 template<class T>
3231 size_t rtrim(
3232 _Inout_z_count_(count) T* str, _In_ size_t count,
3233 _In_ const std::locale& locale)
3234 {
3235 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
3236 for (size_t i = 0, j = 0;;) {
3237 if (i >= count || !str[i]) {
3238 if (j < count) str[j] = 0;
3239 return j;
3240 }
3241 if (!ctype.is(ctype.space, str[i]))
3242 j = ++i;
3243 else
3244 ++i;
3245 }
3246 }
3247
3253 template<class T, class TR = std::char_traits<T>, class AX = std::allocator<T>>
3254 void rtrim(_Inout_ std::basic_string<T, TR, AX>& s)
3255 {
3256 s.erase(
3257 std::find_if(
3258 s.rbegin(),
3259 s.rend(),
3260 [&](_In_ T ch) { return !isspace(ch); }).base(),
3261 s.end());
3262 }
3263
3270 template<class T, class TR = std::char_traits<T>, class AX = std::allocator<T>>
3271 void rtrim(_Inout_ std::basic_string<T, TR, AX>& s, _In_ const std::locale& locale)
3272 {
3273 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
3274 s.erase(
3275 std::find_if(
3276 s.rbegin(),
3277 s.rend(),
3278 [&](_In_ T ch) { return !ctype.is(ctype.space, ch); }).base(),
3279 s.end());
3280 }
3281
3290 template<class T>
3291 size_t trim(
3292 _Inout_z_count_(count) T* str, _In_ size_t count)
3293 {
3294 return ltrim(str, rtrim(str, count));
3295 }
3296
3306 template<class T>
3307 size_t trim(
3308 _Inout_z_count_(count) T* str, _In_ size_t count,
3309 _In_ const std::locale& locale)
3310 {
3311 return ltrim(str, rtrim(str, count, locale), locale);
3312 }
3313
3319 template<class T, class TR = std::char_traits<T>, class AX = std::allocator<T>>
3320 void trim(_Inout_ std::basic_string<T, TR, AX>& s)
3321 {
3322 auto nonspace = [&](_In_ T ch) { return !isspace(ch); };
3323 s.erase(
3324 s.begin(),
3325 std::find_if(
3326 s.begin(),
3327 s.end(),
3328 nonspace));
3329 s.erase(
3330 std::find_if(
3331 s.rbegin(),
3332 s.rend(),
3333 nonspace).base(),
3334 s.end());
3335 }
3336
3343 template<class T, class TR = std::char_traits<T>, class AX = std::allocator<T>>
3344 void trim(_Inout_ std::basic_string<T, TR, AX>& s, _In_ const std::locale& locale)
3345 {
3346 const auto& ctype = std::use_facet<std::ctype<T>>(locale);
3347 auto nonspace = [&](_In_ T ch) { return !ctype.is(ctype.space, ch); };
3348 s.erase(
3349 s.begin(),
3350 std::find_if(
3351 s.begin(),
3352 s.end(),
3353 nonspace));
3354 s.erase(
3355 std::find_if(
3356 s.rbegin(),
3357 s.rend(),
3358 nonspace).base(),
3359 s.end());
3360 }
3361}