@@ -188,32 +188,17 @@ from_chars(UC const *first, UC const *last, T &value,
188188 parse_options_t <UC>(fmt));
189189}
190190
191- /* *
192- * This function overload takes parsed_number_string_t structure that is created
193- * and populated either by from_chars_advanced function taking chars range and
194- * parsing options or other parsing custom function implemented by user.
195- */
196- template <typename T, typename UC>
197- FASTFLOAT_CONSTEXPR20 from_chars_result_t <UC>
198- from_chars_advanced (parsed_number_string_t <UC> &pns, T &value) noexcept {
199-
200- static_assert (is_supported_float_type<T>::value,
201- " only some floating-point types are supported" );
202- static_assert (is_supported_char_type<UC>::value,
203- " only char, wchar_t, char16_t and char32_t are supported" );
204-
205- from_chars_result_t <UC> answer;
206-
207- answer.ec = std::errc (); // be optimistic
208- answer.ptr = pns.lastmatch ;
191+ template <typename T>
192+ fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool
193+ clinger_fast_path_impl (uint64_t mantissa, int64_t exponent, bool is_negative,
194+ T &value) noexcept {
209195 // The implementation of the Clinger's fast path is convoluted because
210196 // we want round-to-nearest in all cases, irrespective of the rounding mode
211197 // selected on the thread.
212198 // We proceed optimistically, assuming that detail::rounds_to_nearest()
213199 // returns true.
214- if (binary_format<T>::min_exponent_fast_path () <= pns.exponent &&
215- pns.exponent <= binary_format<T>::max_exponent_fast_path () &&
216- !pns.too_many_digits ) {
200+ if (binary_format<T>::min_exponent_fast_path () <= exponent &&
201+ exponent <= binary_format<T>::max_exponent_fast_path ()) {
217202 // Unfortunately, the conventional Clinger's fast path is only possible
218203 // when the system rounds to the nearest float.
219204 //
@@ -224,41 +209,64 @@ from_chars_advanced(parsed_number_string_t<UC> &pns, T &value) noexcept {
224209 if (!cpp20_and_in_constexpr () && detail::rounds_to_nearest ()) {
225210 // We have that fegetround() == FE_TONEAREST.
226211 // Next is Clinger's fast path.
227- if (pns. mantissa <= binary_format<T>::max_mantissa_fast_path ()) {
228- value = T (pns. mantissa );
229- if (pns. exponent < 0 ) {
230- value = value / binary_format<T>::exact_power_of_ten (-pns. exponent );
212+ if (mantissa <= binary_format<T>::max_mantissa_fast_path ()) {
213+ value = T (mantissa);
214+ if (exponent < 0 ) {
215+ value = value / binary_format<T>::exact_power_of_ten (-exponent);
231216 } else {
232- value = value * binary_format<T>::exact_power_of_ten (pns. exponent );
217+ value = value * binary_format<T>::exact_power_of_ten (exponent);
233218 }
234- if (pns. negative ) {
219+ if (is_negative ) {
235220 value = -value;
236221 }
237- return answer ;
222+ return true ;
238223 }
239224 } else {
240225 // We do not have that fegetround() == FE_TONEAREST.
241226 // Next is a modified Clinger's fast path, inspired by Jakub Jelínek's
242227 // proposal
243- if (pns.exponent >= 0 &&
244- pns.mantissa <=
245- binary_format<T>::max_mantissa_fast_path (pns.exponent )) {
228+ if (exponent >= 0 &&
229+ mantissa <= binary_format<T>::max_mantissa_fast_path (exponent)) {
246230#if defined(__clang__) || defined(FASTFLOAT_32BIT)
247231 // Clang may map 0 to -0.0 when fegetround() == FE_DOWNWARD
248- if (pns. mantissa == 0 ) {
249- value = pns. negative ? T (-0 .) : T (0 .);
250- return answer ;
232+ if (mantissa == 0 ) {
233+ value = is_negative ? T (-0 .) : T (0 .);
234+ return true ;
251235 }
252236#endif
253- value = T (pns.mantissa ) *
254- binary_format<T>::exact_power_of_ten (pns.exponent );
255- if (pns.negative ) {
237+ value = T (mantissa) * binary_format<T>::exact_power_of_ten (exponent);
238+ if (is_negative) {
256239 value = -value;
257240 }
258- return answer ;
241+ return true ;
259242 }
260243 }
261244 }
245+ return false ;
246+ }
247+
248+ /* *
249+ * This function overload takes parsed_number_string_t structure that is created
250+ * and populated either by from_chars_advanced function taking chars range and
251+ * parsing options or other parsing custom function implemented by user.
252+ */
253+ template <typename T, typename UC>
254+ FASTFLOAT_CONSTEXPR20 from_chars_result_t <UC>
255+ from_chars_advanced (parsed_number_string_t <UC> &pns, T &value) noexcept {
256+ static_assert (is_supported_float_type<T>::value,
257+ " only some floating-point types are supported" );
258+ static_assert (is_supported_char_type<UC>::value,
259+ " only char, wchar_t, char16_t and char32_t are supported" );
260+
261+ from_chars_result_t <UC> answer;
262+
263+ answer.ec = std::errc (); // be optimistic
264+ answer.ptr = pns.lastmatch ;
265+
266+ if (!pns.too_many_digits &&
267+ clinger_fast_path_impl (pns.mantissa , pns.exponent , pns.negative , value))
268+ return answer;
269+
262270 adjusted_mantissa am =
263271 compute_float<binary_format<T>>(pns.exponent , pns.mantissa );
264272 if (pns.too_many_digits && am.power2 >= 0 ) {
@@ -336,6 +344,49 @@ from_chars(UC const *first, UC const *last, T &value, int base) noexcept {
336344 return from_chars_advanced (first, last, value, options);
337345}
338346
347+ FASTFLOAT_CONSTEXPR20 inline double
348+ integer_times_pow10 (uint64_t mantissa, int decimal_exponent) noexcept {
349+ double value;
350+ if (clinger_fast_path_impl (mantissa, decimal_exponent, false , value))
351+ return value;
352+
353+ adjusted_mantissa am =
354+ compute_float<binary_format<double >>(decimal_exponent, mantissa);
355+ to_float (false , am, value);
356+ return value;
357+ }
358+
359+ FASTFLOAT_CONSTEXPR20 inline double
360+ integer_times_pow10 (int64_t mantissa, int decimal_exponent) noexcept {
361+ const bool is_negative = mantissa < 0 ;
362+ const uint64_t m = static_cast <uint64_t >(is_negative ? -mantissa : mantissa);
363+
364+ double value;
365+ if (clinger_fast_path_impl (m, decimal_exponent, is_negative, value))
366+ return value;
367+
368+ adjusted_mantissa am =
369+ compute_float<binary_format<double >>(decimal_exponent, m);
370+ to_float (is_negative, am, value);
371+ return value;
372+ }
373+
374+ // the following overloads are here to avoid surprising ambiguity for int,
375+ // unsigned, etc.
376+ template <typename Int>
377+ FASTFLOAT_CONSTEXPR20 inline typename std::enable_if<
378+ std::is_integral<Int>::value && !std::is_signed<Int>::value, double >::type
379+ integer_times_pow10 (Int mantissa, int decimal_exponent) noexcept {
380+ return integer_times_pow10 (static_cast <uint64_t >(mantissa), decimal_exponent);
381+ }
382+
383+ template <typename Int>
384+ FASTFLOAT_CONSTEXPR20 inline typename std::enable_if<
385+ std::is_integral<Int>::value && std::is_signed<Int>::value, double >::type
386+ integer_times_pow10 (Int mantissa, int decimal_exponent) noexcept {
387+ return integer_times_pow10 (static_cast <int64_t >(mantissa), decimal_exponent);
388+ }
389+
339390template <typename T, typename UC>
340391FASTFLOAT_CONSTEXPR20 from_chars_result_t <UC>
341392from_chars_int_advanced (UC const *first, UC const *last, T &value,
0 commit comments