Explorar o código

Use seperate struct to store meta table names

Ole Krüger %!s(int64=10) %!d(string=hai) anos
pai
achega
ef105e856a
Modificáronse 1 ficheiros con 39 adicións e 36 borrados
  1. 39 36
      lib/luwra/userdata.hpp

+ 39 - 36
lib/luwra/userdata.hpp

@@ -18,27 +18,56 @@
 
 LUWRA_NS_BEGIN
 
+namespace internal {
+	template <typename T>
+	struct MetatableNameStorage {
+		static
+		std::string Name;
+	};
+
+	template <typename T>
+	std::string MetatableNameStorage<T>::Name;
+
+	template <typename T, typename... A>
+	int user_type_ctor(State* state) {
+		return apply(state, std::function<int(A...)>([state](A... args) {
+			return Value<T&>::push(state, args...);
+		}));
+	}
+
+	template <typename T>
+	int user_type_dtor(State* state) {
+		Value<T&>::read(state, 1).~T();
+		return 0;
+	}
+
+	template <typename T>
+	int user_type_tostring(State* state) {
+		return Value<std::string>::push(
+			state,
+			internal::MetatableNameStorage<T>::Name
+		);
+	}
+}
+
 /**
  * Instances of user types shall always be used as references, because Lua values can not be
  * referenced, hence this allows the compiler to differentiate between them.
  */
 template <typename T>
 struct Value<T&> {
-	static
-	std::string MetatableName;
-
 	static inline
 	T& read(State* state, int n) {
-		assert(MetatableName.size() > 0);
+		assert(!internal::MetatableNameStorage<T>::Name.empty());
 
 		return *static_cast<T*>(
-			luaL_checkudata(state, n, MetatableName.c_str())
+			luaL_checkudata(state, n, internal::MetatableNameStorage<T>::Name.c_str())
 		);
 	}
 
 	template <typename... A> static inline
 	int push(State* state, A&&... args) {
-		assert(MetatableName.size() > 0);
+		assert(!internal::MetatableNameStorage<T>::Name.empty());
 
 		void* mem = lua_newuserdata(state, sizeof(T));
 
@@ -51,39 +80,13 @@ struct Value<T&> {
 		new (mem) T(std::forward<A>(args)...);
 
 		// Set metatable for this type
-		luaL_getmetatable(state, MetatableName.c_str());
+		luaL_getmetatable(state, internal::MetatableNameStorage<T>::Name.c_str());
 		lua_setmetatable(state, -2);
 
 		return 1;
 	}
 };
 
-template <typename T>
-std::string Value<T&>::MetatableName;
-
-namespace internal {
-	template <typename T, typename... A>
-	int user_type_ctor(State* state) {
-		return apply(state, std::function<int(A...)>([state](A... args) {
-			return Value<T&>::push(state, args...);
-		}));
-	}
-
-	template <typename T>
-	int user_type_dtor(State* state) {
-		Value<T&>::read(state, 1).~T();
-		return 0;
-	}
-
-	template <typename T>
-	int user_type_tostring(State* state) {
-		return Value<std::string>::push(
-			state,
-			Value<T&>::MetatableName
-		);
-	}
-}
-
 /**
  * Generate the metatable for the userdata 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;
@@ -100,10 +103,10 @@ void register_user_type(
 	std::atomic_size_t mt_counter;
 
 	// Setup an appropriate meta table name
-	if (Value<T&>::MetatableName.size() == 0)
-		Value<T&>::MetatableName = "UD#" + std::to_string(mt_counter++);
+	if (internal::MetatableNameStorage<T>::Name.empty())
+		internal::MetatableNameStorage<T>::Name = "UD#" + std::to_string(mt_counter++);
 
-	luaL_newmetatable(state, Value<T&>::MetatableName.c_str());
+	luaL_newmetatable(state, internal::MetatableNameStorage<T>::Name.c_str());
 
 	// Register methods
 	lua_pushstring(state, "__index");