7 #if !defined(CNL_IMPL_TO_CHARS_H)
8 #define CNL_IMPL_TO_CHARS_H
10 #include "../../integer.h"
11 #include "../cnl_assert.h"
12 #include "../narrow_cast.h"
13 #include "../num_traits/digits.h"
14 #include "../num_traits/rounding.h"
15 #include "../num_traits/set_rounding.h"
16 #include "../numbers/signedness.h"
17 #include "constants.h"
22 #include <string_view>
23 #include <system_error>
29 template<
typename Scalar,
int Base = 10>
30 struct max_to_chars_chars {
32 static constexpr
auto _sign_chars =
static_cast<int>(cnl::numbers::signedness_v<Scalar>);
33 static constexpr
auto _integer_chars = ((digits_v<Scalar> + 2) / 3);
36 static constexpr
auto value = _sign_chars + _integer_chars;
40 template<
typename Scalar>
41 [[nodiscard]] constexpr
auto itoc(Scalar value)
44 std::is_same<
typename rounding<Scalar>::type, native_rounding_tag>::value,
45 "wrong rounding type");
46 auto c = zero_char +
static_cast<int>(value);
47 return static_cast<char>(c);
51 template<
class Integer>
52 [[nodiscard]] constexpr
auto to_chars_natural(
char* ptr,
char* last, Integer
const& value) ->
char*
56 auto const next_ptr =
quotient ? to_chars_natural(ptr, last,
quotient) : ptr;
58 if (next_ptr == last || next_ptr ==
nullptr) {
65 *next_ptr = itoc(remainder);
70 template<
integer Integer>
71 [[nodiscard]] constexpr
auto
72 to_chars_positive(
char*
const first,
char*
const last, Integer
const& value)
74 auto const natural_last = to_chars_natural(first, last, value);
75 return std::to_chars_result{
76 natural_last, natural_last ?
std::errc{} : std::errc::value_too_large};
79 template<
typename Number>
80 [[nodiscard]] constexpr
auto
81 to_chars_non_zero(
char*
const first,
char*
const last, Number
const& value)
83 if constexpr (numbers::signedness_v<Number>) {
84 if (value < Number{}) {
86 if (destination_length < 2) {
87 return std::to_chars_result{last, std::errc::value_too_large};
96 return to_chars_positive(first + 1, last, -value);
100 return to_chars_positive(first, last, value);
105 template<
integer Integer>
106 [[nodiscard]] constexpr
auto to_chars(
109 Integer
const& value)
114 return std::to_chars_result{last, std::errc::value_too_large};
118 *first = _impl::zero_char;
119 return std::to_chars_result{first + 1,
std::errc{}};
122 using native_rounding_type =
set_rounding_t<decltype(value), native_rounding_tag>;
123 auto const& native_rounding_value =
static_cast<native_rounding_type
>(value);
125 return _impl::to_chars_non_zero<native_rounding_type>(
126 first, last, native_rounding_value);
129 template<
int NumChars>
131 struct to_chars_static_result {
138 template<
typename Number>
139 [[nodiscard]] constexpr
auto to_chars_static(Number
const& value)
141 constexpr
auto max_num_chars = _impl::max_to_chars_chars<Number>::value;
144 to_chars_static_result<max_num_chars> result;
146 auto dynamic_result = to_chars(result.chars.data(), result.chars.data() + max_num_chars, value);
147 CNL_ASSERT(dynamic_result.ptr > result.chars.data());
148 CNL_ASSERT(dynamic_result.ptr <= result.chars.data() + max_num_chars);
149 CNL_ASSERT(dynamic_result.ec ==
std::errc{});
151 *dynamic_result.ptr =
'\0';
152 result.length = _impl::narrow_cast<int>(dynamic_result.ptr - result.chars.data());
158 #endif // CNL_IMPL_TO_CHARS_H