changeset 201:8ee4a34e166c

* Adds inheritance to Luae * Use const variables to let user definable
author David Demelier <markand@malikania.fr>
date Sat, 04 Jan 2014 16:59:09 +0100
parents 617459270743
children 99d0887395cc
files C++/Luae.cpp C++/Luae.h
diffstat 2 files changed, 87 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/C++/Luae.cpp	Sat Dec 28 11:16:11 2013 +0100
+++ b/C++/Luae.cpp	Sat Jan 04 16:59:09 2014 +0100
@@ -18,21 +18,21 @@
 
 #include "Luae.h"
 
-namespace malikania {
-
 /* --------------------------------------------------------
  * LuaeState
  * -------------------------------------------------------- */
 
+const char *LuaeState::FieldRefs	= "__refs";
+
 void LuaeState::initRegistry()
 {
-	if (LuaeTable::type(*this, LUA_REGISTRYINDEX, "refs") == LUA_TNIL) {
+	if (LuaeTable::type(*this, LUA_REGISTRYINDEX, FieldRefs) == LUA_TNIL) {
 		lua_createtable(*this, 0, 0);
 		lua_createtable(*this, 0, 1);
 		lua_pushstring(*this, "v");
 		lua_setfield(*this, -2, "__mode");
 		lua_setmetatable(*this, -2);
-		lua_setfield(*this, LUA_REGISTRYINDEX, "refs");
+		lua_setfield(*this, LUA_REGISTRYINDEX, FieldRefs);
 	}
 }
 
@@ -257,11 +257,27 @@
  * LuaeClass
  * -------------------------------------------------------- */
 
+const char *LuaeClass::FieldName	= "__name";
+const char *LuaeClass::FieldParents	= "__parents";
+
 void LuaeClass::create(lua_State *L, const Def &def)
 {
 	LUAE_STACK_CHECKBEGIN(L);
+	luaL_newmetatable(L, def.name.c_str());
 
-	luaL_newmetatable(L, def.name.c_str());
+	// Store the name of the class
+	lua_pushlstring(L, def.name.c_str(), def.name.length());
+	lua_setfield(L, -2, FieldName);
+
+	// Store the parents names
+	int i = 0;
+
+	lua_createtable(L, 0, 0);
+	for (auto d(def.parent); d != nullptr; d = d->parent) {
+		lua_pushlstring(L, d->name.c_str(), d->name.length());
+		lua_rawseti(L, -2, ++i);
+	}
+	lua_setfield(L, -2, FieldParents);
 
 	// Metamethods
 	if (def.metamethods.size() > 0) {
@@ -272,19 +288,20 @@
 	}
 
 	// Methods
-	if (def.methods.size() > 0) {
-		lua_createtable(L, 0, 0);
-
-		for (auto m : def.methods) {
-			lua_pushcfunction(L, m.func);
-			lua_setfield(L, -2, m.name);
-		}
-
-		lua_setfield(L, -2, "__index");
+	lua_createtable(L, 0, 0);
+	for (auto m : def.methods) {
+		lua_pushcfunction(L, m.func);
+		lua_setfield(L, -2, m.name);
 	}
 
+	// Create the inheritance
+	if (def.parent != nullptr) {
+		luaL_newmetatable(L, def.parent->name.c_str());
+		lua_setmetatable(L, -2);
+	}
+	lua_setfield(L, -2, "__index");
+
 	lua_pop(L, 1);
-
 	LUAE_STACK_CHECKEQUALS(L);
 }
 
@@ -378,8 +395,6 @@
 	LUAE_STACK_CHECKEQUALS(L);
 }
 
-} // !malikania
-
 void *operator new(size_t size, lua_State *L)
 {
 	return lua_newuserdata(L, size);
--- a/C++/Luae.h	Sat Dec 28 11:16:11 2013 +0100
+++ b/C++/Luae.h	Sat Jan 04 16:59:09 2014 +0100
@@ -28,8 +28,6 @@
 
 #include <lua.hpp>
 
-namespace malikania {
-
 /* {{{ LuaeState */
 
 /**
@@ -55,6 +53,12 @@
 	void initRegistry();
 
 public:
+	/*
+	 * FieldRefs:		The field stored into the registry to avoid
+	 *			recreation of shared objects.
+	 */
+	static const char *FieldRefs;
+
 	LuaeState(const LuaeState &) = delete;
 	LuaeState &operator=(const LuaeState &) = delete;
 
@@ -251,10 +255,26 @@
 		const Def	*parent;	//! optional parent class
 	};
 
+	/*
+	 * FieldName:		The field stored in the object metatable about 
+	 *			the object metatable name.
+	 *
+	 * FieldParents:	The field that holds all parent classes. It is
+	 *			used to verify casts.
+	 */
+	static const char *FieldName;
+	static const char *FieldParents;
+
+	/**
+	 * Initialize a new object.
+	 *
+	 * @param L the Lua state
+	 * @param def the definition
+	 */
 	static void create(lua_State *L, const Def &def);
 
 	/**
-	 * Push a shared object to Lua, it also push it to the "refs"
+	 * Push a shared object to Lua, it also push it to the "__refs"
 	 * table with __mode = "v". That is if we need to push the object
 	 * again we use the same reference so Lua get always the same
 	 * userdata and gain the following benefits:
@@ -269,7 +289,7 @@
 	template <typename T>
 	static void push(lua_State *L, Ptr<T> o, const std::string &name)
 	{
-		lua_getfield(L, LUA_REGISTRYINDEX, "refs");
+		lua_getfield(L, LUA_REGISTRYINDEX, LuaeState::FieldRefs);
 		assert(lua_type(L, -1) == LUA_TTABLE);
 
 		lua_rawgetp(L, -1, o.get());
@@ -297,9 +317,38 @@
 	template <typename T>
 	static Ptr<T> get(lua_State *L, int index, const char *meta)
 	{
-		Ptr<T> *ptr = static_cast<Ptr<T> *>(luaL_checkudata(L, index, meta));
+		luaL_checktype(L, index, LUA_TUSERDATA);
+		if (!luaL_getmetafield(L, index, FieldName))
+			luaL_error(L, "invalid type");
+
+		// Get the class name
+		const char *name = lua_tostring(L, -1);
+		lua_pop(L, 1);
+
+		bool found(false);
+
+		if (std::string(name) == std::string(meta)) {
+			found = true;
+		} else {
+			if (!luaL_getmetafield(L, index, FieldParents))
+				luaL_error(L, "invalid type");
+
+			LuaeTable::read(L, -1, [&] (lua_State *L, int, int tvalue) {
+				if (tvalue != LUA_TSTRING)
+					return;
+
+				const char *tn = lua_tostring(L, -1);
+				if (std::string(tn) == std::string(meta))
+					found = true;
+			});
+	
+			lua_pop(L, 1);
+		}
+
+		if (!found)
+			luaL_error(L, "invalid cast from `%s' to `%s'", name, meta);
 		
-		return *ptr;
+		return *static_cast<Ptr<T> *>(lua_touserdata(L, index));
 	}
 };
 
@@ -433,8 +482,6 @@
 
 #endif
 
-} // !malikania
-
 void *operator new(size_t size, lua_State *L);
 
 void *operator new(size_t size, lua_State *L, const char *metaname);