mirror of
https://github.com/fmtlib/fmt.git
synced 2025-04-18 11:42:22 +00:00
Relax constexpr
This commit is contained in:
parent
ff9ee0461a
commit
d64b100a30
@ -1694,7 +1694,7 @@ template <typename T> class buffer {
|
|||||||
protected:
|
protected:
|
||||||
// Don't initialize ptr_ since it is not accessed to save a few cycles.
|
// Don't initialize ptr_ since it is not accessed to save a few cycles.
|
||||||
FMT_MSC_WARNING(suppress : 26495)
|
FMT_MSC_WARNING(suppress : 26495)
|
||||||
FMT_CONSTEXPR20 buffer(grow_fun grow, size_t sz) noexcept
|
FMT_CONSTEXPR buffer(grow_fun grow, size_t sz) noexcept
|
||||||
: size_(sz), capacity_(sz), grow_(grow) {}
|
: size_(sz), capacity_(sz), grow_(grow) {}
|
||||||
|
|
||||||
constexpr buffer(grow_fun grow, T* p = nullptr, size_t sz = 0,
|
constexpr buffer(grow_fun grow, T* p = nullptr, size_t sz = 0,
|
||||||
|
@ -876,7 +876,7 @@ class basic_memory_buffer : public detail::buffer<T> {
|
|||||||
using value_type = T;
|
using value_type = T;
|
||||||
using const_reference = const T&;
|
using const_reference = const T&;
|
||||||
|
|
||||||
FMT_CONSTEXPR20 explicit basic_memory_buffer(
|
FMT_CONSTEXPR explicit basic_memory_buffer(
|
||||||
const Allocator& alloc = Allocator())
|
const Allocator& alloc = Allocator())
|
||||||
: detail::buffer<T>(grow), alloc_(alloc) {
|
: detail::buffer<T>(grow), alloc_(alloc) {
|
||||||
this->set(store_, SIZE);
|
this->set(store_, SIZE);
|
||||||
@ -924,7 +924,7 @@ class basic_memory_buffer : public detail::buffer<T> {
|
|||||||
|
|
||||||
/// Resizes the buffer to contain `count` elements. If T is a POD type new
|
/// Resizes the buffer to contain `count` elements. If T is a POD type new
|
||||||
/// elements may not be initialized.
|
/// elements may not be initialized.
|
||||||
FMT_CONSTEXPR20 void resize(size_t count) { this->try_resize(count); }
|
FMT_CONSTEXPR void resize(size_t count) { this->try_resize(count); }
|
||||||
|
|
||||||
/// Increases the buffer capacity to `new_capacity`.
|
/// Increases the buffer capacity to `new_capacity`.
|
||||||
void reserve(size_t new_capacity) { this->try_reserve(new_capacity); }
|
void reserve(size_t new_capacity) { this->try_reserve(new_capacity); }
|
||||||
@ -2663,39 +2663,44 @@ inline FMT_CONSTEXPR20 void adjust_precision(int& precision, int exp10) {
|
|||||||
|
|
||||||
class bigint {
|
class bigint {
|
||||||
private:
|
private:
|
||||||
// A bigint is stored as an array of bigits (big digits), with bigit at index
|
// A bigint is a number in the form bigit_[N - 1] ... bigit_[0] * 32^exp_.
|
||||||
// 0 being the least significant one.
|
using bigit = uint32_t; // A big digit.
|
||||||
using bigit = uint32_t;
|
|
||||||
using double_bigit = uint64_t;
|
using double_bigit = uint64_t;
|
||||||
|
enum { bigit_bits = num_bits<bigit>() };
|
||||||
enum { bigits_capacity = 32 };
|
enum { bigits_capacity = 32 };
|
||||||
basic_memory_buffer<bigit, bigits_capacity> bigits_;
|
basic_memory_buffer<bigit, bigits_capacity> bigits_;
|
||||||
int exp_;
|
int exp_;
|
||||||
|
|
||||||
FMT_CONSTEXPR20 auto operator[](int index) const -> bigit {
|
|
||||||
return bigits_[to_unsigned(index)];
|
|
||||||
}
|
|
||||||
FMT_CONSTEXPR20 auto operator[](int index) -> bigit& {
|
|
||||||
return bigits_[to_unsigned(index)];
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr const int bigit_bits = num_bits<bigit>();
|
|
||||||
|
|
||||||
friend struct formatter<bigint>;
|
friend struct formatter<bigint>;
|
||||||
|
|
||||||
FMT_CONSTEXPR20 void subtract_bigits(int index, bigit other, bigit& borrow) {
|
FMT_CONSTEXPR auto operator[](int index) const -> bigit {
|
||||||
|
return bigits_[to_unsigned(index)];
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR auto operator[](int index) -> bigit& {
|
||||||
|
return bigits_[to_unsigned(index)];
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr auto minimum(int a, int b) -> int { return a < b ? a : b; }
|
||||||
|
static constexpr auto maximum(int a, int b) -> int { return a > b ? a : b; }
|
||||||
|
|
||||||
|
FMT_CONSTEXPR auto get_bigit(int i) const -> bigit {
|
||||||
|
return i >= exp_ && i < num_bigits() ? bigits_[i - exp_] : 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
FMT_CONSTEXPR void subtract_bigits(int index, bigit other, bigit& borrow) {
|
||||||
auto result = static_cast<double_bigit>((*this)[index]) - other - borrow;
|
auto result = static_cast<double_bigit>((*this)[index]) - other - borrow;
|
||||||
(*this)[index] = static_cast<bigit>(result);
|
(*this)[index] = static_cast<bigit>(result);
|
||||||
borrow = static_cast<bigit>(result >> (bigit_bits * 2 - 1));
|
borrow = static_cast<bigit>(result >> (bigit_bits * 2 - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR20 void remove_leading_zeros() {
|
FMT_CONSTEXPR void remove_leading_zeros() {
|
||||||
int num_bigits = static_cast<int>(bigits_.size()) - 1;
|
int num_bigits = static_cast<int>(bigits_.size()) - 1;
|
||||||
while (num_bigits > 0 && (*this)[num_bigits] == 0) --num_bigits;
|
while (num_bigits > 0 && (*this)[num_bigits] == 0) --num_bigits;
|
||||||
bigits_.resize(to_unsigned(num_bigits + 1));
|
bigits_.resize(to_unsigned(num_bigits + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Computes *this -= other assuming aligned bigints and *this >= other.
|
// Computes *this -= other assuming aligned bigints and *this >= other.
|
||||||
FMT_CONSTEXPR20 void subtract_aligned(const bigint& other) {
|
FMT_CONSTEXPR void subtract_aligned(const bigint& other) {
|
||||||
FMT_ASSERT(other.exp_ >= exp_, "unaligned bigints");
|
FMT_ASSERT(other.exp_ >= exp_, "unaligned bigints");
|
||||||
FMT_ASSERT(compare(*this, other) >= 0, "");
|
FMT_ASSERT(compare(*this, other) >= 0, "");
|
||||||
bigit borrow = 0;
|
bigit borrow = 0;
|
||||||
@ -2706,7 +2711,7 @@ class bigint {
|
|||||||
remove_leading_zeros();
|
remove_leading_zeros();
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR20 void multiply(uint32_t value) {
|
FMT_CONSTEXPR void multiply(uint32_t value) {
|
||||||
const double_bigit wide_value = value;
|
const double_bigit wide_value = value;
|
||||||
bigit carry = 0;
|
bigit carry = 0;
|
||||||
for (size_t i = 0, n = bigits_.size(); i < n; ++i) {
|
for (size_t i = 0, n = bigits_.size(); i < n; ++i) {
|
||||||
@ -2719,7 +2724,7 @@ class bigint {
|
|||||||
|
|
||||||
template <typename UInt, FMT_ENABLE_IF(std::is_same<UInt, uint64_t>::value ||
|
template <typename UInt, FMT_ENABLE_IF(std::is_same<UInt, uint64_t>::value ||
|
||||||
std::is_same<UInt, uint128_t>::value)>
|
std::is_same<UInt, uint128_t>::value)>
|
||||||
FMT_CONSTEXPR20 void multiply(UInt value) {
|
FMT_CONSTEXPR void multiply(UInt value) {
|
||||||
using half_uint =
|
using half_uint =
|
||||||
conditional_t<std::is_same<UInt, uint128_t>::value, uint64_t, uint32_t>;
|
conditional_t<std::is_same<UInt, uint128_t>::value, uint64_t, uint32_t>;
|
||||||
const int shift = num_bits<half_uint>() - bigit_bits;
|
const int shift = num_bits<half_uint>() - bigit_bits;
|
||||||
@ -2740,7 +2745,7 @@ class bigint {
|
|||||||
|
|
||||||
template <typename UInt, FMT_ENABLE_IF(std::is_same<UInt, uint64_t>::value ||
|
template <typename UInt, FMT_ENABLE_IF(std::is_same<UInt, uint64_t>::value ||
|
||||||
std::is_same<UInt, uint128_t>::value)>
|
std::is_same<UInt, uint128_t>::value)>
|
||||||
FMT_CONSTEXPR20 void assign(UInt n) {
|
FMT_CONSTEXPR void assign(UInt n) {
|
||||||
size_t num_bigits = 0;
|
size_t num_bigits = 0;
|
||||||
do {
|
do {
|
||||||
bigits_[num_bigits++] = static_cast<bigit>(n);
|
bigits_[num_bigits++] = static_cast<bigit>(n);
|
||||||
@ -2751,13 +2756,13 @@ class bigint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FMT_CONSTEXPR20 bigint() : exp_(0) {}
|
FMT_CONSTEXPR bigint() : exp_(0) {}
|
||||||
explicit bigint(uint64_t n) { assign(n); }
|
explicit bigint(uint64_t n) { assign(n); }
|
||||||
|
|
||||||
bigint(const bigint&) = delete;
|
bigint(const bigint&) = delete;
|
||||||
void operator=(const bigint&) = delete;
|
void operator=(const bigint&) = delete;
|
||||||
|
|
||||||
FMT_CONSTEXPR20 void assign(const bigint& other) {
|
FMT_CONSTEXPR void assign(const bigint& other) {
|
||||||
auto size = other.bigits_.size();
|
auto size = other.bigits_.size();
|
||||||
bigits_.resize(size);
|
bigits_.resize(size);
|
||||||
auto data = other.bigits_.data();
|
auto data = other.bigits_.data();
|
||||||
@ -2765,16 +2770,16 @@ class bigint {
|
|||||||
exp_ = other.exp_;
|
exp_ = other.exp_;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Int> FMT_CONSTEXPR20 void operator=(Int n) {
|
template <typename Int> FMT_CONSTEXPR void operator=(Int n) {
|
||||||
FMT_ASSERT(n > 0, "");
|
FMT_ASSERT(n > 0, "");
|
||||||
assign(uint64_or_128_t<Int>(n));
|
assign(uint64_or_128_t<Int>(n));
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR20 auto num_bigits() const -> int {
|
FMT_CONSTEXPR auto num_bigits() const -> int {
|
||||||
return static_cast<int>(bigits_.size()) + exp_;
|
return static_cast<int>(bigits_.size()) + exp_;
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_NOINLINE FMT_CONSTEXPR20 auto operator<<=(int shift) -> bigint& {
|
FMT_CONSTEXPR auto operator<<=(int shift) -> bigint& {
|
||||||
FMT_ASSERT(shift >= 0, "");
|
FMT_ASSERT(shift >= 0, "");
|
||||||
exp_ += shift / bigit_bits;
|
exp_ += shift / bigit_bits;
|
||||||
shift %= bigit_bits;
|
shift %= bigit_bits;
|
||||||
@ -2789,14 +2794,13 @@ class bigint {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Int>
|
template <typename Int> FMT_CONSTEXPR auto operator*=(Int value) -> bigint& {
|
||||||
FMT_CONSTEXPR20 auto operator*=(Int value) -> bigint& {
|
|
||||||
FMT_ASSERT(value > 0, "");
|
FMT_ASSERT(value > 0, "");
|
||||||
multiply(uint32_or_64_or_128_t<Int>(value));
|
multiply(uint32_or_64_or_128_t<Int>(value));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend FMT_CONSTEXPR20 auto compare(const bigint& lhs, const bigint& rhs)
|
friend FMT_CONSTEXPR auto compare(const bigint& lhs, const bigint& rhs)
|
||||||
-> int {
|
-> int {
|
||||||
int num_lhs_bigits = lhs.num_bigits(), num_rhs_bigits = rhs.num_bigits();
|
int num_lhs_bigits = lhs.num_bigits(), num_rhs_bigits = rhs.num_bigits();
|
||||||
if (num_lhs_bigits != num_rhs_bigits)
|
if (num_lhs_bigits != num_rhs_bigits)
|
||||||
@ -2814,24 +2818,18 @@ class bigint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns compare(lhs1 + lhs2, rhs).
|
// Returns compare(lhs1 + lhs2, rhs).
|
||||||
friend FMT_CONSTEXPR20 auto add_compare(const bigint& lhs1,
|
friend FMT_CONSTEXPR auto add_compare(const bigint& lhs1, const bigint& lhs2,
|
||||||
const bigint& lhs2, const bigint& rhs)
|
const bigint& rhs) -> int {
|
||||||
-> int {
|
|
||||||
auto minimum = [](int a, int b) { return a < b ? a : b; };
|
|
||||||
auto maximum = [](int a, int b) { return a > b ? a : b; };
|
|
||||||
int max_lhs_bigits = maximum(lhs1.num_bigits(), lhs2.num_bigits());
|
int max_lhs_bigits = maximum(lhs1.num_bigits(), lhs2.num_bigits());
|
||||||
int num_rhs_bigits = rhs.num_bigits();
|
int num_rhs_bigits = rhs.num_bigits();
|
||||||
if (max_lhs_bigits + 1 < num_rhs_bigits) return -1;
|
if (max_lhs_bigits + 1 < num_rhs_bigits) return -1;
|
||||||
if (max_lhs_bigits > num_rhs_bigits) return 1;
|
if (max_lhs_bigits > num_rhs_bigits) return 1;
|
||||||
auto get_bigit = [](const bigint& n, int i) -> bigit {
|
|
||||||
return i >= n.exp_ && i < n.num_bigits() ? n[i - n.exp_] : 0;
|
|
||||||
};
|
|
||||||
double_bigit borrow = 0;
|
double_bigit borrow = 0;
|
||||||
int min_exp = minimum(minimum(lhs1.exp_, lhs2.exp_), rhs.exp_);
|
int min_exp = minimum(minimum(lhs1.exp_, lhs2.exp_), rhs.exp_);
|
||||||
for (int i = num_rhs_bigits - 1; i >= min_exp; --i) {
|
for (int i = num_rhs_bigits - 1; i >= min_exp; --i) {
|
||||||
double_bigit sum =
|
double_bigit sum =
|
||||||
static_cast<double_bigit>(get_bigit(lhs1, i)) + get_bigit(lhs2, i);
|
static_cast<double_bigit>(lhs1.get_bigit(i)) + lhs2.get_bigit(i);
|
||||||
bigit rhs_bigit = get_bigit(rhs, i);
|
bigit rhs_bigit = rhs.get_bigit(i);
|
||||||
if (sum > rhs_bigit + borrow) return 1;
|
if (sum > rhs_bigit + borrow) return 1;
|
||||||
borrow = rhs_bigit + borrow - sum;
|
borrow = rhs_bigit + borrow - sum;
|
||||||
if (borrow > 1) return -1;
|
if (borrow > 1) return -1;
|
||||||
@ -2890,7 +2888,7 @@ class bigint {
|
|||||||
|
|
||||||
// If this bigint has a bigger exponent than other, adds trailing zero to make
|
// If this bigint has a bigger exponent than other, adds trailing zero to make
|
||||||
// exponents equal. This simplifies some operations such as subtraction.
|
// exponents equal. This simplifies some operations such as subtraction.
|
||||||
FMT_CONSTEXPR20 void align(const bigint& other) {
|
FMT_CONSTEXPR void align(const bigint& other) {
|
||||||
int exp_difference = exp_ - other.exp_;
|
int exp_difference = exp_ - other.exp_;
|
||||||
if (exp_difference <= 0) return;
|
if (exp_difference <= 0) return;
|
||||||
int num_bigits = static_cast<int>(bigits_.size());
|
int num_bigits = static_cast<int>(bigits_.size());
|
||||||
@ -2903,7 +2901,7 @@ class bigint {
|
|||||||
|
|
||||||
// Divides this bignum by divisor, assigning the remainder to this and
|
// Divides this bignum by divisor, assigning the remainder to this and
|
||||||
// returning the quotient.
|
// returning the quotient.
|
||||||
FMT_CONSTEXPR20 auto divmod_assign(const bigint& divisor) -> int {
|
FMT_CONSTEXPR auto divmod_assign(const bigint& divisor) -> int {
|
||||||
FMT_ASSERT(this != &divisor, "");
|
FMT_ASSERT(this != &divisor, "");
|
||||||
if (compare(*this, divisor) < 0) return 0;
|
if (compare(*this, divisor) < 0) return 0;
|
||||||
FMT_ASSERT(divisor.bigits_[divisor.bigits_.size() - 1u] != 0, "");
|
FMT_ASSERT(divisor.bigits_[divisor.bigits_.size() - 1u] != 0, "");
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
void throw_assertion_failure(const char* message);
|
void throw_assertion_failure(const char* message);
|
||||||
#define FMT_ASSERT(condition, message) \
|
#define FMT_ASSERT(condition, message) \
|
||||||
if (!(condition)) throw_assertion_failure(message);
|
((condition) ? (void)0 : throw_assertion_failure(message))
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user