Skip to content

Commit

Permalink
Merge pull request #216 from boostorg/develop
Browse files Browse the repository at this point in the history
Merge additional bugfix for 1.86
  • Loading branch information
mborland authored Jul 2, 2024
2 parents 42e01be + f19700e commit bde521e
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 4 deletions.
51 changes: 47 additions & 4 deletions include/boost/charconv/detail/from_chars_integer_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,47 @@ static constexpr unsigned char uchar_values[] =

static_assert(sizeof(uchar_values) == 256, "uchar_values should represent all 256 values of unsigned char");

static constexpr double log_2_table[] =
{
0.0,
0.0,
1.0,
0.630929753571,
0.5,
0.430676558073,
0.386852807235,
0.356207187108,
0.333333333333,
0.315464876786,
0.301029995664,
0.289064826318,
0.278942945651,
0.270238154427,
0.262649535037,
0.255958024810,
0.25,
0.244650542118,
0.239812466568,
0.235408913367,
0.231378213160,
0.227670248697,
0.224243824218,
0.221064729458,
0.218104291986,
0.215338279037,
0.212746053553,
0.210309917857,
0.208014597677,
0.205846832460,
0.203795047091,
0.201849086582,
0.2,
0.198239863171,
0.196561632233,
0.194959021894,
0.193426403617
};

// Convert characters for 0-9, A-Z, a-z to 0-35. Anything else is 255
constexpr unsigned char digit_from_char(char val) noexcept
{
Expand Down Expand Up @@ -177,13 +218,15 @@ BOOST_CXX14_CONSTEXPR from_chars_result from_chars_integer_impl(const char* firs

// In non-GNU mode on GCC numeric limits may not be specialized
#if defined(BOOST_CHARCONV_HAS_INT128) && !defined(__GLIBCXX_TYPE_INT_N_0)
constexpr std::ptrdiff_t nd = std::is_same<Integer, boost::int128_type>::value ? 38 :
std::is_same<Integer, boost::uint128_type>::value ? 38 :
std::numeric_limits<Integer>::digits10;
constexpr std::ptrdiff_t nd_2 = std::is_same<Integer, boost::int128_type>::value ? 127 :
std::is_same<Integer, boost::uint128_type>::value ? 128 :
std::numeric_limits<Integer>::digits10;
#else
constexpr std::ptrdiff_t nd = std::numeric_limits<Integer>::digits10;
constexpr std::ptrdiff_t nd_2 = std::numeric_limits<Integer>::digits;
#endif

const auto nd = static_cast<std::ptrdiff_t>(nd_2 * log_2_table[static_cast<std::size_t>(unsigned_base)]);

{
// Check that the first character is valid before proceeding
const unsigned char first_digit = digit_from_char(*next);
Expand Down
1 change: 1 addition & 0 deletions test/Jamfile
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,4 @@ run github_issue_154.cpp ;
run github_issue_158.cpp ;
run github_issue_166.cpp ;
run github_issue_186.cpp ;
run github_issue_212.cpp ;
16 changes: 16 additions & 0 deletions test/from_chars.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@
#include <cerrno>
#include <utility>

#if defined(__has_include)
# if __has_include(<string_view>)
# include <string_view>
# endif
#endif

#ifdef BOOST_CHARCONV_HAS_INT128
template <typename T>
void test_128bit_int()
Expand Down Expand Up @@ -206,6 +212,15 @@ void invalid_argument_test()
auto r11 = boost::charconv::from_chars(buffer11, buffer11 + 2, o);
BOOST_TEST(r11);
BOOST_TEST_EQ(o, static_cast<T>(3));

// https://github.com/boostorg/charconv/issues/213
#if defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L
T segment_result {12};
std::string_view input{"/c"};
auto r12 = boost::charconv::from_chars(input.data(), input.data() + input.size(), segment_result);
BOOST_TEST(r12.ec == std::errc::invalid_argument);
BOOST_TEST_EQ(segment_result, static_cast<T>(12));
#endif
}

// No overflows, negative numbers, locales, etc.
Expand Down Expand Up @@ -272,6 +287,7 @@ int main()

invalid_argument_test<int>();
invalid_argument_test<unsigned>();
invalid_argument_test<std::uint16_t>();

overflow_test<char>();
overflow_test<int>();
Expand Down
52 changes: 52 additions & 0 deletions test/github_issue_212.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright 2024 Matt Borland
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt

#include <boost/charconv.hpp>
#include <boost/core/lightweight_test.hpp>
#include <system_error>
#include <cstdint>
#include <cstring>

template <typename T>
void test()
{
const char* str = "ffffffff1";

for (int i = 11; i < 36; ++i)
{
T segment_result {42U};
const auto r = boost::charconv::from_chars(str, str + std::strlen(str), segment_result, 16);
BOOST_TEST(r.ec == std::errc::result_out_of_range);
BOOST_TEST_EQ(segment_result, UINT32_C(42));
}
}

template <typename T>
void test_64()
{
const char* str = "ffffffffffffffff1";

for (int i = 11; i < 36; ++i)
{
T segment_result {42U};
const auto r = boost::charconv::from_chars(str, str + std::strlen(str), segment_result, 16);
BOOST_TEST(r.ec == std::errc::result_out_of_range);
BOOST_TEST_EQ(segment_result, UINT32_C(42));
}
}

int main()
{
test<std::uint32_t>();
test<std::uint16_t>();
test<std::int32_t>();
test<std::int16_t>();

test_64<std::uint64_t>();
test_64<std::uint32_t>();
test_64<std::int64_t>();
test_64<std::int32_t>();

return boost::report_errors();
}

0 comments on commit bde521e

Please sign in to comment.