Ver código fonte

Add support for all integral types

Ole Krüger 10 anos atrás
pai
commit
0942bd1e31
1 arquivos alterados com 123 adições e 5 exclusões
  1. 123 5
      lib/luwra/types.hpp

+ 123 - 5
lib/luwra/types.hpp

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