libcubescript/src/lib_math.cc

371 lines
13 KiB
C++
Raw Permalink Normal View History

2017-02-08 01:13:49 +01:00
#include <cstdlib>
#include <cmath>
2017-02-09 20:59:14 +01:00
#include <climits>
2017-02-08 01:07:35 +01:00
#include <functional>
2017-02-08 01:13:49 +01:00
#include <algorithm>
2017-02-08 01:07:35 +01:00
2017-06-20 21:21:39 +02:00
#include <cubescript/cubescript.hh>
2016-08-17 20:17:12 +02:00
#include "cs_state.hh"
2021-03-23 23:32:25 +01:00
namespace cubescript {
static constexpr float_type PI = float_type(3.14159265358979323846);
static constexpr float_type LN2 = float_type(0.693147180559945309417);
static constexpr float_type RAD = PI / float_type(180.0);
2016-08-17 20:17:12 +02:00
template<typename T>
2021-03-23 23:29:32 +01:00
struct math_val;
2016-08-17 20:17:12 +02:00
template<>
2021-03-23 23:29:32 +01:00
struct math_val<integer_type> {
static integer_type get(any_value &tv) {
return tv.get_integer();
2016-08-17 20:17:12 +02:00
}
2021-03-23 23:29:32 +01:00
static void set(any_value &res, integer_type val) {
res.set_integer(val);
2016-08-17 20:17:12 +02:00
}
};
template<>
2021-03-23 23:29:32 +01:00
struct math_val<float_type> {
static float_type get(any_value &tv) {
2016-08-17 20:17:12 +02:00
return tv.get_float();
}
2021-03-23 23:29:32 +01:00
static void set(any_value &res, float_type val) {
2016-08-17 20:17:12 +02:00
res.set_float(val);
}
};
template<typename T>
2021-03-23 23:29:32 +01:00
struct math_noop {
2016-08-17 20:17:12 +02:00
T operator()(T arg) {
return arg;
}
};
template<typename T, typename F1, typename F2>
2021-03-23 23:29:32 +01:00
static inline void math_op(
span_type<any_value> args, any_value &res, T initval,
2016-08-17 20:17:12 +02:00
F1 binop, F2 unop
) {
T val;
if (args.size() >= 2) {
2021-03-23 23:29:32 +01:00
val = binop(math_val<T>::get(args[0]), math_val<T>::get(args[1]));
2017-01-25 02:09:50 +01:00
for (size_t i = 2; i < args.size(); ++i) {
2021-03-23 23:29:32 +01:00
val = binop(val, math_val<T>::get(args[i]));
2016-08-17 20:17:12 +02:00
}
} else {
2021-03-23 23:29:32 +01:00
val = unop(!args.empty() ? math_val<T>::get(args[0]) : initval);
2016-08-17 20:17:12 +02:00
}
2021-03-23 23:29:32 +01:00
math_val<T>::set(res, val);
2016-08-17 20:17:12 +02:00
}
template<typename T, typename F>
static inline void cmp_op(span_type<any_value> args, any_value &res, F cmp) {
2016-08-17 20:17:12 +02:00
bool val;
if (args.size() >= 2) {
2021-03-23 23:29:32 +01:00
val = cmp(math_val<T>::get(args[0]), math_val<T>::get(args[1]));
2017-01-25 02:09:50 +01:00
for (size_t i = 2; (i < args.size()) && val; ++i) {
2021-03-23 23:29:32 +01:00
val = cmp(math_val<T>::get(args[i - 1]), math_val<T>::get(args[i]));
2016-08-17 20:17:12 +02:00
}
} else {
2021-03-23 23:29:32 +01:00
val = cmp(!args.empty() ? math_val<T>::get(args[0]) : T(0), T(0));
2016-08-17 20:17:12 +02:00
}
res.set_integer(integer_type(val));
2016-08-17 20:17:12 +02:00
}
LIBCUBESCRIPT_EXPORT void std_init_math(state &cs) {
new_cmd_quiet(cs, "sin", "f", [](auto &, auto args, auto &res) {
2017-02-08 01:13:49 +01:00
res.set_float(std::sin(args[0].get_float() * RAD));
});
new_cmd_quiet(cs, "cos", "f", [](auto &, auto args, auto &res) {
2017-02-08 01:13:49 +01:00
res.set_float(std::cos(args[0].get_float() * RAD));
});
new_cmd_quiet(cs, "tan", "f", [](auto &, auto args, auto &res) {
2017-02-08 01:13:49 +01:00
res.set_float(std::tan(args[0].get_float() * RAD));
});
new_cmd_quiet(cs, "asin", "f", [](auto &, auto args, auto &res) {
2017-02-08 01:13:49 +01:00
res.set_float(std::asin(args[0].get_float()) / RAD);
});
new_cmd_quiet(cs, "acos", "f", [](auto &, auto args, auto &res) {
2017-02-08 01:13:49 +01:00
res.set_float(std::acos(args[0].get_float()) / RAD);
});
new_cmd_quiet(cs, "atan", "f", [](auto &, auto args, auto &res) {
2017-02-08 01:13:49 +01:00
res.set_float(std::atan(args[0].get_float()) / RAD);
});
new_cmd_quiet(cs, "atan2", "ff", [](auto &, auto args, auto &res) {
2017-02-08 01:13:49 +01:00
res.set_float(std::atan2(args[0].get_float(), args[1].get_float()) / RAD);
});
new_cmd_quiet(cs, "sqrt", "f", [](auto &, auto args, auto &res) {
2017-02-08 01:13:49 +01:00
res.set_float(std::sqrt(args[0].get_float()));
});
new_cmd_quiet(cs, "loge", "f", [](auto &, auto args, auto &res) {
2017-02-08 01:13:49 +01:00
res.set_float(std::log(args[0].get_float()));
});
new_cmd_quiet(cs, "log2", "f", [](auto &, auto args, auto &res) {
res.set_float(std::log(args[0].get_float()) / LN2);
});
new_cmd_quiet(cs, "log10", "f", [](auto &, auto args, auto &res) {
2017-02-08 01:13:49 +01:00
res.set_float(std::log10(args[0].get_float()));
});
new_cmd_quiet(cs, "exp", "f", [](auto &, auto args, auto &res) {
2017-02-08 01:13:49 +01:00
res.set_float(std::exp(args[0].get_float()));
});
new_cmd_quiet(cs, "min", "i1...", [](auto &, auto args, auto &res) {
integer_type v = (!args.empty() ? args[0].get_integer() : 0);
2017-01-25 02:09:50 +01:00
for (size_t i = 1; i < args.size(); ++i) {
v = std::min(v, args[i].get_integer());
2016-08-17 20:17:12 +02:00
}
res.set_integer(v);
2016-08-17 20:17:12 +02:00
});
new_cmd_quiet(cs, "max", "i1...", [](auto &, auto args, auto &res) {
integer_type v = (!args.empty() ? args[0].get_integer() : 0);
2017-01-25 02:09:50 +01:00
for (size_t i = 1; i < args.size(); ++i) {
v = std::max(v, args[i].get_integer());
2016-08-17 20:17:12 +02:00
}
res.set_integer(v);
2016-08-17 20:17:12 +02:00
});
new_cmd_quiet(cs, "minf", "f1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
float_type v = (!args.empty() ? args[0].get_float() : 0);
2017-01-25 02:09:50 +01:00
for (size_t i = 1; i < args.size(); ++i) {
2017-02-08 01:13:49 +01:00
v = std::min(v, args[i].get_float());
2016-08-17 20:17:12 +02:00
}
res.set_float(v);
});
new_cmd_quiet(cs, "maxf", "f1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
float_type v = (!args.empty() ? args[0].get_float() : 0);
2017-01-25 02:09:50 +01:00
for (size_t i = 1; i < args.size(); ++i) {
2017-02-08 01:13:49 +01:00
v = std::max(v, args[i].get_float());
2016-08-17 20:17:12 +02:00
}
res.set_float(v);
});
new_cmd_quiet(cs, "abs", "i", [](auto &, auto args, auto &res) {
res.set_integer(std::abs(args[0].get_integer()));
});
new_cmd_quiet(cs, "absf", "f", [](auto &, auto args, auto &res) {
2017-02-08 01:13:49 +01:00
res.set_float(std::abs(args[0].get_float()));
});
new_cmd_quiet(cs, "floor", "f", [](auto &, auto args, auto &res) {
2017-02-08 01:13:49 +01:00
res.set_float(std::floor(args[0].get_float()));
});
new_cmd_quiet(cs, "ceil", "f", [](auto &, auto args, auto &res) {
2017-02-08 01:13:49 +01:00
res.set_float(std::ceil(args[0].get_float()));
});
new_cmd_quiet(cs, "round", "ff", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
float_type step = args[1].get_float();
float_type r = args[0].get_float();
if (step > 0) {
2021-03-31 02:21:32 +02:00
r += float_type(step * ((r < 0) ? -0.5 : 0.5));
r -= float_type(std::fmod(r, step));
} else {
2021-03-31 02:21:32 +02:00
r = float_type((r < 0) ? std::ceil(r - 0.5) : std::floor(r + 0.5));
}
res.set_float(r);
});
new_cmd_quiet(cs, "+", "i1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
math_op<integer_type>(args, res, 0, std::plus<integer_type>(), math_noop<integer_type>());
2016-08-17 20:17:12 +02:00
});
new_cmd_quiet(cs, "*", "i1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
math_op<integer_type>(
args, res, 1, std::multiplies<integer_type>(), math_noop<integer_type>()
2016-08-17 20:17:12 +02:00
);
});
new_cmd_quiet(cs, "-", "i1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
math_op<integer_type>(
args, res, 0, std::minus<integer_type>(), std::negate<integer_type>()
2016-08-17 20:17:12 +02:00
);
});
new_cmd_quiet(cs, "^", "i1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
math_op<integer_type>(
args, res, 0, std::bit_xor<integer_type>(), [](integer_type val) { return ~val; }
2016-08-17 20:17:12 +02:00
);
});
new_cmd_quiet(cs, "~", "i1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
math_op<integer_type>(
args, res, 0, std::bit_xor<integer_type>(), [](integer_type val) { return ~val; }
2016-08-17 20:17:12 +02:00
);
});
new_cmd_quiet(cs, "&", "i1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
math_op<integer_type>(
args, res, 0, std::bit_and<integer_type>(), math_noop<integer_type>()
2016-08-17 20:17:12 +02:00
);
});
new_cmd_quiet(cs, "|", "i1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
math_op<integer_type>(
args, res, 0, std::bit_or<integer_type>(), math_noop<integer_type>()
2016-08-17 20:17:12 +02:00
);
});
/* special combined cases */
new_cmd_quiet(cs, "^~", "i1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
integer_type val;
2016-08-17 20:17:12 +02:00
if (args.size() >= 2) {
val = args[0].get_integer() ^ ~args[1].get_integer();
2017-01-25 02:09:50 +01:00
for (size_t i = 2; i < args.size(); ++i) {
val ^= ~args[i].get_integer();
2016-08-17 20:17:12 +02:00
}
} else {
val = !args.empty() ? args[0].get_integer() : 0;
2016-08-17 20:17:12 +02:00
}
res.set_integer(val);
2016-08-17 20:17:12 +02:00
});
new_cmd_quiet(cs, "&~", "i1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
integer_type val;
2016-08-17 20:17:12 +02:00
if (args.size() >= 2) {
val = args[0].get_integer() & ~args[1].get_integer();
2017-01-25 02:09:50 +01:00
for (size_t i = 2; i < args.size(); ++i) {
val &= ~args[i].get_integer();
2016-08-17 20:17:12 +02:00
}
} else {
val = !args.empty() ? args[0].get_integer() : 0;
2016-08-17 20:17:12 +02:00
}
res.set_integer(val);
2016-08-17 20:17:12 +02:00
});
new_cmd_quiet(cs, "|~", "i1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
integer_type val;
2016-08-17 20:17:12 +02:00
if (args.size() >= 2) {
val = args[0].get_integer() | ~args[1].get_integer();
2017-01-25 02:09:50 +01:00
for (size_t i = 2; i < args.size(); ++i) {
val |= ~args[i].get_integer();
2016-08-17 20:17:12 +02:00
}
} else {
val = !args.empty() ? args[0].get_integer() : 0;
2016-08-17 20:17:12 +02:00
}
res.set_integer(val);
2016-08-17 20:17:12 +02:00
});
new_cmd_quiet(cs, "<<", "i1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
math_op<integer_type>(
args, res, 0, [](integer_type val1, integer_type val2) {
return (val2 < integer_type(sizeof(integer_type) * CHAR_BIT))
? (val1 << std::max(val2, integer_type(0)))
2016-08-17 20:17:12 +02:00
: 0;
2021-03-23 23:29:32 +01:00
}, math_noop<integer_type>()
2016-08-17 20:17:12 +02:00
);
});
new_cmd_quiet(cs, ">>", "i1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
math_op<integer_type>(
args, res, 0, [](integer_type val1, integer_type val2) {
2017-02-08 01:13:49 +01:00
return val1 >> std::clamp(
2021-03-23 23:29:32 +01:00
val2, integer_type(0), integer_type(sizeof(integer_type) * CHAR_BIT)
2016-08-17 20:17:12 +02:00
);
2021-03-23 23:29:32 +01:00
}, math_noop<integer_type>()
2016-08-17 20:17:12 +02:00
);
});
new_cmd_quiet(cs, "+f", "f1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
math_op<float_type>(
args, res, 0, std::plus<float_type>(), math_noop<float_type>()
2016-08-17 20:17:12 +02:00
);
});
new_cmd_quiet(cs, "*f", "f1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
math_op<float_type>(
args, res, 1, std::multiplies<float_type>(), math_noop<float_type>()
2016-08-17 20:17:12 +02:00
);
});
new_cmd_quiet(cs, "-f", "f1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
math_op<float_type>(
args, res, 0, std::minus<float_type>(), std::negate<float_type>()
2016-08-17 20:17:12 +02:00
);
});
new_cmd_quiet(cs, "div", "i1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
math_op<integer_type>(
args, res, 0, [](integer_type val1, integer_type val2) {
2016-08-17 20:17:12 +02:00
if (val2) {
return val1 / val2;
}
2021-03-23 23:29:32 +01:00
return integer_type(0);
}, math_noop<integer_type>()
2016-08-17 20:17:12 +02:00
);
});
new_cmd_quiet(cs, "mod", "i1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
math_op<integer_type>(
args, res, 0, [](integer_type val1, integer_type val2) {
2016-08-17 20:17:12 +02:00
if (val2) {
return val1 % val2;
}
2021-03-23 23:29:32 +01:00
return integer_type(0);
}, math_noop<integer_type>()
2016-08-17 20:17:12 +02:00
);
});
new_cmd_quiet(cs, "divf", "f1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
math_op<float_type>(
args, res, 0, [](float_type val1, float_type val2) {
2016-08-17 20:17:12 +02:00
if (val2) {
return val1 / val2;
}
2021-03-23 23:29:32 +01:00
return float_type(0);
}, math_noop<float_type>()
2016-08-17 20:17:12 +02:00
);
});
new_cmd_quiet(cs, "modf", "f1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
math_op<float_type>(
args, res, 0, [](float_type val1, float_type val2) {
2016-08-17 20:17:12 +02:00
if (val2) {
2021-03-23 23:29:32 +01:00
return float_type(fmod(val1, val2));
2016-08-17 20:17:12 +02:00
}
2021-03-23 23:29:32 +01:00
return float_type(0);
}, math_noop<float_type>()
2016-08-17 20:17:12 +02:00
);
});
new_cmd_quiet(cs, "pow", "f1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
math_op<float_type>(
args, res, 0, [](float_type val1, float_type val2) {
return float_type(pow(val1, val2));
}, math_noop<float_type>()
2016-08-17 20:17:12 +02:00
);
});
new_cmd_quiet(cs, "=", "i1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
cmp_op<integer_type>(args, res, std::equal_to<integer_type>());
2016-08-17 20:17:12 +02:00
});
new_cmd_quiet(cs, "!=", "i1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
cmp_op<integer_type>(args, res, std::not_equal_to<integer_type>());
2016-08-17 20:17:12 +02:00
});
new_cmd_quiet(cs, "<", "i1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
cmp_op<integer_type>(args, res, std::less<integer_type>());
2016-08-17 20:17:12 +02:00
});
new_cmd_quiet(cs, ">", "i1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
cmp_op<integer_type>(args, res, std::greater<integer_type>());
2016-08-17 20:17:12 +02:00
});
new_cmd_quiet(cs, "<=", "i1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
cmp_op<integer_type>(args, res, std::less_equal<integer_type>());
2016-08-17 20:17:12 +02:00
});
new_cmd_quiet(cs, ">=", "i1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
cmp_op<integer_type>(args, res, std::greater_equal<integer_type>());
2016-08-17 20:17:12 +02:00
});
new_cmd_quiet(cs, "=f", "f1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
cmp_op<float_type>(args, res, std::equal_to<float_type>());
2016-08-17 20:17:12 +02:00
});
new_cmd_quiet(cs, "!=f", "f1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
cmp_op<float_type>(args, res, std::not_equal_to<float_type>());
2016-08-17 20:17:12 +02:00
});
new_cmd_quiet(cs, "<f", "f1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
cmp_op<float_type>(args, res, std::less<float_type>());
2016-08-17 20:17:12 +02:00
});
new_cmd_quiet(cs, ">f", "f1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
cmp_op<float_type>(args, res, std::greater<float_type>());
2016-08-17 20:17:12 +02:00
});
new_cmd_quiet(cs, "<=f", "f1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
cmp_op<float_type>(args, res, std::less_equal<float_type>());
2016-08-17 20:17:12 +02:00
});
new_cmd_quiet(cs, ">=f", "f1...", [](auto &, auto args, auto &res) {
2021-03-23 23:29:32 +01:00
cmp_op<float_type>(args, res, std::greater_equal<float_type>());
2016-08-17 20:17:12 +02:00
});
}
2021-03-23 23:32:25 +01:00
} /* namespace cubescript */