Skip to content

Commit 9ba4780

Browse files
committed
Merge branch 'develop' into 1137
2 parents 9a7863a + cc0ad12 commit 9ba4780

File tree

13 files changed

+558
-29
lines changed

13 files changed

+558
-29
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,8 @@ jobs:
389389
sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT update
390390
sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y ${{join(matrix.install, ' ')}} locales libfmt-dev
391391
sudo locale-gen de_DE.UTF-8
392+
sudo locale-gen en_US.UTF-8
393+
sudo locale-gen fr_FR.UTF-8
392394
sudo update-locale
393395
- name: Setup GCC Toolchain
394396
if: matrix.gcc_toolchain

include/boost/decimal/charconv.hpp

Lines changed: 99 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <boost/decimal/detail/countl.hpp>
2727
#include <boost/decimal/detail/remove_trailing_zeros.hpp>
2828
#include <boost/decimal/detail/promotion.hpp>
29+
#include <boost/decimal/detail/quantum_preservation_format.hpp>
2930

3031
#ifndef BOOST_DECIMAL_BUILD_MODULE
3132
#include <cstdint>
@@ -1109,6 +1110,67 @@ constexpr auto to_chars_hex_impl(char* first, char* last, const TargetDecimalTyp
11091110
return to_chars_integer_impl<std::uint32_t>(first, last, static_cast<std::uint32_t>(abs_exp));
11101111
}
11111112

1113+
template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE TargetDecimalType>
1114+
constexpr auto to_chars_cohort_preserving_scientific(char* first, char* last, const TargetDecimalType& value) noexcept -> to_chars_result
1115+
{
1116+
using unsigned_integer = typename TargetDecimalType::significand_type;
1117+
1118+
const auto fp = fpclassify(value);
1119+
if (!(fp == FP_NORMAL || fp == FP_SUBNORMAL))
1120+
{
1121+
// Cohorts are irrelevant for non-finite values
1122+
return to_chars_nonfinite(first, last, value, fp, chars_format::scientific, -1);
1123+
}
1124+
1125+
// First we print the significand of the number by decoding the value,
1126+
// and using our existing to_chars for integers
1127+
//
1128+
// We possibly offset the to_chars by one in the event that we know we will have a fraction
1129+
const auto components {value.to_components()};
1130+
const auto significand {components.sig};
1131+
auto exponent {static_cast<int>(components.exp)};
1132+
1133+
if (components.sign)
1134+
{
1135+
*first++ = '-';
1136+
}
1137+
1138+
const bool fractional_piece {significand > 10U};
1139+
const auto r {to_chars_integer_impl<unsigned_integer>(first + static_cast<std::ptrdiff_t>(fractional_piece), last, significand)};
1140+
1141+
if (BOOST_DECIMAL_UNLIKELY(!r))
1142+
{
1143+
return r; // LCOV_EXCL_LINE
1144+
}
1145+
1146+
// If there is more than one digit in the significand then we are going to need to:
1147+
// First: insert a decimal point
1148+
// Second: figure out how many decimal points we are going to have to adjust the exponent accordingly
1149+
if (fractional_piece)
1150+
{
1151+
*first = *(first + 1);
1152+
*(first + 1) = '.';
1153+
1154+
const auto offset {num_digits(significand) - 1};
1155+
exponent += offset;
1156+
}
1157+
1158+
// Insert the exponent characters ensuring that there are always at least two digits after the "e",
1159+
// e.g. e+07 not e+7
1160+
first = r.ptr;
1161+
*first++ = 'e';
1162+
const bool negative_exp {exponent < 0};
1163+
*first++ = negative_exp ? '-' : '+';
1164+
1165+
const auto abs_exp { static_cast<std::uint32_t>(negative_exp ? -exponent : exponent) };
1166+
if (abs_exp < 10U)
1167+
{
1168+
*first++ = '0';
1169+
}
1170+
1171+
return to_chars_integer_impl<std::uint32_t>(first, last, abs_exp);
1172+
}
1173+
11121174
#ifdef _MSC_VER
11131175
# pragma warning(push)
11141176
# pragma warning(disable: 4702) // Unreachable code
@@ -1181,6 +1243,34 @@ constexpr auto to_chars_impl(char* first, char* last, const TargetDecimalType& v
11811243
return to_chars_scientific_impl(first, last, value, fmt, local_precision); // LCOV_EXCL_LINE
11821244
}
11831245

