Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add string_view interface to from_chars #147

Merged
merged 15 commits into from
Feb 2, 2024
Merged
25 changes: 25 additions & 0 deletions doc/charconv/from_chars.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,32 @@ struct from_chars_result
template <typename Integral>
BOOST_CXX14_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, Integral& value, int base = 10) noexcept;

template <typename Integral>
BOOST_CXX14_CONSTEXPR from_chars_result from_chars(boost::core::string_view sv, Integral& value, int base = 10) noexcept;

BOOST_CXX14_CONSTEXPR from_chars_result from_chars<bool>(const char* first, const char* last, bool& value, int base) = delete;

template <typename Real>
from_chars_result from_chars(const char* first, const char* last, Real& value, chars_format fmt = chars_format::general) noexcept;

template <typename Real>
from_chars_result from_chars(boost::core::string_view sv, Real& value, chars_format fmt = chars_format::general) noexcept;

// See note below Usage notes for from_chars for floating point types

template <typename Real>
from_chars_result from_chars_erange(const char* first, const char* last, Real& value, chars_format fmt = chars_format::general) noexcept;

template <typename Real>
from_chars_result from_chars_erange(boost::core::string_view sv, Real& value, chars_format fmt = chars_format::general) noexcept;

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

== from_chars parameters
* `first`, `last` - pointers to a valid range to parse
* `sv` - string view of a valid range to parse.
Compatible with boost::core::string_view, std::string, and std::string_view
* `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.
Expand Down Expand Up @@ -111,7 +122,15 @@ from_chars_result r = boost::charconv::from_chars(buffer, buffer + std::strlen(b
assert(r.ec == std::errc());
assert(r); // Same as above but less verbose. Added in C++26.
assert(v == 42);

std::string str_buffer (buffer);
boost::core::string_view sv(str_buffer);
int v2;
auto r2 = boost::charconv::from_chars(sv, v2);
assert(r);
assert(v2 == v);
----

==== Floating Point
[source, c++]
----
Expand All @@ -121,6 +140,12 @@ auto r = boost::charconv::from_chars(buffer, buffer + std::strlen(buffer), v);
assert(r.ec == std::errc());
assert(r); // Same as above but less verbose. Added in C++26.
assert(v == 1.2345);

std::string str_buffer(buffer);
double v2;
auto r2 = boost::charconv::from_chars(buffer, v2);
assert(r2);
assert(v == v2);
----

=== Hexadecimal
Expand Down
6 changes: 6 additions & 0 deletions fuzzing/fuzz_from_chars_float.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// https://www.boost.org/LICENSE_1_0.txt

#include <boost/charconv.hpp>
#include <boost/core/detail/string_view.hpp>
#include <iostream>
#include <exception>

Expand All @@ -15,16 +16,21 @@ extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, std::size_t size
const auto formats = {boost::charconv::chars_format::general, boost::charconv::chars_format::fixed,
boost::charconv::chars_format::scientific, boost::charconv::chars_format::hex};

boost::core::string_view sv {c_data, size};

for (const auto format : formats)
{
float f_val;
boost::charconv::from_chars(c_data, c_data + size, f_val, format);
boost::charconv::from_chars(sv, f_val, format);

double val;
boost::charconv::from_chars(c_data, c_data + size, val, format);
boost::charconv::from_chars(sv, val, format);

long double ld_val;
boost::charconv::from_chars(c_data, c_data + size, ld_val, format);
boost::charconv::from_chars(sv, ld_val, format);
}
}
catch(...)
Expand Down
10 changes: 10 additions & 0 deletions fuzzing/fuzz_from_chars_int.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// https://www.boost.org/LICENSE_1_0.txt

#include <boost/charconv.hpp>
#include <boost/core/detail/string_view.hpp>
#include <iostream>
#include <exception>

Expand All @@ -11,32 +12,41 @@ extern "C" int LLVMFuzzerTestOneInput(const std::uint8_t* data, std::size_t size
try
{
auto c_data = reinterpret_cast<const char*>(data);
boost::core::string_view sv {c_data, size};

for (int base = 2; base < 36; ++base)
{
char c_val;
boost::charconv::from_chars(c_data, c_data + size, c_val, base);
boost::charconv::from_chars(sv, c_val, base);

int i_val;
boost::charconv::from_chars(c_data, c_data + size, i_val, base);
boost::charconv::from_chars(sv, i_val, base);

long l_val;
boost::charconv::from_chars(c_data, c_data + size, l_val, base);
boost::charconv::from_chars(sv, l_val, base);

long long ll_val;
boost::charconv::from_chars(c_data, c_data + size, ll_val, base);
boost::charconv::from_chars(sv, ll_val, base);

unsigned char uc_val;
boost::charconv::from_chars(c_data, c_data + size, uc_val, base);
boost::charconv::from_chars(sv, uc_val, base);

unsigned int ui_val;
boost::charconv::from_chars(c_data, c_data + size, ui_val, base);
boost::charconv::from_chars(sv, ui_val, base);

unsigned long ul_val;
boost::charconv::from_chars(c_data, c_data + size, ul_val, base);
boost::charconv::from_chars(sv, ul_val, base);

unsigned long long ull_val;
boost::charconv::from_chars(c_data, c_data + size, ull_val, base);
boost::charconv::from_chars(sv, ull_val, base);
}
}
catch(...)
Expand Down
2 changes: 1 addition & 1 deletion include/boost/charconv/detail/parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ inline from_chars_result parser(const char* first, const char* last, bool& sign,
}
if (dot_position != 0 || fractional)
{
exponent = static_cast<Integer>(dot_position - i) + extra_zeros + leading_zero_powers;
exponent = static_cast<Integer>(dot_position) - static_cast<Integer>(i) + extra_zeros + leading_zero_powers;
}
else
{
Expand Down
106 changes: 106 additions & 0 deletions include/boost/charconv/from_chars.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <boost/charconv/detail/bit_layouts.hpp>
#include <boost/charconv/config.hpp>
#include <boost/charconv/chars_format.hpp>
#include <boost/core/detail/string_view.hpp>
#include <system_error>

namespace boost { namespace charconv {
Expand Down Expand Up @@ -75,6 +76,63 @@ BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, co
}
#endif

BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(boost::core::string_view sv, bool& value, int base = 10) noexcept = delete;
BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(boost::core::string_view sv, char& value, int base = 10) noexcept
{
return detail::from_chars(sv.data(), sv.data() + sv.size(), value, base);
}
BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(boost::core::string_view sv, signed char& value, int base = 10) noexcept
{
return detail::from_chars(sv.data(), sv.data() + sv.size(), value, base);
}
BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(boost::core::string_view sv, unsigned char& value, int base = 10) noexcept
{
return detail::from_chars(sv.data(), sv.data() + sv.size(), value, base);
}
BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(boost::core::string_view sv, short& value, int base = 10) noexcept
{
return detail::from_chars(sv.data(), sv.data() + sv.size(), value, base);
}
BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(boost::core::string_view sv, unsigned short& value, int base = 10) noexcept
{
return detail::from_chars(sv.data(), sv.data() + sv.size(), value, base);
}
BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(boost::core::string_view sv, int& value, int base = 10) noexcept
{
return detail::from_chars(sv.data(), sv.data() + sv.size(), value, base);
}
BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(boost::core::string_view sv, unsigned int& value, int base = 10) noexcept
{
return detail::from_chars(sv.data(), sv.data() + sv.size(), value, base);
}
BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(boost::core::string_view sv, long& value, int base = 10) noexcept
{
return detail::from_chars(sv.data(), sv.data() + sv.size(), value, base);
}
BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(boost::core::string_view sv, unsigned long& value, int base = 10) noexcept
{
return detail::from_chars(sv.data(), sv.data() + sv.size(), value, base);
}
BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(boost::core::string_view sv, long long& value, int base = 10) noexcept
{
return detail::from_chars(sv.data(), sv.data() + sv.size(), value, base);
}
BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(boost::core::string_view sv, unsigned long long& value, int base = 10) noexcept
{
return detail::from_chars(sv.data(), sv.data() + sv.size(), value, base);
}

#ifdef BOOST_CHARCONV_HAS_INT128
BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(boost::core::string_view sv, boost::int128_type& value, int base = 10) noexcept
{
return detail::from_chars128(sv.data(), sv.data() + sv.size(), value, base);
}
BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(boost::core::string_view sv, boost::uint128_type& value, int base = 10) noexcept
{
return detail::from_chars128(sv.data(), sv.data() + sv.size(), value, base);
}
#endif

//----------------------------------------------------------------------------------------------------------------------
// Floating Point
//----------------------------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -104,6 +162,31 @@ BOOST_CHARCONV_DECL from_chars_result from_chars_erange(const char* first, const
BOOST_CHARCONV_DECL from_chars_result from_chars_erange(const char* first, const char* last, std::bfloat16_t& value, chars_format fmt = chars_format::general) noexcept;
#endif

BOOST_CHARCONV_DECL from_chars_result from_chars_erange(boost::core::string_view sv, float& value, chars_format fmt = chars_format::general) noexcept;
BOOST_CHARCONV_DECL from_chars_result from_chars_erange(boost::core::string_view sv, double& value, chars_format fmt = chars_format::general) noexcept;
BOOST_CHARCONV_DECL from_chars_result from_chars_erange(boost::core::string_view sv, long double& value, chars_format fmt = chars_format::general) noexcept;

#ifdef BOOST_CHARCONV_HAS_FLOAT128
BOOST_CHARCONV_DECL from_chars_result from_chars_erange(boost::core::string_view sv, __float128& value, chars_format fmt = chars_format::general) noexcept;
#endif

// <stdfloat> types
#ifdef BOOST_CHARCONV_HAS_FLOAT16
BOOST_CHARCONV_DECL from_chars_result from_chars_erange(boost::core::string_view sv, std::float16_t& value, chars_format fmt = chars_format::general) noexcept;
#endif
#ifdef BOOST_CHARCONV_HAS_FLOAT32
BOOST_CHARCONV_DECL from_chars_result from_chars_erange(boost::core::string_view sv, std::float32_t& value, chars_format fmt = chars_format::general) noexcept;
#endif
#ifdef BOOST_CHARCONV_HAS_FLOAT64
BOOST_CHARCONV_DECL from_chars_result from_chars_erange(boost::core::string_view sv, std::float64_t& value, chars_format fmt = chars_format::general) noexcept;
#endif
#if defined(BOOST_CHARCONV_HAS_STDFLOAT128) && defined(BOOST_CHARCONV_HAS_FLOAT128)
BOOST_CHARCONV_DECL from_chars_result from_chars_erange(boost::core::string_view sv, std::float128_t& value, chars_format fmt = chars_format::general) noexcept;
#endif
#ifdef BOOST_CHARCONV_HAS_BRAINFLOAT16
BOOST_CHARCONV_DECL from_chars_result from_chars_erange(boost::core::string_view sv, std::bfloat16_t& value, chars_format fmt = chars_format::general) noexcept;
#endif

// The following adhere to the standard library definition with std::errc::result_out_of_range
// Returns value unmodified
// See: https://github.com/cppalliance/charconv/issues/110
Expand Down Expand Up @@ -131,6 +214,29 @@ BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char*
BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, std::bfloat16_t& value, chars_format fmt = chars_format::general) noexcept;
#endif

BOOST_CHARCONV_DECL from_chars_result from_chars(boost::core::string_view sv, float& value, chars_format fmt = chars_format::general) noexcept;
BOOST_CHARCONV_DECL from_chars_result from_chars(boost::core::string_view sv, double& value, chars_format fmt = chars_format::general) noexcept;
BOOST_CHARCONV_DECL from_chars_result from_chars(boost::core::string_view sv, long double& value, chars_format fmt = chars_format::general) noexcept;

#ifdef BOOST_CHARCONV_HAS_FLOAT128
BOOST_CHARCONV_DECL from_chars_result from_chars(boost::core::string_view sv, __float128& value, chars_format fmt = chars_format::general) noexcept;
#endif
#ifdef BOOST_CHARCONV_HAS_FLOAT16
BOOST_CHARCONV_DECL from_chars_result from_chars(boost::core::string_view sv, std::float16_t& value, chars_format fmt = chars_format::general) noexcept;
#endif
#ifdef BOOST_CHARCONV_HAS_FLOAT32
BOOST_CHARCONV_DECL from_chars_result from_chars(boost::core::string_view sv, std::float32_t& value, chars_format fmt = chars_format::general) noexcept;
#endif
#ifdef BOOST_CHARCONV_HAS_FLOAT64
BOOST_CHARCONV_DECL from_chars_result from_chars(boost::core::string_view sv, std::float64_t& value, chars_format fmt = chars_format::general) noexcept;
#endif
#if defined(BOOST_CHARCONV_HAS_STDFLOAT128) && defined(BOOST_CHARCONV_HAS_FLOAT128)
BOOST_CHARCONV_DECL from_chars_result from_chars(boost::core::string_view sv, std::float128_t& value, chars_format fmt = chars_format::general) noexcept;
#endif
#ifdef BOOST_CHARCONV_HAS_BRAINFLOAT16
BOOST_CHARCONV_DECL from_chars_result from_chars(boost::core::string_view sv, std::bfloat16_t& value, chars_format fmt = chars_format::general) noexcept;
#endif

} // namespace charconv
} // namespace boost

Expand Down
Loading
Loading