1 // Formatting library for C++ - optional wchar_t and exotic character support 2 // 3 // Copyright (c) 2012 - present, Victor Zverovich 4 // All rights reserved. 5 // 6 // For the license information refer to format.h. 7 8 #ifndef FMT_XCHAR_H_ 9 #define FMT_XCHAR_H_ 10 11 #include "color.h" 12 #include "format.h" 13 #include "ostream.h" 14 #include "ranges.h" 15 16 #ifndef FMT_MODULE 17 # include <cwchar> 18 # if FMT_USE_LOCALE 19 # include <locale> 20 # endif 21 #endif 22 23 FMT_BEGIN_NAMESPACE 24 namespace detail { 25 26 template <typename T> 27 using is_exotic_char = bool_constant<!std::is_same<T, char>::value>; 28 29 template <typename S, typename = void> struct format_string_char {}; 30 31 template <typename S> 32 struct format_string_char< 33 S, void_t<decltype(sizeof(detail::to_string_view(std::declval<S>())))>> { 34 using type = char_t<S>; 35 }; 36 37 template <typename S> 38 struct format_string_char< 39 S, enable_if_t<std::is_base_of<detail::compile_string, S>::value>> { 40 using type = typename S::char_type; 41 }; 42 43 template <typename S> 44 using format_string_char_t = typename format_string_char<S>::type; 45 46 inline auto write_loc(basic_appender<wchar_t> out, loc_value value, 47 const format_specs& specs, locale_ref loc) -> bool { 48 #if FMT_USE_LOCALE 49 auto& numpunct = 50 std::use_facet<std::numpunct<wchar_t>>(loc.get<std::locale>()); 51 auto separator = std::wstring(); 52 auto grouping = numpunct.grouping(); 53 if (!grouping.empty()) separator = std::wstring(1, numpunct.thousands_sep()); 54 return value.visit(loc_writer<wchar_t>{out, specs, separator, grouping, {}}); 55 #endif 56 return false; 57 } 58 } // namespace detail 59 60 FMT_BEGIN_EXPORT 61 62 using wstring_view = basic_string_view<wchar_t>; 63 using wformat_parse_context = parse_context<wchar_t>; 64 using wformat_context = buffered_context<wchar_t>; 65 using wformat_args = basic_format_args<wformat_context>; 66 using wmemory_buffer = basic_memory_buffer<wchar_t>; 67 68 template <typename Char, typename... T> struct basic_fstring { 69 private: 70 basic_string_view<Char> str_; 71 72 static constexpr int num_static_named_args = 73 detail::count_static_named_args<T...>(); 74 75 using checker = detail::format_string_checker< 76 Char, static_cast<int>(sizeof...(T)), num_static_named_args, 77 num_static_named_args != detail::count_named_args<T...>()>; 78 79 using arg_pack = detail::arg_pack<T...>; 80 81 public: 82 using t = basic_fstring; 83 84 template <typename S, 85 FMT_ENABLE_IF( 86 std::is_convertible<const S&, basic_string_view<Char>>::value)> 87 FMT_CONSTEVAL FMT_ALWAYS_INLINE basic_fstring(const S& s) : str_(s) { 88 if (FMT_USE_CONSTEVAL) 89 detail::parse_format_string<Char>(s, checker(s, arg_pack())); 90 } 91 template <typename S, 92 FMT_ENABLE_IF(std::is_base_of<detail::compile_string, S>::value&& 93 std::is_same<typename S::char_type, Char>::value)> 94 FMT_ALWAYS_INLINE basic_fstring(const S&) : str_(S()) { 95 FMT_CONSTEXPR auto sv = basic_string_view<Char>(S()); 96 FMT_CONSTEXPR int ignore = 97 (parse_format_string(sv, checker(sv, arg_pack())), 0); 98 detail::ignore_unused(ignore); 99 } 100 basic_fstring(runtime_format_string<Char> fmt) : str_(fmt.str) {} 101 102 operator basic_string_view<Char>() const { return str_; } 103 auto get() const -> basic_string_view<Char> { return str_; } 104 }; 105 106 template <typename Char, typename... T> 107 using basic_format_string = basic_fstring<Char, T...>; 108 109 template <typename... T> 110 using wformat_string = typename basic_format_string<wchar_t, T...>::t; 111 inline auto runtime(wstring_view s) -> runtime_format_string<wchar_t> { 112 return {{s}}; 113 } 114 115 template <> struct is_char<wchar_t> : std::true_type {}; 116 template <> struct is_char<char16_t> : std::true_type {}; 117 template <> struct is_char<char32_t> : std::true_type {}; 118 119 #ifdef __cpp_char8_t 120 template <> struct is_char<char8_t> : bool_constant<detail::is_utf8_enabled> {}; 121 #endif 122 123 template <typename... T> 124 constexpr auto make_wformat_args(T&... args) 125 -> decltype(fmt::make_format_args<wformat_context>(args...)) { 126 return fmt::make_format_args<wformat_context>(args...); 127 } 128 129 #if !FMT_USE_NONTYPE_TEMPLATE_ARGS 130 inline namespace literals { 131 inline auto operator""_a(const wchar_t* s, size_t) -> detail::udl_arg<wchar_t> { 132 return {s}; 133 } 134 } // namespace literals 135 #endif 136 137 template <typename It, typename Sentinel> 138 auto join(It begin, Sentinel end, wstring_view sep) 139 -> join_view<It, Sentinel, wchar_t> { 140 return {begin, end, sep}; 141 } 142 143 template <typename Range> 144 auto join(Range&& range, wstring_view sep) 145 -> join_view<decltype(std::begin(range)), decltype(std::end(range)), 146 wchar_t> { 147 return join(std::begin(range), std::end(range), sep); 148 } 149 150 template <typename T> 151 auto join(std::initializer_list<T> list, wstring_view sep) 152 -> join_view<const T*, const T*, wchar_t> { 153 return join(std::begin(list), std::end(list), sep); 154 } 155 156 template <typename... T> 157 auto join(const std::tuple<T...>& tuple, basic_string_view<wchar_t> sep) 158 -> tuple_join_view<wchar_t, T...> { 159 return {tuple, sep}; 160 } 161 162 template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)> 163 auto vformat(basic_string_view<Char> fmt, 164 typename detail::vformat_args<Char>::type args) 165 -> std::basic_string<Char> { 166 auto buf = basic_memory_buffer<Char>(); 167 detail::vformat_to(buf, fmt, args); 168 return {buf.data(), buf.size()}; 169 } 170 171 template <typename... T> 172 auto format(wformat_string<T...> fmt, T&&... args) -> std::wstring { 173 return vformat(fmt::wstring_view(fmt), fmt::make_wformat_args(args...)); 174 } 175 176 template <typename OutputIt, typename... T> 177 auto format_to(OutputIt out, wformat_string<T...> fmt, T&&... args) 178 -> OutputIt { 179 return vformat_to(out, fmt::wstring_view(fmt), 180 fmt::make_wformat_args(args...)); 181 } 182 183 // Pass char_t as a default template parameter instead of using 184 // std::basic_string<char_t<S>> to reduce the symbol size. 185 template <typename S, typename... T, 186 typename Char = detail::format_string_char_t<S>, 187 FMT_ENABLE_IF(!std::is_same<Char, char>::value && 188 !std::is_same<Char, wchar_t>::value)> 189 auto format(const S& fmt, T&&... args) -> std::basic_string<Char> { 190 return vformat(detail::to_string_view(fmt), 191 fmt::make_format_args<buffered_context<Char>>(args...)); 192 } 193 194 template <typename S, typename Char = detail::format_string_char_t<S>, 195 FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)> 196 inline auto vformat(detail::locale_ref loc, const S& fmt, 197 typename detail::vformat_args<Char>::type args) 198 -> std::basic_string<Char> { 199 auto buf = basic_memory_buffer<Char>(); 200 detail::vformat_to(buf, detail::to_string_view(fmt), args, 201 detail::locale_ref(loc)); 202 return {buf.data(), buf.size()}; 203 } 204 205 template <typename S, typename... T, 206 typename Char = detail::format_string_char_t<S>, 207 FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)> 208 inline auto format(detail::locale_ref loc, const S& fmt, T&&... args) 209 -> std::basic_string<Char> { 210 return vformat(loc, detail::to_string_view(fmt), 211 fmt::make_format_args<buffered_context<Char>>(args...)); 212 } 213 214 template <typename OutputIt, typename S, 215 typename Char = detail::format_string_char_t<S>, 216 FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& 217 detail::is_exotic_char<Char>::value)> 218 auto vformat_to(OutputIt out, const S& fmt, 219 typename detail::vformat_args<Char>::type args) -> OutputIt { 220 auto&& buf = detail::get_buffer<Char>(out); 221 detail::vformat_to(buf, detail::to_string_view(fmt), args); 222 return detail::get_iterator(buf, out); 223 } 224 225 template <typename OutputIt, typename S, typename... T, 226 typename Char = detail::format_string_char_t<S>, 227 FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value && 228 !std::is_same<Char, char>::value && 229 !std::is_same<Char, wchar_t>::value)> 230 inline auto format_to(OutputIt out, const S& fmt, T&&... args) -> OutputIt { 231 return vformat_to(out, detail::to_string_view(fmt), 232 fmt::make_format_args<buffered_context<Char>>(args...)); 233 } 234 235 template <typename S, typename OutputIt, typename... Args, 236 typename Char = detail::format_string_char_t<S>, 237 FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& 238 detail::is_exotic_char<Char>::value)> 239 inline auto vformat_to(OutputIt out, detail::locale_ref loc, const S& fmt, 240 typename detail::vformat_args<Char>::type args) 241 -> OutputIt { 242 auto&& buf = detail::get_buffer<Char>(out); 243 vformat_to(buf, detail::to_string_view(fmt), args, detail::locale_ref(loc)); 244 return detail::get_iterator(buf, out); 245 } 246 247 template <typename OutputIt, typename S, typename... T, 248 typename Char = detail::format_string_char_t<S>, 249 bool enable = detail::is_output_iterator<OutputIt, Char>::value && 250 detail::is_exotic_char<Char>::value> 251 inline auto format_to(OutputIt out, detail::locale_ref loc, const S& fmt, 252 T&&... args) -> 253 typename std::enable_if<enable, OutputIt>::type { 254 return vformat_to(out, loc, detail::to_string_view(fmt), 255 fmt::make_format_args<buffered_context<Char>>(args...)); 256 } 257 258 template <typename OutputIt, typename Char, typename... Args, 259 FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& 260 detail::is_exotic_char<Char>::value)> 261 inline auto vformat_to_n(OutputIt out, size_t n, basic_string_view<Char> fmt, 262 typename detail::vformat_args<Char>::type args) 263 -> format_to_n_result<OutputIt> { 264 using traits = detail::fixed_buffer_traits; 265 auto buf = detail::iterator_buffer<OutputIt, Char, traits>(out, n); 266 detail::vformat_to(buf, fmt, args); 267 return {buf.out(), buf.count()}; 268 } 269 270 template <typename OutputIt, typename S, typename... T, 271 typename Char = detail::format_string_char_t<S>, 272 FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& 273 detail::is_exotic_char<Char>::value)> 274 inline auto format_to_n(OutputIt out, size_t n, const S& fmt, T&&... args) 275 -> format_to_n_result<OutputIt> { 276 return vformat_to_n(out, n, fmt::basic_string_view<Char>(fmt), 277 fmt::make_format_args<buffered_context<Char>>(args...)); 278 } 279 280 template <typename S, typename... T, 281 typename Char = detail::format_string_char_t<S>, 282 FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)> 283 inline auto formatted_size(const S& fmt, T&&... args) -> size_t { 284 auto buf = detail::counting_buffer<Char>(); 285 detail::vformat_to(buf, detail::to_string_view(fmt), 286 fmt::make_format_args<buffered_context<Char>>(args...)); 287 return buf.count(); 288 } 289 290 inline void vprint(std::FILE* f, wstring_view fmt, wformat_args args) { 291 auto buf = wmemory_buffer(); 292 detail::vformat_to(buf, fmt, args); 293 buf.push_back(L'\0'); 294 if (std::fputws(buf.data(), f) == -1) 295 FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); 296 } 297 298 inline void vprint(wstring_view fmt, wformat_args args) { 299 vprint(stdout, fmt, args); 300 } 301 302 template <typename... T> 303 void print(std::FILE* f, wformat_string<T...> fmt, T&&... args) { 304 return vprint(f, wstring_view(fmt), fmt::make_wformat_args(args...)); 305 } 306 307 template <typename... T> void print(wformat_string<T...> fmt, T&&... args) { 308 return vprint(wstring_view(fmt), fmt::make_wformat_args(args...)); 309 } 310 311 template <typename... T> 312 void println(std::FILE* f, wformat_string<T...> fmt, T&&... args) { 313 return print(f, L"{}\n", fmt::format(fmt, std::forward<T>(args)...)); 314 } 315 316 template <typename... T> void println(wformat_string<T...> fmt, T&&... args) { 317 return print(L"{}\n", fmt::format(fmt, std::forward<T>(args)...)); 318 } 319 320 inline auto vformat(const text_style& ts, wstring_view fmt, wformat_args args) 321 -> std::wstring { 322 auto buf = wmemory_buffer(); 323 detail::vformat_to(buf, ts, fmt, args); 324 return {buf.data(), buf.size()}; 325 } 326 327 template <typename... T> 328 inline auto format(const text_style& ts, wformat_string<T...> fmt, T&&... args) 329 -> std::wstring { 330 return fmt::vformat(ts, fmt, fmt::make_wformat_args(args...)); 331 } 332 333 template <typename... T> 334 FMT_DEPRECATED void print(std::FILE* f, const text_style& ts, 335 wformat_string<T...> fmt, const T&... args) { 336 vprint(f, ts, fmt, fmt::make_wformat_args(args...)); 337 } 338 339 template <typename... T> 340 FMT_DEPRECATED void print(const text_style& ts, wformat_string<T...> fmt, 341 const T&... args) { 342 return print(stdout, ts, fmt, args...); 343 } 344 345 inline void vprint(std::wostream& os, wstring_view fmt, wformat_args args) { 346 auto buffer = basic_memory_buffer<wchar_t>(); 347 detail::vformat_to(buffer, fmt, args); 348 detail::write_buffer(os, buffer); 349 } 350 351 template <typename... T> 352 void print(std::wostream& os, wformat_string<T...> fmt, T&&... args) { 353 vprint(os, fmt, fmt::make_format_args<buffered_context<wchar_t>>(args...)); 354 } 355 356 template <typename... T> 357 void println(std::wostream& os, wformat_string<T...> fmt, T&&... args) { 358 print(os, L"{}\n", fmt::format(fmt, std::forward<T>(args)...)); 359 } 360 361 /// Converts `value` to `std::wstring` using the default format for type `T`. 362 template <typename T> inline auto to_wstring(const T& value) -> std::wstring { 363 return format(FMT_STRING(L"{}"), value); 364 } 365 FMT_END_EXPORT 366 FMT_END_NAMESPACE 367 368 #endif // FMT_XCHAR_H_ 369