Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libc/config/linux/x86_64/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.wchar.wmemchr
libc.src.wchar.wcpcpy
libc.src.wchar.wcpncpy
libc.src.wchar.wcstof
libc.src.wchar.wcstok
libc.src.wchar.wcstol
libc.src.wchar.wcstoll
Expand Down
7 changes: 7 additions & 0 deletions libc/include/wchar.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -360,3 +360,10 @@ functions:
- type: const wchar_t *__restrict
- type: wchar_t **__restrict
- type: int
- name: wcstof
standards:
- stdc
return_type: float
arguments:
- type: const wchar_t *__restrict
- type: wchar_t **__restrict
3 changes: 3 additions & 0 deletions libc/src/__support/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,9 @@ add_header_library(
HDRS
high_precision_decimal.h
DEPENDS
.ctype_utils
.str_to_integer
.wctype_utils
libc.hdr.stdint_proxy
)

Expand All @@ -236,6 +238,7 @@ add_header_library(
.str_to_integer
.str_to_num_result
.uint128
.wctype_utils
libc.hdr.errno_macros
libc.hdr.stdint_proxy
libc.src.__support.common
Expand Down
45 changes: 32 additions & 13 deletions libc/src/__support/high_precision_decimal.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "src/__support/ctype_utils.h"
#include "src/__support/macros/config.h"
#include "src/__support/str_to_integer.h"
#include "src/__support/wctype_utils.h"

namespace LIBC_NAMESPACE_DECL {
namespace internal {
Expand All @@ -38,6 +39,24 @@ struct LShiftTableEntry {
// TODO: Figure out where to put this.
enum class RoundDirection { Up, Down, Nearest };

// These constants are used in both this file and in the main str_to_float.h.
// TODO: Figure out where to put this.
template <typename CharType> struct constants;
template <> struct constants<char> {
static constexpr char DECIMAL_POINT = '.';
static constexpr char DECIMAL_EXPONENT_MARKER = 'e';
static constexpr char HEX_EXPONENT_MARKER = 'p';
static constexpr char INF_STRING[] = "infinity";
static constexpr char NAN_STRING[] = "nan";
};
template <> struct constants<wchar_t> {
static constexpr wchar_t DECIMAL_POINT = L'.';
static constexpr wchar_t DECIMAL_EXPONENT_MARKER = L'e';
static constexpr wchar_t HEX_EXPONENT_MARKER = L'p';
static constexpr wchar_t INF_STRING[] = L"infinity";
static constexpr wchar_t NAN_STRING[] = L"nan";
};

// This is based on the HPD data structure described as part of the Simple
// Decimal Conversion algorithm by Nigel Tao, described at this link:
// https://nigeltao.github.io/blog/2020/parse-number-f64-simple.html
Expand Down Expand Up @@ -314,35 +333,36 @@ class HighPrecisionDecimal {
public:
// num_string is assumed to be a string of numeric characters. It doesn't
// handle leading spaces.
LIBC_INLINE
HighPrecisionDecimal(
const char *__restrict num_string,
template <typename CharType>
LIBC_INLINE HighPrecisionDecimal(
const CharType *__restrict num_string,
const size_t num_len = cpp::numeric_limits<size_t>::max()) {
bool saw_dot = false;
size_t num_cur = 0;
// This counts the digits in the number, even if there isn't space to store
// them all.
uint32_t total_digits = 0;
while (num_cur < num_len &&
(isdigit(num_string[num_cur]) || num_string[num_cur] == '.')) {
if (num_string[num_cur] == '.') {
(isdigit(num_string[num_cur]) ||
num_string[num_cur] == constants<CharType>::DECIMAL_POINT)) {
if (num_string[num_cur] == constants<CharType>::DECIMAL_POINT) {
if (saw_dot) {
break;
}
this->decimal_point = static_cast<int32_t>(total_digits);
saw_dot = true;
} else {
if (num_string[num_cur] == '0' && this->num_digits == 0) {
int digit = b36_char_to_int(num_string[num_cur]);
if (digit == 0 && this->num_digits == 0) {
--this->decimal_point;
++num_cur;
continue;
}
++total_digits;
if (this->num_digits < MAX_NUM_DIGITS) {
this->digits[this->num_digits] = static_cast<uint8_t>(
internal::b36_char_to_int(num_string[num_cur]));
this->digits[this->num_digits] = static_cast<uint8_t>(digit);
++this->num_digits;
} else if (num_string[num_cur] != '0') {
} else if (digit != 0) {
this->truncated = true;
}
}
Expand All @@ -352,11 +372,10 @@ class HighPrecisionDecimal {
if (!saw_dot)
this->decimal_point = static_cast<int32_t>(total_digits);

if (num_cur < num_len &&
(num_string[num_cur] == 'e' || num_string[num_cur] == 'E')) {
if (num_cur < num_len && tolower(num_string[num_cur]) ==
constants<CharType>::DECIMAL_EXPONENT_MARKER) {
++num_cur;
if (isdigit(num_string[num_cur]) || num_string[num_cur] == '+' ||
num_string[num_cur] == '-') {
if (isdigit(num_string[num_cur]) || get_sign(num_string + num_cur) != 0) {
auto result =
strtointeger<int32_t>(num_string + num_cur, 10, num_len - num_cur);
if (result.has_error()) {
Expand Down
Loading
Loading