Sfoglia il codice sorgente

Unify user type wrappers in UserTypeWrapper structure

Ole 9 anni fa
parent
commit
a70cfafdbc
1 ha cambiato i file con 57 aggiunte e 70 eliminazioni
  1. 57 70
      lib/luwra/usertypes.hpp

+ 57 - 70
lib/luwra/usertypes.hpp

@@ -44,63 +44,49 @@ namespace internal {
 	const std::string UserTypeReg<T>::name =
 		LUWRA_REGISTRY_PREFIX + std::to_string(uintptr_t(&id));
 
-	// Register a new metatable for a user type T.
-	template <typename U> static inline
-	void new_user_type_metatable(State* state) {
+	template <typename U>
+	struct UserTypeWrapper {
 		using T = StripUserType<U>;
-		luaL_newmetatable(state, UserTypeReg<T>::name.c_str());
-	}
-
-	// Check if the value at the given index if a user type T.
-	template <typename U> static inline
-	StripUserType<U>* check_user_type(State* state, int index) {
-		using T = StripUserType<U>;
-		return static_cast<T*>(
-			luaL_checkudata(state, index, UserTypeReg<T>::name.c_str())
-		);
-	}
-
-	// Apply U's metatable for the value at the top of the stack.
-	template <typename U> static inline
-	void apply_user_type_meta_table(State* state) {
-		setMetatable(state, UserTypeReg<StripUserType<U>>::name.c_str());
-	}
+		using Reg = UserTypeReg<T>;
 
-	// Lua C function to construct a user type T with parameters A
-	template <typename U, typename... A> static inline
-	int construct_user_type(State* state) {
-		return static_cast<int>(
-			direct<size_t (A...)>(
-				state,
-				&Value<StripUserType<U>&>::template push<A...>,
-				state
-			)
-		);
-	}
-
-	// Lua C function to destruct a user type T
-	template <typename U> static inline
-	int destruct_user_type(State* state) {
-		using T = StripUserType<U>;
+		// Read the userdata instance of T from the stack.
+		static inline
+		T* check(State* state, int index) {
+			return static_cast<T*>(
+				luaL_checkudata(state, index, Reg::name.c_str())
+			);
+		}
 
-		read<T&>(state, 1).~T();
-		return 0;
-	}
+		// Constructs the user type in Lua.
+		template <typename... A> static inline
+		int construct(State* state) {
+			return static_cast<int>(
+				direct<size_t(A...)>(
+					state,
+					&Value<T&>::template push<A...>,
+					state
+				)
+			);
+		}
 
-	// Create a string representation for user type T.
-	template <typename U> static
-	int stringify_user_type(State* state) {
-		using T = StripUserType<U>;
+		// Use this as garbage-collector hook ('__gc' metatable); it will call the destructor.
+		static inline
+		int destruct(State* state) {
+			(*check(state, 1)).~T();
+			return 0;
+		}
 
-		return static_cast<int>(
-			push(
-				state,
-				internal::UserTypeReg<T>::name
-					+ "@"
-					+ std::to_string(uintptr_t(Value<T*>::read(state, 1)))
-			)
-		);
-	}
+		// This is converts the userdata in Lua to a string.
+		static inline
+		int stringify(State* state) {
+			return static_cast<int>(
+				push(
+					state,
+					Reg::name + "@" + std::to_string(uintptr_t(check(state, 1)))
+				)
+			);
+		}
+	};
 }
 
 /**
@@ -114,7 +100,8 @@ namespace internal {
  */
 template <typename U, typename... A> static inline
 internal::StripUserType<U>& construct(State* state, A&&... args) {
-	using T = internal::StripUserType<U>;
+	using Wrapper = internal::UserTypeWrapper<U>;
+	using T = typename Wrapper::T;
 
 	void* mem = lua_newuserdata(state, sizeof(T));
 
@@ -126,8 +113,8 @@ internal::StripUserType<U>& construct(State* state, A&&... args) {
 	// Construct
 	T* value = new (mem) T {std::forward<A>(args)...};
 
-	// Apply metatable for unqualified type T
-	internal::apply_user_type_meta_table<T>(state);
+	// Apply metatable for unqualified type
+	setMetatable(state, Wrapper::Reg::name.c_str());
 
 	return *value;
 }
@@ -148,7 +135,7 @@ struct Value<U&> {
 	static inline
 	U& read(State* state, int n) {
 		// T is unqualified, therefore conversion from T& to U& is allowed
-		return *internal::check_user_type<T>(state, n);
+		return *internal::UserTypeWrapper<T>::check(state, n);
 	}
 
 	/**
@@ -183,7 +170,7 @@ struct Value<U*> {
 	static inline
 	U* read(State* state, int n) {
 		// T is unqualified, therefore conversion from T* to U* is allowed
-		return internal::check_user_type<T>(state, n);
+		return internal::UserTypeWrapper<T>::check(state, n);
 	}
 
 	/**
@@ -218,16 +205,16 @@ void registerUserType(
 	const FieldVector& methods = FieldVector(),
 	const FieldVector& meta_methods = FieldVector()
 ) {
-	using T = internal::StripUserType<U>;
+	using Wrapper = internal::UserTypeWrapper<U>;
 
 	// Setup an appropriate metatable name
-	internal::new_user_type_metatable<T>(state);
+	luaL_newmetatable(state, Wrapper::Reg::name.c_str());
 
 	// Insert methods
 	setFields(state, -1, {
 		{"__index",    methods},
-		{"__gc",       &internal::destruct_user_type<T>},
-		{"__tostring", &internal::stringify_user_type<T>}
+		{"__gc",       &Wrapper::destruct},
+		{"__tostring", &Wrapper::stringify}
 	});
 
 	// Insert meta methods
@@ -246,13 +233,13 @@ namespace internal {
 		);
 	};
 
-	template <typename T, typename... A>
-	struct UserTypeSignature<T (A...)> {
-		using UserType = StripUserType<T>;
+	template <typename U, typename... A>
+	struct UserTypeSignature<U(A...)> {
+		using T = StripUserType<U>;
 
 		static inline
 		void registerConstructor(State* state, const std::string& name) {
-			setGlobal(state, name, &construct_user_type<UserType, A...>);
+			setGlobal(state, name, &UserTypeWrapper<T>::template construct<A...>);
 		}
 	};
 }
@@ -261,16 +248,16 @@ namespace internal {
  * Same as the other `registerUserType` but registers the constructor as well. The template parameter
  * is a signature `U(A...)` where `U` is the user type and `A...` its constructor parameters.
  */
-template <typename T> static inline
+template <typename S> static inline
 void registerUserType(
 	State* state,
 	const std::string& ctor_name,
 	const FieldVector& methods = FieldVector(),
 	const FieldVector& meta_methods = FieldVector()
 ) {
-	using U = typename internal::UserTypeSignature<T>::UserType;
-	registerUserType<U>(state, methods, meta_methods);
-	internal::UserTypeSignature<T>::registerConstructor(state, ctor_name);
+	using T = typename internal::UserTypeSignature<S>::T;
+	registerUserType<T>(state, methods, meta_methods);
+	internal::UserTypeSignature<S>::registerConstructor(state, ctor_name);
 }
 
 LUWRA_NS_END
@@ -282,7 +269,7 @@ LUWRA_NS_END
  * \return Wrapped function as `lua_CFunction`
  */
 #define LUWRA_WRAP_CONSTRUCTOR(type, ...) \
-	(&luwra::internal::construct_user_type<luwra::internal::StripUserType<type>, __VA_ARGS__>)
+	(&luwra::internal::UserTypeWrapper<luwra::internal::StripUserType<type>>::template construct<__VA_ARGS__>)
 
 /**
  * Define the registry name for a user type.