1246+
// TODO(mborland): Remove once other modes are inplace
1247+
#ifdef _MSC_VER
1248+
# pragma warning(push)
1249+
# pragma warning(disable: 4065)
1250+
#endif
1251+
1252+
template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE TargetDecimalType>
1253+
constexpr auto to_chars_impl(char* first, char* last, const TargetDecimalType& value, const chars_format fmt, const quantum_preservation method) noexcept -> to_chars_result
1254+
{
1255+
// No quantum preservation is the same thing as regular to_chars
1256+
if (method == quantum_preservation::off)
1257+
{
1258+
return to_chars_impl(first, last, value, fmt);
1259+
}
1260+
1261+
// Sanity check our bounds
1262+
if (BOOST_DECIMAL_UNLIKELY(first >= last))
1263+
{
1264+
return {last, std::errc::invalid_argument};
1265+
}
1266+
1267+
switch (fmt)
1268+
{
1269+
default:
1270+
return to_chars_cohort_preserving_scientific(first, last, value);
1271+
}
1272+
}
1273+
11841274
#ifdef _MSC_VER
11851275
# pragma warning(pop)
11861276
#endif
@@ -1194,13 +1284,13 @@ constexpr auto to_chars(char* first, char* last, const TargetDecimalType& value)
11941284
}
11951285

11961286
BOOST_DECIMAL_EXPORT template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE TargetDecimalType>
1197-
constexpr auto to_chars(char* first, char* last, const TargetDecimalType& value, chars_format fmt) noexcept -> to_chars_result
1287+
constexpr auto to_chars(char* first, char* last, const TargetDecimalType& value, const chars_format fmt) noexcept -> to_chars_result
11981288
{
11991289
return detail::to_chars_impl(first, last, value, fmt);
12001290
}
12011291

