Przeglądaj źródła

Change relation between Value<T>, Value<T&> and Value<T*>

These generic Value specializations can be used to push/read user type values.
When should you use which?

Use Value<T> to copy a value onto or from the stack.
Use Value<T&> to construct or reference a value on the stack.
Use Value<T*> to copy a value (using a reference to it) onto or reference a value on the stack.
Ole 10 lat temu
rodzic
commit
c92d4cbbbe
3 zmienionych plików z 28 dodań i 66 usunięć
  1. 8 11
      lib/luwra/types.hpp
  2. 3 14
      lib/luwra/usertypes.hpp
  3. 17 41
      tests/usertypes.cpp

+ 8 - 11
lib/luwra/types.hpp

@@ -26,25 +26,20 @@ using CFunction = lua_CFunction;
 
 /**
  * Wrapper for a stack value
- * \note This generic version should not be used since it does not implement anything.
- *       It is not always obvious whether you have used this generic instance or not. Therefore this
- *       class produces an error message when it is being used. Look for `Parameter to Value is not
- *       supported` in your compiler output.
+ * \note This generic version behaves like its specialization for `T&`, except that it will
+ *       always copy from and to the stack (instead of referencing).
  */
 template <typename T>
 struct Value {
-	static_assert(
-		sizeof(T) == -1,
-		"Parameter to Value is not supported"
-	);
-
 	/**
 	 * Retrieve a value from the stack.
 	 * \param state Lua state
 	 * \param index Position of the value
 	 */
 	static
-	T read(State* state, int index);
+	T read(State* state, int index) {
+		return Value<T&>::read(state, index);
+	}
 
 	/**
 	 * Push a value onto the stack.
@@ -53,7 +48,9 @@ struct Value {
 	 * \returns Number of values pushed
 	 */
 	static
-	size_t push(State* state, T value);
+	size_t push(State* state, const T& value) {
+		return Value<T&>::push(state, value);
+	}
 };
 
 // Nil

+ 3 - 14
lib/luwra/usertypes.hpp

@@ -151,8 +151,6 @@ struct Value<U&> {
 
 /**
  * User type 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 U>
 struct Value<U*> {
@@ -164,18 +162,9 @@ struct Value<U*> {
 		return internal::check_user_type<T>(state, n);
 	}
 
-	static inline
-	size_t push(State* state, T* instance) {
-		if (instance == nullptr)
-			return 0;
-
-		// Push instance as light user data
-		lua_pushlightuserdata(state, instance);
-
-		// Apply metatable for unqualified type T
-		internal::apply_user_type_meta_table<T>(state);
-
-		return 1;
+	static
+	size_t push(State* state, const T* ptr) {
+		return Value<T&>::push(state, *ptr);
 	}
 };
 

+ 17 - 41
tests/usertypes.cpp

@@ -12,16 +12,6 @@ struct A {
 TEST_CASE("UserTypeRegistration") {
 	luwra::StateWrapper state;
 	luwra::registerUserType<A>(state);
-
-	// Reference
-	A* instance = new A;
-	luwra::Value<A*>::push(state, instance);
-
-	// Type checks
-	REQUIRE(luwra::internal::check_user_type<A>(state, -1) == instance);
-	REQUIRE(luwra::Value<A*>::read(state, -1) == instance);
-
-	delete instance;
 }
 
 TEST_CASE("UserTypeConstruction") {
@@ -68,39 +58,42 @@ TEST_CASE("UserTypeFields") {
 	);
 
 	// Instantiation
-	B value(1338);
-	luwra::setGlobal(state, "val", &value);
+	luwra::Value<B&>::push(state, 1338);
+	lua_setglobal(state, "value");
+
+	B& value = luwra::getGlobal<B&>(state, "value");
 
 	// Unqualified get
-	REQUIRE(luaL_dostring(state, "return val:n()") == 0);
+	REQUIRE(luaL_dostring(state, "return value:n()") == 0);
+	puts(lua_tostring(state, -1));
 	REQUIRE(luwra::read<int>(state, -1) == value.n);
 
 	// Unqualified set
-	REQUIRE(luaL_dostring(state, "val:n(42)") == 0);
+	REQUIRE(luaL_dostring(state, "value:n(42)") == 0);
 	REQUIRE(value.n == 42);
 
 	// 'const'-qualified get
-	REQUIRE(luaL_dostring(state, "return val:cn()") == 0);
+	REQUIRE(luaL_dostring(state, "return value:cn()") == 0);
 	REQUIRE(luwra::read<int>(state, -1) == value.cn);
 
 	// 'const'-qualified set
-	REQUIRE(luaL_dostring(state, "val:cn(42)") == 0);
+	REQUIRE(luaL_dostring(state, "value:cn(42)") == 0);
 	REQUIRE(value.cn == 1338);
 
 	// 'volatile' get
-	REQUIRE(luaL_dostring(state, "return val:vn()") == 0);
+	REQUIRE(luaL_dostring(state, "return value:vn()") == 0);
 	REQUIRE(luwra::read<int>(state, -1) == value.vn);
 
 	// 'volatile' set
-	REQUIRE(luaL_dostring(state, "val:vn(42)") == 0);
+	REQUIRE(luaL_dostring(state, "value:vn(42)") == 0);
 	REQUIRE(value.vn == 42);
 
 	// 'const volatile'-qualified get
-	REQUIRE(luaL_dostring(state, "return val:cvn()") == 0);
+	REQUIRE(luaL_dostring(state, "return value:cvn()") == 0);
 	REQUIRE(luwra::read<int>(state, -1) == value.cvn);
 
 	// 'const volatile'-qualified set
-	REQUIRE(luaL_dostring(state, "val:cvn(42)") == 0);
+	REQUIRE(luaL_dostring(state, "value:cvn(42)") == 0);
 	REQUIRE(value.cvn == 1338);
 }
 
@@ -143,8 +136,10 @@ TEST_CASE("UserTypeMethods") {
 	);
 
 	// Instantiation
-	C value(1337);
-	luwra::setGlobal(state, "value", &value);
+	luwra::Value<C&>::push(state, 1337);
+	lua_setglobal(state, "value");
+
+	C& value = luwra::getGlobal<C&>(state, "value");
 
 	// Unqualified method
 	REQUIRE(luaL_dostring(state, "return value:foo1(63)") == 0);
@@ -185,22 +180,3 @@ TEST_CASE("UserTypeGarbageCollectionRef") {
 	lua_close(state);
 	REQUIRE(shared_var.use_count() == 1);
 }
-
-TEST_CASE("UserTypeGarbageCollectionPtr") {
-	lua_State* state = luaL_newstate();
-
-	// Registration
-	luwra::registerUserType<std::shared_ptr<int>>(state);
-
-	// Instantiation
-	std::shared_ptr<int> shared_var = std::make_shared<int>(1337);
-	REQUIRE(shared_var.use_count() == 1);
-
-	// Reference
-	luwra::push(state, &shared_var);
-	REQUIRE(shared_var.use_count() == 1);
-
-	// Garbage collection
-	lua_close(state);
-	REQUIRE(shared_var.use_count() == 1);
-}