Skip to content

Commit e797ec6

Browse files
authored
[libc] Templatize strtofloatingpoint and implement wcstof. (llvm#167755)
This change follows the pattern of 315dfe5 by making strtofloat also accept wchar_t* strings (in addition to regular char*). It uses overloads from wctype_utils or specialized functions to ensure comparison with literal characters (or literal strings) pick char or wchar_t variants based on the argument type. The wcstof implementation is added, with unit test cases copied from strtof test suite.
1 parent 12edc56 commit e797ec6

File tree

11 files changed

+414
-136
lines changed

11 files changed

+414
-136
lines changed

libc/config/linux/x86_64/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,7 @@ set(TARGET_LIBC_ENTRYPOINTS
398398
libc.src.wchar.wmemchr
399399
libc.src.wchar.wcpcpy
400400
libc.src.wchar.wcpncpy
401+
libc.src.wchar.wcstof
401402
libc.src.wchar.wcstok
402403
libc.src.wchar.wcstol
403404
libc.src.wchar.wcstoll

libc/include/wchar.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,3 +360,10 @@ functions:
360360
- type: const wchar_t *__restrict
361361
- type: wchar_t **__restrict
362362
- type: int
363+
- name: wcstof
364+
standards:
365+
- stdc
366+
return_type: float
367+
arguments:
368+
- type: const wchar_t *__restrict
369+
- type: wchar_t **__restrict

libc/src/__support/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,9 @@ add_header_library(
221221
HDRS
222222
high_precision_decimal.h
223223
DEPENDS
224+
.ctype_utils
224225
.str_to_integer
226+
.wctype_utils
225227
libc.hdr.stdint_proxy
226228
)
227229

@@ -236,6 +238,7 @@ add_header_library(
236238
.str_to_integer
237239
.str_to_num_result
238240
.uint128
241+
.wctype_utils
239242
libc.hdr.errno_macros
240243
libc.hdr.stdint_proxy
241244
libc.src.__support.common

libc/src/__support/high_precision_decimal.h

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "src/__support/ctype_utils.h"
2121
#include "src/__support/macros/config.h"
2222
#include "src/__support/str_to_integer.h"
23+
#include "src/__support/wctype_utils.h"
2324

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

42+
// These constants are used in both this file and in the main str_to_float.h.
43+
// TODO: Figure out where to put this.
44+
template <typename CharType> struct constants;
45+
template <> struct constants<char> {
46+
static constexpr char DECIMAL_POINT = '.';
47+
static constexpr char DECIMAL_EXPONENT_MARKER = 'e';
48+
static constexpr char HEX_EXPONENT_MARKER = 'p';
49+
static constexpr char INF_STRING[] = "infinity";
50+
static constexpr char NAN_STRING[] = "nan";
51+
};
52+
template <> struct constants<wchar_t> {
53+
static constexpr wchar_t DECIMAL_POINT = L'.';
54+
static constexpr wchar_t DECIMAL_EXPONENT_MARKER = L'e';
55+
static constexpr wchar_t HEX_EXPONENT_MARKER = L'p';
56+
static constexpr wchar_t INF_STRING[] = L"infinity";
57+
static constexpr wchar_t NAN_STRING[] = L"nan";
58+
};
59+
4160
// This is based on the HPD data structure described as part of the Simple
4261
// Decimal Conversion algorithm by Nigel Tao, described at this link:
4362
// https://nigeltao.github.io/blog/2020/parse-number-f64-simple.html
@@ -314,35 +333,36 @@ class HighPrecisionDecimal {
314333
public:
315334
// num_string is assumed to be a string of numeric characters. It doesn't
316335
// handle leading spaces.
317-
LIBC_INLINE
318-
HighPrecisionDecimal(
319-
const char *__restrict num_string,
336+
template <typename CharType>
337+
LIBC_INLINE HighPrecisionDecimal(
338+
const CharType *__restrict num_string,
320339
const size_t num_len = cpp::numeric_limits<size_t>::max()) {
321340
bool saw_dot = false;
322341
size_t num_cur = 0;
323342
// This counts the digits in the number, even if there isn't space to store
324343
// them all.
325344
uint32_t total_digits = 0;
326345
while (num_cur < num_len &&
327-
(isdigit(num_string[num_cur]) || num_string[num_cur] == '.')) {
328-
if (num_string[num_cur] == '.') {
346+
(isdigit(num_string[num_cur]) ||
347+
num_string[num_cur] == constants<CharType>::DECIMAL_POINT)) {
348+
if (num_string[num_cur] == constants<CharType>::DECIMAL_POINT) {
329349
if (saw_dot) {
330350
break;
331351
}
332352
this->decimal_point = static_cast<int32_t>(total_digits);
333353
saw_dot = true;
334354
} else {
335-
if (num_string[num_cur] == '0' && this->num_digits == 0) {
355+
int digit = b36_char_to_int(num_string[num_cur]);
356+
if (digit == 0 && this->num_digits == 0) {
336357
--this->decimal_point;
337358
++num_cur;
338359
continue;
339360
}
340361
++total_digits;
341362
if (this->num_digits < MAX_NUM_DIGITS) {
342-
this->digits[this->num_digits] = static_cast<uint8_t>(
343-
internal::b36_char_to_int(num_string[num_cur]));
363+
this->digits[this->num_digits] = static_cast<uint8_t>(digit);
344364
++this->num_digits;
345-
} else if (num_string[num_cur] != '0') {
365+
} else if (digit != 0) {
346366
this->truncated = true;
347367
}
348368
}
@@ -352,11 +372,10 @@ class HighPrecisionDecimal {
352372
if (!saw_dot)
353373
this->decimal_point = static_cast<int32_t>(total_digits);
354374

355-
if (num_cur < num_len &&
356-
(num_string[num_cur] == 'e' || num_string[num_cur] == 'E')) {
375+
if (num_cur < num_len && tolower(num_string[num_cur]) ==
376+
constants<CharType>::DECIMAL_EXPONENT_MARKER) {
357377
++num_cur;
358-
if (isdigit(num_string[num_cur]) || num_string[num_cur] == '+' ||
359-
num_string[num_cur] == '-') {
378+
if (isdigit(num_string[num_cur]) || get_sign(num_string + num_cur) != 0) {
360379
auto result =
361380
strtointeger<int32_t>(num_string + num_cur, 10, num_len - num_cur);
362381
if (result.has_error()) {

0 commit comments

Comments
 (0)