Skip to content

Commit

Permalink
Make constexpr ceil
Browse files Browse the repository at this point in the history
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
  • Loading branch information
phprus committed May 23, 2023
1 parent 06c5e32 commit a09d23d
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 2 deletions.
29 changes: 27 additions & 2 deletions include/fmt/format.h
Original file line number Diff line number Diff line change
Expand Up @@ -3317,6 +3317,32 @@ FMT_CONSTEXPR20 void format_hexfloat(Float value, int precision,
format_hexfloat(static_cast<double>(value), precision, specs, buf);
}

template <typename Integral, typename Float>
FMT_CONSTEXPR auto iceil(Float value) -> Integral {
static_assert(
std::is_integral<Integral>::value && !std::is_same<Integral, bool>::value,
"Return type is not integer");
auto min = (std::numeric_limits<Integral>::min)();
auto max = (std::numeric_limits<Integral>::max)();
ignore_unused(min, max);
FMT_ASSERT(min <= value && value <= max, "value not in Integral range");
if (is_constant_evaluated()) {
using U = typename std::make_unsigned<Integral>::type;
do {
auto mid =
min +
static_cast<Integral>(
static_cast<U>(static_cast<U>(max) - static_cast<U>(min)) / 2);
if (mid < value)
min = mid;
else
max = mid;
} while (min + 1 != max);
return max;
}
return static_cast<Integral>(std::ceil(value));
}

template <typename Float>
FMT_CONSTEXPR20 auto format_float(Float value, int precision, float_specs specs,
buffer<char>& buf) -> int {
Expand Down Expand Up @@ -3347,8 +3373,7 @@ FMT_CONSTEXPR20 auto format_float(Float value, int precision, float_specs specs,
// 10^(exp - 1) <= value < 10^exp or 10^exp <= value < 10^(exp + 1).
// This is based on log10(value) == log2(value) / log2(10) and approximation
// of log2(value) by e + num_fraction_bits idea from double-conversion.
exp = static_cast<int>(
std::ceil((f.e + count_digits<1>(f.f) - 1) * inv_log2_10 - 1e-10));
exp = iceil<int>((f.e + count_digits<1>(f.f) - 1) * inv_log2_10 - 1e-10);
dragon_flags = dragon::fixup;
} else if (precision < 0) {
// Use Dragonbox for the shortest format.
Expand Down
16 changes: 16 additions & 0 deletions test/format-impl-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -523,3 +523,19 @@ TEST(format_impl_test, to_utf8) {
EXPECT_EQ(s, u.str());
EXPECT_EQ(s.size(), u.size());
}

TEST(format_impl_test, iceil) {
using T = int;
for (double v : std::initializer_list<double>{
((std::numeric_limits<T>::min)() + 0.5),
-1.2,
-0.2,
0.0,
0.2,
1.2,
4.0,
((std::numeric_limits<T>::max)() - 0.5),
}) {
EXPECT_EQ(fmt::detail::iceil<T>(v), static_cast<T>(std::ceil(v)));
}
}

0 comments on commit a09d23d

Please sign in to comment.