소스 검색

Add some Value specializations for STL containers

Ole 9 년 전
부모
커밋
859a753480
2개의 변경된 파일124개의 추가작업 그리고 0개의 파일을 삭제
  1. 68 0
      lib/luwra/types.hpp
  2. 56 0
      tests/types.cpp

+ 68 - 0
lib/luwra/types.hpp

@@ -16,6 +16,10 @@
 #include <type_traits>
 #include <memory>
 #include <limits>
+#include <vector>
+#include <list>
+#include <initializer_list>
+#include <map>
 
 LUWRA_NS_BEGIN
 
@@ -468,6 +472,10 @@ struct Pushable: virtual internal::PushableI {
 		if (interface)
 			delete interface;
 	}
+
+	bool operator <(const Pushable& other) const {
+		return interface < other.interface;
+	}
 };
 
 template <>
@@ -478,6 +486,66 @@ struct Value<Pushable> {
 	}
 };
 
+template <typename T>
+struct Value<std::vector<T>> {
+	static inline
+	size_t push(State* state, const std::vector<T>& vec) {
+		lua_createtable(state, vec.size(), 0);
+
+		int size = static_cast<int>(vec.size());
+		for (int i = 0; i < size; i++) {
+			size_t pushedValues = luwra::push(state, vec[i]);
+			if (pushedValues > 1)
+				lua_pop(state, static_cast<int>(pushedValues - 1));
+
+			lua_rawseti(state, -2, i + 1);
+		}
+
+		return 1;
+	}
+};
+
+template <typename T>
+struct Value<std::list<T>> {
+	static inline
+	size_t push(State* state, const std::list<T>& lst) {
+		lua_createtable(state, lst.size(), 0);
+
+		int i = 0;
+		for (const T& item: lst) {
+			size_t pushedValues = luwra::push(state, item);
+			if (pushedValues > 1)
+				lua_pop(state, static_cast<int>(pushedValues - 1));
+
+			lua_rawseti(state, -2, ++i);
+		}
+
+		return 1;
+	}
+};
+
+template <typename K, typename V>
+struct Value<std::map<K, V>> {
+	static inline
+	size_t push(State* state, const std::map<K, V>& map) {
+		lua_createtable(state, 0, map.size());
+
+		for (const auto& entry: map) {
+			size_t pushedKeys = luwra::push(state, entry.first);
+			if (pushedKeys > 1)
+				lua_pop(state, static_cast<int>(pushedKeys - 1));
+
+			size_t pushedValues = luwra::push(state, entry.second);
+			if (pushedValues > 1)
+				lua_pop(state, static_cast<int>(pushedValues - 1));
+
+			lua_rawset(state, -3);
+		}
+
+		return 1;
+	}
+};
+
 LUWRA_NS_END
 
 #endif

+ 56 - 0
tests/types.cpp

@@ -5,6 +5,9 @@
 #include <string>
 #include <utility>
 #include <type_traits>
+#include <vector>
+#include <list>
+#include <initializer_list>
 
 // Numbers are royally fucked. They might or might not be stored in a floating-point number, which
 // makes testing for integer limits pointless.
@@ -145,3 +148,56 @@ TEST_CASE("Pushable") {
 
 	REQUIRE(luwra::read<int>(state, -1) == 1337);
 }
+
+TEST_CASE("Value<vector>") {
+	luwra::StateWrapper state;
+	state.loadStandardLibrary();
+
+	std::vector<int> v {1, 2, 3, 4, 5};
+	REQUIRE(luwra::push(state, v) == 1);
+
+	state["v"] = v;
+
+	REQUIRE(state.runString(
+		"x = 0\n"
+		"for i, j in ipairs(v) do x = x + i + j end\n"
+		"return x"
+	) == LUA_OK);
+
+	REQUIRE(luwra::read<int>(state, -1) == 30);
+}
+
+TEST_CASE("Value<list>") {
+	luwra::StateWrapper state;
+	state.loadStandardLibrary();
+
+	std::list<int> v {1, 2, 3, 4, 5};
+	REQUIRE(luwra::push(state, v) == 1);
+
+	state["v"] = v;
+
+	REQUIRE(state.runString(
+		"x = 0\n"
+		"for i, j in ipairs(v) do x = x + i + j end\n"
+		"return x"
+	) == LUA_OK);
+
+	REQUIRE(luwra::read<int>(state, -1) == 30);
+}
+
+TEST_CASE("Value<map>") {
+	luwra::StateWrapper state;
+
+	std::map<luwra::Pushable, luwra::Pushable> v {
+		{"hello", 13},
+		{37, "world"}
+	};
+	REQUIRE(luwra::push(state, v) == 1);
+
+	state["v"] = v;
+
+	REQUIRE(state.runString("return v.hello, v[37]") == LUA_OK);
+
+	REQUIRE(luwra::read<int>(state, -2) == 13);
+	REQUIRE(luwra::read<std::string>(state, -1) == "world");
+}