math: Use wchar

This was doing a bunch of work narrowing strings for no reason.
This commit is contained in:
Fabian Homborg 2020-12-14 22:54:53 +01:00
parent edbb8ad0a4
commit 97cd87f3b2
3 changed files with 43 additions and 44 deletions

View file

@ -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.

View file

@ -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<const void *>(static_cast<te_fun1>(fabs)), TE_FUNCTION1},
{"acos", reinterpret_cast<const void *>(static_cast<te_fun1>(acos)), TE_FUNCTION1},
{"asin", reinterpret_cast<const void *>(static_cast<te_fun1>(asin)), TE_FUNCTION1},
{"atan", reinterpret_cast<const void *>(static_cast<te_fun1>(atan)), TE_FUNCTION1},
{"atan2", reinterpret_cast<const void *>(static_cast<te_fun2>(atan2)), TE_FUNCTION2},
{"bitand", reinterpret_cast<const void *>(static_cast<te_fun2>(bit_and)), TE_FUNCTION2},
{"bitor", reinterpret_cast<const void *>(static_cast<te_fun2>(bit_or)), TE_FUNCTION2},
{"bitxor", reinterpret_cast<const void *>(static_cast<te_fun2>(bit_xor)), TE_FUNCTION2},
{"ceil", reinterpret_cast<const void *>(static_cast<te_fun1>(ceil)), TE_FUNCTION1},
{"cos", reinterpret_cast<const void *>(static_cast<te_fun1>(cos)), TE_FUNCTION1},
{"cosh", reinterpret_cast<const void *>(static_cast<te_fun1>(cosh)), TE_FUNCTION1},
{"e", reinterpret_cast<const void *>(static_cast<te_fun0>(e)), TE_FUNCTION0},
{"exp", reinterpret_cast<const void *>(static_cast<te_fun1>(exp)), TE_FUNCTION1},
{"fac", reinterpret_cast<const void *>(static_cast<te_fun1>(fac)), TE_FUNCTION1},
{"floor", reinterpret_cast<const void *>(static_cast<te_fun1>(floor)), TE_FUNCTION1},
{"ln", reinterpret_cast<const void *>(static_cast<te_fun1>(log)), TE_FUNCTION1},
{"log", reinterpret_cast<const void *>(static_cast<te_fun1>(log10)), TE_FUNCTION1},
{"log10", reinterpret_cast<const void *>(static_cast<te_fun1>(log10)), TE_FUNCTION1},
{"ncr", reinterpret_cast<const void *>(static_cast<te_fun2>(ncr)), TE_FUNCTION2},
{"npr", reinterpret_cast<const void *>(static_cast<te_fun2>(npr)), TE_FUNCTION2},
{"pi", reinterpret_cast<const void *>(static_cast<te_fun0>(pi)), TE_FUNCTION0},
{"pow", reinterpret_cast<const void *>(static_cast<te_fun2>(pow)), TE_FUNCTION2},
{"round", reinterpret_cast<const void *>(static_cast<te_fun1>(round)), TE_FUNCTION1},
{"sin", reinterpret_cast<const void *>(static_cast<te_fun1>(sin)), TE_FUNCTION1},
{"sinh", reinterpret_cast<const void *>(static_cast<te_fun1>(sinh)), TE_FUNCTION1},
{"sqrt", reinterpret_cast<const void *>(static_cast<te_fun1>(sqrt)), TE_FUNCTION1},
{"tan", reinterpret_cast<const void *>(static_cast<te_fun1>(tan)), TE_FUNCTION1},
{"tanh", reinterpret_cast<const void *>(static_cast<te_fun1>(tanh)), TE_FUNCTION1},
{"tau", reinterpret_cast<const void *>(static_cast<te_fun0>(tau)), TE_FUNCTION0},
{L"abs", reinterpret_cast<const void *>(static_cast<te_fun1>(fabs)), TE_FUNCTION1},
{L"acos", reinterpret_cast<const void *>(static_cast<te_fun1>(acos)), TE_FUNCTION1},
{L"asin", reinterpret_cast<const void *>(static_cast<te_fun1>(asin)), TE_FUNCTION1},
{L"atan", reinterpret_cast<const void *>(static_cast<te_fun1>(atan)), TE_FUNCTION1},
{L"atan2", reinterpret_cast<const void *>(static_cast<te_fun2>(atan2)), TE_FUNCTION2},
{L"bitand", reinterpret_cast<const void *>(static_cast<te_fun2>(bit_and)), TE_FUNCTION2},
{L"bitor", reinterpret_cast<const void *>(static_cast<te_fun2>(bit_or)), TE_FUNCTION2},
{L"bitxor", reinterpret_cast<const void *>(static_cast<te_fun2>(bit_xor)), TE_FUNCTION2},
{L"ceil", reinterpret_cast<const void *>(static_cast<te_fun1>(ceil)), TE_FUNCTION1},
{L"cos", reinterpret_cast<const void *>(static_cast<te_fun1>(cos)), TE_FUNCTION1},
{L"cosh", reinterpret_cast<const void *>(static_cast<te_fun1>(cosh)), TE_FUNCTION1},
{L"e", reinterpret_cast<const void *>(static_cast<te_fun0>(e)), TE_FUNCTION0},
{L"exp", reinterpret_cast<const void *>(static_cast<te_fun1>(exp)), TE_FUNCTION1},
{L"fac", reinterpret_cast<const void *>(static_cast<te_fun1>(fac)), TE_FUNCTION1},
{L"floor", reinterpret_cast<const void *>(static_cast<te_fun1>(floor)), TE_FUNCTION1},
{L"ln", reinterpret_cast<const void *>(static_cast<te_fun1>(log)), TE_FUNCTION1},
{L"log", reinterpret_cast<const void *>(static_cast<te_fun1>(log10)), TE_FUNCTION1},
{L"log10", reinterpret_cast<const void *>(static_cast<te_fun1>(log10)), TE_FUNCTION1},
{L"ncr", reinterpret_cast<const void *>(static_cast<te_fun2>(ncr)), TE_FUNCTION2},
{L"npr", reinterpret_cast<const void *>(static_cast<te_fun2>(npr)), TE_FUNCTION2},
{L"pi", reinterpret_cast<const void *>(static_cast<te_fun0>(pi)), TE_FUNCTION0},
{L"pow", reinterpret_cast<const void *>(static_cast<te_fun2>(pow)), TE_FUNCTION2},
{L"round", reinterpret_cast<const void *>(static_cast<te_fun1>(round)), TE_FUNCTION1},
{L"sin", reinterpret_cast<const void *>(static_cast<te_fun1>(sin)), TE_FUNCTION1},
{L"sinh", reinterpret_cast<const void *>(static_cast<te_fun1>(sinh)), TE_FUNCTION1},
{L"sqrt", reinterpret_cast<const void *>(static_cast<te_fun1>(sqrt)), TE_FUNCTION1},
{L"tan", reinterpret_cast<const void *>(static_cast<te_fun1>(tan)), TE_FUNCTION1},
{L"tanh", reinterpret_cast<const void *>(static_cast<te_fun1>(tanh)), TE_FUNCTION1},
{L"tau", reinterpret_cast<const void *>(static_cast<te_fun0>(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<char **>(&s->next));
s->value = wcstod(s->next, const_cast<wchar_t **>(&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) {

View file

@ -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__*/