Skip to content

Commit fba5a8e

Browse files
author
John McFarlane
committed
Replace max_to_chars_chars with to_chars_capacity
1 parent f3b7b74 commit fba5a8e

File tree

8 files changed

+148
-97
lines changed

8 files changed

+148
-97
lines changed

Diff for: include/cnl/_impl/charconv/to_chars.h

+2-13
Original file line numberDiff line numberDiff line change
@@ -16,28 +16,17 @@
1616
#include "../num_traits/set_rounding.h"
1717
#include "../numbers/signedness.h"
1818
#include "constants.h"
19+
#include "to_chars_capacity.h"
1920

2021
#include <array>
2122
#include <charconv>
2223
#include <limits>
23-
#include <numbers>
2424
#include <string_view>
2525
#include <system_error>
2626

2727
/// compositional numeric library
2828
namespace cnl {
2929
namespace _impl {
30-
// cnl::_impl::max_to_chars_chars
31-
template<typename Scalar, int Base = 10>
32-
struct max_to_chars_chars {
33-
private:
34-
static constexpr auto _sign_chars = static_cast<int>(cnl::numbers::signedness_v<Scalar>);
35-
static constexpr auto _integer_chars = static_cast<int>(std::numeric_limits<Scalar>::digits * std::numbers::ln2 / std::numbers::ln10) + 1;
36-
37-
public:
38-
static constexpr auto value = _sign_chars + _integer_chars;
39-
};
40-
4130
// cnl::_impl::itoc
4231
[[nodiscard]] constexpr auto itoc(int value)
4332
{
@@ -156,7 +145,7 @@ namespace cnl {
156145
[[nodiscard]] constexpr auto to_chars_static(number auto const& value)
157146
{
158147
using number = std::remove_cvref_t<decltype(value)>;
159-
constexpr auto max_num_chars = _impl::max_to_chars_chars<number, Base>::value;
148+
constexpr auto max_num_chars = _impl::to_chars_capacity<number>{}(Base);
160149

161150
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
162151
to_chars_static_result<max_num_chars> result;

Diff for: include/cnl/_impl/charconv/to_chars_capacity.h

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
2+
// Copyright John McFarlane 2022.
3+
// Distributed under the Boost Software License, Version 1.0.
4+
// (See accompanying file ../LICENSE_1_0.txt or copy at
5+
// http://www.boost.org/LICENSE_1_0.txt)
6+
7+
#if !defined(CNL_IMPL_CHARCONV_TO_CHARS_CAPACITY_H)
8+
#define CNL_IMPL_CHARCONV_TO_CHARS_CAPACITY_H
9+
10+
#include "../../integer.h"
11+
#include "../cnl_assert.h"
12+
#include "../numbers/signedness.h"
13+
14+
#include <limits>
15+
#include <numbers>
16+
17+
namespace cnl::_impl {
18+
// maximum number of characters necessary to represent given Scalar
19+
// in give base in human-readable text excluding nul terminator,
20+
// e.g. to_chars_capacity<int8_t>{}() == 4 // ["-128".."127"]
21+
template<typename Scalar>
22+
struct to_chars_capacity;
23+
24+
template<typename Scalar>
25+
requires integer<Scalar>
26+
struct to_chars_capacity<Scalar> {
27+
[[nodiscard]] constexpr auto operator()(int /*base*/ = 10) const
28+
{
29+
auto const sign_chars = static_cast<int>(cnl::numbers::signedness_v<Scalar>);
30+
auto const integer_chars = static_cast<int>(std::numeric_limits<Scalar>::digits * std::numbers::ln2 / std::numbers::ln10) + 1;
31+
return sign_chars + integer_chars;
32+
}
33+
};
34+
}
35+
36+
#endif // CNL_IMPL_CHARCONV_TO_CHARS_CAPACITY_H

Diff for: include/cnl/_impl/scaled_integer/to_chars.h

+1-58
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "definition.h"
2222
#include "num_traits.h"
2323
#include "numbers.h"
24+
#include "to_chars_capacity.h"
2425

2526
#include <algorithm>
2627
#include <array>
@@ -36,64 +37,6 @@
3637
/// compositional numeric library
3738
namespace cnl {
3839
namespace _impl {
39-
constexpr auto num_digits_from_binary(int num_digits, int radix)
40-
{
41-
switch (radix) {
42-
case 2:
43-
return num_digits;
44-
case 8:
45-
return (num_digits + 2) / 3;
46-
case 10:
47-
return (num_digits * 1000 + 3322) / 3321;
48-
case 16:
49-
return (num_digits + 3) / 4;
50-
default: {
51-
auto const binary_digits_per_digit{used_digits(radix - 1)};
52-
return (num_digits + binary_digits_per_digit - 1) / binary_digits_per_digit;
53-
}
54-
}
55-
}
56-
57-
constexpr auto num_digits_to_binary(int num_digits, int radix)
58-
{
59-
switch (radix) {
60-
case 2:
61-
return num_digits;
62-
case 8:
63-
return num_digits * 3;
64-
case 10:
65-
return (num_digits * 3322 + 678) / 1000;
66-
case 16:
67-
return num_digits * 4;
68-
default:
69-
return num_digits * used_digits(radix - 1);
70-
}
71-
}
72-
73-
template<typename Rep, int Exponent, int Radix>
74-
struct max_to_chars_chars<scaled_integer<Rep, power<Exponent, Radix>>> {
75-
private:
76-
using scalar = cnl::scaled_integer<Rep, power<Exponent, Radix>>;
77-
78-
// This number is a little pessemistic in the case that Radix != 2.
79-
static constexpr auto _fractional_digits =
80-
std::max(cnl::_impl::fractional_digits_v<scalar>, 0);
81-
82-
static constexpr auto _sign_chars = static_cast<int>(cnl::numbers::signedness_v<scalar>);
83-
static constexpr auto _num_significant_integer_bits{cnl::digits_v<scalar> - _fractional_digits};
84-
static constexpr auto _num_trailing_integer_bits{
85-
num_digits_to_binary(std::max(0, Exponent), Radix)};
86-
static constexpr auto _num_integer_bits{
87-
_num_significant_integer_bits + _num_trailing_integer_bits};
88-
static constexpr auto _integer_chars = num_digits_from_binary(_num_integer_bits, 10);
89-
static constexpr auto _radix_chars = static_cast<int>(_fractional_digits > 0);
90-
static constexpr auto _fractional_chars = std::max(0, _fractional_digits);
91-
92-
public:
93-
static constexpr auto value =
94-
_sign_chars + _integer_chars + _radix_chars + _fractional_chars;
95-
};
96-
9740
struct descaled_info {
9841
std::string_view significand_digits;
9942
std::string_view exponent_chars;

Diff for: include/cnl/_impl/scaled_integer/to_chars_capacity.h

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
2+
// Copyright John McFarlane 2022.
3+
// Distributed under the Boost Software License, Version 1.0.
4+
// (See accompanying file ../LICENSE_1_0.txt or copy at
5+
// http://www.boost.org/LICENSE_1_0.txt)
6+
7+
#if !defined(CNL_IMPL_SCALED_INTEGER_TO_CHARS_CAPACITY_H)
8+
#define CNL_IMPL_SCALED_INTEGER_TO_CHARS_CAPACITY_H
9+
10+
#include "../charconv/to_chars_capacity.h"
11+
#include "../scaled/is_scaled_tag.h"
12+
#include "declaration.h"
13+
14+
/// compositional numeric library
15+
namespace cnl::_impl {
16+
constexpr auto num_digits_from_binary(int num_digits, int radix)
17+
{
18+
switch (radix) {
19+
case 2:
20+
return num_digits;
21+
case 8:
22+
return (num_digits + 2) / 3;
23+
case 10:
24+
return (num_digits * 1000 + 3322) / 3321;
25+
case 16:
26+
return (num_digits + 3) / 4;
27+
default: {
28+
auto const binary_digits_per_digit{used_digits(radix - 1)};
29+
return (num_digits + binary_digits_per_digit - 1) / binary_digits_per_digit;
30+
}
31+
}
32+
}
33+
34+
constexpr auto num_digits_to_binary(int num_digits, int radix)
35+
{
36+
switch (radix) {
37+
case 2:
38+
return num_digits;
39+
case 8:
40+
return num_digits * 3;
41+
case 10:
42+
return (num_digits * 3322 + 678) / 1000;
43+
case 16:
44+
return num_digits * 4;
45+
default:
46+
return num_digits * used_digits(radix - 1);
47+
}
48+
}
49+
50+
template<integer Rep, scaled_tag Scale>
51+
struct to_chars_capacity<scaled_integer<Rep, Scale>> {
52+
[[nodiscard]] constexpr auto operator()(int base = 10) const
53+
{
54+
CNL_ASSERT(base == 10);
55+
56+
using type = scaled_integer<Rep, Scale>;
57+
constexpr auto exponent{Scale::exponent};
58+
constexpr auto radix{Scale::radix};
59+
60+
// This number is a little pessemistic in the case that radix != 2.
61+
auto const fractional_digits =
62+
std::max(cnl::_impl::fractional_digits_v<type>, 0);
63+
64+
auto const sign_chars = static_cast<int>(cnl::numbers::signedness_v<type>);
65+
auto const num_significant_integer_bits{cnl::digits_v<type> - fractional_digits};
66+
auto const num_trailing_integer_bits{
67+
num_digits_to_binary(std::max(0, exponent), radix)};
68+
auto const num_integer_bits{
69+
num_significant_integer_bits + num_trailing_integer_bits};
70+
auto const integer_chars = num_digits_from_binary(num_integer_bits, 10);
71+
auto const radix_chars = static_cast<int>(fractional_digits > 0);
72+
auto const fractional_chars = std::max(0, fractional_digits);
73+
74+
return sign_chars + integer_chars + radix_chars + fractional_chars;
75+
}
76+
};
77+
}
78+
79+
#endif // CNL_IMPL_SCALED_INTEGER_TO_CHARS_CAPACITY_H

Diff for: test/unit/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ set(test_sources
100100
overflow/wide/wide_overflow_int.cpp
101101
scaled_int/elastic/make_elastic_scaled_int.cpp
102102
scaled_int/elastic/elastic_scaled_int.cpp
103+
scaled_int/elastic/to_chars_capacity.cpp
103104
scaled_int/rounding/elastic/rounding_elastic_scaled_int.cpp
104105
scaled_int/overflow/elastic/int.cpp
105106
static_int/shift_left.cpp

Diff for: test/unit/scaled_int/elastic/elastic_scaled_int.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,7 @@ TEST(elastic_scaled_integer, issue_88) // NOLINT
634634
TEST(elastic_scaled_integer, to_string_thousand) // NOLINT
635635
{
636636
auto const n{1000_cnl};
637-
static_assert(5 == cnl::_impl::max_to_chars_chars<std::remove_cvref_t<decltype(n)>>::value);
637+
static_assert(5 == cnl::_impl::to_chars_capacity<std::remove_cvref_t<decltype(n)>>{}());
638638

639639
auto const expected{"1000"};
640640
auto const actual{cnl::to_string(1000_cnl)};
@@ -644,7 +644,7 @@ TEST(elastic_scaled_integer, to_string_thousand) // NOLINT
644644
TEST(elastic_scaled_integer, to_string_thousandth) // NOLINT
645645
{
646646
auto const n{.001_cnl};
647-
static_assert(5 == cnl::_impl::max_to_chars_chars<std::remove_cvref_t<decltype(n)>>::value);
647+
static_assert(5 == cnl::_impl::to_chars_capacity<std::remove_cvref_t<decltype(n)>>{}());
648648

649649
auto const expected{".001"};
650650
auto const actual{cnl::to_string(n)};
@@ -654,7 +654,7 @@ TEST(elastic_scaled_integer, to_string_thousandth) // NOLINT
654654
TEST(elastic_scaled_integer, to_string_123_456) // NOLINT
655655
{
656656
auto const n{123.456_cnl};
657-
static_assert(10 == cnl::_impl::max_to_chars_chars<std::remove_cvref_t<decltype(n)>>::value);
657+
static_assert(10 == cnl::_impl::to_chars_capacity<std::remove_cvref_t<decltype(n)>>{}());
658658

659659
auto const expected{"123.456"};
660660
auto const actual{cnl::to_string(n)};
@@ -664,7 +664,7 @@ TEST(elastic_scaled_integer, to_string_123_456) // NOLINT
664664
TEST(elastic_scaled_integer, to_string_quite_wide) // NOLINT
665665
{
666666
auto const n{-12345.67890_cnl};
667-
static_assert(13 == cnl::_impl::max_to_chars_chars<std::remove_cvref_t<decltype(n)>>::value);
667+
static_assert(13 == cnl::_impl::to_chars_capacity<std::remove_cvref_t<decltype(n)>>{}());
668668

669669
auto const expected{"-12345.6789"};
670670
auto const actual{cnl::to_string(n)};

Diff for: test/unit/scaled_int/elastic/to_chars_capacity.cpp

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
// Copyright John McFarlane 2022.
3+
// Distributed under the Boost Software License, Version 1.0.
4+
// (See accompanying file ../LICENSE_1_0.txt or copy at
5+
// http://www.boost.org/LICENSE_1_0.txt)
6+
7+
#include <cnl/_impl/charconv/to_chars_capacity.h>
8+
9+
#include <cnl/elastic_integer.h>
10+
#include <cnl/scaled_integer.h>
11+
12+
#include <cstdint>
13+
14+
namespace test_to_chars_capacity {
15+
static_assert(
16+
4 == cnl::_impl::to_chars_capacity<cnl::scaled_integer<std::uint8_t, cnl::power<2>>>{}()); // 1020
17+
static_assert(
18+
7 == cnl::_impl::to_chars_capacity<cnl::scaled_integer<std::int8_t, cnl::power<-3>>>{}()); // -15.875
19+
static_assert(
20+
5 == cnl::_impl::to_chars_capacity<cnl::scaled_integer<std::uint16_t, cnl::power<>>>{}()); // 65536
21+
static_assert(
22+
41 == cnl::_impl::to_chars_capacity<cnl::scaled_integer<cnl::elastic_integer<41>, cnl::power<-38>>>{}());
23+
static_assert(
24+
44 == cnl::_impl::to_chars_capacity<cnl::scaled_integer<std::int64_t, cnl::power<-32>>>{}()); // −2147483647.99999999976716935634613037109375
25+
}

Diff for: test/unit/scaled_int/to_chars.h

-22
Original file line numberDiff line numberDiff line change
@@ -18,28 +18,6 @@
1818
#include <limits>
1919
#include <string>
2020

21-
namespace test_max_to_chars_chars {
22-
static_assert(
23-
4 == cnl::_impl::max_to_chars_chars<scaled_integer<uint8, cnl::power<2>>>::value,
24-
"cnl::_impl::max_to_chars_chars"); // 1020
25-
static_assert(
26-
7 == cnl::_impl::max_to_chars_chars<scaled_integer<int8, cnl::power<-3>>>::value,
27-
"cnl::_impl::max_to_chars_chars"); // -15.875
28-
static_assert(
29-
5 == cnl::_impl::max_to_chars_chars<scaled_integer<uint16, cnl::power<>>>::value,
30-
"cnl::_impl::max_to_chars_chars"); // 65536
31-
static_assert(
32-
41
33-
== cnl::_impl::max_to_chars_chars<cnl::scaled_integer<
34-
cnl::elastic_integer<41>, cnl::power<-38>>>::value,
35-
"cnl::_impl::max_to_chars_chars");
36-
static_assert(
37-
44
38-
== cnl::_impl::max_to_chars_chars<
39-
cnl::scaled_integer<int64, cnl::power<-32>>>::value,
40-
"cnl::_impl::max_to_chars_chars"); // −2147483647.99999999976716935634613037109375
41-
}
42-
4321
namespace test_to_chars_natural {
4422
template<int BufferSize, typename Integer>
4523
void test(Integer const& value)

0 commit comments

Comments
 (0)