Skip to content

Commit 1c9c8af

Browse files
authored
Add more constexpr into simple_dragonbox.h
1 parent 3ba3d7b commit 1c9c8af

File tree

1 file changed

+43
-46
lines changed

1 file changed

+43
-46
lines changed

subproject/simple/simple_dragonbox.h

+43-46
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ namespace simple_dragonbox {
201201
static constexpr int min_k = -31;
202202
static constexpr int max_k = 46;
203203

204-
static void remove_trailing_zeros(uint32_t& significand, int& exponent) {
204+
static constexpr void remove_trailing_zeros(uint32_t& significand, int& exponent) {
205205
// See https://github.com/jk-jeon/rtz_benchmark.
206206
// The idea of branchless search below is by reddit users r/pigeon768 and
207207
// r/TheoreticalDumbass.
@@ -224,40 +224,40 @@ namespace simple_dragonbox {
224224
exponent += s;
225225
}
226226

227-
static compute_mul_result<uint32_t> compute_mul(uint32_t u, uint64_t cache) {
227+
static constexpr compute_mul_result<uint32_t> compute_mul(uint32_t u, uint64_t cache) {
228228
auto const r = umul96_upper64(u, cache);
229229
return {uint32_t(r >> 32), uint32_t(r) == 0};
230230
}
231231

232-
static uint32_t compute_delta(uint64_t cache, int beta) {
232+
static constexpr uint32_t compute_delta(uint64_t cache, int beta) {
233233
return uint32_t(cache >> (cache_bits - 1 - beta));
234234
}
235235

236-
static compute_mul_parity_result compute_mul_parity(uint32_t two_f, uint64_t cache,
237-
int beta) {
236+
static constexpr compute_mul_parity_result compute_mul_parity(uint32_t two_f, uint64_t cache,
237+
int beta) {
238238
assert(beta >= 1);
239239
assert(beta <= 32);
240240
auto const r = umul96_lower64(two_f, cache);
241241
return {((r >> (64 - beta)) & 1) != 0,
242242
(UINT32_C(0xffffffff) & (r >> (32 - beta))) == 0};
243243
}
244244

245-
static uint32_t compute_left_endpoint_for_shorter_interval_case(uint64_t cache, int beta) {
245+
static constexpr uint32_t compute_left_endpoint_for_shorter_interval_case(uint64_t cache, int beta) {
246246
return (cache - (cache >> (significand_bits + 2))) >>
247247
(cache_bits - significand_bits - 1 - beta);
248248
}
249249

250-
static uint32_t compute_right_endpoint_for_shorter_interval_case(uint64_t cache, int beta) {
250+
static constexpr uint32_t compute_right_endpoint_for_shorter_interval_case(uint64_t cache, int beta) {
251251
return (cache + (cache >> (significand_bits + 1))) >>
252252
(cache_bits - significand_bits - 1 - beta);
253253
}
254254

255-
static uint32_t compute_round_up_for_shorter_interval_case(uint64_t cache, int beta) {
255+
static constexpr uint32_t compute_round_up_for_shorter_interval_case(uint64_t cache, int beta) {
256256
return (uint32_t(cache >> (cache_bits - significand_bits - 2 - beta)) + 1) / 2;
257257
}
258258

259259
template <int N, uint32_t n_max>
260-
static uint32_t divide_by_pow10(uint32_t n) {
260+
static constexpr uint32_t divide_by_pow10(uint32_t n) {
261261
static_assert(N >= 0, "");
262262

263263
// Specialize for 32-bit division by 10.
@@ -353,7 +353,7 @@ namespace simple_dragonbox {
353353
}
354354
}
355355

356-
uint64_t get_cache(int k) const {
356+
constexpr uint64_t get_cache(int k) const {
357357
assert(k >= min_k && k <= max_k);
358358

359359
// Compute the base index.
@@ -406,7 +406,7 @@ namespace simple_dragonbox {
406406
static constexpr int min_k = -292;
407407
static constexpr int max_k = 326;
408408

409-
static void remove_trailing_zeros(uint64_t& significand, int& exponent) {
409+
static constexpr void remove_trailing_zeros(uint64_t& significand, int& exponent) {
410410
// See https://github.com/jk-jeon/rtz_benchmark.
411411
// The idea of branchless search below is by reddit users r/pigeon768 and
412412
// r/TheoreticalDumbass.
@@ -434,17 +434,17 @@ namespace simple_dragonbox {
434434
exponent += s;
435435
}
436436

437-
static compute_mul_result<uint64_t> compute_mul(uint64_t u, uint128 cache) {
437+
static constexpr compute_mul_result<uint64_t> compute_mul(uint64_t u, uint128 cache) {
438438
auto const r = umul192_upper128(u, cache);
439439
return {r.high, r.low == 0};
440440
}
441441

442-
static uint64_t compute_delta(uint128 cache, int beta) {
442+
static constexpr uint64_t compute_delta(uint128 cache, int beta) {
443443
return cache.high >> (total_bits - 1 - beta);
444444
}
445445

446-
static compute_mul_parity_result compute_mul_parity(uint64_t two_f, uint128 cache,
447-
int beta) {
446+
static constexpr compute_mul_parity_result compute_mul_parity(uint64_t two_f, uint128 cache,
447+
int beta) {
448448
assert(beta >= 1);
449449
assert(beta < 64);
450450
auto const r = umul192_lower128(two_f, cache);
@@ -453,22 +453,22 @@ namespace simple_dragonbox {
453453
0};
454454
}
455455

456-
static uint64_t compute_left_endpoint_for_shorter_interval_case(uint128 cache, int beta) {
456+
static constexpr uint64_t compute_left_endpoint_for_shorter_interval_case(uint128 cache, int beta) {
457457
return (cache.high - (cache.high >> (significand_bits + 2))) >>
458458
(total_bits - significand_bits - 1 - beta);
459459
}
460460

461-
static uint64_t compute_right_endpoint_for_shorter_interval_case(uint128 cache, int beta) {
461+
static constexpr uint64_t compute_right_endpoint_for_shorter_interval_case(uint128 cache, int beta) {
462462
return (cache.high + (cache.high >> (significand_bits + 1))) >>
463463
(total_bits - significand_bits - 1 - beta);
464464
}
465465

466-
static uint64_t compute_round_up_for_shorter_interval_case(uint128 cache, int beta) {
466+
static constexpr uint64_t compute_round_up_for_shorter_interval_case(uint128 cache, int beta) {
467467
return ((cache.high >> (total_bits - significand_bits - 2 - beta)) + 1) / 2;
468468
}
469469

470470
template <int N, uint64_t n_max>
471-
static uint64_t divide_by_pow10(uint64_t n) {
471+
static constexpr uint64_t divide_by_pow10(uint64_t n) {
472472
static_assert(N >= 0, "");
473473

474474
// Specialize for 64-bit division by 10.
@@ -1114,7 +1114,7 @@ namespace simple_dragonbox {
11141114

11151115
template <>
11161116
struct cache_holder<cache_type::full> {
1117-
uint128 get_cache(int k) const {
1117+
constexpr uint128 get_cache(int k) const {
11181118
assert(k >= min_k && k <= max_k);
11191119
return cache[k - min_k];
11201120
}
@@ -1141,7 +1141,7 @@ namespace simple_dragonbox {
11411141
}
11421142
}
11431143

1144-
uint128 get_cache(int k) const {
1144+
constexpr uint128 get_cache(int k) const {
11451145
assert(k >= min_k && k <= max_k);
11461146

11471147
// Compute the base index.
@@ -1306,7 +1306,7 @@ namespace simple_dragonbox {
13061306
static constexpr typename format::template cache_holder<CacheType> cache_;
13071307

13081308
template <int N>
1309-
static bool check_divisibility_and_divide_by_pow10(carrier_uint& n) {
1309+
static constexpr bool check_divisibility_and_divide_by_pow10(carrier_uint& n) {
13101310
// Make sure the computation for max_n does not overflow.
13111311
static_assert(N + 1 <= floor_log10_pow2(carrier_bits), "");
13121312
assert(n <= compute_power<N + 1>(carrier_uint(10)));
@@ -1324,14 +1324,14 @@ namespace simple_dragonbox {
13241324
// Compute floor(n / 10^N) for small n and N.
13251325
// Precondition: n <= 10^(N+1)
13261326
template <int N>
1327-
static carrier_uint small_division_by_pow10(carrier_uint n) {
1327+
static constexpr carrier_uint small_division_by_pow10(carrier_uint n) {
13281328
// Make sure the computation for max_n does not overflow.
13291329
static_assert(N + 1 <= floor_log10_pow2(carrier_bits), "");
13301330
assert(n <= compute_power<N + 1>(carrier_uint(10)));
13311331
return carrier_uint((n * divide_magic_number[N - 1]) >> 16);
13321332
}
13331333

1334-
static bool prefer_round_down(carrier_uint decimal_significand) {
1334+
static constexpr bool prefer_round_down(carrier_uint decimal_significand) {
13351335
using e = decimal_round_mode;
13361336
switch (DecimalRoundMode) {
13371337
case e::dont_care:
@@ -1351,7 +1351,7 @@ namespace simple_dragonbox {
13511351
int exponent;
13521352
bool sign;
13531353

1354-
constexpr impl(Float x) {
1354+
constexpr constexpr impl(Float x) {
13551355
carrier_uint bits;
13561356
static_assert(sizeof(x) == sizeof(bits));
13571357
std::memcpy(&bits, &x, sizeof(x));
@@ -1360,15 +1360,15 @@ namespace simple_dragonbox {
13601360
sign = bits >> (format::significand_bits + format::exponent_bits);
13611361
}
13621362

1363-
bool is_finite() const { return exponent != (1u << format::exponent_bits) - 1; }
1363+
constexpr bool is_finite() const { return exponent != (1u << format::exponent_bits) - 1; }
13641364

13651365
struct decimal_result {
13661366
carrier_uint significand;
13671367
int exponent;
13681368
bool sign;
13691369
};
13701370

1371-
decimal_result to_decimal() {
1371+
constexpr decimal_result to_decimal() {
13721372
assert(is_finite() && (significand || exponent));
13731373
bool even = significand % 2 == 0;
13741374
using e = binary_round_mode;
@@ -1404,41 +1404,40 @@ namespace simple_dragonbox {
14041404
}
14051405
}
14061406

1407-
auto nearest_to_even() {
1407+
constexpr auto nearest_to_even() {
14081408
bool even = significand % 2 == 0;
14091409
return nearest({even, even}, {true, true});
14101410
}
14111411

1412-
auto nearest_to_odd() {
1412+
constexpr auto nearest_to_odd() {
14131413
bool even = significand % 2 == 0;
14141414
return nearest({!even, even}, {false, false});
14151415
}
14161416

1417-
auto nearest_toward_plus_infinity() { return nearest({!sign, sign}, {!sign, sign}); }
1417+
constexpr auto nearest_toward_plus_infinity() { return nearest({!sign, sign}, {!sign, sign}); }
14181418

1419-
auto nearest_toward_minus_infinity() { return nearest({sign, !sign}, {sign, !sign}); }
1419+
constexpr auto nearest_toward_minus_infinity() { return nearest({sign, !sign}, {sign, !sign}); }
14201420

1421-
auto nearest_toward_zero() { return nearest({false, true}, {false, true}); }
1421+
constexpr auto nearest_toward_zero() { return nearest({false, true}, {false, true}); }
14221422

1423-
auto nearest_away_from_zero() { return nearest({true, false}, {true, false}); }
1423+
constexpr auto nearest_away_from_zero() { return nearest({true, false}, {true, false}); }
14241424

1425-
auto nearest_always_closed() { return nearest({true, true}, {true, true}); }
1425+
constexpr auto nearest_always_closed() { return nearest({true, true}, {true, true}); }
14261426

1427-
auto nearest_always_open() { return nearest({false, false}, {false, false}); }
1427+
constexpr auto nearest_always_open() { return nearest({false, false}, {false, false}); }
14281428

1429-
decimal_result no_trailing_zeros(carrier_uint significand, int exponent) {
1429+
constexpr decimal_result no_trailing_zeros(carrier_uint significand, int exponent) {
14301430
return {significand, exponent, sign};
14311431
}
14321432

1433-
decimal_result may_have_trailing_zeros(carrier_uint significand, int exponent) {
1433+
constexpr decimal_result may_have_trailing_zeros(carrier_uint significand, int exponent) {
14341434
format::remove_trailing_zeros(significand, exponent);
14351435
return {significand, exponent, sign};
14361436
}
14371437

14381438
//// The main algorithm assumes the input is a normal/subnormal finite number.
14391439

1440-
auto nearest(interval normal_interval, interval shorter_interval) {
1441-
1440+
constexpr auto nearest(interval normal_interval, interval shorter_interval) {
14421441
carrier_uint two_fc = significand * 2;
14431442
auto binary_exponent = exponent;
14441443

@@ -1674,8 +1673,7 @@ namespace simple_dragonbox {
16741673
return no_trailing_zeros(decimal_significand, minus_k + kappa);
16751674
}
16761675

1677-
auto left_closed_directed() {
1678-
1676+
constexpr auto left_closed_directed() {
16791677
carrier_uint two_fc = significand * 2;
16801678
auto binary_exponent = exponent;
16811679

@@ -1780,8 +1778,7 @@ namespace simple_dragonbox {
17801778
return no_trailing_zeros(decimal_significand, minus_k + kappa);
17811779
}
17821780

1783-
auto right_closed_directed() {
1784-
1781+
constexpr auto right_closed_directed() {
17851782
carrier_uint two_fc = significand * 2;
17861783
auto binary_exponent = exponent;
17871784
bool shorter_interval = false;
@@ -1855,17 +1852,17 @@ namespace simple_dragonbox {
18551852
return no_trailing_zeros(decimal_significand, minus_k + kappa);
18561853
}
18571854

1858-
static bool is_right_endpoint_integer_shorter_interval(int binary_exponent) {
1855+
static constexpr bool is_right_endpoint_integer_shorter_interval(int binary_exponent) {
18591856
return binary_exponent >= case_shorter_interval_right_endpoint_lower_threshold &&
18601857
binary_exponent <= case_shorter_interval_right_endpoint_upper_threshold;
18611858
}
18621859

1863-
static bool is_left_endpoint_integer_shorter_interval(int binary_exponent) {
1860+
static constexpr bool is_left_endpoint_integer_shorter_interval(int binary_exponent) {
18641861
return binary_exponent >= case_shorter_interval_left_endpoint_lower_threshold &&
18651862
binary_exponent <= case_shorter_interval_left_endpoint_upper_threshold;
18661863
}
18671864

1868-
char* to_chars(char* buffer) {
1865+
constexpr char* to_chars(char* buffer) {
18691866
if (!is_finite()) {
18701867
if (!significand) {
18711868
if (sign) {

0 commit comments

Comments
 (0)