////
Copyright 2023-2024 Matt Borland
Distributed under the Boost Software License, Version 1.0.
https://www.boost.org/LICENSE_1_0.txt
////

= to_chars
:idprefix: to_chars_

== to_chars overview

`to_chars` is a set of functions that attempts to convert `value` into a character buffer specified by `[first, last)`.
The result of `to_chars` is `to_chars_result` which on success returns `ptr` equal to one-past-the-end of the characters written and `ec == std::errc()` and on failure returns `std::errc::value_too_large` and `ptr == last`.
`to_chars` does not null-terminate the returned characters.

== Definitions
[#to_chars_definitions_]

[source, c++]
----
namespace boost { namespace charconv {

struct to_chars_result
{
    char* ptr;
    std::errc ec;

    friend constexpr bool operator==(const to_chars_result& lhs, const to_chars_result& rhs) noexcept; = default;
    constexpr explicit operator bool() const noexcept { return ec == std::errc{}; }
};

template <typename Integral>
BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, Integral value, int base = 10) noexcept;

template <typename Integral>
BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars<bool>(char* first, char* last, Integral value, int base) noexcept = delete;

template <typename Real>
to_chars_result to_chars(char* first, char* last, Real value, chars_format fmt = chars_format::general, int precision) noexcept;

}} // Namespace boost::charconv
----

== to_chars parameters
* `first, last` - pointers to the beginning and end of the character buffer
* `value` - the value to be parsed into the buffer
* `base` (integer only) - the integer base to use. Must be between 2 and 36 inclusive
* `fmt` (float only) - the floating point format to use.
See <<chars_format overview>> for description.
* `precision` (float only) - the number of decimal places required

== to_chars_result
* `ptr` - On return from `to_chars` points to one-past-the-end of the characters written on success or `last` on failure
* `ec` - https://en.cppreference.com/w/cpp/error/errc[the error code]. Values returned by `to_chars` are:
|===
|Return Value | Description
|`std::errc()` | Successful Parsing
| `std::errc::value_too_large` | 1) Overflow

2) Underflow
|===

* `operator==` - compares the value of ptr and ec for equality

== Usage Notes

=== Usage notes for to_chars for integral types
[#integral_usage_notes_]
* All built-in integral types are allowed except bool which is deleted
* from_chars for integral type is constexpr (BOOST_CHARCONV_CONSTEXPR is defined) when:
** compiled using `-std=c++14` or newer 
** using a compiler with `\__builtin_ is_constant_evaluated`
* These functions have been tested to support `\__int128` and `unsigned __int128`

=== Usage notes for to_chars for floating point types
* The following will be returned when handling different values of `NaN`
** `qNaN` returns "nan"
** `-qNaN` returns "-nan(ind)"
** `sNaN` returns "nan(snan)"
** `-sNaN` returns "-nan(snan)"
* These functions have been tested to support all built-in floating-point types and those from C++23's `<stdfloat>`
** Long doubles can be 64, 80, or 128-bit, but must be IEEE 754 compliant. An example of a non-compliant, and therefore unsupported, format is `ibm128`.
** Use of `__float128` or `std::float128_t` requires compiling with `-std=gnu++xx` and linking GCC's `libquadmath`.
This is done automatically when building with CMake.

== Examples

=== Basic Usage
==== Integral
[source, c++]
----
char buffer[64] {};
int v = 42;
to_chars_result r = boost::charconv::to_chars(buffer, buffer + sizeof(buffer) - 1, v);
assert(r.ec == std::errc());
assert(!strcmp(buffer, "42")); // strcmp returns 0 on match
----
==== Floating Point
[source, c++]
----
char buffer[64] {};
double v = 1e300;
to_chars_result r = boost::charconv::to_chars(buffer, buffer + sizeof(buffer) - 1, v);
assert(r.ec == std::errc());
assert(r); // Same as above but less verbose. Added in C++26.
assert(!strcmp(buffer, "1e+300"));
----

=== Hexadecimal
==== Integral
[source, c++]
----
char buffer[64] {};
int v = 42;
to_chars_result r = boost::charconv::to_chars(buffer, buffer + sizeof(buffer) - 1, v, 16);
assert(r.ec == std::errc());
assert(r); // Same as above but less verbose. Added in C++26.
assert(!strcmp(buffer, "2a")); // strcmp returns 0 on match
----
==== Floating Point
[source, c++]
----
char buffer_u[64] {};
double u = -1.08260383390082950e+20;

char buffer_v[64] {};
double v = -1.08260383390082946e+20;

to_chars(buffer_u, buffer_u + sizeof(buffer_u) - 1, u, chars_format::hex);
to_chars(buffer_v, buffer_v + sizeof(buffer_v) - 1, v, chars_format::hex);

std::cout << "U: " << buffer_u << "\nV: " << buffer_v << std::endl;

// U: -1.779a8946bb5fap+66
// V: -1.779a8946bb5f9p+66
//
// With hexfloats we can see the ULP distance between U and V is a - 9 == 1.

----

=== std::errc::value_too_large
==== Integral
[source, c++]
----
char buffer[3] {};
int v = -1234;
to_chars_result r = boost::charconv::to_chars(buffer, buffer + sizeof(buffer) - 1, v, 16);
assert(r.ec == std::errc::value_too_large);
assert(!r); // Same as above but less verbose. Added in C++26.
----
==== Floating Point
[source, c++]
----
char buffer[3] {};
double v = 1.2345;
auto r = boost::charconv::to_chars(buffer, buffer + sizeof(buffer) - 1, v);
assert(r.ec == std::errc::value_too_large);
assert(!r); // Same as above but less verbose. Added in C++26.
----

In the event of `std::errc::value_too_large`, to_chars_result.ptr is equal to `last`
