|
|
@@ -12,6 +12,8 @@
|
|
|
#include <utility>
|
|
|
#include <tuple>
|
|
|
#include <string>
|
|
|
+#include <type_traits>
|
|
|
+#include <limits>
|
|
|
|
|
|
LUWRA_NS_BEGIN
|
|
|
|
|
|
@@ -46,7 +48,7 @@ struct Value {
|
|
|
* extracts it from the stack and a `pushf(State*, type)` which pushes the value on the stack again.
|
|
|
* This assumes that only one value will be pushed onto the stack.
|
|
|
*/
|
|
|
-#define LUWRA_DEF_VALUE(type, retrf, pushf) \
|
|
|
+#define LUWRA_DEF_VALUE(type, retrf, pushf) \
|
|
|
template <> \
|
|
|
struct Value<type> { \
|
|
|
static inline \
|
|
|
@@ -77,16 +79,132 @@ struct Value {
|
|
|
(lua_pushstring(state, stdstring.c_str()))
|
|
|
#endif
|
|
|
|
|
|
-/* Lua-dependent types */
|
|
|
-LUWRA_DEF_VALUE(Integer, luaL_checkinteger, lua_pushinteger);
|
|
|
-LUWRA_DEF_VALUE(Number, luaL_checknumber, lua_pushnumber);
|
|
|
+namespace internal {
|
|
|
+ template <typename>
|
|
|
+ struct NumericTransportValue;
|
|
|
+
|
|
|
+ // Transport unit `Integer`
|
|
|
+ template <>
|
|
|
+ struct NumericTransportValue<Integer> {
|
|
|
+ static inline
|
|
|
+ Integer read(State* state, int index) {
|
|
|
+ return luaL_checkinteger(state, index);
|
|
|
+ }
|
|
|
+
|
|
|
+ static inline
|
|
|
+ int push(State* state, Integer value) {
|
|
|
+ lua_pushinteger(state, value);
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // Transport unit `Number`
|
|
|
+ template <>
|
|
|
+ struct NumericTransportValue<Number> {
|
|
|
+ static inline
|
|
|
+ Number read(State* state, int index) {
|
|
|
+ return luaL_checknumber(state, index);
|
|
|
+ }
|
|
|
+
|
|
|
+ static inline
|
|
|
+ int push(State* state, Number value) {
|
|
|
+ lua_pushnumber(state, value);
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // Base for `Value<I>` specializations which uses `B` as transport unit, where `I` is smaller
|
|
|
+ // than `B`.
|
|
|
+ template <typename I, typename B>
|
|
|
+ struct NumericContainedValueBase {
|
|
|
+ static constexpr
|
|
|
+ bool Qualifies =
|
|
|
+ std::numeric_limits<I>::max() < std::numeric_limits<B>::max()
|
|
|
+ && std::numeric_limits<I>::min() > std::numeric_limits<B>::min();
|
|
|
+
|
|
|
+ static inline
|
|
|
+ I read(State* state, int index) {
|
|
|
+ return
|
|
|
+ std::max<B>(
|
|
|
+ std::numeric_limits<I>::min(),
|
|
|
+ std::min<B>(
|
|
|
+ std::numeric_limits<I>::max(),
|
|
|
+ NumericTransportValue<B>::read(state, index)
|
|
|
+ )
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ static inline
|
|
|
+ int push(State* state, I value) {
|
|
|
+ NumericTransportValue<B>::push(state, static_cast<B>(value));
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // Base for `Value<I>` specializations which uses `B` as transport unit, where `I` is bigger
|
|
|
+ // than `B`.
|
|
|
+ template <typename I, typename B>
|
|
|
+ struct NumericTruncatingValueBase {
|
|
|
+ static inline
|
|
|
+ I read(State* state, int index) {
|
|
|
+ return static_cast<I>(NumericTransportValue<B>::read(state, index));
|
|
|
+ }
|
|
|
+
|
|
|
+ static inline
|
|
|
+ int push(State*, I) {
|
|
|
+ static_assert(
|
|
|
+ sizeof(I) == -1,
|
|
|
+ "You shold not use 'Value<I>::push' specializations which inherit from NumericTruncatingValueBase"
|
|
|
+ );
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // Base for `Value<I>` specializations which uses `B` as transport unit
|
|
|
+ template <typename I, typename B>
|
|
|
+ using NumericValueBase =
|
|
|
+ typename std::conditional<
|
|
|
+ std::is_same<I, B>::value,
|
|
|
+ NumericTransportValue<B>,
|
|
|
+ typename std::conditional<
|
|
|
+ NumericContainedValueBase<I, B>::Qualifies,
|
|
|
+ NumericContainedValueBase<I, B>,
|
|
|
+ NumericTruncatingValueBase<I, B>
|
|
|
+ >::type
|
|
|
+ >::type;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Define an integral type which will be transported via `Integer`.
|
|
|
+ */
|
|
|
+#define LUWRA_DEF_NUMERIC(base, type) \
|
|
|
+ template <> \
|
|
|
+ struct Value<type>: internal::NumericValueBase<type, base> {};
|
|
|
+
|
|
|
+// Lua-dependent types
|
|
|
+LUWRA_DEF_NUMERIC(Number, float)
|
|
|
+LUWRA_DEF_NUMERIC(Number, double)
|
|
|
+LUWRA_DEF_NUMERIC(Number, long double)
|
|
|
+
|
|
|
+// Integral types
|
|
|
+LUWRA_DEF_NUMERIC(Integer, signed char)
|
|
|
+LUWRA_DEF_NUMERIC(Integer, unsigned char)
|
|
|
+LUWRA_DEF_NUMERIC(Integer, signed short)
|
|
|
+LUWRA_DEF_NUMERIC(Integer, unsigned short)
|
|
|
+LUWRA_DEF_NUMERIC(Integer, signed int)
|
|
|
+LUWRA_DEF_NUMERIC(Integer, unsigned int)
|
|
|
+LUWRA_DEF_NUMERIC(Integer, signed long int)
|
|
|
+LUWRA_DEF_NUMERIC(Integer, unsigned long int)
|
|
|
+LUWRA_DEF_NUMERIC(Integer, signed long long int)
|
|
|
+LUWRA_DEF_NUMERIC(Integer, unsigned long long int)
|
|
|
|
|
|
-/* C/C++ types */
|
|
|
+// C/C++ types
|
|
|
LUWRA_DEF_VALUE(bool, luaL_checkboolean, lua_pushboolean);
|
|
|
LUWRA_DEF_VALUE(const char*, luaL_checkstring, lua_pushstring);
|
|
|
LUWRA_DEF_VALUE(std::string, luaL_checkstring, luaL_pushstdstring);
|
|
|
|
|
|
+// Do not export these macros
|
|
|
#undef LUWRA_DEF_VALUE
|
|
|
+#undef LUWRA_DEF_NUMERIC
|
|
|
|
|
|
/**
|
|
|
* An arbitrary value on an execution stack.
|