mirror of
https://github.com/fish-shell/fish-shell.git
synced 2025-03-02 01:57:41 +08:00
Implement fish_wcstod and adopt it in builtin_test
wcstod_l is enormously slow on the Mac. This makes arithmetic comparisons using builtin_test about 250% as fast on macOS.
This commit is contained in:
parent
8ebf2b8f70
commit
a700acadfa
@ -634,7 +634,7 @@ static bool parse_double(const wchar_t *arg, double *out_res) {
|
|||||||
while (arg && *arg != L'\0' && iswspace(*arg)) arg++;
|
while (arg && *arg != L'\0' && iswspace(*arg)) arg++;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
wchar_t *end = NULL;
|
wchar_t *end = NULL;
|
||||||
*out_res = wcstod_l(arg, &end, fish_c_locale());
|
*out_res = fish_wcstod(arg, &end);
|
||||||
// Consume trailing spaces.
|
// Consume trailing spaces.
|
||||||
while (end && *end != L'\0' && iswspace(*end)) end++;
|
while (end && *end != L'\0' && iswspace(*end)) end++;
|
||||||
return errno == 0 && end > arg && *end == L'\0';
|
return errno == 0 && end > arg && *end == L'\0';
|
||||||
|
@ -2285,6 +2285,24 @@ static void test_test() {
|
|||||||
do_test(run_test_test(0, L"4611686018427387904 -ge 4611686018427387904"));
|
do_test(run_test_test(0, L"4611686018427387904 -ge 4611686018427387904"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_wcstod() {
|
||||||
|
say(L"Testing fish_wcstod");
|
||||||
|
auto tod_test = [](const wchar_t *a, const char *b) {
|
||||||
|
char *narrow_end = nullptr;
|
||||||
|
wchar_t *wide_end = nullptr;
|
||||||
|
double val1 = wcstod(a, &wide_end);
|
||||||
|
double val2 = strtod(b, &narrow_end);
|
||||||
|
do_test((isnan(val1) && isnan(val2)) || fabs(val1 - val2) <= __DBL_EPSILON__);
|
||||||
|
do_test(wide_end - a == narrow_end - b);
|
||||||
|
};
|
||||||
|
tod_test(L"", "");
|
||||||
|
tod_test(L"1.2", "1.2");
|
||||||
|
tod_test(L"1.5", "1.5");
|
||||||
|
tod_test(L"-1000", "-1000");
|
||||||
|
tod_test(L"0.12345", "0.12345");
|
||||||
|
tod_test(L"nope", "nope");
|
||||||
|
}
|
||||||
|
|
||||||
/// Testing colors.
|
/// Testing colors.
|
||||||
static void test_colors() {
|
static void test_colors() {
|
||||||
say(L"Testing colors");
|
say(L"Testing colors");
|
||||||
@ -4949,6 +4967,7 @@ int main(int argc, char **argv) {
|
|||||||
if (should_test_function("ifind_fuzzy")) test_ifind_fuzzy();
|
if (should_test_function("ifind_fuzzy")) test_ifind_fuzzy();
|
||||||
if (should_test_function("abbreviations")) test_abbreviations();
|
if (should_test_function("abbreviations")) test_abbreviations();
|
||||||
if (should_test_function("test")) test_test();
|
if (should_test_function("test")) test_test();
|
||||||
|
if (should_test_function("wcstod")) test_wcstod();
|
||||||
if (should_test_function("path")) test_path();
|
if (should_test_function("path")) test_path();
|
||||||
if (should_test_function("pager_navigation")) test_pager_navigation();
|
if (should_test_function("pager_navigation")) test_pager_navigation();
|
||||||
if (should_test_function("pager_layout")) test_pager_layout();
|
if (should_test_function("pager_layout")) test_pager_layout();
|
||||||
|
@ -700,6 +700,27 @@ unsigned long long fish_wcstoull(const wchar_t *str, const wchar_t **endptr, int
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Like wcstod(), but wcstod() is enormously expensive on some platforms so this tries to have a
|
||||||
|
/// fast path.
|
||||||
|
double fish_wcstod(const wchar_t *str, wchar_t **endptr) {
|
||||||
|
// The "fast path." If we're all ASCII and we fit inline, use strtod().
|
||||||
|
char narrow[128];
|
||||||
|
size_t len_plus_0 = 1 + wcslen(str);
|
||||||
|
auto is_ascii = [](wchar_t c) { return c >= 0 && c <= 127; };
|
||||||
|
if (len_plus_0 <= sizeof narrow && std::all_of(str, str + len_plus_0, is_ascii)) {
|
||||||
|
// Fast path. Copy the string into a local buffer and run strtod() on it.
|
||||||
|
std::copy(str, str + len_plus_0, narrow);
|
||||||
|
char *narrow_endptr = nullptr;
|
||||||
|
double ret = strtod(narrow, endptr ? &narrow_endptr : nullptr);
|
||||||
|
if (endptr) {
|
||||||
|
assert(narrow_endptr && "narrow_endptr should not be null");
|
||||||
|
*endptr = const_cast<wchar_t *>(str + (narrow_endptr - narrow));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return wcstod_l(str, endptr, fish_c_locale());
|
||||||
|
}
|
||||||
|
|
||||||
file_id_t file_id_t::from_stat(const struct stat &buf) {
|
file_id_t file_id_t::from_stat(const struct stat &buf) {
|
||||||
file_id_t result = {};
|
file_id_t result = {};
|
||||||
result.device = buf.st_dev;
|
result.device = buf.st_dev;
|
||||||
|
@ -131,7 +131,7 @@ int fish_wcstoi(const wchar_t *str, const wchar_t **endptr = NULL, int base = 10
|
|||||||
long fish_wcstol(const wchar_t *str, const wchar_t **endptr = NULL, int base = 10);
|
long fish_wcstol(const wchar_t *str, const wchar_t **endptr = NULL, int base = 10);
|
||||||
long long fish_wcstoll(const wchar_t *str, const wchar_t **endptr = NULL, int base = 10);
|
long long fish_wcstoll(const wchar_t *str, const wchar_t **endptr = NULL, int base = 10);
|
||||||
unsigned long long fish_wcstoull(const wchar_t *str, const wchar_t **endptr = NULL, int base = 10);
|
unsigned long long fish_wcstoull(const wchar_t *str, const wchar_t **endptr = NULL, int base = 10);
|
||||||
double fish_wcstod(const wchar_t *str, const wchar_t **endptr);
|
double fish_wcstod(const wchar_t *str, wchar_t **endptr);
|
||||||
|
|
||||||
/// Class for representing a file's inode. We use this to detect and avoid symlink loops, among
|
/// Class for representing a file's inode. We use this to detect and avoid symlink loops, among
|
||||||
/// other things. While an inode / dev pair is sufficient to distinguish co-existing files, Linux
|
/// other things. While an inode / dev pair is sufficient to distinguish co-existing files, Linux
|
||||||
|
Loading…
x
Reference in New Issue
Block a user