<charconv> Conversions
beman::big_int provides to_chars and from_chars overloads that convert
between a basic_big_int and its textual representation. They mirror the
behavior of the standard std::to_chars and std::from_chars functions from
<charconv>: the conversion is locale-independent, never allocates a result
buffer of its own, never throws, and is usable in a constant expression.
Synopsis
namespace beman::big_int {
template <std::size_t b, class L, class A>
constexpr std::to_chars_result
to_chars(char* first, char* last, const basic_big_int<b, L, A>& value, int base = 10);
template <std::size_t b, class L, class A>
constexpr std::to_chars_result
to_chars(char* first, char* last, basic_big_int<b, L, A>&& value, int base = 10);
template <std::size_t b, class L, class A>
constexpr std::from_chars_result
from_chars(const char* first, const char* last, basic_big_int<b, L, A>& value, int base = 10);
} // namespace beman::big_int
In every base, digits with a value below ten use the characters 0-9; digits
with a value of ten or more use the lowercase letters a-z when writing and
accept either case when reading. No prefix (such as 0x) is written or
consumed, and no leading whitespace is skipped.
to_chars
template <std::size_t b, class L, class A>
constexpr std::to_chars_result
to_chars(char* first, char* last, const basic_big_int<b, L, A>& value, int base = 10);
template <std::size_t b, class L, class A>
constexpr std::to_chars_result
to_chars(char* first, char* last, basic_big_int<b, L, A>&& value, int base = 10);
Writes the integer value of value into the character range [first, last),
in the given base, as if by repeated division. The magnitude is written with
no leading zeros, except that a value of zero is written as the single
character 0. A negative value is prefixed with a -; non-negative values are
written with no sign. No null terminator is written. An lvalue, and a const
rvalue, select the first overload; a non-const rvalue selects the second.
Both overloads write exactly the same characters. They differ only in what they
may do to value along the way. The repeated-division path divides the
magnitude down one limb-sized block of digits at a time, which destroys it, so
the lvalue overload renders a copy; the rvalue overload, having been handed the
value, divides down the storage value already owns and allocates nothing.
That path is the only one that consumes anything, and it is reached only by a
magnitude spanning more than one limb, in a base that is not a power of two,
and below the size at which the sub-quadratic conversion kernel takes over. A
power-of-two base reads the limbs directly, a single-limb magnitude is handed
to std::to_chars, and a magnitude past the kernel’s gate is rendered from a
read-only view of the limbs. In those three cases the rvalue overload does no
less work than the lvalue one — but no more either, so handing the value over
is never the worse choice when the caller is finished with it:
big_int x = (1_n << 512) + 1; // 155 decimal digits: the repeated-division path
std::string text(160, '\0');
to_chars(text.data(), text.data() + text.size(), x, 10); // Copies; x still holds 2^512 + 1.
to_chars(text.data(), text.data() + text.size(), std::move(x), 10); // Divides x down where it already lives.
-
Preconditions:
[first, last)is a valid range, and2 <= base <= 36. -
Postconditions: For the lvalue overload,
valueis unchanged. For the rvalue overload,valueis in a valid but unspecified state, whether or not the call succeeded. -
Returns: A
std::to_chars_result. On success,ec == std::errc{}andptris the one-past-the-end pointer of the characters written. If the range is too small to hold the full representation,ec == std::errc::value_too_large,ptr == last, and the contents of[first, last)are unspecified. -
Throws: Nothing.
-
Remarks: Both overloads are usable in a constant expression. When the magnitude fits in a single limb (or, where wider, in a
std::uintmax_t) the conversion is delegated tostd::to_chars; larger magnitudes use the library’s own multiprecision conversion.
from_chars
template <std::size_t b, class L, class A>
constexpr std::from_chars_result
from_chars(const char* first, const char* last, basic_big_int<b, L, A>& value, int base = 10);
Parses an integer from the longest prefix of [first, last) that forms a valid
number in the given base and, on success, stores it in value. The accepted
grammar is an optional leading - followed by one or more digits valid for
base. A leading + is not accepted, and a - is the only sign recognized.
Parsing stops at the first character that is not a valid digit, so trailing
characters (for example, a . or a digit that is out of range for base) are
left unconsumed and still constitute a successful parse of the prefix before
them.
Because basic_big_int is elastic, it grows to hold whatever value is parsed;
unlike the built-in integer conversions, from_chars never reports
std::errc::result_out_of_range.
-
Preconditions:
[first, last)is a valid range. -
Postconditions: If
ec == std::errc{},valueholds the parsed integer; otherwisevalueis unchanged. -
Returns: A
std::from_chars_result. On success,ec == std::errc{}andptrpoints one past the last character consumed. If the range does not begin with a valid number — because it is empty,firstis null, it contains only a-,baseis outside[2, 36], or the first character is not a valid digit — thenec == std::errc::invalid_argument,valueis unchanged, andptr == last. -
Throws: Nothing.
-
Remarks: The function is usable in a constant expression.