|
| 1 | +//===----------------------------------------------------------------------===// |
| 2 | +// |
| 3 | +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | +// See https://llvm.org/LICENSE.txt for license information. |
| 5 | +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | +// |
| 7 | +//===----------------------------------------------------------------------===// |
| 8 | + |
| 9 | +#ifndef _LIBCPP_SRC_INCLUDE_FROM_CHARS_FLOATING_POINT_H |
| 10 | +#define _LIBCPP_SRC_INCLUDE_FROM_CHARS_FLOATING_POINT_H |
| 11 | + |
| 12 | +// NEVER DO THIS FOR REAL, this is just for demonstration purposes. |
| 13 | +#define LIBC_NAMESPACE libc_namespace_in_libcxx |
| 14 | + |
| 15 | +// This header is in the shared LLVM-libc header library. |
| 16 | +#include "shared/str_to_float.h" |
| 17 | + |
| 18 | +#include <__assert> |
| 19 | +#include <__config> |
| 20 | +#include <charconv> |
| 21 | +#include <limits> |
| 22 | +#include <type_traits> |
| 23 | + |
| 24 | +// Included for the _Floating_type_traits class |
| 25 | +#include "to_chars_floating_point.h" |
| 26 | + |
| 27 | +_LIBCPP_BEGIN_NAMESPACE_STD |
| 28 | + |
| 29 | +template <typename _Tp, __enable_if_t<std::is_floating_point<_Tp>::value, int> = 0> |
| 30 | +from_chars_result from_chars_floating_point(const char* __first, const char* __last, _Tp& value, chars_format fmt) { |
| 31 | + using _Traits = _Floating_type_traits<_Tp>; |
| 32 | + using _Uint_type = typename _Traits::_Uint_type; |
| 33 | + ptrdiff_t length = __last - __first; |
| 34 | + _LIBCPP_ASSERT_INTERNAL(length > 0, ""); |
| 35 | + |
| 36 | + // hacky parsing code as example. Not intended for actual use. I'm just going to handle the base 10 |
| 37 | + // chars_format::general case. Also, no sign, inf, or nan handling. |
| 38 | + _LIBCPP_ASSERT_INTERNAL(fmt == std::chars_format::general, ""); |
| 39 | + |
| 40 | + const char* src = __first; // rename to match the libc code copied for this section. |
| 41 | + |
| 42 | + _Uint_type mantissa = 0; |
| 43 | + int exponent = 0; |
| 44 | + bool truncated = false; |
| 45 | + bool seen_digit = false; |
| 46 | + bool after_decimal = false; |
| 47 | + size_t index = 0; |
| 48 | + const size_t BASE = 10; |
| 49 | + constexpr char EXPONENT_MARKER = 'e'; |
| 50 | + constexpr char DECIMAL_POINT = '.'; |
| 51 | + |
| 52 | + // The loop fills the mantissa with as many digits as it can hold |
| 53 | + const _Uint_type bitstype_max_div_by_base = numeric_limits<_Uint_type>::max() / BASE; |
| 54 | + while (index < length) { |
| 55 | + if (LIBC_NAMESPACE::internal::isdigit(src[index])) { |
| 56 | + uint32_t digit = src[index] - '0'; |
| 57 | + seen_digit = true; |
| 58 | + |
| 59 | + if (mantissa < bitstype_max_div_by_base) { |
| 60 | + mantissa = (mantissa * BASE) + digit; |
| 61 | + if (after_decimal) { |
| 62 | + --exponent; |
| 63 | + } |
| 64 | + } else { |
| 65 | + if (digit > 0) |
| 66 | + truncated = true; |
| 67 | + if (!after_decimal) |
| 68 | + ++exponent; |
| 69 | + } |
| 70 | + |
| 71 | + ++index; |
| 72 | + continue; |
| 73 | + } |
| 74 | + if (src[index] == DECIMAL_POINT) { |
| 75 | + if (after_decimal) { |
| 76 | + break; // this means that src[index] points to a second decimal point, ending the number. |
| 77 | + } |
| 78 | + after_decimal = true; |
| 79 | + ++index; |
| 80 | + continue; |
| 81 | + } |
| 82 | + // The character is neither a digit nor a decimal point. |
| 83 | + break; |
| 84 | + } |
| 85 | + |
| 86 | + if (!seen_digit) |
| 87 | + return {src + index, {}}; |
| 88 | + |
| 89 | + if (index < length && LIBC_NAMESPACE::internal::tolower(src[index]) == EXPONENT_MARKER) { |
| 90 | + bool has_sign = false; |
| 91 | + if (index + 1 < length && (src[index + 1] == '+' || src[index + 1] == '-')) { |
| 92 | + has_sign = true; |
| 93 | + } |
| 94 | + if (index + 1 + static_cast<size_t>(has_sign) < length && |
| 95 | + LIBC_NAMESPACE::internal::isdigit(src[index + 1 + static_cast<size_t>(has_sign)])) { |
| 96 | + ++index; |
| 97 | + auto result = LIBC_NAMESPACE::internal::strtointeger<int32_t>(src + index, 10); |
| 98 | + // if (result.has_error()) |
| 99 | + // output.error = result.error; |
| 100 | + int32_t add_to_exponent = result.value; |
| 101 | + index += result.parsed_len; |
| 102 | + |
| 103 | + // Here we do this operation as int64 to avoid overflow. |
| 104 | + int64_t temp_exponent = static_cast<int64_t>(exponent) + static_cast<int64_t>(add_to_exponent); |
| 105 | + |
| 106 | + // If the result is in the valid range, then we use it. The valid range is |
| 107 | + // also within the int32 range, so this prevents overflow issues. |
| 108 | + if (temp_exponent > LIBC_NAMESPACE::fputil::FPBits<_Tp>::MAX_BIASED_EXPONENT) { |
| 109 | + exponent = LIBC_NAMESPACE::fputil::FPBits<_Tp>::MAX_BIASED_EXPONENT; |
| 110 | + } else if (temp_exponent < -LIBC_NAMESPACE::fputil::FPBits<_Tp>::MAX_BIASED_EXPONENT) { |
| 111 | + exponent = -LIBC_NAMESPACE::fputil::FPBits<_Tp>::MAX_BIASED_EXPONENT; |
| 112 | + } else { |
| 113 | + exponent = static_cast<int32_t>(temp_exponent); |
| 114 | + } |
| 115 | + } |
| 116 | + } |
| 117 | + |
| 118 | + LIBC_NAMESPACE::internal::ExpandedFloat<_Tp> expanded_float = {0, 0}; |
| 119 | + if (mantissa != 0) { |
| 120 | + auto temp = LIBC_NAMESPACE::shared::decimal_exp_to_float<_Tp>( |
| 121 | + {mantissa, exponent}, truncated, LIBC_NAMESPACE::internal::RoundDirection::Nearest, src, length); |
| 122 | + expanded_float = temp.num; |
| 123 | + // Note: there's also an error value in temp.error. I'm not doing that error handling right now though. |
| 124 | + } |
| 125 | + |
| 126 | + auto result = LIBC_NAMESPACE::fputil::FPBits<_Tp>(); |
| 127 | + result.set_mantissa(expanded_float.mantissa); |
| 128 | + result.set_biased_exponent(expanded_float.exponent); |
| 129 | + value = result.get_val(); |
| 130 | + return {src + index, {}}; |
| 131 | +} |
| 132 | + |
| 133 | +_LIBCPP_END_NAMESPACE_STD |
| 134 | + |
| 135 | +#endif //_LIBCPP_SRC_INCLUDE_FROM_CHARS_FLOATING_POINT_H |
0 commit comments