ソースを参照

Add macros for field and method wrapping

Ole 10 年 前
コミット
e87aff9101
共有3 個のファイルを変更した83 個の追加12 個の削除を含む
  1. 4 4
      examples/usertypes.cpp
  2. 71 0
      lib/luwra/usertypes.hpp
  3. 8 8
      tests/usertypes.cpp

+ 4 - 4
examples/usertypes.cpp

@@ -37,13 +37,13 @@ int main() {
 		state,
 		// Methods which shall be availabe in the Lua user data, need to be declared here
 		{
-			{"scale", luwra::wrap_method<Point, void(double), &Point::scale>},
-			{"x",     luwra::wrap_field<Point, double, &Point::x>},
-			{"y",     luwra::wrap_field<Point, double, &Point::y>}
+			{"scale", LUWRA_WRAP_METHOD(Point::scale)},
+			{"x",     LUWRA_WRAP_FIELD(Point::x)},
+			{"y",     LUWRA_WRAP_FIELD(Point::y)}
 		},
 		// Meta methods may be registered aswell
 		{
-			{"__tostring", luwra::wrap_method<const Point, std::string(), &Point::toString>}
+			{"__tostring", LUWRA_WRAP_METHOD(Point::toString)}
 		}
 	);
 

+ 71 - 0
lib/luwra/usertypes.hpp

@@ -137,6 +137,17 @@ namespace internal {
 		}
 	};
 
+	template <typename T>
+	struct FieldWrapperHelper {
+		static_assert(
+			sizeof(T) == -1,
+			"Parameter to FieldWrapperHelper is not a function pointer"
+		);
+	};
+
+	template <typename T, typename R>
+	struct FieldWrapperHelper<R T::*>: FieldWrapper<T, R> {};
+
 	/**
 	 * Helper struct for wrapping user type methods
 	 */
@@ -158,6 +169,11 @@ namespace internal {
 		R call(const volatile T* parent, A... args) {
 			return (parent->*method_pointer)(std::forward<A>(args)...);
 		}
+
+		template <MethodPointerType method_pointer> static inline
+		int invoke(State* state) {
+			return FunctionWrapper<FunctionSignature>::template invoke<call<method_pointer>>(state);
+		}
 	};
 
 	// 'const'-qualified methods
@@ -170,6 +186,11 @@ namespace internal {
 		R call(const T* parent, A... args) {
 			return (parent->*method_pointer)(std::forward<A>(args)...);
 		}
+
+		template <MethodPointerType method_pointer> static inline
+		int invoke(State* state) {
+			return FunctionWrapper<FunctionSignature>::template invoke<call<method_pointer>>(state);
+		}
 	};
 
 	// 'volatile'-qualified methods
@@ -182,6 +203,11 @@ namespace internal {
 		R call(volatile T* parent, A... args) {
 			return (parent->*method_pointer)(std::forward<A>(args)...);
 		}
+
+		template <MethodPointerType method_pointer> static inline
+		int invoke(State* state) {
+			return FunctionWrapper<FunctionSignature>::template invoke<call<method_pointer>>(state);
+		}
 	};
 
 	// unqualified methods
@@ -194,7 +220,40 @@ namespace internal {
 		R call(T* parent, A... args) {
 			return (parent->*method_pointer)(std::forward<A>(args)...);
 		}
+
+		template <MethodPointerType method_pointer> static inline
+		int invoke(State* state) {
+			return FunctionWrapper<FunctionSignature>::template invoke<call<method_pointer>>(state);
+		}
 	};
+
+	template <typename T>
+	struct MethodWrapperHelper {
+		static_assert(
+			sizeof(T) == -1,
+			"Parameter to MethodWrapperHelper is not a function pointer"
+		);
+	};
+
+	template <typename T, typename R, typename... A>
+	struct MethodWrapperHelper<R (T::*)(A...) const volatile>:
+		MethodWrapper<const volatile T, R(A...)>
+	{};
+
+	template <typename T, typename R, typename... A>
+	struct MethodWrapperHelper<R (T::*)(A...) const>:
+		MethodWrapper<const T, R(A...)>
+	{};
+
+	template <typename T, typename R, typename... A>
+	struct MethodWrapperHelper<R (T::*)(A...) volatile>:
+		MethodWrapper<volatile T, R(A...)>
+	{};
+
+	template <typename T, typename R, typename... A>
+	struct MethodWrapperHelper<R (T::*)(A...)>:
+		MethodWrapper<T, R(A...)>
+	{};
 }
 
 /**
@@ -298,6 +357,12 @@ constexpr CFunction wrap_method =
 		internal::MethodWrapper<T, S>::template call<method_pointer>
 	>;
 
+/**
+ * This macro allows you to wrap methods without supplying template parameters.
+ */
+#define LUWRA_WRAP_METHOD(meth) \
+	(&luwra::internal::MethodWrapperHelper<decltype(&meth)>::template invoke<&meth>)
+
 /**
  * Property accessor method
  *
@@ -317,6 +382,12 @@ template <
 constexpr CFunction wrap_field =
 	&internal::FieldWrapper<T, R>::template invoke<field_pointer>;
 
+/**
+ * This macro allows you to wrap fields without supplying template parameters.
+ */
+#define LUWRA_WRAP_FIELD(field) \
+	(&luwra::internal::FieldWrapperHelper<decltype(&field)>::invoke<&field>)
+
 /**
  * Register the metatable for user type `T`. This function allows you to register methods
  * which are shared across all instances of this type. A garbage-collector hook is also inserted.

+ 8 - 8
tests/usertypes.cpp

@@ -68,10 +68,10 @@ TEST_CASE("usertypes_wrap_fields") {
 	luwra::register_user_type<B>(
 		state,
 		{
-			{"n", luwra::wrap_field<B, int, &B::n>},
-			{"cn", luwra::wrap_field<B, const int, &B::cn>},
-			{"vn", luwra::wrap_field<B, volatile int, &B::vn>},
-			{"cvn", luwra::wrap_field<B, const volatile int, &B::cvn>}
+			{"n", LUWRA_WRAP_FIELD(B::n)},
+			{"cn", LUWRA_WRAP_FIELD(B::cn)},
+			{"vn", LUWRA_WRAP_FIELD(B::vn)},
+			{"cvn", LUWRA_WRAP_FIELD(B::cvn)}
 		}
 	);
 
@@ -145,10 +145,10 @@ TEST_CASE("usertypes_wrap_methods") {
 	luwra::register_user_type<C>(
 		state,
 		{
-			{"foo1", luwra::wrap_method<C, int(int), &C::foo1>},
-			{"foo2", luwra::wrap_method<const C, int(int), &C::foo2>},
-			{"foo3", luwra::wrap_method<volatile C, int(int), &C::foo3>},
-			{"foo4", luwra::wrap_method<const volatile C, int(int), &C::foo4>}
+			{"foo1", LUWRA_WRAP_METHOD(C::foo1)},
+			{"foo2", LUWRA_WRAP_METHOD(C::foo2)},
+			{"foo3", LUWRA_WRAP_METHOD(C::foo3)},
+			{"foo4", LUWRA_WRAP_METHOD(C::foo4)}
 		}
 	);