blob: 513834f6b8f4eaccffae858b28752f52775bd289 [file] [log] [blame]
Victor Zverovichc0954452018-01-06 09:09:50 -08001// Formatting library for C++
2//
3// Copyright (c) 2012 - 2016, Victor Zverovich
4// All rights reserved.
5//
6// For the license information refer to format.h.
Victor Zverovichb076df42012-12-07 08:31:09 -08007
Victor Zverovich3da71d52018-03-21 07:50:59 -07008#ifndef FMT_FORMAT_INL_H_
9#define FMT_FORMAT_INL_H_
10
Victor Zverovichf853d942018-01-20 10:28:10 -080011#include "format.h"
Victor Zverovichfbfedcf2013-01-14 15:16:20 -080012
Victor Zverovich859a4972014-04-30 06:55:21 -070013#include <string.h>
14
Victor Zverovich72f896d2012-12-12 09:17:28 -080015#include <cctype>
Victor Zverovich5d15bdd2014-07-01 16:23:50 -070016#include <cerrno>
Victor Zverovichf28645f2014-04-24 12:37:06 -070017#include <climits>
Victor Zverovich9ff3b972013-09-07 10:15:08 -070018#include <cmath>
Victor Zverovicha684d0c2013-12-27 08:00:10 -080019#include <cstdarg>
vitaut7dcf0512015-11-13 06:52:13 -080020#include <cstddef> // for std::ptrdiff_t
Victor Zverovich0de44a42018-08-26 08:12:35 -070021#include <cstring> // for std::memmove
Thomas Bernardabde38b2018-08-17 11:22:56 +020022#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
23# include <locale>
24#endif
Victor Zverovich9ff3b972013-09-07 10:15:08 -070025
vitaut24c309f2015-06-12 07:15:57 -070026#if FMT_USE_WINDOWS_H
Victor Zverovichc753a2a2018-01-28 20:26:25 -080027# if !defined(FMT_HEADER_ONLY) && !defined(WIN32_LEAN_AND_MEAN)
28# define WIN32_LEAN_AND_MEAN
29# endif
vitaut67ce3942015-04-30 07:48:36 -070030# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)
31# include <windows.h>
32# else
33# define NOMINMAX
34# include <windows.h>
35# undef NOMINMAX
36# endif
Ryuuke5a9dc8f2015-02-08 16:08:29 +000037#endif
38
Victor Zverovich8b76e972014-10-06 08:30:55 -070039#if FMT_EXCEPTIONS
40# define FMT_TRY try
41# define FMT_CATCH(x) catch (x)
42#else
43# define FMT_TRY if (true)
44# define FMT_CATCH(x) if (false)
45#endif
46
Ingo van Lilb4b13ee2015-11-02 12:34:46 +010047#ifdef _MSC_VER
jdale88a9862fd2014-03-11 18:56:24 +000048# pragma warning(push)
Victor Zverovich8b76e972014-10-06 08:30:55 -070049# pragma warning(disable: 4127) // conditional expression is constant
Daniel.Perrybd0067e2014-11-25 18:01:09 -050050# pragma warning(disable: 4702) // unreachable code
vitautdf47d812015-03-16 18:53:14 -070051// Disable deprecation warning for strerror. The latter is not called but
52// MSVC fails to detect it.
53# pragma warning(disable: 4996)
jdale88a9862fd2014-03-11 18:56:24 +000054#endif
55
vitaut341b98c2015-03-14 13:39:33 -070056// Dummy implementations of strerror_r and strerror_s called if corresponding
57// system functions are not available.
Victor Zverovich6cb68f92018-02-10 06:28:33 -080058inline fmt::internal::null<> strerror_r(int, char *, ...) {
Victor Zverovichc333dca2017-02-19 08:41:38 -080059 return fmt::internal::null<>();
vitaut341b98c2015-03-14 13:39:33 -070060}
Victor Zverovich6cb68f92018-02-10 06:28:33 -080061inline fmt::internal::null<> strerror_s(char *, std::size_t, ...) {
Victor Zverovichc333dca2017-02-19 08:41:38 -080062 return fmt::internal::null<>();
vitaut341b98c2015-03-14 13:39:33 -070063}
64
Victor Zverovich838400d2018-05-12 08:33:51 -070065FMT_BEGIN_NAMESPACE
Victor Zverovichb26e76e2016-06-14 08:11:33 -070066
Victor Zverovich9ff3b972013-09-07 10:15:08 -070067namespace {
68
69#ifndef _MSC_VER
Victor Zverovichb9a568b2014-09-19 07:51:42 -070070# define FMT_SNPRINTF snprintf
Victor Zverovicha684d0c2013-12-27 08:00:10 -080071#else // _MSC_VER
Victor Zverovich406c6122014-08-19 08:47:38 -070072inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {
Victor Zverovicha684d0c2013-12-27 08:00:10 -080073 va_list args;
74 va_start(args, format);
75 int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
76 va_end(args);
77 return result;
78}
Victor Zverovichb9a568b2014-09-19 07:51:42 -070079# define FMT_SNPRINTF fmt_snprintf
Victor Zverovich9ff3b972013-09-07 10:15:08 -070080#endif // _MSC_VER
Victor Zverovich43fe1002014-02-19 14:20:26 -080081
cstamford55836ca2015-03-10 07:04:31 +000082#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
83# define FMT_SWPRINTF snwprintf
84#else
85# define FMT_SWPRINTF swprintf
86#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)
87
Victor Zverovichc2fecb92018-01-14 14:15:59 -080088typedef void (*FormatFunc)(internal::buffer &, int, string_view);
Victor Zverovich22f75d82014-09-03 08:03:05 -070089
Victor Zverovichf2c9df82014-09-05 08:44:41 -070090// Portable thread-safe version of strerror.
91// Sets buffer to point to a string describing the error code.
92// This can be either a pointer to a string stored in buffer,
93// or a pointer to some static immutable string.
94// Returns one of the following values:
95// 0 - success
96// ERANGE - buffer is not large enough to store the error message
97// other - failure
98// Buffer should be at least of size 1.
99int safe_strerror(
Carter Lie2583ab2015-02-14 09:58:29 +0800100 int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {
Victor Zverovich92a250f2018-02-07 07:16:00 -0800101 FMT_ASSERT(buffer != FMT_NULL && buffer_size != 0, "invalid buffer");
vitaut341b98c2015-03-14 13:39:33 -0700102
Victor Zverovich69823bf2018-05-19 08:57:31 -0700103 class dispatcher {
vitaut341b98c2015-03-14 13:39:33 -0700104 private:
105 int error_code_;
106 char *&buffer_;
107 std::size_t buffer_size_;
108
vitautda052ae2015-03-21 07:53:39 -0700109 // A noop assignment operator to avoid bogus warnings.
Victor Zverovich69823bf2018-05-19 08:57:31 -0700110 void operator=(const dispatcher &) {}
vitautda052ae2015-03-21 07:53:39 -0700111
vitaut341b98c2015-03-14 13:39:33 -0700112 // Handle the result of XSI-compliant version of strerror_r.
113 int handle(int result) {
vitaute1776ac2015-03-14 14:05:02 -0700114 // glibc versions before 2.13 return result in errno.
115 return result == -1 ? errno : result;
vitaut341b98c2015-03-14 13:39:33 -0700116 }
117
118 // Handle the result of GNU-specific version of strerror_r.
119 int handle(char *message) {
120 // If the buffer is full then the message is probably truncated.
121 if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)
122 return ERANGE;
123 buffer_ = message;
124 return 0;
125 }
126
127 // Handle the case when strerror_r is not available.
Victor Zverovichc333dca2017-02-19 08:41:38 -0800128 int handle(internal::null<>) {
vitaut341b98c2015-03-14 13:39:33 -0700129 return fallback(strerror_s(buffer_, buffer_size_, error_code_));
130 }
131
132 // Fallback to strerror_s when strerror_r is not available.
133 int fallback(int result) {
134 // If the buffer is full then the message is probably truncated.
135 return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?
136 ERANGE : result;
137 }
138
139 // Fallback to strerror if strerror_r and strerror_s are not available.
Victor Zverovichc333dca2017-02-19 08:41:38 -0800140 int fallback(internal::null<>) {
vitaut341b98c2015-03-14 13:39:33 -0700141 errno = 0;
142 buffer_ = strerror(error_code_);
143 return errno;
144 }
145
146 public:
Victor Zverovich69823bf2018-05-19 08:57:31 -0700147 dispatcher(int err_code, char *&buf, std::size_t buf_size)
Radu Popescu0affb232015-08-04 12:52:44 +0200148 : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {}
vitaut341b98c2015-03-14 13:39:33 -0700149
vitaut63f6c102015-06-14 09:36:23 -0700150 int run() {
vitaut63f6c102015-06-14 09:36:23 -0700151 return handle(strerror_r(error_code_, buffer_, buffer_size_));
152 }
vitaut341b98c2015-03-14 13:39:33 -0700153 };
Victor Zverovich69823bf2018-05-19 08:57:31 -0700154 return dispatcher(error_code, buffer, buffer_size).run();
Victor Zverovichf2c9df82014-09-05 08:44:41 -0700155}
156
Victor Zverovichc2fecb92018-01-14 14:15:59 -0800157void format_error_code(internal::buffer &out, int error_code,
Victor Zverovich50e71672017-02-18 06:52:52 -0800158 string_view message) FMT_NOEXCEPT {
Victor Zverovich22f75d82014-09-03 08:03:05 -0700159 // Report error code making sure that the output fits into
Victor Zverovichf1ede632018-03-04 10:33:42 -0800160 // inline_buffer_size to avoid dynamic memory allocation and potential
Victor Zverovich22f75d82014-09-03 08:03:05 -0700161 // bad_alloc.
Victor Zverovichf423e462017-03-11 07:43:26 -0800162 out.resize(0);
Victor Zverovich22f75d82014-09-03 08:03:05 -0700163 static const char SEP[] = ": ";
vitaut1addec92015-03-21 20:16:36 -0700164 static const char ERROR_STR[] = "error ";
vitaut1addec92015-03-21 20:16:36 -0700165 // Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
166 std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800167 typedef internal::int_traits<int>::main_type main_type;
168 main_type abs_value = static_cast<main_type>(error_code);
vitaut9d577ca2016-03-02 07:01:21 -0800169 if (internal::is_negative(error_code)) {
170 abs_value = 0 - abs_value;
171 ++error_code_size;
172 }
vitautbfdca8b2016-04-20 09:11:33 -0700173 error_code_size += internal::count_digits(abs_value);
Victor Zverovich217e7c72018-01-14 07:19:23 -0800174 writer w(out);
Victor Zverovichf1ede632018-03-04 10:33:42 -0800175 if (message.size() <= inline_buffer_size - error_code_size) {
Victor Zverovichfefaf072017-02-14 16:29:47 -0500176 w.write(message);
177 w.write(SEP);
Victor Zverovichec15ef72017-01-22 07:40:21 -0800178 }
Victor Zverovichfefaf072017-02-14 16:29:47 -0500179 w.write(ERROR_STR);
180 w.write(error_code);
Victor Zverovichf1ede632018-03-04 10:33:42 -0800181 assert(out.size() <= inline_buffer_size);
Victor Zverovich22f75d82014-09-03 08:03:05 -0700182}
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700183
vitautbfdca8b2016-04-20 09:11:33 -0700184void report_error(FormatFunc func, int error_code,
Victor Zverovich50e71672017-02-18 06:52:52 -0800185 string_view message) FMT_NOEXCEPT {
Victor Zverovicheedfd072017-02-18 09:13:12 -0800186 memory_buffer full_message;
Victor Zverovich88e0db82014-09-05 08:04:26 -0700187 func(full_message, error_code, message);
188 // Use Writer::data instead of Writer::c_str to avoid potential memory
189 // allocation.
190 std::fwrite(full_message.data(), full_message.size(), 1, stderr);
191 std::fputc('\n', stderr);
Victor Zverovichb605b392013-09-09 22:21:40 -0700192}
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700193} // namespace
vitaut270069b2015-06-16 07:36:32 -0700194
Victor Zverovich38325242018-10-03 18:22:26 -0700195FMT_FUNC size_t internal::count_code_points(basic_string_view<char8_t> s) {
Victor Zverovichf8027412018-09-30 11:39:20 -0700196 const char8_t *data = s.data();
197 size_t num_code_points = 0;
198 for (size_t i = 0, size = s.size(); i != size; ++i) {
199 if ((data[i] & 0xc0) != 0x80)
200 ++num_code_points;
201 }
202 return num_code_points;
203}
204
Thomas Bernardabde38b2018-08-17 11:22:56 +0200205#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
Victor Zverovichf8027412018-09-30 11:39:20 -0700206namespace internal {
Victor Zverovichf2ee9882018-11-14 09:39:37 -0800207
208template <typename Locale>
209locale_ref::locale_ref(const Locale &loc) : locale_(&loc) {
210 static_assert(std::is_same<Locale, std::locale>::value, "");
211}
212
213template <typename Locale>
214Locale locale_ref::get() const {
215 static_assert(std::is_same<Locale, std::locale>::value, "");
216 return locale_ ? *static_cast<const std::locale*>(locale_) : std::locale();
217}
218
Victor Zverovich7f351de2017-12-03 09:18:06 -0800219template <typename Char>
Victor Zverovichf2ee9882018-11-14 09:39:37 -0800220FMT_FUNC Char thousands_sep_impl(locale_ref loc) {
221 return std::use_facet<std::numpunct<Char> >(
222 loc.get<std::locale>()).thousands_sep();
Victor Zverovich7f351de2017-12-03 09:18:06 -0800223}
Victor Zverovichf8027412018-09-30 11:39:20 -0700224}
Thomas Bernardabde38b2018-08-17 11:22:56 +0200225#else
226template <typename Char>
Victor Zverovichf2ee9882018-11-14 09:39:37 -0800227FMT_FUNC Char internal::thousands_sep(locale_ref) {
Thomas Bernardabde38b2018-08-17 11:22:56 +0200228 return FMT_STATIC_THOUSANDS_SEPARATOR;
229}
230#endif
Victor Zverovich7f351de2017-12-03 09:18:06 -0800231
Victor Zverovichc333dca2017-02-19 08:41:38 -0800232FMT_FUNC void system_error::init(
Victor Zverovich81bd9e82017-12-03 07:32:04 -0800233 int err_code, string_view format_str, format_args args) {
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800234 error_code_ = err_code;
Victor Zverovicheedfd072017-02-18 09:13:12 -0800235 memory_buffer buffer;
236 format_system_error(buffer, err_code, vformat(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700237 std::runtime_error &base = *this;
Victor Zverovicheedfd072017-02-18 09:13:12 -0800238 base = std::runtime_error(to_string(buffer));
Victor Zverovich53201032014-06-30 14:26:29 -0700239}
240
Victor Zverovichcd900972018-04-21 17:26:24 -0700241namespace internal {
Victor Zverovichb605b392013-09-09 22:21:40 -0700242template <typename T>
Victor Zverovichcd900972018-04-21 17:26:24 -0700243int char_traits<char>::format_float(
Victor Zverovichb60a5c52018-05-28 20:16:30 -0700244 char *buffer, std::size_t size, const char *format, int precision, T value) {
Victor Zverovichb605b392013-09-09 22:21:40 -0700245 return precision < 0 ?
Victor Zverovichb60a5c52018-05-28 20:16:30 -0700246 FMT_SNPRINTF(buffer, size, format, value) :
247 FMT_SNPRINTF(buffer, size, format, precision, value);
Victor Zverovichb605b392013-09-09 22:21:40 -0700248}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700249
Victor Zverovichb605b392013-09-09 22:21:40 -0700250template <typename T>
Victor Zverovichcd900972018-04-21 17:26:24 -0700251int char_traits<wchar_t>::format_float(
Victor Zverovichb60a5c52018-05-28 20:16:30 -0700252 wchar_t *buffer, std::size_t size, const wchar_t *format, int precision,
253 T value) {
Victor Zverovichb605b392013-09-09 22:21:40 -0700254 return precision < 0 ?
Victor Zverovichb60a5c52018-05-28 20:16:30 -0700255 FMT_SWPRINTF(buffer, size, format, value) :
256 FMT_SWPRINTF(buffer, size, format, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700257}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800258
Victor Zverovich311251e2014-11-29 06:58:00 -0800259template <typename T>
Victor Zverovichcd900972018-04-21 17:26:24 -0700260const char basic_data<T>::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800261 "0001020304050607080910111213141516171819"
262 "2021222324252627282930313233343536373839"
263 "4041424344454647484950515253545556575859"
264 "6061626364656667686970717273747576777879"
265 "8081828384858687888990919293949596979899";
Victor Zveroviche9b21912014-02-19 12:43:55 -0800266
Victor Zverovichf1d85162014-02-19 13:02:22 -0800267#define FMT_POWERS_OF_10(factor) \
268 factor * 10, \
269 factor * 100, \
270 factor * 1000, \
271 factor * 10000, \
272 factor * 100000, \
273 factor * 1000000, \
274 factor * 10000000, \
275 factor * 100000000, \
276 factor * 1000000000
Victor Zveroviche9b21912014-02-19 12:43:55 -0800277
Victor Zverovich311251e2014-11-29 06:58:00 -0800278template <typename T>
Victor Zverovichcd900972018-04-21 17:26:24 -0700279const uint32_t basic_data<T>::POWERS_OF_10_32[] = {
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700280 1, FMT_POWERS_OF_10(1)
281};
282
283template <typename T>
284const uint32_t basic_data<T>::ZERO_OR_POWERS_OF_10_32[] = {
Victor Zverovich311251e2014-11-29 06:58:00 -0800285 0, FMT_POWERS_OF_10(1)
286};
287
288template <typename T>
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700289const uint64_t basic_data<T>::ZERO_OR_POWERS_OF_10_64[] = {
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800290 0,
Victor Zverovichf1d85162014-02-19 13:02:22 -0800291 FMT_POWERS_OF_10(1),
Victor Zverovich016aceb2017-08-26 09:09:43 -0700292 FMT_POWERS_OF_10(1000000000ull),
293 10000000000000000000ull
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800294};
Victor Zverovich877abaf2013-01-08 09:56:05 -0800295
Victor Zverovich2768af22018-04-29 06:33:05 -0700296// Normalized 64-bit significands of pow(10, k), for k = -348, -340, ..., 340.
297// These are generated by support/compute-powers.py.
298template <typename T>
299const uint64_t basic_data<T>::POW10_SIGNIFICANDS[] = {
Victor Zverovich9de31212018-08-15 06:54:43 -0700300 0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, 0x8b16fb203055ac76,
301 0xcf42894a5dce35ea, 0x9a6bb0aa55653b2d, 0xe61acf033d1a45df,
302 0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f, 0xbe5691ef416bd60c,
303 0x8dd01fad907ffc3c, 0xd3515c2831559a83, 0x9d71ac8fada6c9b5,
304 0xea9c227723ee8bcb, 0xaecc49914078536d, 0x823c12795db6ce57,
305 0xc21094364dfb5637, 0x9096ea6f3848984f, 0xd77485cb25823ac7,
306 0xa086cfcd97bf97f4, 0xef340a98172aace5, 0xb23867fb2a35b28e,
307 0x84c8d4dfd2c63f3b, 0xc5dd44271ad3cdba, 0x936b9fcebb25c996,
308 0xdbac6c247d62a584, 0xa3ab66580d5fdaf6, 0xf3e2f893dec3f126,
309 0xb5b5ada8aaff80b8, 0x87625f056c7c4a8b, 0xc9bcff6034c13053,
310 0x964e858c91ba2655, 0xdff9772470297ebd, 0xa6dfbd9fb8e5b88f,
311 0xf8a95fcf88747d94, 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b,
312 0xcdb02555653131b6, 0x993fe2c6d07b7fac, 0xe45c10c42a2b3b06,
313 0xaa242499697392d3, 0xfd87b5f28300ca0e, 0xbce5086492111aeb,
314 0x8cbccc096f5088cc, 0xd1b71758e219652c, 0x9c40000000000000,
315 0xe8d4a51000000000, 0xad78ebc5ac620000, 0x813f3978f8940984,
316 0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70, 0xd5d238a4abe98068,
317 0x9f4f2726179a2245, 0xed63a231d4c4fb27, 0xb0de65388cc8ada8,
318 0x83c7088e1aab65db, 0xc45d1df942711d9a, 0x924d692ca61be758,
319 0xda01ee641a708dea, 0xa26da3999aef774a, 0xf209787bb47d6b85,
320 0xb454e4a179dd1877, 0x865b86925b9bc5c2, 0xc83553c5c8965d3d,
321 0x952ab45cfa97a0b3, 0xde469fbd99a05fe3, 0xa59bc234db398c25,
322 0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece, 0x88fcf317f22241e2,
323 0xcc20ce9bd35c78a5, 0x98165af37b2153df, 0xe2a0b5dc971f303a,
324 0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c, 0xbb764c4ca7a44410,
325 0x8bab8eefb6409c1a, 0xd01fef10a657842c, 0x9b10a4e5e9913129,
326 0xe7109bfba19c0c9d, 0xac2820d9623bf429, 0x80444b5e7aa7cf85,
327 0xbf21e44003acdd2d, 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841,
328 0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, 0xaf87023b9bf0ee6b,
Victor Zverovich2768af22018-04-29 06:33:05 -0700329};
330
331// Binary exponents of pow(10, k), for k = -348, -340, ..., 340, corresponding
332// to significands above.
333template <typename T>
334const int16_t basic_data<T>::POW10_EXPONENTS[] = {
335 -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954,
336 -927, -901, -874, -847, -821, -794, -768, -741, -715, -688, -661,
337 -635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369,
338 -343, -316, -289, -263, -236, -210, -183, -157, -130, -103, -77,
339 -50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216,
340 242, 269, 295, 322, 348, 375, 402, 428, 455, 481, 508,
341 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800,
342 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066
343};
344
Daniela Engert73c53d72018-09-17 18:21:24 +0200345template <typename T> const char basic_data<T>::FOREGROUND_COLOR[] = "\x1b[38;2;";
346template <typename T> const char basic_data<T>::BACKGROUND_COLOR[] = "\x1b[48;2;";
Dhruv Paranjapeec218a32018-06-28 10:43:00 +0530347template <typename T> const char basic_data<T>::RESET_COLOR[] = "\x1b[0m";
348template <typename T> const wchar_t basic_data<T>::WRESET_COLOR[] = L"\x1b[0m";
349
Victor Zverovichdd8c5ce2018-08-29 09:34:57 -0700350// A handmade floating-point number f * pow(2, e).
351class fp {
352 private:
353 typedef uint64_t significand_type;
354
355 // All sizes are in bits.
356 static FMT_CONSTEXPR_DECL const int char_size =
357 std::numeric_limits<unsigned char>::digits;
358 // Subtract 1 to account for an implicit most significant bit in the
359 // normalized form.
360 static FMT_CONSTEXPR_DECL const int double_significand_size =
361 std::numeric_limits<double>::digits - 1;
362 static FMT_CONSTEXPR_DECL const uint64_t implicit_bit =
363 1ull << double_significand_size;
364
365 public:
366 significand_type f;
367 int e;
368
369 static FMT_CONSTEXPR_DECL const int significand_size =
370 sizeof(significand_type) * char_size;
371
372 fp(): f(0), e(0) {}
373 fp(uint64_t f, int e): f(f), e(e) {}
374
375 // Constructs fp from an IEEE754 double. It is a template to prevent compile
376 // errors on platforms where double is not IEEE754.
377 template <typename Double>
378 explicit fp(Double d) {
379 // Assume double is in the format [sign][exponent][significand].
380 typedef std::numeric_limits<Double> limits;
medithe8cbfb6e2018-09-11 15:14:39 +0200381 const int double_size = static_cast<int>(sizeof(Double) * char_size);
Victor Zverovichdd8c5ce2018-08-29 09:34:57 -0700382 const int exponent_size =
383 double_size - double_significand_size - 1; // -1 for sign
384 const uint64_t significand_mask = implicit_bit - 1;
385 const uint64_t exponent_mask = (~0ull >> 1) & ~significand_mask;
386 const int exponent_bias = (1 << exponent_size) - limits::max_exponent - 1;
387 auto u = bit_cast<uint64_t>(d);
388 auto biased_e = (u & exponent_mask) >> double_significand_size;
389 f = u & significand_mask;
390 if (biased_e != 0)
391 f += implicit_bit;
392 else
393 biased_e = 1; // Subnormals use biased exponent 1 (min exponent).
394 e = static_cast<int>(biased_e - exponent_bias - double_significand_size);
395 }
396
397 // Normalizes the value converted from double and multiplied by (1 << SHIFT).
398 template <int SHIFT = 0>
399 void normalize() {
400 // Handle subnormals.
401 auto shifted_implicit_bit = implicit_bit << SHIFT;
402 while ((f & shifted_implicit_bit) == 0) {
403 f <<= 1;
404 --e;
405 }
406 // Subtract 1 to account for hidden bit.
407 auto offset = significand_size - double_significand_size - SHIFT - 1;
408 f <<= offset;
409 e -= offset;
410 }
411
412 // Compute lower and upper boundaries (m^- and m^+ in the Grisu paper), where
413 // a boundary is a value half way between the number and its predecessor
414 // (lower) or successor (upper). The upper boundary is normalized and lower
415 // has the same exponent but may be not normalized.
416 void compute_boundaries(fp &lower, fp &upper) const {
417 lower = f == implicit_bit ?
418 fp((f << 2) - 1, e - 2) : fp((f << 1) - 1, e - 1);
419 upper = fp((f << 1) + 1, e - 1);
420 upper.normalize<1>(); // 1 is to account for the exponent shift above.
421 lower.f <<= lower.e - upper.e;
422 lower.e = upper.e;
423 }
424};
425
426// Returns an fp number representing x - y. Result may not be normalized.
427inline fp operator-(fp x, fp y) {
428 FMT_ASSERT(x.f >= y.f && x.e == y.e, "invalid operands");
429 return fp(x.f - y.f, x.e);
430}
431
432// Computes an fp number r with r.f = x.f * y.f / pow(2, 64) rounded to nearest
433// with half-up tie breaking, r.e = x.e + y.e + 64. Result may not be normalized.
434FMT_API fp operator*(fp x, fp y);
435
436// Returns cached power (of 10) c_k = c_k.f * pow(2, c_k.e) such that its
437// (binary) exponent satisfies min_exponent <= c_k.e <= min_exponent + 3.
438FMT_API fp get_cached_power(int min_exponent, int &pow10_exponent);
439
Victor Zverovichcd900972018-04-21 17:26:24 -0700440FMT_FUNC fp operator*(fp x, fp y) {
441 // Multiply 32-bit parts of significands.
442 uint64_t mask = (1ULL << 32) - 1;
443 uint64_t a = x.f >> 32, b = x.f & mask;
444 uint64_t c = y.f >> 32, d = y.f & mask;
445 uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d;
446 // Compute mid 64-bit of result and round.
447 uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31);
Daniela Engert6cd66612018-04-30 10:07:43 +0200448 return fp(ac + (ad >> 32) + (bc >> 32) + (mid >> 32), x.e + y.e + 64);
Victor Zverovichcd900972018-04-21 17:26:24 -0700449}
Victor Zverovich468c2432018-05-27 10:57:26 -0700450
451FMT_FUNC fp get_cached_power(int min_exponent, int &pow10_exponent) {
452 const double one_over_log2_10 = 0.30102999566398114; // 1 / log2(10)
453 int index = static_cast<int>(std::ceil(
Victor Zverovich4e4b8572018-05-28 11:25:07 -0700454 (min_exponent + fp::significand_size - 1) * one_over_log2_10));
Victor Zverovich468c2432018-05-27 10:57:26 -0700455 // Decimal exponent of the first (smallest) cached power of 10.
456 const int first_dec_exp = -348;
Victor Zverovich9de31212018-08-15 06:54:43 -0700457 // Difference between 2 consecutive decimal exponents in cached powers of 10.
Victor Zverovich468c2432018-05-27 10:57:26 -0700458 const int dec_exp_step = 8;
459 index = (index - first_dec_exp - 1) / dec_exp_step + 1;
460 pow10_exponent = first_dec_exp + index * dec_exp_step;
461 return fp(data::POW10_SIGNIFICANDS[index], data::POW10_EXPONENTS[index]);
462}
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700463
Victor Zverovich50b18a32018-10-13 22:14:36 -0700464FMT_FUNC bool grisu2_round(
465 char *buffer, size_t &size, size_t max_digits, uint64_t delta,
466 uint64_t remainder, uint64_t exp, uint64_t diff, int &exp10) {
Victor Zverovich69929752018-10-13 07:44:34 -0700467 while (remainder < diff && delta - remainder >= exp &&
468 (remainder + exp < diff || diff - remainder > remainder + exp - diff)) {
469 --buffer[size - 1];
470 remainder += exp;
471 }
Victor Zverovich50b18a32018-10-13 22:14:36 -0700472 if (size > max_digits) {
473 --size;
474 ++exp10;
475 if (buffer[size] >= '5')
476 return false;
477 }
478 return true;
Victor Zverovich69929752018-10-13 07:44:34 -0700479}
480
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700481// Generates output using Grisu2 digit-gen algorithm.
Victor Zverovich50b18a32018-10-13 22:14:36 -0700482FMT_FUNC bool grisu2_gen_digits(
483 char *buffer, size_t &size, uint32_t hi, uint64_t lo, int &exp,
484 uint64_t delta, const fp &one, const fp &diff, size_t max_digits) {
Victor Zverovich69929752018-10-13 07:44:34 -0700485 // Generate digits for the most significant part (hi).
Victor Zverovich0de44a42018-08-26 08:12:35 -0700486 while (exp > 0) {
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700487 uint32_t digit = 0;
488 // This optimization by miloyip reduces the number of integer divisions by
489 // one per iteration.
Victor Zverovich0de44a42018-08-26 08:12:35 -0700490 switch (exp) {
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700491 case 10: digit = hi / 1000000000; hi %= 1000000000; break;
492 case 9: digit = hi / 100000000; hi %= 100000000; break;
493 case 8: digit = hi / 10000000; hi %= 10000000; break;
494 case 7: digit = hi / 1000000; hi %= 1000000; break;
495 case 6: digit = hi / 100000; hi %= 100000; break;
496 case 5: digit = hi / 10000; hi %= 10000; break;
497 case 4: digit = hi / 1000; hi %= 1000; break;
498 case 3: digit = hi / 100; hi %= 100; break;
499 case 2: digit = hi / 10; hi %= 10; break;
500 case 1: digit = hi; hi = 0; break;
501 default:
502 FMT_ASSERT(false, "invalid number of digits");
503 }
504 if (digit != 0 || size != 0)
medithe95a71892018-08-29 15:38:56 +0200505 buffer[size++] = static_cast<char>('0' + digit);
Victor Zverovich0de44a42018-08-26 08:12:35 -0700506 --exp;
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700507 uint64_t remainder = (static_cast<uint64_t>(hi) << -one.e) + lo;
Victor Zverovich50b18a32018-10-13 22:14:36 -0700508 if (remainder <= delta || size > max_digits) {
509 return grisu2_round(
510 buffer, size, max_digits, delta, remainder,
511 static_cast<uint64_t>(data::POWERS_OF_10_32[exp]) << -one.e,
512 diff.f, exp);
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700513 }
514 }
Victor Zverovich69929752018-10-13 07:44:34 -0700515 // Generate digits for the least significant part (lo).
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700516 for (;;) {
517 lo *= 10;
518 delta *= 10;
519 char digit = static_cast<char>(lo >> -one.e);
520 if (digit != 0 || size != 0)
medithe95a71892018-08-29 15:38:56 +0200521 buffer[size++] = static_cast<char>('0' + digit);
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700522 lo &= one.f - 1;
Victor Zverovich0de44a42018-08-26 08:12:35 -0700523 --exp;
Victor Zverovich50b18a32018-10-13 22:14:36 -0700524 if (lo < delta || size > max_digits) {
525 return grisu2_round(buffer, size, max_digits, delta, lo, one.f,
526 diff.f * data::POWERS_OF_10_32[-exp], exp);
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700527 }
528 }
529}
530
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700531#if FMT_CLANG_VERSION
532# define FMT_FALLTHROUGH [[clang::fallthrough]];
medithe981797f2018-09-07 17:53:15 +0200533#elif FMT_GCC_VERSION >= 700
534# define FMT_FALLTHROUGH [[gnu::fallthrough]];
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700535#else
536# define FMT_FALLTHROUGH
537#endif
Victor Zveroviche483a012018-08-26 09:51:49 -0700538
Victor Zverovich50b18a32018-10-13 22:14:36 -0700539struct gen_digits_params {
Victor Zverovichdda47c92018-10-17 10:49:30 -0700540 unsigned num_digits;
Victor Zverovich50b18a32018-10-13 22:14:36 -0700541 bool fixed;
542 bool upper;
543 bool trailing_zeros;
Victor Zverovich13d472b2018-10-17 20:13:38 -0700544};
Victor Zverovich50b18a32018-10-13 22:14:36 -0700545
Victor Zverovich13d472b2018-10-17 20:13:38 -0700546struct prettify_handler {
547 char *data;
548 size_t size;
549 buffer &buf;
550
551 explicit prettify_handler(buffer &b, size_t n)
552 : data(b.data()), size(n), buf(b) {}
553 ~prettify_handler() {
554 assert(buf.size() >= size);
555 buf.resize(size);
556 }
557
558 template <typename F>
559 void insert(size_t pos, size_t n, F f) {
560 std::memmove(data + pos + n, data + pos, size - pos);
561 f(data + pos);
562 size += n;
563 }
564
565 void insert(size_t pos, char c) {
566 std::memmove(data + pos + 1, data + pos, size - pos);
567 data[pos] = c;
568 ++size;
569 }
570
571 void append(size_t n, char c) {
572 std::uninitialized_fill_n(data + size, n, c);
573 size += n;
574 }
575
576 void append(char c) { data[size++] = c; }
577
578 void remove_trailing(char c) {
579 while (data[size - 1] == c) --size;
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700580 }
Victor Zverovich50b18a32018-10-13 22:14:36 -0700581};
582
Victor Zverovich13d472b2018-10-17 20:13:38 -0700583// Writes the exponent exp in the form "[+-]d{2,3}" to buffer.
584template <typename Handler>
585FMT_FUNC void write_exponent(int exp, Handler &&h) {
586 FMT_ASSERT(-1000 < exp && exp < 1000, "exponent out of range");
587 if (exp < 0) {
588 h.append('-');
589 exp = -exp;
590 } else {
591 h.append('+');
592 }
593 if (exp >= 100) {
594 h.append(static_cast<char>('0' + exp / 100));
595 exp %= 100;
596 const char *d = data::DIGITS + exp * 2;
597 h.append(d[0]);
598 h.append(d[1]);
599 } else {
600 const char *d = data::DIGITS + exp * 2;
601 h.append(d[0]);
602 h.append(d[1]);
603 }
604}
605
Victor Zverovich2d2326a2018-10-22 21:05:59 -0700606struct fill {
607 size_t n;
608 void operator()(char *buffer) const {
609 buffer[0] = '0';
610 buffer[1] = '.';
611 std::uninitialized_fill_n(buffer + 2, n, '0');
612 }
613};
614
Victor Zverovich13d472b2018-10-17 20:13:38 -0700615// The number is given as v = f * pow(10, exp), where f has size digits.
616template <typename Handler>
617FMT_FUNC void grisu2_prettify(const gen_digits_params &params,
618 size_t size, int exp, Handler &&handler) {
Victor Zverovich50b18a32018-10-13 22:14:36 -0700619 if (!params.fixed) {
620 // Insert a decimal point after the first digit and add an exponent.
Victor Zverovich13d472b2018-10-17 20:13:38 -0700621 handler.insert(1, '.');
Victor Zverovich50b18a32018-10-13 22:14:36 -0700622 exp += static_cast<int>(size) - 1;
Victor Zverovich13d472b2018-10-17 20:13:38 -0700623 if (size < params.num_digits)
624 handler.append(params.num_digits - size, '0');
625 handler.append(params.upper ? 'E' : 'e');
626 write_exponent(exp, handler);
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700627 return;
628 }
Victor Zverovich50b18a32018-10-13 22:14:36 -0700629 // pow(10, full_exp - 1) <= v <= pow(10, full_exp).
630 int int_size = static_cast<int>(size);
631 int full_exp = int_size + exp;
632 const int exp_threshold = 21;
633 if (int_size <= full_exp && full_exp <= exp_threshold) {
634 // 1234e7 -> 12340000000[.0+]
Victor Zverovich13d472b2018-10-17 20:13:38 -0700635 handler.append(full_exp - int_size, '0');
Victor Zverovichdda47c92018-10-17 10:49:30 -0700636 int num_zeros = static_cast<int>(params.num_digits) - full_exp;
Victor Zverovich50b18a32018-10-13 22:14:36 -0700637 if (num_zeros > 0 && params.trailing_zeros) {
Victor Zverovich13d472b2018-10-17 20:13:38 -0700638 handler.append('.');
639 handler.append(num_zeros, '0');
Victor Zverovich50b18a32018-10-13 22:14:36 -0700640 }
Victor Zverovich50b18a32018-10-13 22:14:36 -0700641 } else if (full_exp > 0) {
642 // 1234e-2 -> 12.34[0+]
Victor Zverovich13d472b2018-10-17 20:13:38 -0700643 handler.insert(full_exp, '.');
Victor Zverovich50b18a32018-10-13 22:14:36 -0700644 if (!params.trailing_zeros) {
645 // Remove trailing zeros.
Victor Zverovich13d472b2018-10-17 20:13:38 -0700646 handler.remove_trailing('0');
647 } else if (params.num_digits > size) {
Victor Zverovich50b18a32018-10-13 22:14:36 -0700648 // Add trailing zeros.
Victor Zverovich13d472b2018-10-17 20:13:38 -0700649 size_t num_zeros = params.num_digits - size;
650 handler.append(num_zeros, '0');
Victor Zverovich50b18a32018-10-13 22:14:36 -0700651 }
652 } else {
653 // 1234e-6 -> 0.001234
Victor Zverovich13d472b2018-10-17 20:13:38 -0700654 handler.insert(0, 2 - full_exp, fill{to_unsigned(-full_exp)});
Victor Zverovich50b18a32018-10-13 22:14:36 -0700655 }
656}
657
Victor Zverovich13d472b2018-10-17 20:13:38 -0700658struct char_counter {
659 size_t size;
660
661 template <typename F>
662 void insert(size_t, size_t n, F) { size += n; }
663 void insert(size_t, char) { ++size; }
664 void append(size_t n, char) { size += n; }
665 void append(char) { ++size; }
666 void remove_trailing(char) {}
667};
668
669// Converts format specifiers into parameters for digit generation and computes
670// output buffer size for a number in the range [pow(10, exp - 1), pow(10, exp)
671// or 0 if exp == 1.
672FMT_FUNC gen_digits_params process_specs(const core_format_specs &specs,
673 int exp, buffer &buf) {
674 auto params = gen_digits_params();
675 int num_digits = specs.precision >= 0 ? specs.precision : 6;
676 switch (specs.type) {
677 case 'G':
678 params.upper = true;
679 FMT_FALLTHROUGH
680 case '\0': case 'g':
681 params.trailing_zeros = (specs.flags & HASH_FLAG) != 0;
682 if (-4 <= exp && exp < num_digits + 1) {
683 params.fixed = true;
684 if (!specs.type && params.trailing_zeros && exp >= 0)
685 num_digits = exp + 1;
686 }
687 break;
688 case 'F':
689 params.upper = true;
690 FMT_FALLTHROUGH
691 case 'f': {
692 params.fixed = true;
693 params.trailing_zeros = true;
694 int adjusted_min_digits = num_digits + exp;
695 if (adjusted_min_digits > 0)
696 num_digits = adjusted_min_digits;
697 break;
698 }
699 case 'E':
700 params.upper = true;
701 FMT_FALLTHROUGH
702 case 'e':
703 ++num_digits;
704 break;
705 }
706 params.num_digits = to_unsigned(num_digits);
707 char_counter counter{params.num_digits};
708 grisu2_prettify(params, params.num_digits, exp - num_digits, counter);
709 buf.resize(counter.size);
710 return params;
711}
712
Victor Zverovich50b18a32018-10-13 22:14:36 -0700713template <typename Double>
714FMT_FUNC typename std::enable_if<sizeof(Double) == sizeof(uint64_t), bool>::type
Victor Zverovichbda5f9a2018-10-17 08:55:45 -0700715 grisu2_format(Double value, buffer &buf, core_format_specs specs) {
Victor Zverovich50b18a32018-10-13 22:14:36 -0700716 FMT_ASSERT(value >= 0, "value is negative");
717 if (value == 0) {
Victor Zverovich13d472b2018-10-17 20:13:38 -0700718 gen_digits_params params = process_specs(specs, 1, buf);
719 const size_t size = 1;
720 buf[0] = '0';
721 grisu2_prettify(params, size, 0, prettify_handler(buf, size));
Victor Zverovich50b18a32018-10-13 22:14:36 -0700722 return true;
723 }
724
725 fp fp_value(value);
726 fp lower, upper; // w^- and w^+ in the Grisu paper.
727 fp_value.compute_boundaries(lower, upper);
728
729 // Find a cached power of 10 close to 1 / upper and use it to scale upper.
730 const int min_exp = -60; // alpha in Grisu.
731 int cached_exp = 0; // K in Grisu.
732 auto cached_pow = get_cached_power( // \tilde{c}_{-k} in Grisu.
733 min_exp - (upper.e + fp::significand_size), cached_exp);
734 cached_exp = -cached_exp;
735 upper = upper * cached_pow; // \tilde{M}^+ in Grisu.
736 --upper.f; // \tilde{M}^+ - 1 ulp -> M^+_{\downarrow}.
737 fp one(1ull << -upper.e, upper.e);
738 // hi (p1 in Grisu) contains the most significant digits of scaled_upper.
739 // hi = floor(upper / one).
740 uint32_t hi = static_cast<uint32_t>(upper.f >> -one.e);
741 int exp = static_cast<int>(count_digits(hi)); // kappa in Grisu.
Victor Zverovich13d472b2018-10-17 20:13:38 -0700742 gen_digits_params params = process_specs(specs, cached_exp + exp, buf);
Victor Zverovich50b18a32018-10-13 22:14:36 -0700743 fp_value.normalize();
744 fp scaled_value = fp_value * cached_pow;
745 lower = lower * cached_pow; // \tilde{M}^- in Grisu.
746 ++lower.f; // \tilde{M}^- + 1 ulp -> M^-_{\uparrow}.
747 uint64_t delta = upper.f - lower.f;
748 fp diff = upper - scaled_value; // wp_w in Grisu.
749 // lo (p2 in Grisu) contains the least significants digits of scaled_upper.
750 // lo = supper % one.
751 uint64_t lo = upper.f & (one.f - 1);
Victor Zveroviche8efdef2018-10-17 08:19:46 -0700752 size_t size = 0;
Victor Zverovich13d472b2018-10-17 20:13:38 -0700753 if (!grisu2_gen_digits(buf.data(), size, hi, lo, exp, delta, one, diff,
Victor Zverovichdda47c92018-10-17 10:49:30 -0700754 params.num_digits)) {
Victor Zverovichbda5f9a2018-10-17 08:55:45 -0700755 buf.clear();
Victor Zverovich50b18a32018-10-13 22:14:36 -0700756 return false;
757 }
Victor Zverovich13d472b2018-10-17 20:13:38 -0700758 grisu2_prettify(params, size, cached_exp + exp, prettify_handler(buf, size));
Victor Zverovich50b18a32018-10-13 22:14:36 -0700759 return true;
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700760}
Victor Zverovich29246222018-10-17 09:15:29 -0700761
762template <typename Double>
Victor Zverovich13d472b2018-10-17 20:13:38 -0700763void sprintf_format(Double value, internal::buffer &buffer,
764 core_format_specs spec) {
Victor Zverovich29246222018-10-17 09:15:29 -0700765 // Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail.
766 FMT_ASSERT(buffer.capacity() != 0, "empty buffer");
767
768 // Build format string.
769 enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg
770 char format[MAX_FORMAT_SIZE];
771 char *format_ptr = format;
772 *format_ptr++ = '%';
773 if (spec.has(HASH_FLAG))
774 *format_ptr++ = '#';
775 if (spec.precision >= 0) {
776 *format_ptr++ = '.';
777 *format_ptr++ = '*';
778 }
779 if (std::is_same<Double, long double>::value)
780 *format_ptr++ = 'L';
781 *format_ptr++ = spec.type;
782 *format_ptr = '\0';
783
784 // Format using snprintf.
785 char *start = FMT_NULL;
786 for (;;) {
787 std::size_t buffer_size = buffer.capacity();
788 start = &buffer[0];
789 int result = internal::char_traits<char>::format_float(
790 start, buffer_size, format, spec.precision, value);
791 if (result >= 0) {
792 unsigned n = internal::to_unsigned(result);
793 if (n < buffer.capacity()) {
794 buffer.resize(n);
795 break; // The buffer is large enough - continue with formatting.
796 }
797 buffer.reserve(n + 1);
798 } else {
799 // If result is negative we ask to increase the capacity by at least 1,
800 // but as std::vector, the buffer grows exponentially.
801 buffer.reserve(buffer.capacity() + 1);
802 }
803 }
804}
Victor Zverovichcd900972018-04-21 17:26:24 -0700805} // namespace internal
806
vitaut24c309f2015-06-12 07:15:57 -0700807#if FMT_USE_WINDOWS_H
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700808
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800809FMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) {
Victor Zverovichdff21372014-12-16 07:01:01 -0800810 static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
vitautc3ba6152015-08-07 07:34:58 -0700811 if (s.size() > INT_MAX)
Victor Zverovichc333dca2017-02-19 08:41:38 -0800812 FMT_THROW(windows_error(ERROR_INVALID_PARAMETER, ERROR_MSG));
vitautc3ba6152015-08-07 07:34:58 -0700813 int s_size = static_cast<int>(s.size());
Vasili Galkaacb469a2018-03-12 14:43:29 +0200814 if (s_size == 0) {
815 // MultiByteToWideChar does not support zero length, handle separately.
816 buffer_.resize(1);
817 buffer_[0] = 0;
818 return;
819 }
820
vitautc3ba6152015-08-07 07:34:58 -0700821 int length = MultiByteToWideChar(
Victor Zverovichd8c25a12018-01-20 18:37:57 -0800822 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700823 if (length == 0)
Victor Zverovichc333dca2017-02-19 08:41:38 -0800824 FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
vitaut71542382015-06-27 09:11:15 -0700825 buffer_.resize(length + 1);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700826 length = MultiByteToWideChar(
vitautc3ba6152015-08-07 07:34:58 -0700827 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700828 if (length == 0)
Victor Zverovichc333dca2017-02-19 08:41:38 -0800829 FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
vitaut71542382015-06-27 09:11:15 -0700830 buffer_[length] = 0;
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700831}
832
Victor Zverovichc333dca2017-02-19 08:41:38 -0800833FMT_FUNC internal::utf16_to_utf8::utf16_to_utf8(wstring_view s) {
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700834 if (int error_code = convert(s)) {
Victor Zverovichc333dca2017-02-19 08:41:38 -0800835 FMT_THROW(windows_error(error_code,
Victor Zverovich8b76e972014-10-06 08:30:55 -0700836 "cannot convert string from UTF-16 to UTF-8"));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700837 }
838}
839
Victor Zverovichc333dca2017-02-19 08:41:38 -0800840FMT_FUNC int internal::utf16_to_utf8::convert(wstring_view s) {
vitautca747812015-08-07 07:08:46 -0700841 if (s.size() > INT_MAX)
842 return ERROR_INVALID_PARAMETER;
843 int s_size = static_cast<int>(s.size());
Vasili Galkaacb469a2018-03-12 14:43:29 +0200844 if (s_size == 0) {
845 // WideCharToMultiByte does not support zero length, handle separately.
846 buffer_.resize(1);
847 buffer_[0] = 0;
848 return 0;
849 }
850
Victor Zverovichd8c25a12018-01-20 18:37:57 -0800851 int length = WideCharToMultiByte(
852 CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700853 if (length == 0)
854 return GetLastError();
vitaut71542382015-06-27 09:11:15 -0700855 buffer_.resize(length + 1);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700856 length = WideCharToMultiByte(
Victor Zverovichd8c25a12018-01-20 18:37:57 -0800857 CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700858 if (length == 0)
859 return GetLastError();
vitaut71542382015-06-27 09:11:15 -0700860 buffer_[length] = 0;
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700861 return 0;
862}
863
Victor Zverovichc333dca2017-02-19 08:41:38 -0800864FMT_FUNC void windows_error::init(
Victor Zverovich7f351de2017-12-03 09:18:06 -0800865 int err_code, string_view format_str, format_args args) {
Carter Li3f574c12015-02-17 10:11:42 +0800866 error_code_ = err_code;
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800867 memory_buffer buffer;
Victor Zveroviche022c212017-02-17 06:38:53 -0800868 internal::format_windows_error(buffer, err_code, vformat(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700869 std::runtime_error &base = *this;
Victor Zveroviche022c212017-02-17 06:38:53 -0800870 base = std::runtime_error(to_string(buffer));
Victor Zverovich53201032014-06-30 14:26:29 -0700871}
872
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700873FMT_FUNC void internal::format_windows_error(
Victor Zverovichf6fd38b2018-01-15 08:22:31 -0800874 internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700875 FMT_TRY {
Victor Zverovichc0954452018-01-06 09:09:50 -0800876 wmemory_buffer buf;
Victor Zverovichf1ede632018-03-04 10:33:42 -0800877 buf.resize(inline_buffer_size);
Michael Winterberg2a05a872016-03-02 17:35:34 -0800878 for (;;) {
Victor Zverovichc0954452018-01-06 09:09:50 -0800879 wchar_t *system_message = &buf[0];
Victor Zverovichf85d5f42016-10-22 08:04:20 -0700880 int result = FormatMessageW(
881 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
Victor Zverovichd8c25a12018-01-20 18:37:57 -0800882 FMT_NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
883 system_message, static_cast<uint32_t>(buf.size()), FMT_NULL);
Michael Winterberg2a05a872016-03-02 17:35:34 -0800884 if (result != 0) {
Victor Zverovichc333dca2017-02-19 08:41:38 -0800885 utf16_to_utf8 utf8_message;
Michael Winterberg2a05a872016-03-02 17:35:34 -0800886 if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
Victor Zverovich217e7c72018-01-14 07:19:23 -0800887 writer w(out);
Victor Zveroviche022c212017-02-17 06:38:53 -0800888 w.write(message);
889 w.write(": ");
890 w.write(utf8_message);
Michael Winterberg2a05a872016-03-02 17:35:34 -0800891 return;
892 }
893 break;
Victor Zverovich22f75d82014-09-03 08:03:05 -0700894 }
Michael Winterberg2a05a872016-03-02 17:35:34 -0800895 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
896 break; // Can't get error message, report error code instead.
Victor Zverovichc0954452018-01-06 09:09:50 -0800897 buf.resize(buf.size() * 2);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700898 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700899 } FMT_CATCH(...) {}
Victor Zverovichc0954452018-01-06 09:09:50 -0800900 format_error_code(out, error_code, message);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700901}
vitaut24c309f2015-06-12 07:15:57 -0700902
903#endif // FMT_USE_WINDOWS_H
904
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700905FMT_FUNC void format_system_error(
Victor Zverovichc2fecb92018-01-14 14:15:59 -0800906 internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
vitaut24c309f2015-06-12 07:15:57 -0700907 FMT_TRY {
Victor Zverovich36634142017-12-26 09:00:22 -0800908 memory_buffer buf;
Victor Zverovichf1ede632018-03-04 10:33:42 -0800909 buf.resize(inline_buffer_size);
vitaut24c309f2015-06-12 07:15:57 -0700910 for (;;) {
Victor Zverovich36634142017-12-26 09:00:22 -0800911 char *system_message = &buf[0];
912 int result = safe_strerror(error_code, system_message, buf.size());
vitaut24c309f2015-06-12 07:15:57 -0700913 if (result == 0) {
Victor Zverovich217e7c72018-01-14 07:19:23 -0800914 writer w(out);
Victor Zverovichfefaf072017-02-14 16:29:47 -0500915 w.write(message);
916 w.write(": ");
917 w.write(system_message);
vitaut24c309f2015-06-12 07:15:57 -0700918 return;
919 }
920 if (result != ERANGE)
921 break; // Can't get error message, report error code instead.
Victor Zverovich36634142017-12-26 09:00:22 -0800922 buf.resize(buf.size() * 2);
vitaut24c309f2015-06-12 07:15:57 -0700923 }
924 } FMT_CATCH(...) {}
Victor Zverovichf164e4c2018-02-01 16:49:47 -0800925 format_error_code(out, error_code, message);
vitaut24c309f2015-06-12 07:15:57 -0700926}
Victor Zverovich53b4c312014-04-30 15:00:41 -0700927
Abdó Roig-Marangesaf0f21d2017-12-09 16:50:53 +0100928FMT_FUNC void internal::error_handler::on_error(const char *message) {
Victor Zverovich94edb1a2017-12-06 07:42:42 -0800929 FMT_THROW(format_error(message));
930}
931
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700932FMT_FUNC void report_system_error(
Victor Zverovich50e71672017-02-18 06:52:52 -0800933 int error_code, fmt::string_view message) FMT_NOEXCEPT {
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700934 report_error(format_system_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700935}
936
vitaut24c309f2015-06-12 07:15:57 -0700937#if FMT_USE_WINDOWS_H
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700938FMT_FUNC void report_windows_error(
Victor Zverovich50e71672017-02-18 06:52:52 -0800939 int error_code, fmt::string_view message) FMT_NOEXCEPT {
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700940 report_error(internal::format_windows_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700941}
Victor Zverovich400812a2014-04-30 12:38:17 -0700942#endif
Victor Zverovichf7939862014-04-30 10:18:11 -0700943
Victor Zverovich81bd9e82017-12-03 07:32:04 -0800944FMT_FUNC void vprint(std::FILE *f, string_view format_str, format_args args) {
Victor Zverovicheedfd072017-02-18 09:13:12 -0800945 memory_buffer buffer;
Victor Zverovich0a96c032018-10-25 07:20:02 -0700946 internal::vformat_to(buffer, format_str,
947 basic_format_args<buffer_context<char>::type>(args));
Victor Zverovichfefaf072017-02-14 16:29:47 -0500948 std::fwrite(buffer.data(), 1, buffer.size(), f);
Victor Zverovichd5b81962014-06-28 21:56:40 -0700949}
950
Daniela Engert2570f1a2018-04-26 20:32:14 +0200951FMT_FUNC void vprint(std::FILE *f, wstring_view format_str, wformat_args args) {
952 wmemory_buffer buffer;
Victor Zverovich0a96c032018-10-25 07:20:02 -0700953 internal::vformat_to(buffer, format_str, args);
Daniela Engert2570f1a2018-04-26 20:32:14 +0200954 std::fwrite(buffer.data(), sizeof(wchar_t), buffer.size(), f);
955}
956
Victor Zverovich81bd9e82017-12-03 07:32:04 -0800957FMT_FUNC void vprint(string_view format_str, format_args args) {
Victor Zverovich0028ce52016-08-26 17:23:13 -0700958 vprint(stdout, format_str, args);
Victor Zverovich163178e2014-09-25 07:08:25 -0700959}
960
Daniela Engert2570f1a2018-04-26 20:32:14 +0200961FMT_FUNC void vprint(wstring_view format_str, wformat_args args) {
962 vprint(stdout, format_str, args);
963}
964
Victor Zverovich838400d2018-05-12 08:33:51 -0700965FMT_END_NAMESPACE
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700966
Ingo van Lilb4b13ee2015-11-02 12:34:46 +0100967#ifdef _MSC_VER
jdale88a9862fd2014-03-11 18:56:24 +0000968# pragma warning(pop)
969#endif
Victor Zverovich3da71d52018-03-21 07:50:59 -0700970
971#endif // FMT_FORMAT_INL_H_