From 97cd87f3b24ea75a79b0184f54fb726df678277e Mon Sep 17 00:00:00 2001 From: Fabian Homborg Date: Mon, 14 Dec 2020 22:54:53 +0100 Subject: [PATCH] math: Use wchar This was doing a bunch of work narrowing strings for no reason. --- src/builtin_math.cpp | 3 +- src/tinyexpr.cpp | 82 ++++++++++++++++++++++---------------------- src/tinyexpr.h | 2 +- 3 files changed, 43 insertions(+), 44 deletions(-) diff --git a/src/builtin_math.cpp b/src/builtin_math.cpp index 7a878b70a..5ccae2ca1 100644 --- a/src/builtin_math.cpp +++ b/src/builtin_math.cpp @@ -223,13 +223,12 @@ static int evaluate_expression(const wchar_t *cmd, const parser_t &parser, io_st int retval = STATUS_CMD_OK; te_error_t error; - std::string narrow_str = wcs2string(expression); // Switch locale while computing stuff. // This means that the "." is always the radix character, // so numbers work the same across locales. char *saved_locale = strdup(setlocale(LC_NUMERIC, nullptr)); setlocale(LC_NUMERIC, "C"); - double v = te_interp(narrow_str.c_str(), &error); + double v = te_interp(expression.c_str(), &error); if (error.position == 0) { // Check some runtime errors after the fact. diff --git a/src/tinyexpr.cpp b/src/tinyexpr.cpp index d858bf284..ffe9f0efe 100644 --- a/src/tinyexpr.cpp +++ b/src/tinyexpr.cpp @@ -75,7 +75,7 @@ typedef struct te_expr { } te_expr; using te_builtin = struct { - const char *name; + const wchar_t *name; const void *address; int type; }; @@ -85,15 +85,15 @@ using state = struct { double value; const void *function; }; - const char *start; - const char *next; + const wchar_t *start; + const wchar_t *next; int type; te_error_type_t error; }; /* Parses the input expression. */ /* Returns NULL on error. */ -te_expr *te_compile(const char *expression, te_error_t *error); +te_expr *te_compile(const wchar_t *expression, te_error_t *error); /* Evaluates the expression. */ double te_eval(const te_expr *n); @@ -182,47 +182,47 @@ static constexpr double bit_xor(double a, double b) { static const te_builtin functions[] = { /* must be in alphabetical order */ - {"abs", reinterpret_cast(static_cast(fabs)), TE_FUNCTION1}, - {"acos", reinterpret_cast(static_cast(acos)), TE_FUNCTION1}, - {"asin", reinterpret_cast(static_cast(asin)), TE_FUNCTION1}, - {"atan", reinterpret_cast(static_cast(atan)), TE_FUNCTION1}, - {"atan2", reinterpret_cast(static_cast(atan2)), TE_FUNCTION2}, - {"bitand", reinterpret_cast(static_cast(bit_and)), TE_FUNCTION2}, - {"bitor", reinterpret_cast(static_cast(bit_or)), TE_FUNCTION2}, - {"bitxor", reinterpret_cast(static_cast(bit_xor)), TE_FUNCTION2}, - {"ceil", reinterpret_cast(static_cast(ceil)), TE_FUNCTION1}, - {"cos", reinterpret_cast(static_cast(cos)), TE_FUNCTION1}, - {"cosh", reinterpret_cast(static_cast(cosh)), TE_FUNCTION1}, - {"e", reinterpret_cast(static_cast(e)), TE_FUNCTION0}, - {"exp", reinterpret_cast(static_cast(exp)), TE_FUNCTION1}, - {"fac", reinterpret_cast(static_cast(fac)), TE_FUNCTION1}, - {"floor", reinterpret_cast(static_cast(floor)), TE_FUNCTION1}, - {"ln", reinterpret_cast(static_cast(log)), TE_FUNCTION1}, - {"log", reinterpret_cast(static_cast(log10)), TE_FUNCTION1}, - {"log10", reinterpret_cast(static_cast(log10)), TE_FUNCTION1}, - {"ncr", reinterpret_cast(static_cast(ncr)), TE_FUNCTION2}, - {"npr", reinterpret_cast(static_cast(npr)), TE_FUNCTION2}, - {"pi", reinterpret_cast(static_cast(pi)), TE_FUNCTION0}, - {"pow", reinterpret_cast(static_cast(pow)), TE_FUNCTION2}, - {"round", reinterpret_cast(static_cast(round)), TE_FUNCTION1}, - {"sin", reinterpret_cast(static_cast(sin)), TE_FUNCTION1}, - {"sinh", reinterpret_cast(static_cast(sinh)), TE_FUNCTION1}, - {"sqrt", reinterpret_cast(static_cast(sqrt)), TE_FUNCTION1}, - {"tan", reinterpret_cast(static_cast(tan)), TE_FUNCTION1}, - {"tanh", reinterpret_cast(static_cast(tanh)), TE_FUNCTION1}, - {"tau", reinterpret_cast(static_cast(tau)), TE_FUNCTION0}, + {L"abs", reinterpret_cast(static_cast(fabs)), TE_FUNCTION1}, + {L"acos", reinterpret_cast(static_cast(acos)), TE_FUNCTION1}, + {L"asin", reinterpret_cast(static_cast(asin)), TE_FUNCTION1}, + {L"atan", reinterpret_cast(static_cast(atan)), TE_FUNCTION1}, + {L"atan2", reinterpret_cast(static_cast(atan2)), TE_FUNCTION2}, + {L"bitand", reinterpret_cast(static_cast(bit_and)), TE_FUNCTION2}, + {L"bitor", reinterpret_cast(static_cast(bit_or)), TE_FUNCTION2}, + {L"bitxor", reinterpret_cast(static_cast(bit_xor)), TE_FUNCTION2}, + {L"ceil", reinterpret_cast(static_cast(ceil)), TE_FUNCTION1}, + {L"cos", reinterpret_cast(static_cast(cos)), TE_FUNCTION1}, + {L"cosh", reinterpret_cast(static_cast(cosh)), TE_FUNCTION1}, + {L"e", reinterpret_cast(static_cast(e)), TE_FUNCTION0}, + {L"exp", reinterpret_cast(static_cast(exp)), TE_FUNCTION1}, + {L"fac", reinterpret_cast(static_cast(fac)), TE_FUNCTION1}, + {L"floor", reinterpret_cast(static_cast(floor)), TE_FUNCTION1}, + {L"ln", reinterpret_cast(static_cast(log)), TE_FUNCTION1}, + {L"log", reinterpret_cast(static_cast(log10)), TE_FUNCTION1}, + {L"log10", reinterpret_cast(static_cast(log10)), TE_FUNCTION1}, + {L"ncr", reinterpret_cast(static_cast(ncr)), TE_FUNCTION2}, + {L"npr", reinterpret_cast(static_cast(npr)), TE_FUNCTION2}, + {L"pi", reinterpret_cast(static_cast(pi)), TE_FUNCTION0}, + {L"pow", reinterpret_cast(static_cast(pow)), TE_FUNCTION2}, + {L"round", reinterpret_cast(static_cast(round)), TE_FUNCTION1}, + {L"sin", reinterpret_cast(static_cast(sin)), TE_FUNCTION1}, + {L"sinh", reinterpret_cast(static_cast(sinh)), TE_FUNCTION1}, + {L"sqrt", reinterpret_cast(static_cast(sqrt)), TE_FUNCTION1}, + {L"tan", reinterpret_cast(static_cast(tan)), TE_FUNCTION1}, + {L"tanh", reinterpret_cast(static_cast(tanh)), TE_FUNCTION1}, + {L"tau", reinterpret_cast(static_cast(tau)), TE_FUNCTION0}, }; -static const te_builtin *find_builtin(const char *name, int len) { +static const te_builtin *find_builtin(const wchar_t *name, int len) { const auto end = std::end(functions); const te_builtin *found = std::lower_bound(std::begin(functions), end, name, - [len](const te_builtin &lhs, const char *rhs) { + [len](const te_builtin &lhs, const wchar_t *rhs) { // The length is important because that's where // the parens start - return std::strncmp(lhs.name, rhs, len) < 0; + return std::wcsncmp(lhs.name, rhs, len) < 0; }); // We need to compare again because we might have gotten the first "larger" element. - if (found != end && std::strncmp(found->name, name, len) == 0 && found->name[len] == 0) + if (found != end && std::wcsncmp(found->name, name, len) == 0 && found->name[len] == 0) return found; return nullptr; } @@ -250,7 +250,7 @@ static void next_token(state *s) { /* Try reading a number. */ if ((s->next[0] >= '0' && s->next[0] <= '9') || s->next[0] == '.') { - s->value = strtod(s->next, const_cast(&s->next)); + s->value = wcstod(s->next, const_cast(&s->next)); s->type = TOK_NUMBER; } else { /* Look for a function call. */ @@ -258,7 +258,7 @@ static void next_token(state *s) { // - that's the alternative multiplication operator. if (s->next[0] >= 'a' && s->next[0] <= 'z' && !(s->next[0] == 'x' && isspace(s->next[1]))) { - const char *start; + const wchar_t *start; start = s->next; while ((s->next[0] >= 'a' && s->next[0] <= 'z') || (s->next[0] >= '0' && s->next[0] <= '9') || (s->next[0] == '_')) @@ -571,7 +571,7 @@ static void optimize(te_expr *n) { } } -te_expr *te_compile(const char *expression, te_error_t *error) { +te_expr *te_compile(const wchar_t *expression, te_error_t *error) { state s; s.start = s.next = expression; s.error = TE_ERROR_NONE; @@ -602,7 +602,7 @@ te_expr *te_compile(const char *expression, te_error_t *error) { } } -double te_interp(const char *expression, te_error_t *error) { +double te_interp(const wchar_t *expression, te_error_t *error) { te_expr *n = te_compile(expression, error); double ret; if (n) { diff --git a/src/tinyexpr.h b/src/tinyexpr.h index fec012fd4..76b930722 100644 --- a/src/tinyexpr.h +++ b/src/tinyexpr.h @@ -47,6 +47,6 @@ typedef struct te_error_t { /* Parses the input expression, evaluates it, and frees it. */ /* Returns NaN on error. */ -double te_interp(const char *expression, te_error_t *error); +double te_interp(const wchar_t *expression, te_error_t *error); #endif /*__TINYEXPR_H__*/