Skip to content

Commit

Permalink
Merge pull request #129 from cppalliance/develop
Browse files Browse the repository at this point in the history
Merge review week 1 changes to master
  • Loading branch information
mborland authored Jan 22, 2024
2 parents f356223 + b404767 commit 7c45e1a
Show file tree
Hide file tree
Showing 20 changed files with 377 additions and 195 deletions.
21 changes: 0 additions & 21 deletions .drone.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -197,27 +197,6 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
"g++-13-multilib",
),

linux_pipeline(
"Linux 16.04 Clang 3.5",
"cppalliance/droneubuntu1604:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-3.5', CXXSTD: '03,11' },
"clang-3.5",
),

linux_pipeline(
"Linux 16.04 Clang 3.6",
"cppalliance/droneubuntu1604:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-3.6', CXXSTD: '03,11,14' },
"clang-3.6",
),

linux_pipeline(
"Linux 16.04 Clang 3.7",
"cppalliance/droneubuntu1604:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-3.7', CXXSTD: '03,11,14' },
"clang-3.7",
),

linux_pipeline(
"Linux 16.04 Clang 3.8",
"cppalliance/droneubuntu1604:1",
Expand Down
22 changes: 3 additions & 19 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,6 @@ jobs:
os: ubuntu-22.04
install:
- g++-12-multilib
- toolset: gcc-12
cxxstd: "03,11,14,17,20,23"
address_model: 32,64
os: ubuntu-22.04
install:
- g++-12-multilib
define: "BOOST_CHARCONV_STD_ERANGE"
- toolset: gcc-12
cxxstd: "03-gnu,11-gnu,14-gnu,17-gnu,20-gnu,23-gnu"
address_model: 32,64
Expand All @@ -120,13 +113,6 @@ jobs:
- g++-12-multilib

# Linux, clang
- toolset: clang
compiler: clang++-3.7
cxxstd: "03,11,14"
os: ubuntu-latest
container: ubuntu:16.04
install:
- clang-3.7
- toolset: clang
compiler: clang++-3.8
cxxstd: "03,11,14"
Expand Down Expand Up @@ -350,7 +336,9 @@ jobs:
done
fi
sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT update
sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y ${{join(matrix.install, ' ')}}
sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y ${{join(matrix.install, ' ')}} locales
sudo locale-gen de_DE.UTF-8
sudo update-locale
- name: Setup GCC Toolchain
if: matrix.gcc_toolchain
run: |
Expand Down Expand Up @@ -461,10 +449,6 @@ jobs:
then
B2_ARGS+=("address-model=${{matrix.address_model}}")
fi
if [ -n "${{matrix.define}}" ]
then
B2_ARGS+=("define=${{matrix.define}}")
fi
B2_ARGS+=("libs/$LIBRARY/test")
./b2 "${B2_ARGS[@]}"
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,9 @@ jobs:
else
pkgs="${{matrix.install}}"
fi
sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y $pkgs
sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y $pkgs locales
sudo locale-gen de_DE.UTF-8
sudo update-locale
- name: Setup GCC Toolchain
if: matrix.gcc_toolchain
Expand Down
2 changes: 2 additions & 0 deletions doc/charconv.adoc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
////
Copyright 2022 Peter Dimov
Copyright 2023-2024 Matt Borland
Distributed under the Boost Software License, Version 1.0.
https://www.boost.org/LICENSE_1_0.txt
////
Expand All @@ -21,6 +22,7 @@ include::charconv/build.adoc[]
include::charconv/from_chars.adoc[]
include::charconv/to_chars.adoc[]
include::charconv/chars_format.adoc[]
include::charconv/limits.adoc[]
include::charconv/reference.adoc[]
include::charconv/benchmarks.adoc[]
include::charconv/sources.adoc[]
Expand Down
49 changes: 33 additions & 16 deletions doc/charconv/from_chars.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ https://www.boost.org/LICENSE_1_0.txt
:idprefix: from_chars_

== from_chars overview

`from_chars` is a set of functions that parse a string from `[first, last)` in an attempt to convert the string into `value` according to the `chars_format` specified (if applicable).
The result of `from_chars` is `from_chars_result` which on success returns `ptr == last` and `ec == std::errc()`, and on failure returns `ptr` equal to the last valid character parsed or `last` on underflow/overflow, and `ec == std::errc::invalid_argument` or `std::errc::result_out_of_range` respectively.

[source, c++]
----
namespace boost { namespace charconv {
Expand All @@ -17,8 +21,7 @@ struct from_chars_result
const char* ptr;
std::errc ec;
friend constexpr bool operator==(const from_chars_result& lhs, const from_chars_result& rhs) noexcept
friend constexpr bool operator!=(const from_chars_result& lhs, const from_chars_result& rhs) noexcept
friend constexpr bool operator==(const from_chars_result& lhs, const from_chars_result& rhs) noexcept = default;
constexpr explicit operator bool() const noexcept { return ec == std::errc{}; }
}
Expand All @@ -30,23 +33,26 @@ BOOST_CXX14_CONSTEXPR from_chars_result from_chars<bool>(const char* first, cons
template <typename Real>
from_chars_result from_chars(const char* first, const char* last, Real& value, chars_format fmt = chars_format::general) noexcept;
// See note below in from_chars for floating point types
template <typename Real>
from_chars_result from_chars_strict(const char* first, const char* last, Real& value, chars_format fmt = chars_format::general) noexcept;
}} // Namespace boost::charconv
----

== from_chars_result
* ptr - points to the first character not matching the pattern, or has the value of last if all characters are successfully parsed.
* ec - the error code. Valid values for are:
** std::errc() - successful parsing
** std::errc::invalid_argument - invalid argument (e.g. parsing a negative number into an unsigned type)
** std::errc::result_out_of_range - result out of range (e.g. overflow)
* operator== - compares the values of ptr and ec for equality
* operator! - compares the value of ptr and ec for inequality
* `ptr` - On return from `from_chars` it is a pointer to the first character not matching the pattern, or pointer to `last` if all characters are successfully parsed.
* `ec` - the error code. Values returned by `from_chars` are:
** `std::errc()` - successful parsing
** `std::errc::invalid_argument` - invalid argument (e.g. parsing a negative number into an unsigned type)
** `std::errc::result_out_of_range` - result out of range (e.g. overflow)
* `operator==` - compares the values of ptr and ec for equality

== from_chars
* first, last - valid range to parse
* value - where the output is stored upon successful parsing
* base (integer only) - the integer base to use. Must be between 2 and 36 inclusive
* fmt (floating point only) - The format of the buffer. See <<chars_format overview>> for description.
* `first`, `last` - valid range to parse
* `value` - where the output is stored upon successful parsing
* `base` (integer only) - the integer base to use. Must be between 2 and 36 inclusive
* `fmt` (floating point only) - The format of the buffer. See <<chars_format overview>> for description.

=== from_chars for integral types
* All built-in integral types are allowed except bool which is deleted
Expand All @@ -55,9 +61,20 @@ from_chars_result from_chars(const char* first, const char* last, Real& value, c
** One known exception is GCC 5 which does not support constexpr comparison of `const char*`.

=== from_chars for floating point types
* On std::errc::result_out_of_range we return ±0 for small values (e.g. 1.0e-99999) or ±HUGE_VAL for large values (e.g. 1.0e+99999) to match the handling of `std::strtod`.
* On `std::errc::result_out_of_range` we return ±0 for small values (e.g. 1.0e-99999) or ±HUGE_VAL for large values (e.g. 1.0e+99999) to match the handling of `std::strtod`.
This is a divergence from the standard which states we should return the `value` argument unmodified.
** If you want the behavior from the standard, compile the library with `BOOST_CHARCONV_STD_ERANGE` defined.

** The rationale for this divergence is an open issue with LWG here: https://cplusplus.github.io/LWG/lwg-active.html#3081.
The standard for <charconv> does not distinguish between underflow and overflow like strtod does.
Let's say you are writing a JSON library, and you replace `std::strtod` with `boost::charconv::from_chars` for performance reasons.
Charconv returns std::errc::result_out_of_range on some conversion.
You would then have to parse the string again yourself to figure out which of the four possible reasons you got `std::errc::result_out_of_range`.
Charconv already had this information but could not give it to you.
By implementing the resolution to the LWG issue that matches the established strtod behavior I think we are providing the correct behavior without waiting on the committee's decision.

** If you prefer the handling required by the standard (e.g. value is returned unmodified on `std::errc::result_out_of_range`) use `boost::charconv::from_chars_strict`.
The handling of `std::errc::result_out_of_range` is the only difference between `from_chars` and `from_chars_strict`.

* 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`.
Expand Down Expand Up @@ -137,4 +154,4 @@ assert(r.ec == std::errc::result_out_of_range);
assert(!r); // Same as above but less verbose. Added in C++26.
assert(v == 0)
----
Note: In the event of std::errc::result_out_of_range, v is not modified by `from_chars`
Note: In the event of `std::errc::result_out_of_range`, v is not modified by `from_chars`
66 changes: 66 additions & 0 deletions doc/charconv/limits.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
////
Copyright 2024 Matt Borland
Distributed under the Boost Software License, Version 1.0.
https://www.boost.org/LICENSE_1_0.txt
////

= Limits
:idprefix: limits_

== Limits overview

The contents of `<boost/charconv/limits.hpp>` are designed to help the user optimize the size of the buffer required for `to_chars`.

[source, c++]
----
namespace boost { namespace charconv {
template <typename T>
constexpr int limits<T>::max_chars10;
template <typename T>
constexpr int limits<T>::max_chars;
}} // Namespace boost::charconv
----

=== max_chars10

The minimum size of the buffer that needs to be
passed to `to_chars` to guarantee successful conversion for all values of type T, when either no base is passed, or base 10 is passed.

=== max_chars

The minimum size of the buffer that needs to be passed to `to_chars` to guarantee successful conversion for all values of type T, for any value of base.

== Examples

[source, c++]
----
char buffer [boost::charconv::limits<std::int32_t>::max_chars10;
auto r = boost::charconv::to_chars(buffer, buffer + sizeof(buffer), std::numeric_limits<std::int32_t>::max());
assert(r.ec == std::errc());
assert(r); // Same as above but less verbose. Added in C++26.
assert(!strcmp(buffer, "2147483647")); // strcmp returns 0 on match
----

[source, c++]
----
char buffer [boost::charconv::limits<float>::max_chars10;
auto r = boost::charconv::to_chars(buffer, buffer + sizeof(buffer), std::numeric_limits<float>::max());
assert(r.ec == std::errc());
assert(r); // Same as above but less verbose. Added in C++26.
assert(!strcmp(buffer, "3.40282347e+38")); // strcmp returns 0 on match
----

[source, c++]
----
char buffer [boost::charconv::limits<std::uint16_t>::max_chars;
auto r = boost::charconv::to_chars(buffer, buffer + sizeof(buffer), std::numeric_limits<std::uint16_t>::max(), 2);
assert(r.ec == std::errc());
assert(r); // Same as above but less verbose. Added in C++26.
assert(!strcmp(buffer, "1111111111111111")); // strcmp returns 0 on match
----
2 changes: 1 addition & 1 deletion doc/charconv/overview.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ assert(!strncmp(buffer, "123456", 6)); // Strncmp returns 0 on match
== Supported Compilers

* GCC 5 or later
* Clang 3.7 or later
* Clang 3.8 or later
* Visual Studio 2015 (14.0) or later

Tested on https://github.com/cppalliance/charconv/actions[Github Actions] and https://drone.cpp.al/cppalliance/charconv[Drone].
Expand Down
40 changes: 20 additions & 20 deletions doc/charconv/to_chars.adoc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
////
Copyright 2023 Matt Borland
Copyright 2023-2024 Matt Borland
Distributed under the Boost Software License, Version 1.0.
https://www.boost.org/LICENSE_1_0.txt
////
Expand All @@ -8,6 +8,9 @@ https://www.boost.org/LICENSE_1_0.txt
: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::result_out_of_range` and `ptr == last`.

[source, c++]
----
namespace boost { namespace charconv {
Expand All @@ -17,8 +20,7 @@ struct to_chars_result
char* ptr;
std::errc ec;
friend constexpr bool operator==(const to_chars_result& lhs, const to_chars_result& rhs) noexcept;
friend constexpr bool operator!=(const to_chars_result& lhs, const to_chars_result& rhs) noexcept;
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{}; }
};
Expand All @@ -35,21 +37,19 @@ to_chars_result to_chars(char* first, char* last, Real value, chars_format fmt =
----

== to_chars_result
* ptr - points to the first character
* ec - the error code. Valid values from are:
** 0 - successful parsing
** std::errc::invalid_argument - invalid argument
** std::errc::result_out_of_range - result out of range (e.g. overflow)
* operator== - compares the value of ptr and ec for equality
* operator!= - compares the value of ptr and ec for inequality
* `ptr` - On return from `to_chars` points to one-past-the-end of the characters written on success or `last` on failure
* `ec` - the error code from `to_chars`. Returned values are:
** `std::errc()` - successful parsing
** `std::errc::result_out_of_range` - result out of range (e.g. overflow)
* `operator==` - compares the value of ptr and ec for equality

== to_chars
* first, last - pointers to 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.
* `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
* `precision` (float only) - the number of decimal places required

=== to_chars for integral types
* All built-in integral types are allowed except bool which is deleted
Expand All @@ -60,10 +60,10 @@ See <<chars_format overview>> for description.

=== 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)"
** `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`.
Expand Down Expand Up @@ -143,4 +143,4 @@ assert(r.ec == std::errc::result_out_of_range);
assert(!r); // Same as above but less verbose. Added in C++26.
----

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

0 comments on commit 7c45e1a

Please sign in to comment.