瀏覽代碼

Merge wrapper facilities into GenericWrapper

Ole 9 年之前
父節點
當前提交
a91995ef22
共有 7 個文件被更改,包括 139 次插入283 次删除
  1. 1 3
      lib/luwra.hpp
  2. 0 59
      lib/luwra/fields.hpp
  3. 0 32
      lib/luwra/functions.hpp
  4. 0 70
      lib/luwra/generic.hpp
  5. 0 115
      lib/luwra/methods.hpp
  6. 134 0
      lib/luwra/wrappers.hpp
  7. 4 4
      tests/functions.cpp

+ 1 - 3
lib/luwra.hpp

@@ -7,10 +7,8 @@
 #include "luwra/stack.hpp"
 #include "luwra/auxiliary.hpp"
 #include "luwra/functions.hpp"
-#include "luwra/methods.hpp"
-#include "luwra/fields.hpp"
 #include "luwra/usertypes.hpp"
-#include "luwra/generic.hpp"
 #include "luwra/state.hpp"
+#include "luwra/wrappers.hpp"
 
 #endif

+ 0 - 59
lib/luwra/fields.hpp

@@ -1,59 +0,0 @@
-/* Luwra
- * Minimal-overhead Lua wrapper for C++
- *
- * Copyright (C) 2015, Ole Krüger <ole@vprsm.de>
- */
-
-#ifndef LUWRA_FIELDS_H_
-#define LUWRA_FIELDS_H_
-
-#include "common.hpp"
-#include "types.hpp"
-
-LUWRA_NS_BEGIN
-
-namespace internal {
-	/**
-	 * Helper struct for wrapping user type fields
-	 */
-	template <typename T>
-	struct FieldWrapper {
-		static_assert(
-			sizeof(T) == -1,
-			"Parameter to FieldWrapper is not a property signature"
-		);
-	};
-
-	template <typename T, typename R>
-	struct FieldWrapper<R T::*> {
-		template <R T::* field_pointer> static inline
-		int invoke(State* state) {
-			if (lua_gettop(state) > 1) {
-				read<T*>(state, 1)->*field_pointer = read<R>(state, 2);
-				return 0;
-			} else {
-				return static_cast<int>(push(state, read<T*>(state, 1)->*field_pointer));
-			}
-		}
-	};
-
-	template <typename T, typename R>
-	struct FieldWrapper<const R T::*> {
-		template <const R T::* field_pointer> static inline
-		int invoke(State* state) {
-			return static_cast<int>(push(state, read<T*>(state, 1)->*field_pointer));
-		}
-	};
-}
-
-LUWRA_NS_END
-
-/**
- * Generate a `lua_CFunction` get/set wrapper for a property accessor.
- * \param field Fully qualified property name (Do not supply a pointer)
- * \return Wrapped function as `lua_CFunction`
- */
-#define LUWRA_WRAP_FIELD(field) \
-	(&luwra::internal::FieldWrapper<decltype(&field)>::invoke<&field>)
-
-#endif

+ 0 - 32
lib/luwra/functions.hpp

@@ -13,30 +13,6 @@
 
 LUWRA_NS_BEGIN
 
-namespace internal {
-	template <typename T>
-	struct FunctionWrapper {
-		static_assert(
-			sizeof(T) == -1,
-			"Parameter to FunctionWrapper is not a valid signature"
-		);
-	};
-
-	template <typename R, typename... A>
-	struct FunctionWrapper<R(A...)> {
-		template <R (* fun)(A...)> static inline
-		int invoke(State* state) {
-			return static_cast<int>(
-				map<R(A...)>(state, fun)
-			);
-		}
-	};
-
-	// We need an alias, because function pointers are weird
-	template <typename R, typename... A>
-	struct FunctionWrapper<R (*)(A...)>: FunctionWrapper<R (A...)> {};
-}
-
 /**
  * A callable native Lua function.
  */
