Skip to content

Commit d7bdf09

Browse files
authored
Merge pull request #1231 from cppalliance/rearch
Re-work architecture of charconv to fix sting construction with old clangs
2 parents 00d6406 + dc5b705 commit d7bdf09

File tree

12 files changed

+333
-345
lines changed

12 files changed

+333
-345
lines changed

examples/promotion.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <boost/decimal/iostream.hpp> // For decimal type support to <iostream>
1010
#include <type_traits>
1111
#include <iostream>
12+
#include <limits>
1213

1314
int main()
1415
{

include/boost/decimal/charconv.hpp

Lines changed: 5 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2024 Matt Borland
1+
// Copyright 2024 - 2025 Matt Borland
22
// Distributed under the Boost Software License, Version 1.0.
33
// https://www.boost.org/LICENSE_1_0.txt
44

@@ -28,6 +28,7 @@
2828
#include <boost/decimal/detail/promotion.hpp>
2929
#include <boost/decimal/detail/write_payload.hpp>
3030
#include <boost/decimal/detail/formatting_limits.hpp>
31+
#include <boost/decimal/detail/from_chars_impl.hpp>
3132

3233
#ifndef BOOST_DECIMAL_BUILD_MODULE
3334
#include <cstdint>
@@ -43,111 +44,11 @@ namespace boost {
4344
namespace decimal {
4445

4546
// ---------------------------------------------------------------------------------------------------------------------
46-
// from_chars and implementation
47+
// from_chars
4748
// ---------------------------------------------------------------------------------------------------------------------
4849

49-
namespace detail {
50-
51-
#ifdef _MSC_VER
52-
# pragma warning(push)
53-
# pragma warning(disable:4127)
54-
#endif
55-
56-
template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE TargetDecimalType>
57-
constexpr auto from_chars_general_impl(const char* first, const char* last, TargetDecimalType& value, const chars_format fmt) noexcept -> from_chars_result
58-
{
59-
using significand_type = std::conditional_t<(std::numeric_limits<typename TargetDecimalType::significand_type>::digits >
60-
std::numeric_limits<std::uint64_t>::digits),
61-
int128::uint128_t, std::uint64_t>;
62-
63-
BOOST_DECIMAL_IF_CONSTEXPR (is_fast_type_v<TargetDecimalType>)
64-
{
65-
if (fmt == chars_format::cohort_preserving_scientific)
66-
{
67-
return {first, std::errc::invalid_argument};
68-
}
69-
}
70-
71-
if (BOOST_DECIMAL_UNLIKELY(first >= last))
72-
{
73-
return {first, std::errc::invalid_argument};
74-
}
75-
76-
bool sign {};
77-
significand_type significand {};
78-
std::int32_t expval {};
79-
80-
auto r {detail::parser(first, last, sign, significand, expval, fmt)};
81-
82-
if (!r)
83-
{
84-
if (r.ec == std::errc::not_supported)
85-
{
86-
using resultant_sig_type = typename TargetDecimalType::significand_type;
87-
88-
resultant_sig_type payload_value {};
89-
if (significand < std::numeric_limits<resultant_sig_type>::max())
90-
{
91-
payload_value = static_cast<resultant_sig_type>(significand);
92-
}
93-
94-
if (expval > 0)
95-
{
96-
value = write_payload<TargetDecimalType, true>(payload_value);
97-
}
98-
else
99-
{
100-
value = write_payload<TargetDecimalType, false>(payload_value);
101-
}
102-
103-
if (sign)
104-
{
105-
value = -value;
106-
}
107-
108-
r.ec = std::errc();
109-
}
110-
else if (r.ec == std::errc::value_too_large)
111-
{
112-
value = sign ? -std::numeric_limits<TargetDecimalType>::infinity() :
113-
std::numeric_limits<TargetDecimalType>::infinity();
114-
r.ec = std::errc();
115-
}
116-
else
117-
{
118-
value = std::numeric_limits<TargetDecimalType>::signaling_NaN();
119-
errno = static_cast<int>(r.ec);
120-
}
121-
}
122-
else
123-
{
124-
BOOST_DECIMAL_IF_CONSTEXPR (!is_fast_type_v<TargetDecimalType>)
125-
{
126-
if (fmt == chars_format::cohort_preserving_scientific)
127-
{
128-
const auto sig_digs {detail::num_digits(significand)};
129-
if (sig_digs > precision_v<TargetDecimalType>)
130-
{
131-
// If we are parsing more digits than are representable there's no concept of cohorts
132-
return {last, std::errc::value_too_large};
133-
}
134-
}
135-
}
136-
137-
value = TargetDecimalType(significand, expval, sign);
138-
}
139-
140-
return r;
141-
}
142-
143-
#ifdef _MSC_VER
144-
# pragma warning(pop)
145-
#endif
146-
147-
} //namespace detail
148-
149-
template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE TargetDecimalType>
150-
constexpr auto from_chars(const char* first, const char* last, TargetDecimalType& value, const chars_format fmt) noexcept -> from_chars_result
50+
BOOST_DECIMAL_EXPORT template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE TargetDecimalType>
51+
constexpr auto from_chars(const char* first, const char* last, TargetDecimalType& value, const chars_format fmt = chars_format::general) noexcept -> from_chars_result
15152
{
15253
return detail::from_chars_general_impl(first, last, value, fmt);
15354
}

include/boost/decimal/decimal128_t.hpp

Lines changed: 47 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@
3939
#include <boost/decimal/detail/to_chars_result.hpp>
4040
#include <boost/decimal/detail/chars_format.hpp>
4141
#include <boost/decimal/detail/components.hpp>
42-
#include <boost/decimal/detail/from_string.hpp>
4342
#include <boost/decimal/detail/construction_sign.hpp>
43+
#include <boost/decimal/detail/from_chars_impl.hpp>
4444

4545
#ifndef BOOST_DECIMAL_BUILD_MODULE
4646

@@ -971,47 +971,6 @@ constexpr decimal128_t::decimal128_t(const Decimal val) noexcept
971971
*this = to_decimal<decimal128_t>(val);
972972
}
973973

974-
#if !defined(BOOST_DECIMAL_DISABLE_CLIB)
975-
976-
constexpr decimal128_t::decimal128_t(const char* str, std::size_t len)
977-
{
978-
if (str == nullptr || len == 0)
979-
{
980-
bits_ = detail::d128_nan_mask;
981-
BOOST_DECIMAL_THROW_EXCEPTION(std::runtime_error("Can not construct from invalid string"));
982-
return; // LCOV_EXCL_LINE
983-
}
984-
985-
// Normally plus signs aren't allowed
986-
auto first {str};
987-
if (*first == '+')
988-
{
989-
++first;
990-
}
991-
992-
decimal128_t v;
993-
const auto r {from_chars(first, str + len, v)};
994-
if (r)
995-
{
996-
*this = v;
997-
}
998-
else
999-
{
1000-
bits_ = detail::d128_nan_mask;
1001-
BOOST_DECIMAL_THROW_EXCEPTION(std::runtime_error("Can not construct from invalid string"));
1002-
}
1003-
}
1004-
1005-
constexpr decimal128_t::decimal128_t(const char* str) : decimal128_t(str, detail::strlen(str)) {}
1006-
1007-
#ifndef BOOST_DECIMAL_HAS_STD_STRING_VIEW
1008-
inline decimal128_t::decimal128_t(const std::string& str) : decimal128_t(str.c_str(), str.size()) {}
1009-
#else
1010-
constexpr decimal128_t::decimal128_t(std::string_view str) : decimal128_t(str.data(), str.size()) {}
1011-
#endif
1012-
1013-
#endif // BOOST_DECIMAL_DISABLE_CLIB
1014-
1015974
constexpr decimal128_t::operator bool() const noexcept
1016975
{
1017976
constexpr decimal128_t zero {0, 0};
@@ -2320,6 +2279,51 @@ class numeric_limits<boost::decimal::decimal128_t> :
23202279

23212280
} //namespace std
23222281

2323-
#include <boost/decimal/charconv.hpp>
2282+
namespace boost {
2283+
namespace decimal {
2284+
2285+
#if !defined(BOOST_DECIMAL_DISABLE_CLIB)
2286+
2287+
constexpr decimal128_t::decimal128_t(const char* str, std::size_t len)
2288+
{
2289+
if (str == nullptr || len == 0)
2290+
{
2291+
bits_ = detail::d128_nan_mask;
2292+
BOOST_DECIMAL_THROW_EXCEPTION(std::runtime_error("Can not construct from invalid string"));
2293+
return; // LCOV_EXCL_LINE
2294+
}
2295+
2296+
// Normally plus signs aren't allowed
2297+
auto first {str};
2298+
if (*first == '+')
2299+
{
2300+
++first;
2301+
}
2302+
2303+
decimal128_t v;
2304+
const auto r {detail::from_chars_general_impl(first, str + len, v, chars_format::general)};
2305+
if (r)
2306+
{
2307+
*this = v;
2308+
}
2309+
else
2310+
{
2311+
bits_ = detail::d128_nan_mask;
2312+
BOOST_DECIMAL_THROW_EXCEPTION(std::runtime_error("Can not construct from invalid string"));
2313+
}
2314+
}
2315+
2316+
constexpr decimal128_t::decimal128_t(const char* str) : decimal128_t(str, detail::strlen(str)) {}
2317+
2318+
#ifndef BOOST_DECIMAL_HAS_STD_STRING_VIEW
2319+
inline decimal128_t::decimal128_t(const std::string& str) : decimal128_t(str.c_str(), str.size()) {}
2320+
#else
2321+
constexpr decimal128_t::decimal128_t(std::string_view str) : decimal128_t(str.data(), str.size()) {}
2322+
#endif
2323+
2324+
#endif // BOOST_DECIMAL_DISABLE_CLIB
2325+
2326+
} // namespace decimal
2327+
} // namespace boost
23242328

23252329
#endif //BOOST_DECIMAL_decimal128_t_HPP

include/boost/decimal/decimal32_t.hpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@
4040
#include <boost/decimal/detail/cmath/next.hpp>
4141
#include <boost/decimal/detail/to_chars_result.hpp>
4242
#include <boost/decimal/detail/chars_format.hpp>
43-
#include <boost/decimal/detail/from_string.hpp>
4443
#include <boost/decimal/detail/construction_sign.hpp>
44+
#include <boost/decimal/detail/from_chars_impl.hpp>
4545

4646
#ifndef BOOST_DECIMAL_BUILD_MODULE
4747

@@ -2348,10 +2348,6 @@ class numeric_limits<boost::decimal::decimal32_t> :
23482348

23492349
} // Namespace std
23502350

2351-
// TODO(mborland): Break charconv up since we only need the from_chars implementation here
2352-
// Probably shouldn't be bringing in everything
2353-
#include <boost/decimal/charconv.hpp>
2354-
23552351
namespace boost {
23562352
namespace decimal {
23572353

@@ -2374,7 +2370,7 @@ constexpr decimal32_t::decimal32_t(const char* str, const std::size_t len)
23742370
}
23752371

23762372
decimal32_t v;
2377-
const auto r {from_chars(first, str + len, v)};
2373+
const auto r {detail::from_chars_general_impl(first, str + len, v, chars_format::general)};
23782374
if (r)
23792375
{
23802376
*this = v;

include/boost/decimal/decimal64_t.hpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@
4242
#include <boost/decimal/detail/cmath/next.hpp>
4343
#include <boost/decimal/detail/chars_format.hpp>
4444
#include <boost/decimal/detail/to_chars_result.hpp>
45-
#include <boost/decimal/detail/from_string.hpp>
4645
#include <boost/decimal/detail/construction_sign.hpp>
46+
#include <boost/decimal/detail/from_chars_impl.hpp>
4747

4848
#ifndef BOOST_DECIMAL_BUILD_MODULE
4949

@@ -2257,8 +2257,6 @@ class numeric_limits<boost::decimal::decimal64_t> :
22572257

22582258
} // Namespace std
22592259

2260-
#include <boost/decimal/charconv.hpp>
2261-
22622260
namespace boost {
22632261
namespace decimal {
22642262

@@ -2281,7 +2279,7 @@ constexpr decimal64_t::decimal64_t(const char* str, std::size_t len)
22812279
}
22822280

22832281
decimal64_t v;
2284-
const auto r {from_chars(first, str + len, v)};
2282+
const auto r {detail::from_chars_general_impl(first, str + len, v, chars_format::general)};
22852283
if (r)
22862284
{
22872285
*this = v;

0 commit comments

Comments
 (0)