12021292
BOOST_DECIMAL_EXPORT template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE TargetDecimalType>
1203-
constexpr auto to_chars(char* first, char* last, const TargetDecimalType& value, chars_format fmt, int precision) noexcept -> to_chars_result
1293+
constexpr auto to_chars(char* first, char* last, const TargetDecimalType& value, const chars_format fmt, int precision) noexcept -> to_chars_result
12041294
{
12051295
if (precision < 0)
12061296
{
@@ -1210,6 +1300,13 @@ constexpr auto to_chars(char* first, char* last, const TargetDecimalType& value,
12101300
return detail::to_chars_impl(first, last, value, fmt, precision);
12111301
}
12121302

1303+
BOOST_DECIMAL_EXPORT template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE TargetDecimalType>
1304+
constexpr auto to_chars(char* first, char* last, const TargetDecimalType& value, const chars_format fmt, const quantum_preservation method) noexcept -> to_chars_result
1305+
{
1306+
static_assert(detail::is_ieee_type_v<TargetDecimalType>, "Fast types are automatically normalized, so they have no concept of quantum preservation");
1307+
return detail::to_chars_impl(first, last, value, fmt, method);
1308+
}
1309+
12131310
#ifdef BOOST_DECIMAL_HAS_STD_CHARCONV
12141311

12151312
BOOST_DECIMAL_EXPORT template <typename DecimalType>

include/boost/decimal/cstdio.hpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -227,9 +227,10 @@ inline auto snprintf_impl(char* buffer, const std::size_t buf_size, const char*
227227
{
228228
detail::make_uppercase(buffer, r.ptr);
229229
}
230-
convert_pointer_pair_to_local_locale(buffer, r.ptr);
230+
*r.ptr = '\0';
231+
const auto offset {convert_pointer_pair_to_local_locale(buffer, buffer + buf_size - byte_count)};
231232

232-
buffer = r.ptr;
233+
buffer = r.ptr + (offset == -1 ? 0 : offset);
233234

234235
if (value_iter != values_list.end())
235236
{
@@ -276,7 +277,7 @@ inline auto fprintf(std::FILE* buffer, const char* format, const T... values) no
276277
int bytes {};
277278
char char_buffer[1024];
278279

279-
if (format_len + value_space <= 1024U)
280+
if (format_len + value_space <= ((1024 * 2) / 3))
280281
{
281282
bytes = detail::snprintf_impl(char_buffer, sizeof(char_buffer), format, values...);
282283
if (bytes)
@@ -287,7 +288,8 @@ inline auto fprintf(std::FILE* buffer, const char* format, const T... values) no
287288
else
288289
{
289290
// LCOV_EXCL_START
290-
std::unique_ptr<char[]> longer_char_buffer(new(std::nothrow) char[format_len + value_space + 1]);
291+
// Add 50% overage in case we need to do locale conversion
292+
std::unique_ptr<char[]> longer_char_buffer(new(std::nothrow) char[(3 * (format_len + value_space + 1)) / 2]);
291293
if (longer_char_buffer == nullptr)
292294
{
293295
errno = ENOMEM;

include/boost/decimal/decimal128_t.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ constexpr auto to_chars_fixed_impl(char* first, char* last, const TargetDecimalT
9898
template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE TargetDecimalType>
9999
constexpr auto to_chars_hex_impl(char* first, char* last, const TargetDecimalType& value) noexcept -> to_chars_result;
100100

101+
template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE TargetDecimalType>
102+
constexpr auto to_chars_cohort_preserving_scientific(char* first, char* last, const TargetDecimalType& value) noexcept -> to_chars_result;
103+
101104
} //namespace detail
102105

103106
BOOST_DECIMAL_EXPORT class decimal128_t final
@@ -205,6 +208,9 @@ BOOST_DECIMAL_EXPORT class decimal128_t final
205208
template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE TargetDecimalType>
206209
friend constexpr auto detail::to_chars_hex_impl(char* first, char* last, const TargetDecimalType& value) noexcept -> to_chars_result;
207210

211+
template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE TargetDecimalType>
212+
friend constexpr auto detail::to_chars_cohort_preserving_scientific(char* first, char* last, const TargetDecimalType& value) noexcept -> to_chars_result;
213+
208214
#if !defined(BOOST_DECIMAL_DISABLE_CLIB)
209215
constexpr decimal128_t(const char* str, std::size_t len);
210216
#endif

include/boost/decimal/decimal32_t.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ constexpr auto to_chars_fixed_impl(char* first, char* last, const TargetDecimalT
102102
template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE TargetDecimalType>
103103
constexpr auto to_chars_hex_impl(char* first, char* last, const TargetDecimalType& value) noexcept -> to_chars_result;
104104

105+
template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE TargetDecimalType>
106+
constexpr auto to_chars_cohort_preserving_scientific(char* first, char* last, const TargetDecimalType& value) noexcept -> to_chars_result;
107+
105108
template <bool checked, BOOST_DECIMAL_DECIMAL_FLOATING_TYPE T>
106109
constexpr auto d32_fma_impl(T x, T y, T z) noexcept -> T;
107110

@@ -215,6 +218,9 @@ BOOST_DECIMAL_EXPORT class decimal32_t final // NOLINT(cppcoreguidelines-special
215218
template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE TargetDecimalType>
216219
friend constexpr auto detail::to_chars_hex_impl(char* first, char* last, const TargetDecimalType& value) noexcept -> to_chars_result;
217220

221+
template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE TargetDecimalType>
222+
friend constexpr auto detail::to_chars_cohort_preserving_scientific(char* first, char* last, const TargetDecimalType& value) noexcept -> to_chars_result;
223+
218224
#if !defined(BOOST_DECIMAL_DISABLE_CLIB)
219225
constexpr decimal32_t(const char* str, std::size_t len);
220226
#endif

include/boost/decimal/decimal64_t.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ constexpr auto to_chars_fixed_impl(char* first, char* last, const TargetDecimalT
101101
template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE TargetDecimalType>
102102
constexpr auto to_chars_hex_impl(char* first, char* last, const TargetDecimalType& value) noexcept -> to_chars_result;
103103

104+
template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE TargetDecimalType>
105+
constexpr auto to_chars_cohort_preserving_scientific(char* first, char* last, const TargetDecimalType& value) noexcept -> to_chars_result;
106+
104107
template <bool checked, BOOST_DECIMAL_DECIMAL_FLOATING_TYPE T>
105108
constexpr auto d64_fma_impl(T x, T y, T z) noexcept -> T;
106109

@@ -220,6 +223,9 @@ BOOST_DECIMAL_EXPORT class decimal64_t final
220223
template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE TargetDecimalType>
221224
friend constexpr auto detail::to_chars_hex_impl(char* first, char* last, const TargetDecimalType& value) noexcept -> to_chars_result;
222225

226+
template <BOOST_DECIMAL_DECIMAL_FLOATING_TYPE TargetDecimalType>
227+
friend constexpr auto detail::to_chars_cohort_preserving_scientific(char* first, char* last, const TargetDecimalType& value) noexcept -> to_chars_result;
228+
223229
template <bool checked, BOOST_DECIMAL_DECIMAL_FLOATING_TYPE T>
224230
friend constexpr auto detail::d64_fma_impl(T x, T y, T z) noexcept -> T;
225231

include/boost/decimal/detail/io.hpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ auto operator>>(std::basic_istream<charT, traits>& is, DecimalType& d)
7979
std::memcpy(buffer, t_buffer.c_str(), t_buffer.size());
8080
}
8181

82-
detail::convert_string_to_c_locale(buffer);
82+
detail::convert_string_to_c_locale(buffer, is.getloc());
8383

8484
auto fmt {chars_format::general};
8585
const auto flags {is.flags()};
@@ -170,8 +170,7 @@ auto operator<<(std::basic_ostream<charT, traits>& os, const DecimalType& d)
170170
}
171171

172172
*r.ptr = '\0';
173-
174-
detail::convert_string_to_local_locale(buffer);
173+
detail::convert_pointer_pair_to_local_locale(buffer, buffer + sizeof(buffer), os.getloc());
175174

176175
BOOST_DECIMAL_IF_CONSTEXPR (!std::is_same<charT, char>::value)
177176
{

0 commit comments

Comments
 (0)