@@ -105,12 +81,4 @@ struct Value<NativeFunction<R>> {
 
 LUWRA_NS_END
 
-/**
- * Generate a `lua_CFunction` wrapper for a function.
- * \param fun Fully qualified function name (Do not supply a pointer)
- * \returns Wrapped function as `lua_CFunction`
- */
-#define LUWRA_WRAP_FUNCTION(fun) \
-	(&luwra::internal::FunctionWrapper<decltype(&fun)>::template invoke<&fun>)
-
 #endif

+ 0 - 70
lib/luwra/generic.hpp

@@ -1,70 +0,0 @@
-#ifndef LUWRA_GENERIC_H_
-#define LUWRA_GENERIC_H_
-
-#include "common.hpp"
-#include "functions.hpp"
-#include "methods.hpp"
-#include "fields.hpp"
-
-LUWRA_NS_BEGIN
-
-namespace internal {
-	template <typename T>
-	struct GenericWrapper {
-		static_assert(
-			sizeof(T) == -1,
-			"Parameter to GenericWrapper is not a valid type"
-		);
-	};
-
-	// Functions
-	template <typename R, typename... A>
-	struct GenericWrapper<R (A...)>:
-		FunctionWrapper<R (A...)> {};
-
-	template <typename R, typename... A>
-	struct GenericWrapper<R (*)(A...)>:
-		FunctionWrapper<R (*)(A...)> {};
-
-	// Methods
-	template <typename T, typename R, typename... A>
-	struct GenericWrapper<R (T::*)(A...) const volatile>:
-		MethodWrapper<R (T::*)(A...) const volatile> {};
-
-	template <typename T, typename R, typename... A>
-	struct GenericWrapper<R (T::*)(A...) const>:
-		MethodWrapper<R (T::*)(A...) const> {};
-
-	template <typename T, typename R, typename... A>
-	struct GenericWrapper<R (T::*)(A...) volatile>:
-		MethodWrapper<R (T::*)(A...) volatile> {};
-
-	template <typename T, typename R, typename... A>
-	struct GenericWrapper<R (T::*)(A...)>:
-		MethodWrapper<R (T::*)(A...)> {};
-
-	// Fields
-	template <typename T, typename R>
-	struct GenericWrapper<R T::*>: FieldWrapper<R T::*> {};
-
-	template <typename T, typename R>
-	struct GenericWrapper<const R T::*>: FieldWrapper<const R T::*> {};
-}
-
-LUWRA_NS_END
-
-/**
- * Generate a `lua_CFunction` wrapper for a field, method or function.
- * \returns Wrapped entity as `lua_CFunction`
- */
-#define LUWRA_WRAP(entity) \
-	(&luwra::internal::GenericWrapper<decltype(&entity)>::template invoke<&entity>)
-
-/**
- * Generate a user type member manifest. This is basically a type which can be constructed using a
- * string and whatever `LUWRA_WRAP` produces. For example `std::pair<Pushable, Pushable>`.
- */
-#define LUWRA_MEMBER(type, name) \
-	{#name, LUWRA_WRAP(__LUWRA_NS_RESOLVE(type, name))}
-
-#endif

+ 0 - 115
lib/luwra/methods.hpp

@@ -1,115 +0,0 @@
-/* Luwra
- * Minimal-overhead Lua wrapper for C++
- *
- * Copyright (C) 2015, Ole Krüger <ole@vprsm.de>
- */
-
-#ifndef LUWRA_METHODS_H_
-#define LUWRA_METHODS_H_
-
-#include "common.hpp"
-#include "stack.hpp"
-#include "functions.hpp"
-
-LUWRA_NS_BEGIN
-
-namespace internal {
-	/**
-	 * Helper struct for wrapping user type methods
-	 */
-	template <typename T>
-	struct MethodWrapper {
-		static_assert(
-			sizeof(T) == -1,
-			"Undefined template MethodWrapper"
-		);
-	};
-
-	// 'const volatile'-qualified methods
-	template <typename T, typename R, typename... A>
-	struct MethodWrapper<R (T::*)(A...) const volatile> {
-		using MethodPointerType = R (T::*)(A...) const volatile;
-		using FunctionSignature = R (const volatile T*, A...);
-
-		template <MethodPointerType meth> static inline
-		R hook(const volatile T* parent, A&&... args) {
-			return (parent->*meth)(std::forward<A>(args)...);
-		}
-
-		template <MethodPointerType meth> static inline
-		int invoke(State* state) {
-			return static_cast<int>(
-				map<FunctionSignature>(state, hook<meth>)
-			);
-		}
-	};
-
-	// 'const'-qualified methods
-	template <typename T, typename R, typename... A>
-	struct MethodWrapper<R (T::*)(A...) const> {
-		using MethodPointerType = R (T::*)(A...) const;
-		using FunctionSignature = R (const T*, A...);
-
-		template <MethodPointerType meth> static inline
-		R hook(const T* parent, A... args) {
-			return (parent->*meth)(std::forward<A>(args)...);
-		}
-
-		template <MethodPointerType meth> static inline
-		int invoke(State* state) {
-			return static_cast<int>(
-				map<FunctionSignature>(state, hook<meth>)
-			);
-		}
-	};
-
-	// 'volatile'-qualified methods
-	template <typename T, typename R, typename... A>
-	struct MethodWrapper<R (T::*)(A...) volatile> {
-		using MethodPointerType = R (T::*)(A...) volatile;
-		using FunctionSignature = R (volatile T*, A...);
-
-		template <MethodPointerType meth> static inline
-		R hook(volatile T* parent, A... args) {
-			return (parent->*meth)(std::forward<A>(args)...);
-		}
-
-		template <MethodPointerType meth> static inline
-		int invoke(State* state) {
-			return static_cast<int>(
-				map<FunctionSignature>(state, hook<meth>)
-			);
-		}
-	};
-
-	// unqualified methods
-	template <typename T, typename R, typename... A>
-	struct MethodWrapper<R (T::*)(A...)> {
-		using MethodPointerType = R (T::*)(A...);
-		using FunctionSignature = R (T*, A...);
-
-		template <MethodPointerType meth> static inline
-		R hook(T* parent, A... args) {
-			return (parent->*meth)(std::forward<A>(args)...);
-		}
-
-		template <MethodPointerType meth> static inline
-		int invoke(State* state) {
-			return static_cast<int>(
-				map<FunctionSignature>(state, hook<meth>)
-			);
-		}
-	};
-}
-
-LUWRA_NS_END
-
-/**
- * Generate a `lua_CFunction` wrapper for a method.
- * \param meth Fully qualified method name (Do not supply a pointer)
- * \return Wrapped function as `lua_CFunction`
- */
-#define LUWRA_WRAP_METHOD(meth) \
-	(&luwra::internal::MethodWrapper<decltype(&meth)>::template invoke<&meth>)
-
-#endif

+ 134 - 0
lib/luwra/wrappers.hpp

@@ -0,0 +1,134 @@
+/* Luwra
+ * Minimal-overhead Lua wrapper for C++
+ *
+ * Copyright (C) 2016, Ole Krüger <ole@vprsm.de>
+ */
+
+#ifndef LUWRA_WRAPPERS_H_
+#define LUWRA_WRAPPERS_H_
+
+#include "common.hpp"
+#include "types.hpp"
+#include "stack.hpp"
+
+LUWRA_NS_BEGIN
+
+namespace internal {
+	// Specializations of this template shall provide a static function `int invoke(State* state)`,
+	// which serves as an instance of `lua_CFunction`.
+	// Pointers to these functions can be passed to the Lua VM, so that their functionality is
+	// available within a Lua program.
+	template <typename T>
+	struct GenericWrapper {
+		static_assert(
+			sizeof(T) == -1,
+			"Template parameter to GenericWrapper is not valid"
+		);
+	};
+
+	// This wraps generic functions. All parameters are read off the stack using their respective
+	// `Value` specialization and subsequently passed to the function. The returned value will be
+	// pushed onto the stack.
+	template <typename R, typename... A>
+	struct GenericWrapper<R(A...)> {
+		template <R (* fun)(A...)> static inline
+		int invoke(State* state) {
+			return static_cast<int>(
+				map<R(A...)>(state, fun)
+			);
+		}
+	};
+
+	// An alias for the `R(A...)` specialization. It primarily exists because functions aren't
+	// passable as values, instead they are referenced using a function pointer.
+	template <typename R, typename... A>
+	struct GenericWrapper<R (*)(A...)>: GenericWrapper<R(A...)> {};
+
+	// To avoid repeating the same code for the several types of method pointers, the base code is
+	// unified here.
+	template <typename MP, typename T, typename R, typename... A>
+	struct MethodWrapperImpl {
+		template <MP meth> static inline
+		R hook(T* parent, A&&... args) {
+			return (parent->*meth)(std::forward<A>(args)...);
+		}
+
+		template <MP meth> static inline
+		int invoke(State* state) {
+			return static_cast<int>(
+				map<R(T*, A...)>(state, hook<meth>)
+			);
+		}
+	};
+
+	// Wrap methods that expect `this` to be 'const volatile'-qualified.
+	template <typename T, typename R, typename... A>
+	struct GenericWrapper<R (T::*)(A...) const volatile>:
+		MethodWrapperImpl<R (T::*)(A...) const volatile, T, R, A...>
+	{};
+
+	// Wrap methods that expect `this` to be 'const'-qualified.
+	template <typename T, typename R, typename... A>
+	struct GenericWrapper<R (T::*)(A...) const>:
+		MethodWrapperImpl<R (T::*)(A...) const, T, R, A...>
+	{};
+
+	// Wrap methods that expect `this` to be 'volatile'-qualified.
+	template <typename T, typename R, typename... A>
+	struct GenericWrapper<R (T::*)(A...) volatile>:
+		MethodWrapperImpl<R (T::*)(A...) volatile, T, R, A...>
+	{};
+
+	// Wrap methods that expect `this` to be unqualified.
+	template <typename T, typename R, typename... A>
+	struct GenericWrapper<R (T::*)(A...)>:
+		MethodWrapperImpl<R (T::*)(A...), T, R, A...>
+	{};
+
+	// Wrap a 'const'-qualified field accessor. Because the field can not be changed, this wrapper
+	// does not provide a setter mechanism.
+	template <typename T, typename R>
+	struct GenericWrapper<const R T::*> {
+		template <const R T::* accessor> static inline
+		int invoke(State* state) {
+			return static_cast<int>(
+				push(state, read<T*>(state, 1)->*accessor)
+			);
+		}
+	};
+
+	// Wrap a field accessor. The wrapper provides both setter and getter mechanism.
+	template <typename T, typename R>
+	struct GenericWrapper<R T::*> {
+		template <R T::* accessor> static inline
+		int invoke(State* state) {
+			if (lua_gettop(state) > 1) {
+				read<T*>(state, 1)->*accessor = read<R>(state, 2);
+				return 0;
+			} else {
+				return static_cast<int>(
+					push(state, read<T*>(state, 1)->*accessor)
+				);
+			}
+		}
+	};
+
+}
+
+LUWRA_NS_END
+
+/**
+ * Generate a `lua_CFunction` wrapper for a field, method or function.
+ * \returns Wrapped entity as `lua_CFunction`
+ */
+#define LUWRA_WRAP(entity) \
+	(&luwra::internal::GenericWrapper<decltype(&entity)>::template invoke<&entity>)
+
+/**
+ * Generate a user type member manifest. This is basically any type which can be constructed using a
+ * string and a `lua_CFunction`. For example `std::pair<Pushable, Pushable>`.
+ */
+#define LUWRA_MEMBER(type, name) \
+	{#name, LUWRA_WRAP(__LUWRA_NS_RESOLVE(type, name))}
+
+#endif

+ 4 - 4
tests/functions.cpp

@@ -32,7 +32,7 @@ TEST_CASE("FunctionWrapper") {
 		noret_environment = 1337;
 
 		// Wrap function
-		lua_CFunction cfun = LUWRA_WRAP_FUNCTION(test_function_noret_noparams);
+		lua_CFunction cfun = LUWRA_WRAP(test_function_noret_noparams);
 		REQUIRE(cfun != nullptr);
 
 		// Register function
@@ -50,7 +50,7 @@ TEST_CASE("FunctionWrapper") {
 		int req_environemt = noret_environment;
 
 		// Wrap function
-		lua_CFunction cfun = LUWRA_WRAP_FUNCTION(test_function_noret);
+		lua_CFunction cfun = LUWRA_WRAP(test_function_noret);
 		REQUIRE(cfun != nullptr);
 
 		// Register function
@@ -64,7 +64,7 @@ TEST_CASE("FunctionWrapper") {
 
 	SECTION("with return value, without parameters") {
 		// Wrap function
-		lua_CFunction cfun = LUWRA_WRAP_FUNCTION(test_function_noparams);
+		lua_CFunction cfun = LUWRA_WRAP(test_function_noparams);
 		REQUIRE(cfun != nullptr);
 
 		// Register function
@@ -78,7 +78,7 @@ TEST_CASE("FunctionWrapper") {
 
 	SECTION("with return value, with parameters") {
 		// Wrap function
-		lua_CFunction cfun = LUWRA_WRAP_FUNCTION(test_function);
+		lua_CFunction cfun = LUWRA_WRAP(test_function);
 		REQUIRE(cfun != nullptr);
 
 		// Register function