Add FMT_USE_SMALLEST_INT flag
When defined and set to zero, will use the largest available integer container for writing ints. The has the benefit of reducing instances the of int_writer class which will reduce the binary cost.
This commit is contained in:
parent
b8f53a0813
commit
cb0a609280
@ -311,6 +311,10 @@ struct int128_t {};
|
|||||||
struct uint128_t {};
|
struct uint128_t {};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !defined(FMT_USE_SMALLEST_INT)
|
||||||
|
#define FMT_USE_SMALLEST_INT 1
|
||||||
|
#endif
|
||||||
|
|
||||||
// Casts a nonnegative integer to unsigned.
|
// Casts a nonnegative integer to unsigned.
|
||||||
template <typename Int>
|
template <typename Int>
|
||||||
FMT_CONSTEXPR typename std::make_unsigned<Int>::type to_unsigned(Int value) {
|
FMT_CONSTEXPR typename std::make_unsigned<Int>::type to_unsigned(Int value) {
|
||||||
|
|||||||
@ -726,18 +726,19 @@ FMT_CONSTEXPR bool is_supported_floating_point(T) {
|
|||||||
(std::is_same<T, long double>::value && FMT_USE_LONG_DOUBLE);
|
(std::is_same<T, long double>::value && FMT_USE_LONG_DOUBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if FMT_USE_SMALLEST_INT
|
||||||
// Smallest of uint32_t, uint64_t, uint128_t that is large enough to
|
// Smallest of uint32_t, uint64_t, uint128_t that is large enough to
|
||||||
// represent all values of T.
|
// represent all values of T.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using uint32_or_64_or_128_t = conditional_t<
|
using uint32_or_64_or_128_t = conditional_t<
|
||||||
std::numeric_limits<T>::digits <= 32, uint32_t,
|
std::numeric_limits<T>::digits <= 32, uint32_t,
|
||||||
conditional_t<std::numeric_limits<T>::digits <= 64, uint64_t, uint128_t>>;
|
conditional_t<std::numeric_limits<T>::digits <= 64, uint64_t, uint128_t>>;
|
||||||
|
#else
|
||||||
// Selects the between uint64_t or uint128_t based on the how uint128_t is
|
// Pick the largest integer container to represent represent all values of T.
|
||||||
// defined. If macro FMT_USE_INT128 defined as 0, then its size will be 1 byte,
|
template <typename T>
|
||||||
// meaning the largest sized int that can be used is uint64_t.
|
using uint32_or_64_or_128_t =
|
||||||
using uint_largest_t =
|
|
||||||
conditional_t<sizeof(uint128_t) < sizeof(uint64_t), uint64_t, uint128_t>;
|
conditional_t<sizeof(uint128_t) < sizeof(uint64_t), uint64_t, uint128_t>;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Static data is placed in this class template for the header-only config.
|
// Static data is placed in this class template for the header-only config.
|
||||||
template <typename T = void> struct FMT_EXTERN_TEMPLATE_API basic_data {
|
template <typename T = void> struct FMT_EXTERN_TEMPLATE_API basic_data {
|
||||||
@ -1464,21 +1465,11 @@ OutputIt write(OutputIt out, basic_string_view<StrChar> s,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The handle_int_type_spec handler that writes an integer.
|
// The handle_int_type_spec handler that writes an integer.
|
||||||
template <typename OutputIt, typename Char> struct int_writer {
|
template <typename OutputIt, typename Char, typename UInt> struct int_writer {
|
||||||
enum class int_bytes {
|
|
||||||
byte1 = sizeof(uint8_t),
|
|
||||||
byte2 = sizeof(uint16_t),
|
|
||||||
byte4 = sizeof(uint32_t),
|
|
||||||
byte8 = sizeof(uint64_t),
|
|
||||||
byte16 = 16, // Must be directly set because uint128_t can be 16 bytes if
|
|
||||||
// FMT_USE_INT128 == 1 and 1 byte if FMT_USE_INT128 == 0.
|
|
||||||
};
|
|
||||||
|
|
||||||
OutputIt out;
|
OutputIt out;
|
||||||
locale_ref locale;
|
locale_ref locale;
|
||||||
const basic_format_specs<Char>& specs;
|
const basic_format_specs<Char>& specs;
|
||||||
uint_largest_t abs_value;
|
UInt abs_value;
|
||||||
int_bytes value_bytes;
|
|
||||||
char prefix[4];
|
char prefix[4];
|
||||||
unsigned prefix_size;
|
unsigned prefix_size;
|
||||||
|
|
||||||
@ -1493,11 +1484,9 @@ template <typename OutputIt, typename Char> struct int_writer {
|
|||||||
: out(output),
|
: out(output),
|
||||||
locale(loc),
|
locale(loc),
|
||||||
specs(s),
|
specs(s),
|
||||||
abs_value(static_cast<decltype(abs_value)>(value)),
|
abs_value(static_cast<UInt>(value)),
|
||||||
value_bytes(int_bytes::byte8),
|
|
||||||
prefix_size(0) {
|
prefix_size(0) {
|
||||||
value_bytes = static_cast<int_bytes>(sizeof(value));
|
static_assert(std::is_same<uint32_or_64_or_128_t<Int>, UInt>::value, "");
|
||||||
|
|
||||||
if (is_negative(value)) {
|
if (is_negative(value)) {
|
||||||
prefix[0] = '-';
|
prefix[0] = '-';
|
||||||
++prefix_size;
|
++prefix_size;
|
||||||
@ -1509,28 +1498,7 @@ template <typename OutputIt, typename Char> struct int_writer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void on_dec() {
|
void on_dec() {
|
||||||
int num_digits = 0;
|
auto num_digits = count_digits(abs_value);
|
||||||
|
|
||||||
switch (value_bytes) {
|
|
||||||
case int_bytes::byte1:
|
|
||||||
case int_bytes::byte2:
|
|
||||||
case int_bytes::byte4:
|
|
||||||
num_digits = count_digits(static_cast<uint32_t>(abs_value));
|
|
||||||
break;
|
|
||||||
case int_bytes::byte8:
|
|
||||||
num_digits = count_digits(static_cast<uint64_t>(abs_value));
|
|
||||||
break;
|
|
||||||
#if !FMT_USE_INT128
|
|
||||||
case int_bytes::byte16:
|
|
||||||
num_digits = count_digits(static_cast<uint64_t>(abs_value));
|
|
||||||
break;
|
|
||||||
#else
|
|
||||||
case int_bytes::byte16:
|
|
||||||
num_digits = count_digits(abs_value);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
out = write_int(
|
out = write_int(
|
||||||
out, num_digits, get_prefix(), specs, [this, num_digits](iterator it) {
|
out, num_digits, get_prefix(), specs, [this, num_digits](iterator it) {
|
||||||
return format_decimal<Char>(it, abs_value, num_digits).end;
|
return format_decimal<Char>(it, abs_value, num_digits).end;
|
||||||
@ -1870,7 +1838,8 @@ class arg_formatter_base {
|
|||||||
detail::reserve(std::declval<iterator&>(), 0))>;
|
detail::reserve(std::declval<iterator&>(), 0))>;
|
||||||
|
|
||||||
template <typename T> void write_int(T value, const format_specs& spec) {
|
template <typename T> void write_int(T value, const format_specs& spec) {
|
||||||
int_writer<iterator, Char> w(out_, locale_, value, spec);
|
using uint_type = uint32_or_64_or_128_t<T>;
|
||||||
|
int_writer<iterator, Char, uint_type> w(out_, locale_, value, spec);
|
||||||
handle_int_type_spec(spec.type, w);
|
handle_int_type_spec(spec.type, w);
|
||||||
out_ = w.out;
|
out_ = w.out;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user