blob: 019282fb13f1e18455fb924aa2ecf10fa57bd65b [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
Thomas Bernardabde38b2018-08-17 11:22:56 +0200195#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
Victor Zverovich6ebc1a92018-05-20 17:16:34 -0700196class locale {
197 private:
198 std::locale locale_;
199
200 public:
201 explicit locale(std::locale loc = std::locale()) : locale_(loc) {}
202 std::locale get() { return locale_; }
203};
204
Victor Zverovich2a4e9482018-07-21 09:13:21 -0700205FMT_FUNC size_t internal::count_code_points(u8string_view s) {
206 const char8_t *data = s.data();
207 int num_code_points = 0;
208 for (size_t i = 0, size = s.size(); i != size; ++i) {
209 if ((data[i].value & 0xc0) != 0x80)
210 ++num_code_points;
211 }
212 return num_code_points;
213}
214
Victor Zverovich7f351de2017-12-03 09:18:06 -0800215template <typename Char>
Victor Zverovichd165d9c2017-12-26 17:22:07 -0800216FMT_FUNC Char internal::thousands_sep(locale_provider *lp) {
217 std::locale loc = lp ? lp->locale().get() : std::locale();
218 return std::use_facet<std::numpunct<Char>>(loc).thousands_sep();
Victor Zverovich7f351de2017-12-03 09:18:06 -0800219}
Thomas Bernardabde38b2018-08-17 11:22:56 +0200220#else
221template <typename Char>
222FMT_FUNC Char internal::thousands_sep(locale_provider *lp) {
223 return FMT_STATIC_THOUSANDS_SEPARATOR;
224}
225#endif
Victor Zverovich7f351de2017-12-03 09:18:06 -0800226
Victor Zverovichc333dca2017-02-19 08:41:38 -0800227FMT_FUNC void system_error::init(
Victor Zverovich81bd9e82017-12-03 07:32:04 -0800228 int err_code, string_view format_str, format_args args) {
Victor Zverovichf9fc8fd2014-12-09 07:45:54 -0800229 error_code_ = err_code;
Victor Zverovicheedfd072017-02-18 09:13:12 -0800230 memory_buffer buffer;
231 format_system_error(buffer, err_code, vformat(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700232 std::runtime_error &base = *this;
Victor Zverovicheedfd072017-02-18 09:13:12 -0800233 base = std::runtime_error(to_string(buffer));
Victor Zverovich53201032014-06-30 14:26:29 -0700234}
235
Victor Zverovichcd900972018-04-21 17:26:24 -0700236namespace internal {
Victor Zverovichb605b392013-09-09 22:21:40 -0700237template <typename T>
Victor Zverovichcd900972018-04-21 17:26:24 -0700238int char_traits<char>::format_float(
Victor Zverovichb60a5c52018-05-28 20:16:30 -0700239 char *buffer, std::size_t size, const char *format, int precision, T value) {
Victor Zverovichb605b392013-09-09 22:21:40 -0700240 return precision < 0 ?
Victor Zverovichb60a5c52018-05-28 20:16:30 -0700241 FMT_SNPRINTF(buffer, size, format, value) :
242 FMT_SNPRINTF(buffer, size, format, precision, value);
Victor Zverovichb605b392013-09-09 22:21:40 -0700243}
Victor Zverovich9ff3b972013-09-07 10:15:08 -0700244
Victor Zverovichb605b392013-09-09 22:21:40 -0700245template <typename T>
Victor Zverovichcd900972018-04-21 17:26:24 -0700246int char_traits<wchar_t>::format_float(
Victor Zverovichb60a5c52018-05-28 20:16:30 -0700247 wchar_t *buffer, std::size_t size, const wchar_t *format, int precision,
248 T value) {
Victor Zverovichb605b392013-09-09 22:21:40 -0700249 return precision < 0 ?
Victor Zverovichb60a5c52018-05-28 20:16:30 -0700250 FMT_SWPRINTF(buffer, size, format, value) :
251 FMT_SWPRINTF(buffer, size, format, precision, value);
Victor Zverovich65d47e52013-09-09 06:51:03 -0700252}
Victor Zveroviche8ba9602012-12-12 09:29:50 -0800253
Victor Zverovich311251e2014-11-29 06:58:00 -0800254template <typename T>
Victor Zverovichcd900972018-04-21 17:26:24 -0700255const char basic_data<T>::DIGITS[] =
Victor Zverovich687301c2013-01-26 16:07:28 -0800256 "0001020304050607080910111213141516171819"
257 "2021222324252627282930313233343536373839"
258 "4041424344454647484950515253545556575859"
259 "6061626364656667686970717273747576777879"
260 "8081828384858687888990919293949596979899";
Victor Zveroviche9b21912014-02-19 12:43:55 -0800261
Victor Zverovichf1d85162014-02-19 13:02:22 -0800262#define FMT_POWERS_OF_10(factor) \
263 factor * 10, \
264 factor * 100, \
265 factor * 1000, \
266 factor * 10000, \
267 factor * 100000, \
268 factor * 1000000, \
269 factor * 10000000, \
270 factor * 100000000, \
271 factor * 1000000000
Victor Zveroviche9b21912014-02-19 12:43:55 -0800272
Victor Zverovich311251e2014-11-29 06:58:00 -0800273template <typename T>
Victor Zverovichcd900972018-04-21 17:26:24 -0700274const uint32_t basic_data<T>::POWERS_OF_10_32[] = {
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700275 1, FMT_POWERS_OF_10(1)
276};
277
278template <typename T>
279const uint32_t basic_data<T>::ZERO_OR_POWERS_OF_10_32[] = {
Victor Zverovich311251e2014-11-29 06:58:00 -0800280 0, FMT_POWERS_OF_10(1)
281};
282
283template <typename T>
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700284const uint64_t basic_data<T>::ZERO_OR_POWERS_OF_10_64[] = {
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800285 0,
Victor Zverovichf1d85162014-02-19 13:02:22 -0800286 FMT_POWERS_OF_10(1),
Victor Zverovich016aceb2017-08-26 09:09:43 -0700287 FMT_POWERS_OF_10(1000000000ull),
288 10000000000000000000ull
Victor Zverovich6f0387f2014-02-14 10:36:17 -0800289};
Victor Zverovich877abaf2013-01-08 09:56:05 -0800290
Victor Zverovich2768af22018-04-29 06:33:05 -0700291// Normalized 64-bit significands of pow(10, k), for k = -348, -340, ..., 340.
292// These are generated by support/compute-powers.py.
293template <typename T>
294const uint64_t basic_data<T>::POW10_SIGNIFICANDS[] = {
Victor Zverovich9de31212018-08-15 06:54:43 -0700295 0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, 0x8b16fb203055ac76,
296 0xcf42894a5dce35ea, 0x9a6bb0aa55653b2d, 0xe61acf033d1a45df,
297 0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f, 0xbe5691ef416bd60c,
298 0x8dd01fad907ffc3c, 0xd3515c2831559a83, 0x9d71ac8fada6c9b5,
299 0xea9c227723ee8bcb, 0xaecc49914078536d, 0x823c12795db6ce57,
300 0xc21094364dfb5637, 0x9096ea6f3848984f, 0xd77485cb25823ac7,
301 0xa086cfcd97bf97f4, 0xef340a98172aace5, 0xb23867fb2a35b28e,
302 0x84c8d4dfd2c63f3b, 0xc5dd44271ad3cdba, 0x936b9fcebb25c996,
303 0xdbac6c247d62a584, 0xa3ab66580d5fdaf6, 0xf3e2f893dec3f126,
304 0xb5b5ada8aaff80b8, 0x87625f056c7c4a8b, 0xc9bcff6034c13053,
305 0x964e858c91ba2655, 0xdff9772470297ebd, 0xa6dfbd9fb8e5b88f,
306 0xf8a95fcf88747d94, 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b,
307 0xcdb02555653131b6, 0x993fe2c6d07b7fac, 0xe45c10c42a2b3b06,
308 0xaa242499697392d3, 0xfd87b5f28300ca0e, 0xbce5086492111aeb,
309 0x8cbccc096f5088cc, 0xd1b71758e219652c, 0x9c40000000000000,
310 0xe8d4a51000000000, 0xad78ebc5ac620000, 0x813f3978f8940984,
311 0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70, 0xd5d238a4abe98068,
312 0x9f4f2726179a2245, 0xed63a231d4c4fb27, 0xb0de65388cc8ada8,
313 0x83c7088e1aab65db, 0xc45d1df942711d9a, 0x924d692ca61be758,
314 0xda01ee641a708dea, 0xa26da3999aef774a, 0xf209787bb47d6b85,
315 0xb454e4a179dd1877, 0x865b86925b9bc5c2, 0xc83553c5c8965d3d,
316 0x952ab45cfa97a0b3, 0xde469fbd99a05fe3, 0xa59bc234db398c25,
317 0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece, 0x88fcf317f22241e2,
318 0xcc20ce9bd35c78a5, 0x98165af37b2153df, 0xe2a0b5dc971f303a,
319 0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c, 0xbb764c4ca7a44410,
320 0x8bab8eefb6409c1a, 0xd01fef10a657842c, 0x9b10a4e5e9913129,
321 0xe7109bfba19c0c9d, 0xac2820d9623bf429, 0x80444b5e7aa7cf85,
322 0xbf21e44003acdd2d, 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841,
323 0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, 0xaf87023b9bf0ee6b,
Victor Zverovich2768af22018-04-29 06:33:05 -0700324};
325
326// Binary exponents of pow(10, k), for k = -348, -340, ..., 340, corresponding
327// to significands above.
328template <typename T>
329const int16_t basic_data<T>::POW10_EXPONENTS[] = {
330 -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954,
331 -927, -901, -874, -847, -821, -794, -768, -741, -715, -688, -661,
332 -635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369,
333 -343, -316, -289, -263, -236, -210, -183, -157, -130, -103, -77,
334 -50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216,
335 242, 269, 295, 322, 348, 375, 402, 428, 455, 481, 508,
336 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800,
337 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066
338};
339
Dhruv Paranjapeec218a32018-06-28 10:43:00 +0530340template <typename T> const char basic_data<T>::RESET_COLOR[] = "\x1b[0m";
341template <typename T> const wchar_t basic_data<T>::WRESET_COLOR[] = L"\x1b[0m";
342
Victor Zverovichdd8c5ce2018-08-29 09:34:57 -0700343// A handmade floating-point number f * pow(2, e).
344class fp {
345 private:
346 typedef uint64_t significand_type;
347
348 // All sizes are in bits.
349 static FMT_CONSTEXPR_DECL const int char_size =
350 std::numeric_limits<unsigned char>::digits;
351 // Subtract 1 to account for an implicit most significant bit in the
352 // normalized form.
353 static FMT_CONSTEXPR_DECL const int double_significand_size =
354 std::numeric_limits<double>::digits - 1;
355 static FMT_CONSTEXPR_DECL const uint64_t implicit_bit =
356 1ull << double_significand_size;
357
358 public:
359 significand_type f;
360 int e;
361
362 static FMT_CONSTEXPR_DECL const int significand_size =
363 sizeof(significand_type) * char_size;
364
365 fp(): f(0), e(0) {}
366 fp(uint64_t f, int e): f(f), e(e) {}
367
368 // Constructs fp from an IEEE754 double. It is a template to prevent compile
369 // errors on platforms where double is not IEEE754.
370 template <typename Double>
371 explicit fp(Double d) {
372 // Assume double is in the format [sign][exponent][significand].
373 typedef std::numeric_limits<Double> limits;
medithe8cbfb6e2018-09-11 15:14:39 +0200374 const int double_size = static_cast<int>(sizeof(Double) * char_size);
Victor Zverovichdd8c5ce2018-08-29 09:34:57 -0700375 const int exponent_size =
376 double_size - double_significand_size - 1; // -1 for sign
377 const uint64_t significand_mask = implicit_bit - 1;
378 const uint64_t exponent_mask = (~0ull >> 1) & ~significand_mask;
379 const int exponent_bias = (1 << exponent_size) - limits::max_exponent - 1;
380 auto u = bit_cast<uint64_t>(d);
381 auto biased_e = (u & exponent_mask) >> double_significand_size;
382 f = u & significand_mask;
383 if (biased_e != 0)
384 f += implicit_bit;
385 else
386 biased_e = 1; // Subnormals use biased exponent 1 (min exponent).
387 e = static_cast<int>(biased_e - exponent_bias - double_significand_size);
388 }
389
390 // Normalizes the value converted from double and multiplied by (1 << SHIFT).
391 template <int SHIFT = 0>
392 void normalize() {
393 // Handle subnormals.
394 auto shifted_implicit_bit = implicit_bit << SHIFT;
395 while ((f & shifted_implicit_bit) == 0) {
396 f <<= 1;
397 --e;
398 }
399 // Subtract 1 to account for hidden bit.
400 auto offset = significand_size - double_significand_size - SHIFT - 1;
401 f <<= offset;
402 e -= offset;
403 }
404
405 // Compute lower and upper boundaries (m^- and m^+ in the Grisu paper), where
406 // a boundary is a value half way between the number and its predecessor
407 // (lower) or successor (upper). The upper boundary is normalized and lower
408 // has the same exponent but may be not normalized.
409 void compute_boundaries(fp &lower, fp &upper) const {
410 lower = f == implicit_bit ?
411 fp((f << 2) - 1, e - 2) : fp((f << 1) - 1, e - 1);
412 upper = fp((f << 1) + 1, e - 1);
413 upper.normalize<1>(); // 1 is to account for the exponent shift above.
414 lower.f <<= lower.e - upper.e;
415 lower.e = upper.e;
416 }
417};
418
419// Returns an fp number representing x - y. Result may not be normalized.
420inline fp operator-(fp x, fp y) {
421 FMT_ASSERT(x.f >= y.f && x.e == y.e, "invalid operands");
422 return fp(x.f - y.f, x.e);
423}
424
425// Computes an fp number r with r.f = x.f * y.f / pow(2, 64) rounded to nearest
426// with half-up tie breaking, r.e = x.e + y.e + 64. Result may not be normalized.
427FMT_API fp operator*(fp x, fp y);
428
429// Returns cached power (of 10) c_k = c_k.f * pow(2, c_k.e) such that its
430// (binary) exponent satisfies min_exponent <= c_k.e <= min_exponent + 3.
431FMT_API fp get_cached_power(int min_exponent, int &pow10_exponent);
432
Victor Zverovichcd900972018-04-21 17:26:24 -0700433FMT_FUNC fp operator*(fp x, fp y) {
434 // Multiply 32-bit parts of significands.
435 uint64_t mask = (1ULL << 32) - 1;
436 uint64_t a = x.f >> 32, b = x.f & mask;
437 uint64_t c = y.f >> 32, d = y.f & mask;
438 uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d;
439 // Compute mid 64-bit of result and round.
440 uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31);
Daniela Engert6cd66612018-04-30 10:07:43 +0200441 return fp(ac + (ad >> 32) + (bc >> 32) + (mid >> 32), x.e + y.e + 64);
Victor Zverovichcd900972018-04-21 17:26:24 -0700442}
Victor Zverovich468c2432018-05-27 10:57:26 -0700443
444FMT_FUNC fp get_cached_power(int min_exponent, int &pow10_exponent) {
445 const double one_over_log2_10 = 0.30102999566398114; // 1 / log2(10)
446 int index = static_cast<int>(std::ceil(
Victor Zverovich4e4b8572018-05-28 11:25:07 -0700447 (min_exponent + fp::significand_size - 1) * one_over_log2_10));
Victor Zverovich468c2432018-05-27 10:57:26 -0700448 // Decimal exponent of the first (smallest) cached power of 10.
449 const int first_dec_exp = -348;
Victor Zverovich9de31212018-08-15 06:54:43 -0700450 // Difference between 2 consecutive decimal exponents in cached powers of 10.
Victor Zverovich468c2432018-05-27 10:57:26 -0700451 const int dec_exp_step = 8;
452 index = (index - first_dec_exp - 1) / dec_exp_step + 1;
453 pow10_exponent = first_dec_exp + index * dec_exp_step;
454 return fp(data::POW10_SIGNIFICANDS[index], data::POW10_EXPONENTS[index]);
455}
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700456
457// Generates output using Grisu2 digit-gen algorithm.
458FMT_FUNC void grisu2_gen_digits(
459 const fp &scaled_value, const fp &scaled_upper, uint64_t delta,
460 char *buffer, size_t &size, int &dec_exp) {
461 internal::fp one(1ull << -scaled_upper.e, scaled_upper.e);
Victor Zverovich0de44a42018-08-26 08:12:35 -0700462 // hi (p1 in Grisu) contains the most significant digits of scaled_upper.
463 // hi = floor(scaled_upper / one).
464 uint32_t hi = static_cast<uint32_t>(scaled_upper.f >> -one.e);
465 // lo (p2 in Grisu) contains the least significants digits of scaled_upper.
466 // lo = scaled_upper mod 1.
467 uint64_t lo = scaled_upper.f & (one.f - 1);
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700468 size = 0;
Victor Zverovich0de44a42018-08-26 08:12:35 -0700469 auto exp = count_digits(hi); // kappa in Grisu.
470 while (exp > 0) {
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700471 uint32_t digit = 0;
472 // This optimization by miloyip reduces the number of integer divisions by
473 // one per iteration.
Victor Zverovich0de44a42018-08-26 08:12:35 -0700474 switch (exp) {
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700475 case 10: digit = hi / 1000000000; hi %= 1000000000; break;
476 case 9: digit = hi / 100000000; hi %= 100000000; break;
477 case 8: digit = hi / 10000000; hi %= 10000000; break;
478 case 7: digit = hi / 1000000; hi %= 1000000; break;
479 case 6: digit = hi / 100000; hi %= 100000; break;
480 case 5: digit = hi / 10000; hi %= 10000; break;
481 case 4: digit = hi / 1000; hi %= 1000; break;
482 case 3: digit = hi / 100; hi %= 100; break;
483 case 2: digit = hi / 10; hi %= 10; break;
484 case 1: digit = hi; hi = 0; break;
485 default:
486 FMT_ASSERT(false, "invalid number of digits");
487 }
488 if (digit != 0 || size != 0)
medithe95a71892018-08-29 15:38:56 +0200489 buffer[size++] = static_cast<char>('0' + digit);
Victor Zverovich0de44a42018-08-26 08:12:35 -0700490 --exp;
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700491 uint64_t remainder = (static_cast<uint64_t>(hi) << -one.e) + lo;
492 if (remainder <= delta) {
Victor Zverovich0de44a42018-08-26 08:12:35 -0700493 dec_exp += exp;
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700494 // TODO: use scaled_value
495 (void)scaled_value;
496 return;
497 }
498 }
499 for (;;) {
500 lo *= 10;
501 delta *= 10;
502 char digit = static_cast<char>(lo >> -one.e);
503 if (digit != 0 || size != 0)
medithe95a71892018-08-29 15:38:56 +0200504 buffer[size++] = static_cast<char>('0' + digit);
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700505 lo &= one.f - 1;
Victor Zverovich0de44a42018-08-26 08:12:35 -0700506 --exp;
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700507 if (lo < delta) {
Victor Zverovich0de44a42018-08-26 08:12:35 -0700508 dec_exp += exp;
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700509 return;
510 }
511 }
512}
513
Victor Zverovichdd8c5ce2018-08-29 09:34:57 -0700514FMT_FUNC void grisu2_format_positive(double value, char *buffer, size_t &size,
515 int &dec_exp) {
516 FMT_ASSERT(value > 0, "value is nonpositive");
517 fp fp_value(value);
518 fp lower, upper; // w^- and w^+ in the Grisu paper.
519 fp_value.compute_boundaries(lower, upper);
520 // Find a cached power of 10 close to 1 / upper.
521 const int min_exp = -60; // alpha in Grisu.
522 auto dec_pow = get_cached_power( // \tilde{c}_{-k} in Grisu.
523 min_exp - (upper.e + fp::significand_size), dec_exp);
524 dec_exp = -dec_exp;
525 fp_value.normalize();
526 fp scaled_value = fp_value * dec_pow;
527 fp scaled_lower = lower * dec_pow; // \tilde{M}^- in Grisu.
528 fp scaled_upper = upper * dec_pow; // \tilde{M}^+ in Grisu.
529 ++scaled_lower.f; // \tilde{M}^- + 1 ulp -> M^-_{\uparrow}.
530 --scaled_upper.f; // \tilde{M}^+ - 1 ulp -> M^+_{\downarrow}.
531 uint64_t delta = scaled_upper.f - scaled_lower.f;
532 grisu2_gen_digits(scaled_value, scaled_upper, delta, buffer, size, dec_exp);
533}
534
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700535FMT_FUNC void round(char *buffer, size_t &size, int &exp,
536 int digits_to_remove) {
537 size -= to_unsigned(digits_to_remove);
538 exp += digits_to_remove;
539 int digit = buffer[size] - '0';
540 // TODO: proper rounding and carry
541 if (digit > 5 || (digit == 5 && (digits_to_remove > 1 ||
542 (buffer[size - 1] - '0') % 2) != 0)) {
543 ++buffer[size - 1];
544 }
545}
546
547// Writes the exponent exp in the form "[+-]d{1,3}" to buffer.
548FMT_FUNC char *write_exponent(char *buffer, int exp) {
549 FMT_ASSERT(-1000 < exp && exp < 1000, "exponent out of range");
550 if (exp < 0) {
551 *buffer++ = '-';
552 exp = -exp;
553 } else {
554 *buffer++ = '+';
555 }
556 if (exp >= 100) {
557 *buffer++ = static_cast<char>('0' + exp / 100);
558 exp %= 100;
559 const char *d = data::DIGITS + exp * 2;
560 *buffer++ = d[0];
561 *buffer++ = d[1];
562 } else {
563 const char *d = data::DIGITS + exp * 2;
564 *buffer++ = d[0];
565 *buffer++ = d[1];
566 }
567 return buffer;
568}
569
570FMT_FUNC void format_exp_notation(
571 char *buffer, size_t &size, int exp, int precision, bool upper) {
572 // Insert a decimal point after the first digit and add an exponent.
573 std::memmove(buffer + 2, buffer + 1, size - 1);
574 buffer[1] = '.';
575 exp += static_cast<int>(size) - 1;
576 int num_digits = precision - static_cast<int>(size) + 1;
577 if (num_digits > 0) {
578 std::uninitialized_fill_n(buffer + size + 1, num_digits, '0');
579 size += to_unsigned(num_digits);
580 } else if (num_digits < 0) {
581 round(buffer, size, exp, -num_digits);
582 }
583 char *p = buffer + size + 1;
584 *p++ = upper ? 'E' : 'e';
585 size = to_unsigned(write_exponent(p, exp) - buffer);
586}
587
Victor Zverovich0de44a42018-08-26 08:12:35 -0700588// Prettifies the output of the Grisu2 algorithm.
589// The number is given as v = buffer * 10^exp.
Victor Zverovichdd8c5ce2018-08-29 09:34:57 -0700590FMT_FUNC void grisu2_prettify(char *buffer, size_t &size, int exp,
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700591 int precision, bool upper) {
Victor Zverovichdd8c5ce2018-08-29 09:34:57 -0700592 // pow(10, full_exp - 1) <= v <= pow(10, full_exp).
Victor Zveroviche483a012018-08-26 09:51:49 -0700593 int int_size = static_cast<int>(size);
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700594 int full_exp = int_size + exp;
Victor Zverovichdd8c5ce2018-08-29 09:34:57 -0700595 const int exp_threshold = 21;
596 if (int_size <= full_exp && full_exp <= exp_threshold) {
597 // 1234e7 -> 12340000000[.0+]
Victor Zveroviche483a012018-08-26 09:51:49 -0700598 std::uninitialized_fill_n(buffer + int_size, full_exp - int_size, '0');
599 char *p = buffer + full_exp;
Victor Zverovichdd8c5ce2018-08-29 09:34:57 -0700600 if (precision > 0) {
Victor Zveroviche483a012018-08-26 09:51:49 -0700601 *p++ = '.';
Victor Zverovichdd8c5ce2018-08-29 09:34:57 -0700602 std::uninitialized_fill_n(p, precision, '0');
603 p += precision;
Victor Zveroviche483a012018-08-26 09:51:49 -0700604 }
605 size = to_unsigned(p - buffer);
Victor Zverovichdd8c5ce2018-08-29 09:34:57 -0700606 } else if (0 < full_exp && full_exp <= exp_threshold) {
607 // 1234e-2 -> 12.34[0+]
608 int fractional_size = -exp;
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700609 std::memmove(buffer + full_exp + 1, buffer + full_exp,
610 to_unsigned(fractional_size));
Victor Zveroviche483a012018-08-26 09:51:49 -0700611 buffer[full_exp] = '.';
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700612 int num_zeros = precision - fractional_size;
613 if (num_zeros > 0) {
Victor Zveroviche483a012018-08-26 09:51:49 -0700614 std::uninitialized_fill_n(buffer + size + 1, num_zeros, '0');
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700615 size += to_unsigned(num_zeros);
Victor Zveroviche483a012018-08-26 09:51:49 -0700616 }
617 ++size;
618 } else if (-6 < full_exp && full_exp <= 0) {
619 // 1234e-6 -> 0.001234
620 int offset = 2 - full_exp;
621 std::memmove(buffer + offset, buffer, size);
622 buffer[0] = '0';
623 buffer[1] = '.';
624 std::uninitialized_fill_n(buffer + 2, -full_exp, '0');
625 size = to_unsigned(int_size + offset);
626 } else {
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700627 format_exp_notation(buffer, size, exp, precision, upper);
Victor Zveroviche483a012018-08-26 09:51:49 -0700628 }
Victor Zverovich0de44a42018-08-26 08:12:35 -0700629}
630
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700631#if FMT_CLANG_VERSION
632# define FMT_FALLTHROUGH [[clang::fallthrough]];
medithe981797f2018-09-07 17:53:15 +0200633#elif FMT_GCC_VERSION >= 700
634# define FMT_FALLTHROUGH [[gnu::fallthrough]];
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700635#else
636# define FMT_FALLTHROUGH
637#endif
Victor Zveroviche483a012018-08-26 09:51:49 -0700638
Victor Zverovichdd8c5ce2018-08-29 09:34:57 -0700639// Formats a nonnegative value using Grisu2 algorithm. Grisu2 doesn't give any
640// guarantees on the shortness of the result.
Victor Zveroviche483a012018-08-26 09:51:49 -0700641FMT_FUNC void grisu2_format(double value, char *buffer, size_t &size, char type,
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700642 int precision, bool write_decimal_point) {
Victor Zveroviche483a012018-08-26 09:51:49 -0700643 FMT_ASSERT(value >= 0, "value is negative");
644 int dec_exp = 0; // K in Grisu.
645 if (value > 0) {
646 grisu2_format_positive(value, buffer, size, dec_exp);
647 } else {
648 *buffer = '0';
649 size = 1;
650 }
Victor Zverovichdd8c5ce2018-08-29 09:34:57 -0700651 const int default_precision = 6;
652 if (precision < 0)
653 precision = default_precision;
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700654 bool upper = false;
655 switch (type) {
656 case 'G':
657 upper = true;
658 FMT_FALLTHROUGH
659 case '\0': case 'g': {
660 int digits_to_remove = static_cast<int>(size) - precision;
661 if (digits_to_remove > 0) {
662 round(buffer, size, dec_exp, digits_to_remove);
663 // Remove trailing zeros.
664 while (size > 0 && buffer[size - 1] == '0') {
665 --size;
666 ++dec_exp;
667 }
Victor Zverovichdd8c5ce2018-08-29 09:34:57 -0700668 }
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700669 precision = 0;
670 break;
Victor Zveroviche483a012018-08-26 09:51:49 -0700671 }
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700672 case 'F':
673 upper = true;
674 FMT_FALLTHROUGH
675 case 'f': {
676 int digits_to_remove = -dec_exp - precision;
677 if (digits_to_remove > 0) {
678 if (digits_to_remove >= static_cast<int>(size))
679 digits_to_remove = static_cast<int>(size) - 1;
680 round(buffer, size, dec_exp, digits_to_remove);
681 }
682 break;
683 }
684 case 'e': case 'E':
685 format_exp_notation(buffer, size, dec_exp, precision, type == 'E');
686 return;
687 }
688 if (write_decimal_point && precision < 1)
Victor Zverovichdd8c5ce2018-08-29 09:34:57 -0700689 precision = 1;
Victor Zverovich1489d3b2018-08-29 10:07:29 -0700690 grisu2_prettify(buffer, size, dec_exp, precision, upper);
Victor Zverovichf0d0a1e2018-08-25 16:08:32 -0700691}
Victor Zverovichcd900972018-04-21 17:26:24 -0700692} // namespace internal
693
vitaut24c309f2015-06-12 07:15:57 -0700694#if FMT_USE_WINDOWS_H
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700695
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800696FMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) {
Victor Zverovichdff21372014-12-16 07:01:01 -0800697 static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
vitautc3ba6152015-08-07 07:34:58 -0700698 if (s.size() > INT_MAX)
Victor Zverovichc333dca2017-02-19 08:41:38 -0800699 FMT_THROW(windows_error(ERROR_INVALID_PARAMETER, ERROR_MSG));
vitautc3ba6152015-08-07 07:34:58 -0700700 int s_size = static_cast<int>(s.size());
Vasili Galkaacb469a2018-03-12 14:43:29 +0200701 if (s_size == 0) {
702 // MultiByteToWideChar does not support zero length, handle separately.
703 buffer_.resize(1);
704 buffer_[0] = 0;
705 return;
706 }
707
vitautc3ba6152015-08-07 07:34:58 -0700708 int length = MultiByteToWideChar(
Victor Zverovichd8c25a12018-01-20 18:37:57 -0800709 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700710 if (length == 0)
Victor Zverovichc333dca2017-02-19 08:41:38 -0800711 FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
vitaut71542382015-06-27 09:11:15 -0700712 buffer_.resize(length + 1);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700713 length = MultiByteToWideChar(
vitautc3ba6152015-08-07 07:34:58 -0700714 CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700715 if (length == 0)
Victor Zverovichc333dca2017-02-19 08:41:38 -0800716 FMT_THROW(windows_error(GetLastError(), ERROR_MSG));
vitaut71542382015-06-27 09:11:15 -0700717 buffer_[length] = 0;
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700718}
719
Victor Zverovichc333dca2017-02-19 08:41:38 -0800720FMT_FUNC internal::utf16_to_utf8::utf16_to_utf8(wstring_view s) {
Victor Zverovich5d4803a2014-07-27 12:53:42 -0700721 if (int error_code = convert(s)) {
Victor Zverovichc333dca2017-02-19 08:41:38 -0800722 FMT_THROW(windows_error(error_code,
Victor Zverovich8b76e972014-10-06 08:30:55 -0700723 "cannot convert string from UTF-16 to UTF-8"));
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700724 }
725}
726
Victor Zverovichc333dca2017-02-19 08:41:38 -0800727FMT_FUNC int internal::utf16_to_utf8::convert(wstring_view s) {
vitautca747812015-08-07 07:08:46 -0700728 if (s.size() > INT_MAX)
729 return ERROR_INVALID_PARAMETER;
730 int s_size = static_cast<int>(s.size());
Vasili Galkaacb469a2018-03-12 14:43:29 +0200731 if (s_size == 0) {
732 // WideCharToMultiByte does not support zero length, handle separately.
733 buffer_.resize(1);
734 buffer_[0] = 0;
735 return 0;
736 }
737
Victor Zverovichd8c25a12018-01-20 18:37:57 -0800738 int length = WideCharToMultiByte(
739 CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700740 if (length == 0)
741 return GetLastError();
vitaut71542382015-06-27 09:11:15 -0700742 buffer_.resize(length + 1);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700743 length = WideCharToMultiByte(
Victor Zverovichd8c25a12018-01-20 18:37:57 -0800744 CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL);
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700745 if (length == 0)
746 return GetLastError();
vitaut71542382015-06-27 09:11:15 -0700747 buffer_[length] = 0;
Victor Zverovichda9aeab2014-04-30 07:23:43 -0700748 return 0;
749}
750
Victor Zverovichc333dca2017-02-19 08:41:38 -0800751FMT_FUNC void windows_error::init(
Victor Zverovich7f351de2017-12-03 09:18:06 -0800752 int err_code, string_view format_str, format_args args) {
Carter Li3f574c12015-02-17 10:11:42 +0800753 error_code_ = err_code;
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800754 memory_buffer buffer;
Victor Zveroviche022c212017-02-17 06:38:53 -0800755 internal::format_windows_error(buffer, err_code, vformat(format_str, args));
Victor Zverovich53201032014-06-30 14:26:29 -0700756 std::runtime_error &base = *this;
Victor Zveroviche022c212017-02-17 06:38:53 -0800757 base = std::runtime_error(to_string(buffer));
Victor Zverovich53201032014-06-30 14:26:29 -0700758}
759
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700760FMT_FUNC void internal::format_windows_error(
Victor Zverovichf6fd38b2018-01-15 08:22:31 -0800761 internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
Victor Zverovich8b76e972014-10-06 08:30:55 -0700762 FMT_TRY {
Victor Zverovichc0954452018-01-06 09:09:50 -0800763 wmemory_buffer buf;
Victor Zverovichf1ede632018-03-04 10:33:42 -0800764 buf.resize(inline_buffer_size);
Michael Winterberg2a05a872016-03-02 17:35:34 -0800765 for (;;) {
Victor Zverovichc0954452018-01-06 09:09:50 -0800766 wchar_t *system_message = &buf[0];
Victor Zverovichf85d5f42016-10-22 08:04:20 -0700767 int result = FormatMessageW(
768 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
Victor Zverovichd8c25a12018-01-20 18:37:57 -0800769 FMT_NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
770 system_message, static_cast<uint32_t>(buf.size()), FMT_NULL);
Michael Winterberg2a05a872016-03-02 17:35:34 -0800771 if (result != 0) {
Victor Zverovichc333dca2017-02-19 08:41:38 -0800772 utf16_to_utf8 utf8_message;
Michael Winterberg2a05a872016-03-02 17:35:34 -0800773 if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
Victor Zverovich217e7c72018-01-14 07:19:23 -0800774 writer w(out);
Victor Zveroviche022c212017-02-17 06:38:53 -0800775 w.write(message);
776 w.write(": ");
777 w.write(utf8_message);
Michael Winterberg2a05a872016-03-02 17:35:34 -0800778 return;
779 }
780 break;
Victor Zverovich22f75d82014-09-03 08:03:05 -0700781 }
Michael Winterberg2a05a872016-03-02 17:35:34 -0800782 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
783 break; // Can't get error message, report error code instead.
Victor Zverovichc0954452018-01-06 09:09:50 -0800784 buf.resize(buf.size() * 2);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700785 }
Victor Zverovich8b76e972014-10-06 08:30:55 -0700786 } FMT_CATCH(...) {}
Victor Zverovichc0954452018-01-06 09:09:50 -0800787 format_error_code(out, error_code, message);
Victor Zverovich53b4c312014-04-30 15:00:41 -0700788}
vitaut24c309f2015-06-12 07:15:57 -0700789
790#endif // FMT_USE_WINDOWS_H
791
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700792FMT_FUNC void format_system_error(
Victor Zverovichc2fecb92018-01-14 14:15:59 -0800793 internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
vitaut24c309f2015-06-12 07:15:57 -0700794 FMT_TRY {
Victor Zverovich36634142017-12-26 09:00:22 -0800795 memory_buffer buf;
Victor Zverovichf1ede632018-03-04 10:33:42 -0800796 buf.resize(inline_buffer_size);
vitaut24c309f2015-06-12 07:15:57 -0700797 for (;;) {
Victor Zverovich36634142017-12-26 09:00:22 -0800798 char *system_message = &buf[0];
799 int result = safe_strerror(error_code, system_message, buf.size());
vitaut24c309f2015-06-12 07:15:57 -0700800 if (result == 0) {
Victor Zverovich217e7c72018-01-14 07:19:23 -0800801 writer w(out);
Victor Zverovichfefaf072017-02-14 16:29:47 -0500802 w.write(message);
803 w.write(": ");
804 w.write(system_message);
vitaut24c309f2015-06-12 07:15:57 -0700805 return;
806 }
807 if (result != ERANGE)
808 break; // Can't get error message, report error code instead.
Victor Zverovich36634142017-12-26 09:00:22 -0800809 buf.resize(buf.size() * 2);
vitaut24c309f2015-06-12 07:15:57 -0700810 }
811 } FMT_CATCH(...) {}
Victor Zverovichf164e4c2018-02-01 16:49:47 -0800812 format_error_code(out, error_code, message);
vitaut24c309f2015-06-12 07:15:57 -0700813}
Victor Zverovich53b4c312014-04-30 15:00:41 -0700814
jamboree7487bde2015-06-10 09:32:59 +0800815template <typename Char>
Victor Zverovich6a2ff282017-02-19 06:46:51 -0800816void basic_fixed_buffer<Char>::grow(std::size_t) {
Victor Zverovich7c0d5752015-03-01 18:19:56 -0800817 FMT_THROW(std::runtime_error("buffer overflow"));
818}
819
Abdó Roig-Marangesaf0f21d2017-12-09 16:50:53 +0100820FMT_FUNC void internal::error_handler::on_error(const char *message) {
Victor Zverovich94edb1a2017-12-06 07:42:42 -0800821 FMT_THROW(format_error(message));
822}
823
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700824FMT_FUNC void report_system_error(
Victor Zverovich50e71672017-02-18 06:52:52 -0800825 int error_code, fmt::string_view message) FMT_NOEXCEPT {
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700826 report_error(format_system_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700827}
828
vitaut24c309f2015-06-12 07:15:57 -0700829#if FMT_USE_WINDOWS_H
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700830FMT_FUNC void report_windows_error(
Victor Zverovich50e71672017-02-18 06:52:52 -0800831 int error_code, fmt::string_view message) FMT_NOEXCEPT {
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700832 report_error(internal::format_windows_error, error_code, message);
Victor Zverovich1a2d7be2014-05-03 09:48:54 -0700833}
Victor Zverovich400812a2014-04-30 12:38:17 -0700834#endif
Victor Zverovichf7939862014-04-30 10:18:11 -0700835
Victor Zverovich81bd9e82017-12-03 07:32:04 -0800836FMT_FUNC void vprint(std::FILE *f, string_view format_str, format_args args) {
Victor Zverovicheedfd072017-02-18 09:13:12 -0800837 memory_buffer buffer;
Victor Zverovichfefaf072017-02-14 16:29:47 -0500838 vformat_to(buffer, format_str, args);
839 std::fwrite(buffer.data(), 1, buffer.size(), f);
Victor Zverovichd5b81962014-06-28 21:56:40 -0700840}
841
Daniela Engert2570f1a2018-04-26 20:32:14 +0200842FMT_FUNC void vprint(std::FILE *f, wstring_view format_str, wformat_args args) {
843 wmemory_buffer buffer;
844 vformat_to(buffer, format_str, args);
845 std::fwrite(buffer.data(), sizeof(wchar_t), buffer.size(), f);
846}
847
Victor Zverovich81bd9e82017-12-03 07:32:04 -0800848FMT_FUNC void vprint(string_view format_str, format_args args) {
Victor Zverovich0028ce52016-08-26 17:23:13 -0700849 vprint(stdout, format_str, args);
Victor Zverovich163178e2014-09-25 07:08:25 -0700850}
851
Daniela Engert2570f1a2018-04-26 20:32:14 +0200852FMT_FUNC void vprint(wstring_view format_str, wformat_args args) {
853 vprint(stdout, format_str, args);
854}
855
Remotionce500632018-06-09 00:33:39 +0200856#ifndef FMT_EXTENDED_COLORS
Victor Zverovichbb471092018-03-04 11:25:40 -0800857FMT_FUNC void vprint_colored(color c, string_view format, format_args args) {
Victor Zverovich2dc108b2014-07-01 09:10:43 -0700858 char escape[] = "\x1b[30m";
Ingo van Lilf4d88842015-11-02 19:14:47 +0100859 escape[3] = static_cast<char>('0' + c);
Victor Zverovich2dc108b2014-07-01 09:10:43 -0700860 std::fputs(escape, stdout);
Victor Zverovich0028ce52016-08-26 17:23:13 -0700861 vprint(format, args);
Dhruv Paranjapeec218a32018-06-28 10:43:00 +0530862 std::fputs(internal::data::RESET_COLOR, stdout);
Victor Zverovich2dc108b2014-07-01 09:10:43 -0700863}
864
Daniela Engert2570f1a2018-04-26 20:32:14 +0200865FMT_FUNC void vprint_colored(color c, wstring_view format, wformat_args args) {
866 wchar_t escape[] = L"\x1b[30m";
867 escape[3] = static_cast<wchar_t>('0' + c);
868 std::fputws(escape, stdout);
869 vprint(format, args);
Dhruv Paranjapeec218a32018-06-28 10:43:00 +0530870 std::fputws(internal::data::WRESET_COLOR, stdout);
Daniela Engert2570f1a2018-04-26 20:32:14 +0200871}
Remotionce500632018-06-09 00:33:39 +0200872#else
873namespace internal {
874FMT_CONSTEXPR void to_esc(uint8_t c, char out[], int offset) {
875 out[offset + 0] = static_cast<char>('0' + c / 100);
876 out[offset + 1] = static_cast<char>('0' + c / 10 % 10);
877 out[offset + 2] = static_cast<char>('0' + c % 10);
878}
879} // namespace internal
880
881FMT_FUNC void vprint_rgb(rgb fd, string_view format, format_args args) {
882 char escape_fd[] = "\x1b[38;2;000;000;000m";
Remotionce500632018-06-09 00:33:39 +0200883 internal::to_esc(fd.r, escape_fd, 7);
884 internal::to_esc(fd.g, escape_fd, 11);
885 internal::to_esc(fd.b, escape_fd, 15);
886
887 std::fputs(escape_fd, stdout);
888 vprint(format, args);
Dhruv Paranjapeec218a32018-06-28 10:43:00 +0530889 std::fputs(internal::data::RESET_COLOR, stdout);
Remotionce500632018-06-09 00:33:39 +0200890}
891
892FMT_FUNC void vprint_rgb(rgb fd, rgb bg, string_view format, format_args args) {
893 char escape_fd[] = "\x1b[38;2;000;000;000m"; // foreground color
894 char escape_bg[] = "\x1b[48;2;000;000;000m"; // background color
Remotionce500632018-06-09 00:33:39 +0200895 internal::to_esc(fd.r, escape_fd, 7);
896 internal::to_esc(fd.g, escape_fd, 11);
897 internal::to_esc(fd.b, escape_fd, 15);
898
899 internal::to_esc(bg.r, escape_bg, 7);
900 internal::to_esc(bg.g, escape_bg, 11);
901 internal::to_esc(bg.b, escape_bg, 15);
902
903 std::fputs(escape_fd, stdout);
904 std::fputs(escape_bg, stdout);
905 vprint(format, args);
Dhruv Paranjapeec218a32018-06-28 10:43:00 +0530906 std::fputs(internal::data::RESET_COLOR, stdout);
Remotionce500632018-06-09 00:33:39 +0200907}
908#endif
Thomas Bernardabde38b2018-08-17 11:22:56 +0200909#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
Victor Zverovichd165d9c2017-12-26 17:22:07 -0800910FMT_FUNC locale locale_provider::locale() { return fmt::locale(); }
Thomas Bernardabde38b2018-08-17 11:22:56 +0200911#endif
Victor Zverovichd165d9c2017-12-26 17:22:07 -0800912
Victor Zverovich838400d2018-05-12 08:33:51 -0700913FMT_END_NAMESPACE
Victor Zverovich0d5ef5c2016-07-12 06:59:35 -0700914
Ingo van Lilb4b13ee2015-11-02 12:34:46 +0100915#ifdef _MSC_VER
jdale88a9862fd2014-03-11 18:56:24 +0000916# pragma warning(pop)
917#endif
Victor Zverovich3da71d52018-03-21 07:50:59 -0700918
919#endif // FMT_FORMAT_INL_H_