Explorar el Código

Strip qualifiers from user types to achieve clean abstraction

Ole hace 10 años
padre
commit
acaca780f8
Se han modificado 1 ficheros con 36 adiciones y 29 borrados
  1. 36 29
      lib/luwra/usertypes.hpp

+ 36 - 29
lib/luwra/usertypes.hpp

@@ -20,8 +20,7 @@ namespace internal {
 	using UserTypeID = const void*;
 
 	template <typename T>
-	using CleanUserType =
-			std::remove_pointer_t<std::remove_reference_t<std::remove_cv_t<T>>>;
+	using StripUserType = std::remove_cv_t<T>;
 
 	/**
 	 * User type identifier
@@ -34,17 +33,18 @@ namespace internal {
 	 */
 	template <typename T>
 	std::string user_type_reg_name =
-		"UD#" + std::to_string(uintptr_t(&user_type_id<CleanUserType<T>>));
+		"UD#" + std::to_string(uintptr_t(&user_type_id<T>));
+
 	/**
 	 * Register a new meta table for a user type T.
 	 */
-	template <typename T> static inline
+	template <typename U> static inline
 	void new_user_type_id(State* state) {
-		luaL_newmetatable(state, user_type_reg_name<CleanUserType<T>>.c_str());
+		using T = StripUserType<U>;
 
 		// Use the address as user type identifier
-		UserTypeID ut_id = lua_topointer(state, -1);
-		user_type_id<CleanUserType<T>> = ut_id;
+		luaL_newmetatable(state, user_type_reg_name<T>.c_str());
+		user_type_id<T> = lua_topointer(state, -1);
 	}
 
 	/**
@@ -67,22 +67,23 @@ namespace internal {
 	/**
 	 * Check if the value at the given index if a user type T.
 	 */
-	template <typename T> static inline
-	T* check_user_type(State* state, int index) {
-		UserTypeID uid = get_user_type_id(state, index);
-		if (uid == user_type_id<CleanUserType<T>>) {
+	template <typename U> static inline
+	StripUserType<U>* check_user_type(State* state, int index) {
+		using T = StripUserType<U>;
+
+		if (get_user_type_id(state, index) == user_type_id<T>) {
 			return static_cast<T*>(lua_touserdata(state, index));
 		} else {
 			std::string error_msg =
-				"Expected user type " + std::to_string(uintptr_t(user_type_id<CleanUserType<T>>));
+				"Expected user type " + std::to_string(uintptr_t(user_type_id<T>));
 			luaL_argerror(state, index, error_msg.c_str());
 			return nullptr;
 		}
 	}
 
-	template <typename T> static inline
+	template <typename U> static inline
 	void apply_user_type_meta_table(State* state) {
-		luaL_getmetatable(state, user_type_reg_name<CleanUserType<T>>.c_str());
+		luaL_getmetatable(state, user_type_reg_name<StripUserType<U>>.c_str());
 		lua_setmetatable(state, -2);
 	}
 
@@ -113,12 +114,14 @@ namespace internal {
 	/**
 	 * Create a string representation for user type T.
 	 */
-	template <typename T> static
-	std::string stringify_user_type(T& val) {
-		return
-			internal::user_type_reg_name<CleanUserType<T>>
+	template <typename U> static
+	int stringify_user_type(State* state) {
+		return Value<std::string>::push(
+			state,
+			internal::user_type_reg_name<StripUserType<U>>
 			+ "@"
-			+ std::to_string(uintptr_t(&val));
+			+ std::to_string(uintptr_t(Value<U*>::read(state, 1)))
+		);
 	}
 
 	/**
@@ -128,11 +131,11 @@ namespace internal {
 	int access_user_type_property(State* state) {
 		if (lua_gettop(state) > 1) {
 			// Setter
-			(Value<T&>::read(state, 1).*property_pointer) = Value<R>::read(state, 2);
+			(Value<T*>::read(state, 1)->*property_pointer) = Value<R>::read(state, 2);
 			return 0;
 		} else {
 			// Getter
-			return push(state, Value<T&>::read(state, 1).*property_pointer);
+			return push(state, Value<T*>::read(state, 1)->*property_pointer);
 		}
 	}
 
@@ -147,14 +150,14 @@ namespace internal {
 	template <typename T, typename R, typename... A>
 	struct MethodWrapper<T, R(A...)> {
 		using MethodPointerType = R (T::*)(A...);
-		using FunctionSignature = R (T&, A...);
+		using FunctionSignature = R (T*, A...);
 
 		/**
 		 * This function is a wrapped around the invocation of a given method.
 		 */
 		template <MethodPointerType method_pointer> static inline
-		R call(T& parent, A... args) {
-			return (parent.*method_pointer)(std::forward<A>(args)...);
+		R call(T* parent, A... args) {
+			return (parent->*method_pointer)(std::forward<A>(args)...);
 		}
 	};
 }
@@ -165,8 +168,10 @@ namespace internal {
  * types in Lua. The default garbage-collecting hook will destruct the user type, once it has
  * been marked.
  */
-template <typename T>
-struct Value<T&> {
+template <typename U>
+struct Value<U&> {
+	using T = internal::StripUserType<U>;
+
 	static inline
 	T& read(State* state, int n) {
 		return *internal::check_user_type<T>(state, n);
@@ -196,8 +201,10 @@ struct Value<T&> {
  * Instances created using this specialization are allocated as light user data in Lua.
  * The default garbage-collector does not destruct light user data types.
  */
-template <typename T>
-struct Value<T*> {
+template <typename U>
+struct Value<U*> {
+	using T = internal::StripUserType<U>;
+
 	static inline
 	T* read(State* state, int n) {
 		return internal::check_user_type<T>(state, n);
@@ -310,7 +317,7 @@ void register_user_type(
 	// Register string representation function
 	if (meta_methods.count("__tostring") == 0) {
 		push(state, "__tostring");
-		push(state, wrap_function<std::string(T&), &internal::stringify_user_type<T>>);
+		push(state, &internal::stringify_user_type<T>);
 		lua_rawset(state, -3);
 	}