Merge branch 'master' into ci

This commit is contained in:
Elias Kosunen 2018-06-05 02:11:02 +03:00 committed by GitHub
commit 739af475b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 334 additions and 223 deletions

View File

@ -56,7 +56,7 @@ def create_build_env(dirname='virtualenv'):
pip_install('sphinx-doc/sphinx', '12b83372ac9316e8cbe86e7fed889296a4cc29ee',
min_version='1.4.1.dev20160531')
pip_install('michaeljones/breathe',
'6b1c5bb7a1866f15fc328b8716258354b10c1daa',
'129222318f7c8f865d2631e7da7b033567e7f56a',
min_version='4.2.0')
def build_docs(version='dev', **kwargs):

View File

@ -16,7 +16,7 @@
#include <type_traits>
// The fmt library version in the form major * 10000 + minor * 100 + patch.
#define FMT_VERSION 50000
#define FMT_VERSION 50100
#ifdef __has_feature
# define FMT_HAS_FEATURE(x) __has_feature(x)
@ -804,8 +804,9 @@ class arg_map {
~arg_map() { delete [] map_; }
basic_format_arg<Context> find(basic_string_view<char_type> name) const {
auto end = map_ + size_; // Define end outside of loop to make nvcc happy.
// The list is unsorted, so just return the first matching name.
for (auto it = map_, end = map_ + size_; it != end; ++it) {
for (auto it = map_; it != end; ++it) {
if (it->name == name)
return it->arg;
}
@ -990,16 +991,17 @@ class format_arg_store {
friend class basic_format_args<Context>;
static FMT_CONSTEXPR uint64_t get_types() {
return IS_PACKED ? internal::get_types<Context, Args...>()
: -static_cast<int64_t>(NUM_ARGS);
static FMT_CONSTEXPR int64_t get_types() {
return IS_PACKED ?
static_cast<int64_t>(internal::get_types<Context, Args...>()) :
-static_cast<int64_t>(NUM_ARGS);
}
public:
#if FMT_USE_CONSTEXPR
static constexpr uint64_t TYPES = get_types();
static constexpr int64_t TYPES = get_types();
#else
static const uint64_t TYPES;
static const int64_t TYPES;
#endif
#if FMT_GCC_VERSION && FMT_GCC_VERSION <= 405
@ -1015,7 +1017,7 @@ class format_arg_store {
#if !FMT_USE_CONSTEXPR
template <typename Context, typename ...Args>
const uint64_t format_arg_store<Context, Args...>::TYPES = get_types();
const int64_t format_arg_store<Context, Args...>::TYPES = get_types();
#endif
/**

View File

@ -223,30 +223,19 @@ FMT_FUNC void system_error::init(
namespace internal {
template <typename T>
int char_traits<char>::format_float(
char *buffer, std::size_t size, const char *format,
unsigned width, int precision, T value) {
if (width == 0) {
return precision < 0 ?
FMT_SNPRINTF(buffer, size, format, value) :
FMT_SNPRINTF(buffer, size, format, precision, value);
}
char *buffer, std::size_t size, const char *format, int precision, T value) {
return precision < 0 ?
FMT_SNPRINTF(buffer, size, format, width, value) :
FMT_SNPRINTF(buffer, size, format, width, precision, value);
FMT_SNPRINTF(buffer, size, format, value) :
FMT_SNPRINTF(buffer, size, format, precision, value);
}
template <typename T>
int char_traits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format,
unsigned width, int precision, T value) {
if (width == 0) {
return precision < 0 ?
FMT_SWPRINTF(buffer, size, format, value) :
FMT_SWPRINTF(buffer, size, format, precision, value);
}
wchar_t *buffer, std::size_t size, const wchar_t *format, int precision,
T value) {
return precision < 0 ?
FMT_SWPRINTF(buffer, size, format, width, value) :
FMT_SWPRINTF(buffer, size, format, width, precision, value);
FMT_SWPRINTF(buffer, size, format, value) :
FMT_SWPRINTF(buffer, size, format, precision, value);
}
template <typename T>
@ -285,35 +274,28 @@ const uint64_t basic_data<T>::POWERS_OF_10_64[] = {
// These are generated by support/compute-powers.py.
template <typename T>
const uint64_t basic_data<T>::POW10_SIGNIFICANDS[] = {
0xfa8fd5a0081c0288ull, 0xbaaee17fa23ebf76ull, 0x8b16fb203055ac76ull,
0xcf42894a5dce35eaull, 0x9a6bb0aa55653b2dull, 0xe61acf033d1a45dfull,
0xab70fe17c79ac6caull, 0xff77b1fcbebcdc4full, 0xbe5691ef416bd60cull,
0x8dd01fad907ffc3cull, 0xd3515c2831559a83ull, 0x9d71ac8fada6c9b5ull,
0xea9c227723ee8bcbull, 0xaecc49914078536dull, 0x823c12795db6ce57ull,
0xc21094364dfb5637ull, 0x9096ea6f3848984full, 0xd77485cb25823ac7ull,
0xa086cfcd97bf97f4ull, 0xef340a98172aace5ull, 0xb23867fb2a35b28eull,
0x84c8d4dfd2c63f3bull, 0xc5dd44271ad3cdbaull, 0x936b9fcebb25c996ull,
0xdbac6c247d62a584ull, 0xa3ab66580d5fdaf6ull, 0xf3e2f893dec3f126ull,
0xb5b5ada8aaff80b8ull, 0x87625f056c7c4a8bull, 0xc9bcff6034c13053ull,
0x964e858c91ba2655ull, 0xdff9772470297ebdull, 0xa6dfbd9fb8e5b88full,
0xf8a95fcf88747d94ull, 0xb94470938fa89bcfull, 0x8a08f0f8bf0f156bull,
0xcdb02555653131b6ull, 0x993fe2c6d07b7facull, 0xe45c10c42a2b3b06ull,
0xaa242499697392d3ull, 0xfd87b5f28300ca0eull, 0xbce5086492111aebull,
0x8cbccc096f5088ccull, 0xd1b71758e219652cull, 0x9c40000000000000ull,
0xe8d4a51000000000ull, 0xad78ebc5ac620000ull, 0x813f3978f8940984ull,
0xc097ce7bc90715b3ull, 0x8f7e32ce7bea5c70ull, 0xd5d238a4abe98068ull,
0x9f4f2726179a2245ull, 0xed63a231d4c4fb27ull, 0xb0de65388cc8ada8ull,
0x83c7088e1aab65dbull, 0xc45d1df942711d9aull, 0x924d692ca61be758ull,
0xda01ee641a708deaull, 0xa26da3999aef774aull, 0xf209787bb47d6b85ull,
0xb454e4a179dd1877ull, 0x865b86925b9bc5c2ull, 0xc83553c5c8965d3dull,
0x952ab45cfa97a0b3ull, 0xde469fbd99a05fe3ull, 0xa59bc234db398c25ull,
0xf6c69a72a3989f5cull, 0xb7dcbf5354e9beceull, 0x88fcf317f22241e2ull,
0xcc20ce9bd35c78a5ull, 0x98165af37b2153dfull, 0xe2a0b5dc971f303aull,
0xa8d9d1535ce3b396ull, 0xfb9b7cd9a4a7443cull, 0xbb764c4ca7a44410ull,
0x8bab8eefb6409c1aull, 0xd01fef10a657842cull, 0x9b10a4e5e9913129ull,
0xe7109bfba19c0c9dull, 0xac2820d9623bf429ull, 0x80444b5e7aa7cf85ull,
0xbf21e44003acdd2dull, 0x8e679c2f5e44ff8full, 0xd433179d9c8cb841ull,
0x9e19db92b4e31ba9ull, 0xeb96bf6ebadf77d9ull, 0xaf87023b9bf0ee6bull
0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, 0x8b16fb203055ac76, 0xcf42894a5dce35ea,
0x9a6bb0aa55653b2d, 0xe61acf033d1a45df, 0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f,
0xbe5691ef416bd60c, 0x8dd01fad907ffc3c, 0xd3515c2831559a83, 0x9d71ac8fada6c9b5,
0xea9c227723ee8bcb, 0xaecc49914078536d, 0x823c12795db6ce57, 0xc21094364dfb5637,
0x9096ea6f3848984f, 0xd77485cb25823ac7, 0xa086cfcd97bf97f4, 0xef340a98172aace5,
0xb23867fb2a35b28e, 0x84c8d4dfd2c63f3b, 0xc5dd44271ad3cdba, 0x936b9fcebb25c996,
0xdbac6c247d62a584, 0xa3ab66580d5fdaf6, 0xf3e2f893dec3f126, 0xb5b5ada8aaff80b8,
0x87625f056c7c4a8b, 0xc9bcff6034c13053, 0x964e858c91ba2655, 0xdff9772470297ebd,
0xa6dfbd9fb8e5b88f, 0xf8a95fcf88747d94, 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b,
0xcdb02555653131b6, 0x993fe2c6d07b7fac, 0xe45c10c42a2b3b06, 0xaa242499697392d3,
0xfd87b5f28300ca0e, 0xbce5086492111aeb, 0x8cbccc096f5088cc, 0xd1b71758e219652c,
0x9c40000000000000, 0xe8d4a51000000000, 0xad78ebc5ac620000, 0x813f3978f8940984,
0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70, 0xd5d238a4abe98068, 0x9f4f2726179a2245,
0xed63a231d4c4fb27, 0xb0de65388cc8ada8, 0x83c7088e1aab65db, 0xc45d1df942711d9a,
0x924d692ca61be758, 0xda01ee641a708dea, 0xa26da3999aef774a, 0xf209787bb47d6b85,
0xb454e4a179dd1877, 0x865b86925b9bc5c2, 0xc83553c5c8965d3d, 0x952ab45cfa97a0b3,
0xde469fbd99a05fe3, 0xa59bc234db398c25, 0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece,
0x88fcf317f22241e2, 0xcc20ce9bd35c78a5, 0x98165af37b2153df, 0xe2a0b5dc971f303a,
0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c, 0xbb764c4ca7a44410, 0x8bab8eefb6409c1a,
0xd01fef10a657842c, 0x9b10a4e5e9913129, 0xe7109bfba19c0c9d, 0xac2820d9623bf429,
0x80444b5e7aa7cf85, 0xbf21e44003acdd2d, 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841,
0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, 0xaf87023b9bf0ee6b
};
// Binary exponents of pow(10, k), for k = -348, -340, ..., 340, corresponding
@ -340,6 +322,19 @@ FMT_FUNC fp operator*(fp x, fp y) {
uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31);
return fp(ac + (ad >> 32) + (bc >> 32) + (mid >> 32), x.e + y.e + 64);
}
FMT_FUNC fp get_cached_power(int min_exponent, int &pow10_exponent) {
const double one_over_log2_10 = 0.30102999566398114; // 1 / log2(10)
int index = static_cast<int>(std::ceil(
(min_exponent + fp::significand_size - 1) * one_over_log2_10));
// Decimal exponent of the first (smallest) cached power of 10.
const int first_dec_exp = -348;
// Difference between two consecutive decimal exponents in cached powers of 10.
const int dec_exp_step = 8;
index = (index - first_dec_exp - 1) / dec_exp_step + 1;
pow10_exponent = first_dec_exp + index * dec_exp_step;
return fp(data::POW10_SIGNIFICANDS[index], data::POW10_EXPONENTS[index]);
}
} // namespace internal
#if FMT_USE_WINDOWS_H

View File

@ -88,7 +88,23 @@
#ifndef FMT_THROW
# if FMT_EXCEPTIONS
# define FMT_THROW(x) throw x
# if FMT_MSC_VER
FMT_BEGIN_NAMESPACE
namespace internal {
template <typename Exception>
inline void do_throw(const Exception &x) {
// Silence unreachable code warnings in MSVC because these are nearly
// impossible to fix in a generic code.
volatile bool b = true;
if (b)
throw x;
}
}
FMT_END_NAMESPACE
# define FMT_THROW(x) fmt::internal::do_throw(x)
# else
# define FMT_THROW(x) throw x
# endif
# else
# define FMT_THROW(x) do { static_cast<void>(sizeof(x)); assert(false); } while(false);
# endif
@ -105,8 +121,9 @@
# endif
#endif
#if FMT_USE_USER_DEFINED_LITERALS && __cplusplus >= 201402L && \
(FMT_GCC_VERSION >= 600 || FMT_CLANG_VERSION >= 304)
#if FMT_USE_USER_DEFINED_LITERALS && !defined(FMT_ICC_VERSION) && \
((FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L) || \
(defined(FMT_CLANG_VERSION) && FMT_CLANG_VERSION >= 304))
# define FMT_UDL_TEMPLATE 1
#else
# define FMT_UDL_TEMPLATE 0
@ -122,7 +139,8 @@
# endif
#endif
#if FMT_HAS_GXX_CXX11 || FMT_HAS_FEATURE(cxx_trailing_return) || FMT_MSC_VER >= 1600
#if FMT_HAS_GXX_CXX11 || FMT_HAS_FEATURE(cxx_trailing_return) || \
FMT_MSC_VER >= 1600
# define FMT_USE_TRAILING_RETURN 1
#else
# define FMT_USE_TRAILING_RETURN 0
@ -134,6 +152,10 @@
# define FMT_USE_RVALUE_REFERENCES 0
#endif
#ifndef FMT_USE_GRISU
# define FMT_USE_GRISU 0
#endif
// __builtin_clz is broken in clang with Microsoft CodeGen:
// https://github.com/fmtlib/fmt/issues/519
#ifndef _MSC_VER
@ -256,10 +278,24 @@ inline dummy_int isnan(...) { return dummy_int(); }
inline dummy_int _isnan(...) { return dummy_int(); }
// A handmade floating-point number f * pow(2, e).
struct fp {
uint64_t f;
class fp {
private:
typedef uint64_t significand_type;
// All sizes are in bits.
static constexpr int char_size = std::numeric_limits<unsigned char>::digits;
// Subtract 1 to account for an implicit most significant bit in the
// normalized form.
static constexpr int double_significand_size =
std::numeric_limits<double>::digits - 1;
static constexpr uint64_t implicit_bit = 1ull << double_significand_size;
public:
significand_type f;
int e;
static constexpr int significand_size = sizeof(significand_type) * char_size;
fp(uint64_t f, int e): f(f), e(e) {}
// Constructs fp from an IEEE754 double. It is a template to prevent compile
@ -268,24 +304,35 @@ struct fp {
explicit fp(Double d) {
// Assume double is in the format [sign][exponent][significand].
typedef std::numeric_limits<Double> limits;
const int double_size =
sizeof(Double) * std::numeric_limits<unsigned char>::digits;
// Subtract 1 to account for an implicit most significant bit in the
// normalized form.
const int significand_size = limits::digits - 1;
const int exponent_size = double_size - significand_size - 1; // -1 for sign
const uint64_t implicit_bit = 1ull << significand_size;
const int double_size = sizeof(Double) * char_size;
const int exponent_size =
double_size - double_significand_size - 1; // -1 for sign
const uint64_t significand_mask = implicit_bit - 1;
const uint64_t exponent_mask = (~0ull >> 1) & ~significand_mask;
const int exponent_bias = (1 << exponent_size) - limits::max_exponent - 1;
auto u = bit_cast<uint64_t>(d);
auto biased_e = (u & exponent_mask) >> significand_size;
auto biased_e = (u & exponent_mask) >> double_significand_size;
f = u & significand_mask;
if (biased_e != 0)
f += implicit_bit;
else
biased_e = 1; // Subnormals use biased exponent 1 (min exponent).
e = biased_e - exponent_bias - significand_size;
e = biased_e - exponent_bias - double_significand_size;
}
// Normalizes the value converted from double and multiplied by (1 << SHIFT).
template <int SHIFT = 0>
void normalize() {
// Handle subnormals.
auto shifted_implicit_bit = implicit_bit << SHIFT;
while ((f & shifted_implicit_bit) == 0) {
f <<= 1;
--e;
}
// Subtract 1 to account for hidden bit.
auto offset = significand_size - double_significand_size - SHIFT - 1;
f <<= offset;
e -= offset;
}
};
@ -295,16 +342,13 @@ inline fp operator-(fp x, fp y) {
return fp(x.f - y.f, x.e);
}
// Computes an fp number r with r.f = x.f * y.f / pow(2, 32) rounded to nearest
// with half-up tie breaking, r.e = x.e + y.e + 32. Result may not be normalized.
// Computes an fp number r with r.f = x.f * y.f / pow(2, 64) rounded to nearest
// with half-up tie breaking, r.e = x.e + y.e + 64. Result may not be normalized.
fp operator*(fp x, fp y);
// Compute k such that its cached power c_k = c_k.f * pow(2, c_k.e) satisfies
// min_exponent <= c_k.e + e <= min_exponent + 3.
inline int compute_cached_power_index(int e, int min_exponent) {
FMT_CONSTEXPR_DECL double one_over_log2_10 = 0.30102999566398114; // 1 / log2(10)
return static_cast<int>(std::ceil((min_exponent - e + 63) * one_over_log2_10));
}
// Returns cached power (of 10) c_k = c_k.f * pow(2, c_k.e) such that its
// (binary) exponent satisfies min_exponent <= c_k.e <= min_exponent + 3.
fp get_cached_power(int min_exponent, int &pow10_exponent);
template <typename Allocator>
typename Allocator::value_type *allocate(Allocator& alloc, std::size_t n) {
@ -370,6 +414,38 @@ FMT_BEGIN_NAMESPACE
template <typename Range>
class basic_writer;
template <typename OutputIt, typename T = typename OutputIt::value_type>
class output_range {
private:
OutputIt it_;
// Unused yet.
typedef void sentinel;
sentinel end() const;
public:
typedef OutputIt iterator;
typedef T value_type;
explicit output_range(OutputIt it): it_(it) {}
OutputIt begin() const { return it_; }
};
// A range where begin() returns back_insert_iterator.
template <typename Container>
class back_insert_range:
public output_range<std::back_insert_iterator<Container>> {
typedef output_range<std::back_insert_iterator<Container>> base;
public:
typedef typename Container::value_type value_type;
back_insert_range(Container &c): base(std::back_inserter(c)) {}
back_insert_range(typename base::iterator it): base(it) {}
};
typedef basic_writer<back_insert_range<internal::buffer>> writer;
typedef basic_writer<back_insert_range<internal::wbuffer>> wwriter;
/** A formatting error such as invalid format string. */
class format_error : public std::runtime_error {
public:
@ -597,30 +673,30 @@ struct char_traits<char> {
// Formats a floating-point number.
template <typename T>
FMT_API static int format_float(char *buffer, std::size_t size,
const char *format, unsigned width, int precision, T value);
const char *format, int precision, T value);
};
template <>
struct char_traits<wchar_t> {
template <typename T>
FMT_API static int format_float(wchar_t *buffer, std::size_t size,
const wchar_t *format, unsigned width, int precision, T value);
const wchar_t *format, int precision, T value);
};
#if FMT_USE_EXTERN_TEMPLATES
extern template int char_traits<char>::format_float<double>(
char *buffer, std::size_t size, const char* format, unsigned width,
int precision, double value);
char *buffer, std::size_t size, const char* format, int precision,
double value);
extern template int char_traits<char>::format_float<long double>(
char *buffer, std::size_t size, const char* format, unsigned width,
int precision, long double value);
char *buffer, std::size_t size, const char* format, int precision,
long double value);
extern template int char_traits<wchar_t>::format_float<double>(
wchar_t *buffer, std::size_t size, const wchar_t* format, unsigned width,
int precision, double value);
wchar_t *buffer, std::size_t size, const wchar_t* format, int precision,
double value);
extern template int char_traits<wchar_t>::format_float<long double>(
wchar_t *buffer, std::size_t size, const wchar_t* format, unsigned width,
int precision, long double value);
wchar_t *buffer, std::size_t size, const wchar_t* format, int precision,
long double value);
#endif
template <typename Container>
@ -1982,41 +2058,42 @@ struct precision_adapter {
template <typename Iterator, typename SpecHandler>
FMT_CONSTEXPR Iterator parse_format_specs(Iterator it, SpecHandler &&handler) {
typedef typename std::iterator_traits<Iterator>::value_type char_type;
char_type c = *it;
if (c == '}' || !c)
return it;
// Parse fill and alignment.
if (char_type c = *it) {
alignment align = ALIGN_DEFAULT;
int i = 1;
do {
auto p = it + i;
switch (*p) {
case '<':
align = ALIGN_LEFT;
break;
case '>':
align = ALIGN_RIGHT;
break;
case '=':
align = ALIGN_NUMERIC;
break;
case '^':
align = ALIGN_CENTER;
break;
}
if (align != ALIGN_DEFAULT) {
handler.on_align(align);
if (p != it) {
if (c == '}') break;
if (c == '{') {
handler.on_error("invalid fill character '{'");
return it;
}
it += 2;
handler.on_fill(c);
} else ++it;
alignment align = ALIGN_DEFAULT;
int i = 1;
do {
auto p = it + i;
switch (*p) {
case '<':
align = ALIGN_LEFT;
break;
}
} while (--i >= 0);
}
case '>':
align = ALIGN_RIGHT;
break;
case '=':
align = ALIGN_NUMERIC;
break;
case '^':
align = ALIGN_CENTER;
break;
}
if (align != ALIGN_DEFAULT) {
if (p != it) {
if (c == '{') {
handler.on_error("invalid fill character '{'");
return it;
}
it += 2;
handler.on_fill(c);
} else ++it;
handler.on_align(align);
break;
}
} while (--i >= 0);
// Parse sign.
switch (*it) {
@ -2600,6 +2677,9 @@ class basic_writer {
// Formats a floating-point number (double or long double).
template <typename T>
void write_double(T value, const format_specs &spec);
template <typename T>
void write_double_sprintf(T value, const format_specs &spec,
internal::basic_buffer<char_type>& buffer);
template <typename Char>
struct str_writer {
@ -2822,60 +2902,39 @@ void basic_writer<Range>::write_double(T value, const format_specs &spec) {
return write_inf_or_nan(handler.upper ? "INF" : "inf");
basic_memory_buffer<char_type> buffer;
unsigned width = spec.width();
if (sign) {
buffer.reserve(width > 1u ? width : 1u);
if (width > 0)
--width;
}
// Build format string.
enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg
char_type format[MAX_FORMAT_SIZE];
char_type *format_ptr = format;
*format_ptr++ = '%';
unsigned width_for_sprintf = width;
if (spec.flag(HASH_FLAG))
*format_ptr++ = '#';
width_for_sprintf = 0;
if (spec.precision() >= 0) {
*format_ptr++ = '.';
*format_ptr++ = '*';
}
append_float_length(format_ptr, value);
*format_ptr++ = handler.type;
*format_ptr = '\0';
// Format using snprintf.
unsigned n = 0;
char_type *start = FMT_NULL;
for (;;) {
std::size_t buffer_size = buffer.capacity();
#if FMT_MSC_VER
// MSVC's vsnprintf_s doesn't work with zero size, so reserve
// space for at least one extra character to make the size non-zero.
// Note that the buffer's capacity may increase by more than 1.
if (buffer_size == 0) {
buffer.reserve(1);
buffer_size = buffer.capacity();
}
#endif
start = &buffer[0];
int result = internal::char_traits<char_type>::format_float(
start, buffer_size, format, width_for_sprintf, spec.precision(), value);
if (result >= 0) {
n = internal::to_unsigned(result);
if (n < buffer.capacity())
break; // The buffer is large enough - continue with formatting.
buffer.reserve(n + 1);
} else {
// If result is negative we ask to increase the capacity by at least 1,
// but as std::vector, the buffer grows exponentially.
buffer.reserve(buffer.capacity() + 1);
if (FMT_USE_GRISU && sizeof(T) <= sizeof(double) &&
std::numeric_limits<double>::is_iec559) {
internal::fp fp_value(static_cast<double>(value));
fp_value.normalize();
// Find a cached power of 10 close to 1 / fp_value.
int dec_exp = 0;
const int min_exp = -60;
auto dec_pow = internal::get_cached_power(
min_exp - (fp_value.e + internal::fp::significand_size), dec_exp);
internal::fp product = fp_value * dec_pow;
// Generate output.
internal::fp one(1ull << -product.e, product.e);
uint32_t hi = product.f >> -one.e;
uint64_t f = product.f & (one.f - 1);
typedef back_insert_range<internal::basic_buffer<char_type>> range;
basic_writer<range> w{range(buffer)};
w.write(hi);
unsigned digits = buffer.size();
w.write('.');
const unsigned max_digits = 18;
while (digits++ < max_digits) {
f *= 10;
w.write(static_cast<char>('0' + (f >> -one.e)));
f &= one.f - 1;
}
w.write('e');
w.write(-dec_exp);
} else {
format_specs normalized_spec(spec);
normalized_spec.type_ = handler.type;
write_double_sprintf(value, normalized_spec, buffer);
}
unsigned n = buffer.size();
align_spec as = spec;
if (spec.align() == ALIGN_NUMERIC) {
if (sign) {
@ -2894,37 +2953,51 @@ void basic_writer<Range>::write_double(T value, const format_specs &spec) {
write_padded(n, as, double_writer{n, sign, buffer});
}
template <typename OutputIt, typename T = typename OutputIt::value_type>
class output_range {
private:
OutputIt it_;
template <typename Range>
template <typename T>
void basic_writer<Range>::write_double_sprintf(
T value, const format_specs &spec,
internal::basic_buffer<char_type>& buffer) {
// Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail.
FMT_ASSERT(buffer.capacity() != 0, "empty buffer");
// Unused yet.
typedef void sentinel;
sentinel end() const;
// Build format string.
enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg
char_type format[MAX_FORMAT_SIZE];
char_type *format_ptr = format;
*format_ptr++ = '%';
if (spec.flag(HASH_FLAG))
*format_ptr++ = '#';
if (spec.precision() >= 0) {
*format_ptr++ = '.';
*format_ptr++ = '*';
}
public:
typedef OutputIt iterator;
typedef T value_type;
append_float_length(format_ptr, value);
*format_ptr++ = spec.type();
*format_ptr = '\0';
explicit output_range(OutputIt it): it_(it) {}
OutputIt begin() const { return it_; }
};
// A range where begin() returns back_insert_iterator.
template <typename Container>
class back_insert_range:
public output_range<std::back_insert_iterator<Container>> {
typedef output_range<std::back_insert_iterator<Container>> base;
public:
typedef typename Container::value_type value_type;
back_insert_range(Container &c): base(std::back_inserter(c)) {}
back_insert_range(typename base::iterator it): base(it) {}
};
typedef basic_writer<back_insert_range<internal::buffer>> writer;
typedef basic_writer<back_insert_range<internal::wbuffer>> wwriter;
// Format using snprintf.
char_type *start = FMT_NULL;
for (;;) {
std::size_t buffer_size = buffer.capacity();
start = &buffer[0];
int result = internal::char_traits<char_type>::format_float(
start, buffer_size, format, spec.precision(), value);
if (result >= 0) {
unsigned n = internal::to_unsigned(result);
if (n < buffer.capacity()) {
buffer.resize(n);
break; // The buffer is large enough - continue with formatting.
}
buffer.reserve(n + 1);
} else {
// If result is negative we ask to increase the capacity by at least 1,
// but as std::vector, the buffer grows exponentially.
buffer.reserve(buffer.capacity() + 1);
}
}
}
// Reports a system error without throwing an exception.
// Can be used to report errors from destructors.

View File

@ -21,12 +21,12 @@ template void internal::arg_map<format_context>::init(
const basic_format_args<format_context> &args);
template FMT_API int internal::char_traits<char>::format_float(
char *buffer, std::size_t size, const char *format,
unsigned width, int precision, double value);
char *buffer, std::size_t size, const char *format, int precision,
double value);
template FMT_API int internal::char_traits<char>::format_float(
char *buffer, std::size_t size, const char *format,
unsigned width, int precision, long double value);
char *buffer, std::size_t size, const char *format, int precision,
long double value);
// Explicit instantiations for wchar_t.
@ -39,9 +39,9 @@ template void internal::arg_map<wformat_context>::init(
template FMT_API int internal::char_traits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format,
unsigned width, int precision, double value);
int precision, double value);
template FMT_API int internal::char_traits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format,
unsigned width, int precision, long double value);
int precision, long double value);
FMT_END_NAMESPACE

View File

@ -4,7 +4,7 @@ include $(CLEAR_VARS)
LOCAL_MODULE := fmt_static
LOCAL_MODULE_FILENAME := libfmt
LOCAL_SRC_FILES := fmt/format.cc
LOCAL_SRC_FILES := ../src/format.cc
LOCAL_C_INCLUDES := $(LOCAL_PATH)
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)

View File

@ -39,12 +39,15 @@ for i, exp in enumerate(range(min_exponent, max_exponent + 1, step)):
print('Significands:', end='')
for i, fp in enumerate(powers):
if i % 3 == 0:
if i % 4 == 0:
print(end='\n ')
print(' {:0<#16x}ull'.format(fp.f, ), end=',')
print(' {:0<#16x}'.format(fp.f, ), end=',')
print('\n\nExponents:', end='')
for i, fp in enumerate(powers):
if i % 11 == 0:
print(end='\n ')
print(' {:5}'.format(fp.e), end=',')
print('\n\nMax exponent difference:',
max([x.e - powers[i - 1].e for i, x in enumerate(powers)][1:]))

View File

@ -152,7 +152,9 @@ def update_site(env):
if os.path.exists(html_dir):
shutil.rmtree(html_dir)
include_dir = env.fmt_repo.dir
if LooseVersion(version) >= LooseVersion('3.0.0'):
if LooseVersion(version) >= LooseVersion('5.0.0'):
include_dir = os.path.join(include_dir, 'include', 'fmt')
elif LooseVersion(version) >= LooseVersion('3.0.0'):
include_dir = os.path.join(include_dir, 'fmt')
import build
build.build_docs(version, doc_dir=target_doc_dir,

View File

@ -435,6 +435,7 @@ TEST(FormatterTest, Fill) {
EXPECT_EQ("c****", format("{0:*<5}", 'c'));
EXPECT_EQ("abc**", format("{0:*<5}", "abc"));
EXPECT_EQ("**0xface", format("{0:*>8}", reinterpret_cast<void*>(0xface)));
EXPECT_EQ("foo=", format("{:}=", "foo"));
}
TEST(FormatterTest, PlusSign) {

View File

@ -882,17 +882,52 @@ TEST(UtilTest, ParseNonnegativeInt) {
fmt::format_error, "number is too big");
}
TEST(UtilTest, FPSubtract) {
auto r = fp(123, 1) - fp(102, 1);
EXPECT_EQ(r.f, 21u);
EXPECT_EQ(r.e, 1);
template <bool is_iec559>
void test_construct_from_double() {
fmt::print("warning: double is not IEC559, skipping FP tests\n");
}
TEST(UtilTest, FPMultiply) {
auto r = fp(123ULL << 32, 4) * fp(56ULL << 32, 7);
EXPECT_EQ(r.f, 123u * 56u);
EXPECT_EQ(r.e, 4 + 7 + 64);
r = fp(123ULL << 32, 4) * fp(567ULL << 31, 8);
EXPECT_EQ(r.f, (123 * 567 + 1u) / 2);
EXPECT_EQ(r.e, 4 + 8 + 64);
template <>
void test_construct_from_double<true>() {
auto v = fp(1.23);
EXPECT_EQ(v.f, 0x13ae147ae147aeu);
EXPECT_EQ(v.e, -52);
}
TEST(FPTest, ConstructFromDouble) {
test_construct_from_double<std::numeric_limits<double>::is_iec559>();
}
TEST(FPTest, Normalize) {
auto v = fp(0xbeef, 42);
v.normalize();
EXPECT_EQ(0xbeef000000000000, v.f);
EXPECT_EQ(-6, v.e);
}
TEST(FPTest, Subtract) {
auto v = fp(123, 1) - fp(102, 1);
EXPECT_EQ(v.f, 21u);
EXPECT_EQ(v.e, 1);
}
TEST(FPTest, Multiply) {
auto v = fp(123ULL << 32, 4) * fp(56ULL << 32, 7);
EXPECT_EQ(v.f, 123u * 56u);
EXPECT_EQ(v.e, 4 + 7 + 64);
v = fp(123ULL << 32, 4) * fp(567ULL << 31, 8);
EXPECT_EQ(v.f, (123 * 567 + 1u) / 2);
EXPECT_EQ(v.e, 4 + 8 + 64);
}
TEST(FPTest, GetCachedPower) {
typedef std::numeric_limits<double> limits;
for (auto exp = limits::min_exponent; exp <= limits::max_exponent; ++exp) {
int dec_exp = 0;
auto fp = fmt::internal::get_cached_power(exp, dec_exp);
EXPECT_LE(exp, fp.e);
int dec_exp_step = 8;
EXPECT_LE(fp.e, exp + dec_exp_step * log2(10));
EXPECT_DOUBLE_EQ(pow(10, dec_exp), ldexp(fp.f, fp.e));
}
}