|
11 | 11 |
|
12 | 12 | #include <cstdarg>
|
13 | 13 |
|
| 14 | +#if __has_include(<format>) |
| 15 | + #include <format> |
| 16 | +#endif |
| 17 | + |
14 | 18 | namespace sysstr
|
15 | 19 | {
|
16 | 20 | namespace util
|
@@ -80,43 +84,138 @@ namespace sysstr
|
80 | 84 |
|
81 | 85 | return std::ranges::equal(test.begin(), test.end(), access.begin(), access.begin() + test_size);
|
82 | 86 | }
|
| 87 | + |
| 88 | + template<class Storage, class Func> |
| 89 | + inline |
| 90 | + decltype(auto) with_output_string(const sys_string_t<Storage> & val, Func func) |
| 91 | + { |
| 92 | + if constexpr (std::ranges::contiguous_range<typename sys_string_t<Storage>::char_access> && |
| 93 | + std::is_same_v<typename sys_string_t<Storage>::storage_type, char>) |
| 94 | + { |
| 95 | + typename sysstr::sys_string_t<Storage>::char_access access(val); |
| 96 | + return func(std::string_view(access.data(), access.size())); |
| 97 | + } |
| 98 | + else |
| 99 | + { |
| 100 | + std::string out; |
| 101 | + typename sysstr::sys_string_t<Storage>::utf8_access(val).each([&out](char c) { |
| 102 | + out += c; |
| 103 | + }); |
| 104 | + return func(std::string_view(out)); |
| 105 | + } |
| 106 | + } |
| 107 | + |
| 108 | + #if SYS_STRING_WCHAR_T_IS_UTF16 |
| 109 | + template<class Storage, class Func> |
| 110 | + inline |
| 111 | + decltype(auto) with_output_wstring(const sys_string_t<Storage> & val, Func func) |
| 112 | + { |
| 113 | + if constexpr (std::ranges::contiguous_range<typename sys_string_t<Storage>::char_access> && |
| 114 | + std::is_same_v<typename sys_string_t<Storage>::storage_type, char16_t>) |
| 115 | + { |
| 116 | + typename sysstr::sys_string_t<Storage>::char_access access(val); |
| 117 | + return func(std::wstring_view((const wchar_t *)access.data(), access.size())); |
| 118 | + } |
| 119 | + else |
| 120 | + { |
| 121 | + std::wstring out; |
| 122 | + typename sysstr::sys_string_t<Storage>::utf16_access(val).each([&out](char16_t c) { |
| 123 | + out += wchar_t(c); |
| 124 | + }); |
| 125 | + return func(std::wstring_view(out)); |
| 126 | + } |
| 127 | + } |
| 128 | + #elif SYS_STRING_WCHAR_T_IS_UTF32 |
| 129 | + template<class Storage, class Func> |
| 130 | + inline |
| 131 | + decltype(auto) with_output_wstring(const sys_string_t<Storage> & val, Func func) |
| 132 | + { |
| 133 | + if constexpr (std::ranges::contiguous_range<typename sys_string_t<Storage>::char_access> && |
| 134 | + std::is_same_v<typename sys_string_t<Storage>::storage_type, char32_t>) |
| 135 | + { |
| 136 | + typename sysstr::sys_string_t<Storage>::char_access access(val); |
| 137 | + return func(std::wstring_view((const wchar_t *)access.data(), access.size())); |
| 138 | + } |
| 139 | + else |
| 140 | + { |
| 141 | + std::wstring out; |
| 142 | + typename sysstr::sys_string_t<Storage>::utf32_access(val).each([&out](char32_t c) { |
| 143 | + out += wchar_t(c); |
| 144 | + }); |
| 145 | + return func(std::wstring_view(out)); |
| 146 | + } |
| 147 | + } |
| 148 | + #endif |
83 | 149 | }
|
84 | 150 |
|
85 | 151 |
|
86 | 152 | template<class Storage>
|
87 | 153 | inline
|
88 | 154 | auto operator<<(std::ostream & str, const sys_string_t<Storage> & val) -> std::ostream &
|
89 |
| - { |
90 |
| - for(char c: typename sys_string_t<Storage>::utf8_view(val)) |
91 |
| - str << c; |
92 |
| - return str; |
| 155 | + { |
| 156 | + return util::with_output_string(val, [&](auto view) -> std::ostream & { |
| 157 | + return str << view; |
| 158 | + }); |
93 | 159 | }
|
94 | 160 |
|
95 |
| -#if defined(_WIN32) |
| 161 | +#if SYS_STRING_WCHAR_T_IS_UTF16 || SYS_STRING_WCHAR_T_IS_UTF32 |
96 | 162 |
|
97 | 163 | template<class Storage>
|
98 | 164 | inline
|
99 | 165 | auto operator<<(std::wostream & str, const sys_string_t<Storage> & val) -> std::wostream &
|
| 166 | + { |
| 167 | + return util::with_output_wstring(val, [&](auto view) -> std::wostream & { |
| 168 | + return str << view; |
| 169 | + }); |
| 170 | + } |
| 171 | + |
| 172 | +#endif |
| 173 | +} |
| 174 | + |
| 175 | +//See https://github.com/llvm/llvm-project/issues/77773 for the sad story of how feature test |
| 176 | +//macros are useless with libc++ |
| 177 | +#if __cpp_lib_format >= 201907L || (defined(_LIBCPP_VERSION) && __has_include(<format>)) |
| 178 | + |
| 179 | +template<class Storage> struct std::formatter<sysstr::sys_string_t<Storage>> : private std::formatter<std::string_view> |
| 180 | +{ |
| 181 | + using super = std::formatter<std::string_view>; |
| 182 | + |
| 183 | + using super::formatter; |
| 184 | + using super::parse; |
| 185 | + |
| 186 | + template <typename FormatContext> |
| 187 | + auto format(const sysstr::sys_string_t<Storage> & str, FormatContext & ctx) const -> decltype(ctx.out()) |
100 | 188 | {
|
101 |
| - for(char16_t c: typename sys_string_t<Storage>::utf16_view(val)) |
102 |
| - str << wchar_t(c); |
103 |
| - return str; |
| 189 | + return sysstr::util::with_output_string(str, [&](auto view) { |
| 190 | + return super::format(view, ctx); |
| 191 | + }); |
104 | 192 | }
|
| 193 | +}; |
105 | 194 |
|
106 |
| -#elif defined(__STDC_ISO_10646__) |
| 195 | +#if SYS_STRING_WCHAR_T_IS_UTF16 || SYS_STRING_WCHAR_T_IS_UTF32 |
107 | 196 |
|
108 |
| - template<class Storage> |
109 |
| - inline |
110 |
| - auto operator<<(std::wostream & str, const sys_string_t<Storage> & val) -> std::wostream & |
| 197 | +template<class Storage> struct std::formatter<sysstr::sys_string_t<Storage>, wchar_t> : private std::formatter<std::wstring_view, wchar_t> |
| 198 | +{ |
| 199 | + using super = std::formatter<std::wstring_view, wchar_t>; |
| 200 | + |
| 201 | + using super::formatter; |
| 202 | + using super::parse; |
| 203 | + |
| 204 | + template <typename FormatContext> |
| 205 | + auto format(const sysstr::sys_string_t<Storage> & str, FormatContext & ctx) const -> decltype(ctx.out()) |
111 | 206 | {
|
112 |
| - for(char32_t c: typename sys_string_t<Storage>::utf32_view(val)) |
113 |
| - str << wchar_t(c); |
114 |
| - return str; |
| 207 | + return sysstr::util::with_output_wstring(str, [&](auto view) { |
| 208 | + return super::format(view, ctx); |
| 209 | + }); |
115 | 210 | }
|
| 211 | +}; |
116 | 212 |
|
117 | 213 | #endif
|
118 | 214 |
|
| 215 | +#endif |
119 | 216 |
|
| 217 | +namespace sysstr |
| 218 | +{ |
120 | 219 | template<class Storage>
|
121 | 220 | inline
|
122 | 221 | auto sys_string_t<Storage>::to_lower() const -> sys_string_t<Storage>
|
|
0 commit comments