changeset 225:e01ee0c72c43

Luae: begin refactoring of Luae
author David Demelier <markand@malikania.fr>
date Fri, 09 May 2014 17:12:25 +0200
parents ca69910b1407
children 24501d428db3
files C++/Luae.cpp C++/Luae.h C++/LuaeClass.cpp C++/LuaeClass.h C++/LuaeEnum.cpp C++/LuaeEnum.h C++/LuaeState.cpp C++/LuaeState.h C++/LuaeTable.cpp C++/LuaeTable.h C++/LuaeVariant.cpp C++/LuaeVariant.h C++/Tests/Luae/CMakeLists.txt C++/Tests/Luae/TestLuae.cpp C++/Tests/Luae/TestLuae.h C++/Tests/Luae/scripts/loading.lua C++/Tests/Luae/scripts/push.lua C++/Tests/Luae/scripts/standard.lua CMakeLists.txt cmake/FindLua52.cmake
diffstat 20 files changed, 1867 insertions(+), 1300 deletions(-) [+]
line wrap: on
line diff
--- a/C++/Luae.cpp	Fri May 09 09:15:52 2014 +0200
+++ b/C++/Luae.cpp	Fri May 09 17:12:25 2014 +0200
@@ -20,398 +20,6 @@
 
 #include "Luae.h"
 
-/* --------------------------------------------------------
- * LuaeState
- * -------------------------------------------------------- */
-
-const char *LuaeState::FieldRefs	= "__refs";
-
-void LuaeState::initRegistry()
-{
-	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, FieldRefs);
-	}
-}
-
-LuaeState::LuaeState()
-{
-	m_state = Ptr(luaL_newstate());
-
-	initRegistry();
-}
-
-LuaeState::LuaeState(lua_State *L)
-{
-	m_state = Ptr(L);
-
-	initRegistry();
-}
-
-LuaeState::LuaeState(LuaeState &&state)
-{
-	m_state = std::move(state.m_state);
-
-	initRegistry();
-}
-
-LuaeState &LuaeState::operator=(LuaeState &&state)
-{
-	m_state = std::move(state.m_state);
-
-	initRegistry();
-
-	return *this;
-}
-
-LuaeState::operator lua_State*()
-{
-	return m_state.get();
-}
-
-/* --------------------------------------------------------
- * LuaeValue
- * -------------------------------------------------------- */
-
-LuaeValue LuaeValue::copy(lua_State *L, int index)
-{
-	LuaeValue v;
-
-	v.type = lua_type(L, index);
-
-	switch (v.type) {
-	case LUA_TBOOLEAN:
-		v.boolean = lua_toboolean(L, index);
-		break;
-	case LUA_TNUMBER:
-		v.number = lua_tonumber(L, index);
-		break;
-	case LUA_TSTRING:
-		v.str = lua_tostring(L, index);
-		break;
-	case LUA_TTABLE:
-	{
-		if (index < 0)
-			-- index;
-
-		lua_pushnil(L);
-		while (lua_next(L, index)) {
-			v.table.push_back(std::make_pair(copy(L, -2), copy(L, -1)));
-			lua_pop(L, 1);
-		}
-
-		break;
-	}
-	default:
-		v.type = LUA_TNIL;
-		break;
-	}
-
-	return v;
-}
-
-void LuaeValue::push(lua_State *L, const LuaeValue &value)
-{
-	switch (value.type) {
-	case LUA_TBOOLEAN:
-		lua_pushboolean(L, value.boolean);
-		break;
-	case LUA_TSTRING:
-		lua_pushlstring(L,  value.str.c_str(), value.str.size());
-		break;
-	case LUA_TNUMBER:
-		lua_pushnumber(L, value.number);
-		break;
-	case LUA_TTABLE:
-	{
-		lua_createtable(L, 0, 0);
-
-		for (auto p : value.table) {
-			push(L, p.first);
-			push(L, p.second);
-
-			lua_settable(L, -3);
-		}
-		break;
-	}
-	default:
-		lua_pushnil(L);
-		break;
-	}
-}
-
-LuaeValue::LuaeValue()
-	: type(LUA_TNIL)
-{
-}
-
-/* --------------------------------------------------------
- * LuaeTable
- * -------------------------------------------------------- */
-
-void LuaeTable::create(lua_State *L, int nrec, int narr)
-{
-	LUAE_STACK_CHECKBEGIN(L);
-
-	lua_createtable(L, nrec, narr);
-
-	LUAE_STACK_CHECKEND(L, - 1);
-}
-
-int LuaeTable::type(lua_State *L, int idx, const std::string &name)
-{
-	int type;
-
-	LUAE_STACK_CHECKBEGIN(L);
-
-	lua_getfield(L, idx, name.c_str());
-	type = lua_type(L, -1);
-	lua_pop(L, 1);
-
-	LUAE_STACK_CHECKEQUALS(L);
-
-	return type;
-}
-
-void LuaeTable::read(lua_State *L, int idx, ReadFunction func)
-{
-	LUAE_STACK_CHECKBEGIN(L);
-
-	lua_pushnil(L);
-
-	if (idx < 0)
-		--idx;
-
-	while (lua_next(L, idx)) {
-		func(L, lua_type(L, -2), lua_type(L, -1));
-		lua_pop(L, 1);
-	}
-
-	LUAE_STACK_CHECKEQUALS(L);
-}
-
-int LuaeTable::ref(lua_State *L, int idx, int type, const std::string &name)
-{
-	int ref = LUA_REFNIL;
-
-	lua_getfield(L, idx, name.c_str());
-
-	if (lua_type(L, -1) == type) {
-		lua_pushvalue(L, -1);
-		ref = luaL_ref(L, LUA_REGISTRYINDEX);
-	}
-
-	lua_pop(L, 1);
-
-	return ref;
-}
-
-/* --------------------------------------------------------
- * 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());
-
-	// 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) {
-		for (auto m : def.metamethods) {
-			lua_pushcfunction(L, m.func);
-			lua_setfield(L, -2, m.name);
-		}
-	}
-
-	// Methods
-	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);
-}
-
-void LuaeClass::testShared(lua_State *L, int index, const char *meta)
-{
-	LUAE_STACK_CHECKBEGIN(L);
-
-	luaL_checktype(L, index, LUA_TUSERDATA);
-	if (!luaL_getmetafield(L, index, FieldName))
-		luaL_error(L, "invalid type cast");
-
-	// 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 cast");
-
-		lua_pushnil(L);
-		while (lua_next(L, -2) != 0) {
-			if (lua_type(L, -2) != LUA_TSTRING) {
-				lua_pop(L, 1);
-				continue;
-			}
-
-			auto tn = lua_tostring(L, -1);
-			if (std::string(tn) == std::string(meta))
-				found = true;
-
-			lua_pop(L, 1);
-		}
-
-		lua_pop(L, 1);
-	}
-
-	if (!found)
-		luaL_error(L, "invalid cast from `%s' to `%s'", name, meta);
-
-	LUAE_STACK_CHECKEQUALS(L);
-}
-
-/* --------------------------------------------------------
- * LuaeEnum
- * -------------------------------------------------------- */
-
-void LuaeEnum::create(lua_State *L, const Def &def)
-{
-	LUAE_STACK_CHECKBEGIN(L);
-
-	lua_createtable(L, 0, 0);
-
-	for (auto p : def) {
-		lua_pushinteger(L, p.second);
-		lua_setfield(L, -2, p.first);
-	}
-
-	LUAE_STACK_CHECKEND(L, - 1);
-}
-
-void LuaeEnum::create(lua_State *L, const Def &def, int index)
-{
-	LUAE_STACK_CHECKBEGIN(L);
-
-	if (index < 0)
-		-- index;
-
-	for (auto p : def) {
-		lua_pushinteger(L, p.second);
-		lua_setfield(L, index, p.first);
-	}
-
-	LUAE_STACK_CHECKEQUALS(L);
-}
-
-void LuaeEnum::create(lua_State *L,
-		      const Def &def,
-		      int index,
-		      const std::string &name)
-{
-	LUAE_STACK_CHECKBEGIN(L);
-
-	create(L, def);
-
-	if (index < 0)
-		-- index;
-
-	lua_setfield(L, index, name.c_str());
-
-	LUAE_STACK_CHECKEQUALS(L);
-}
-
-void LuaeEnum::push(lua_State *L, const Def &def, int value)
-{
-	LUAE_STACK_CHECKBEGIN(L);
-	lua_createtable(L, 0, 0);
-
-	for (auto p : def) {
-		if (value & p.second) {
-			lua_pushinteger(L, p.second);
-			lua_rawseti(L, -2, p.second);
-		}
-	}
-
-	LUAE_STACK_CHECKEND(L, - 1);
-}
-
-int LuaeEnum::get(lua_State *L, int index)
-{
-	int value = 0;
-
-	LUAE_STACK_CHECKBEGIN(L);
-
-	if (lua_type(L, index) == LUA_TTABLE) {
-		if (index < 0)
-			-- index;
-
-		lua_pushnil(L);
-		while (lua_next(L, index)) {
-			if (lua_type(L, -1) == LUA_TNUMBER)
-				value |= lua_tointeger(L, -1);
-
-			lua_pop(L, 1);
-		}
-	}
-
-	LUAE_STACK_CHECKEQUALS(L);
-
-	return value;
-}
-
-int LuaeEnum::require(lua_State *L, int index)
-{
-	int value = 0;
-
-	LUAE_STACK_CHECKBEGIN(L);
-
-	luaL_checktype(L, index, LUA_TTABLE);
-	value = LuaeEnum::get(L, index);
-
-	LUAE_STACK_CHECKEQUALS(L);
-
-	return value;
-}
-
-/* --------------------------------------------------------
- * Luae
- * -------------------------------------------------------- */
-
 void Luae::doexecute(lua_State *L, int status)
 {
 	if (status != LUA_OK) {
@@ -422,9 +30,37 @@
 	}
 }
 
+void Luae::assertBegin(lua_State *L)
+{
+#if !defined(NDEBUG)
+	lua_pushinteger(L, lua_gettop(L));
+	lua_setfield(L, LUA_REGISTRYINDEX, FieldTop);
+#endif
+}
+
+void Luae::assertEnd(lua_State *L, int expected)
+{
+#if !defined(NDEBUG)
+	lua_getfield(L, LUA_REGISTRYINDEX, FieldTop);
+	if (lua_type(L, -1) == LUA_TNIL)
+		luaL_error(L, "stack verification without top field, call assertBegin");
+		// NOTREACHED
+
+	auto before = lua_tointeger(L, -1);
+	lua_pop(L, 1);
+
+	if (before != (gettop(L) - expected))
+		luaL_error(L, "stack size error: expected %d, got %d", expected, gettop(L) - before);
+		// NOTREACHED
+
+	lua_pushnil(L);
+	lua_setfield(L, LUA_REGISTRYINDEX, FieldTop);
+#endif
+}
+
 void Luae::preload(lua_State *L, const std::string &name, lua_CFunction func)
 {
-	LUAE_STACK_CHECKBEGIN(L);
+	assertBegin(L);
 
 	lua_getglobal(L, "package");
 	lua_getfield(L, -1, "preload");
@@ -432,17 +68,17 @@
 	lua_setfield(L, -2, name.c_str());
 	lua_pop(L, 2);
 
-	LUAE_STACK_CHECKEQUALS(L);
+	assertEnd(L, 0);
 }
 
-void Luae::require(lua_State *L, const std::string &name, lua_CFunction func, bool global)
+void Luae::require(lua_State *L, const std::string &name, lua_CFunction func)
 {
-	LUAE_STACK_CHECKBEGIN(L);
+	assertBegin(L);
 
-	luaL_requiref(L, name.c_str(), func, global);
+	luaL_requiref(L, name.c_str(), func, false);
 	lua_pop(L, 1);
 
-	LUAE_STACK_CHECKEQUALS(L);
+	assertEnd(L, 0);
 }
 
 void *operator new(size_t size, lua_State *L)
--- a/C++/Luae.h	Fri May 09 09:15:52 2014 +0200
+++ b/C++/Luae.h	Fri May 09 17:12:25 2014 +0200
@@ -36,332 +36,6 @@
 
 #include <lua.hpp>
 
-#if !defined(NDEBUG)
-
-/**
- * Store the current stack size. Should be called at the beginning of a
- * function.
- *
- * @param L the Lua state
- */
-#define LUAE_STACK_CHECKBEGIN(L)					\
-	int __topstack = lua_gettop((L))
-
-/**
- * Check if the current stack size match the beginning. LUAE_STACK_CHECKBEGIN
- * must have been called.
- *
- * @param L the Lua state
- */
-#define LUAE_STACK_CHECKEQUALS(L)					\
-	assert(lua_gettop((L)) == __topstack)
-
-/**
- * Check if the current stack size match the condition. LUAE_STACK_CHECKBEGIN
- * must have been called.
- *
- * @param L the Lua state
- * @param cond the condition
- */
-#define LUAE_STACK_CHECKEND(L, cond)					\
-	assert(lua_gettop((L)) cond == __topstack)
-
-#else
-
-/**
- * Store the current stack size. Should be called at the beginning of a
- * function.
- *
- * @param L the Lua state
- */
-#define LUAE_STACK_CHECKBEGIN(L)
-
-/**
- * Check if the current stack size match the beginning. LUAE_STACK_CHECKBEGIN
- * must have been called.
- *
- * @param L the Lua state
- */
-#define LUAE_STACK_CHECKEQUALS(L)
-
-/**
- * Check if the current stack size match the condition. LUAE_STACK_CHECKBEGIN
- * must have been called.
- *
- * @param L the Lua state
- * @param cond the condition
- */
-#define LUAE_STACK_CHECKEND(L, cond)
-
-#endif
-
-/* {{{ LuaeState */
-
-/**
- * @class LuaeState
- * @brief Wrapper for lua_State
- *
- * This class automatically create a new Lua state and add implicit
- * cast operator plus RAII destruction.
- */
-class LuaeState {
-private:
-	struct Deleter {
-		void operator()(lua_State *L)
-		{
-			lua_close(L);
-		}
-	};
-
-	using Ptr = std::unique_ptr<lua_State, Deleter>;
-
-	Ptr m_state;
-
-	void initRegistry();
-
-public:
-	/**
-	 * The field stored into the registry to avoid recreation of shared
-	 * objects.
-	 */
-	static const char *FieldRefs;
-
-	/**
-	 * Deleted copy constructor.
-	 */
-	LuaeState(const LuaeState &) = delete;
-
-	/**
-	 * Deleted copy assignment.
-	 */
-	LuaeState &operator=(const LuaeState &) = delete;
-
-	/**
-	 * Default constructor. Create a new state.
-	 */
-	LuaeState();
-
-	/**
-	 * Use the already created state.
-	 *
-	 * @param L the state to use
-	 */
-	LuaeState(lua_State *L);
-
-	/**
-	 * Move constructor.
-	 *
-	 * @param state the Lua state to move
-	 */
-	LuaeState(LuaeState &&state);
-
-	/**
-	 * Move assignment operator.
-	 *
-	 * @param state the Lua state to move
-	 */
-	LuaeState &operator=(LuaeState &&state);
-
-	/**
-	 * Implicit cast operator for convenient usage to C Lua API.
-	 *
-	 * @return the state as lua_State *
-	 */
-	operator lua_State*();
-};
-
-/* }}} */
-
-/* {{{ LuaeClass */
-
-/**
- * @class LuaeClass
- * @brief Support for object oriented programming between C++ and Lua
- *
- * This class provides functions for passing and retrieving objects from C++ and
- * Lua.
- */
-class LuaeClass {
-public:
-	/**
-	 * Methods for a class.
-	 */
-	using Methods	= std::vector<luaL_Reg>;
-
-	/**
-	 * Smart pointer for Luae objects.
-	 */
-	template <typename T>
-	using Ptr	= std::shared_ptr<T>;
-
-	/**
-	 * @struct Def
-	 * @brief Definition of a class
-	 */
-	struct Def {
-		std::string	name;		//!< metatable name
-		Methods		methods;	//!< methods
-		Methods		metamethods;	//!< metamethods
-		const Def	*parent;	//!< optional parent class
-	};
-
-	/**
-	 * The field stored in the object metatable about the object metatable
-	 * name.
-	 */
-	static const char *FieldName;
-
-	/**
-	 * The field that holds all parent classes. It is used to verify casts.
-	 */
-	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"
-	 * 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:
-	 *
-	 * 1. The user can use the userdata as table key
-	 * 2. A performance gain thanks to less allocations
-	 *
-	 * @param L the Lua state
-	 * @param o the object to push
-	 * @param name the object metatable name
-	 */
-	template <typename T>
-	static void pushShared(lua_State *L, Ptr<T> o, const std::string &name)
-	{
-		LUAE_STACK_CHECKBEGIN(L);
-
-		lua_getfield(L, LUA_REGISTRYINDEX, LuaeState::FieldRefs);
-		assert(lua_type(L, -1) == LUA_TTABLE);
-
-		lua_rawgetp(L, -1, o.get());
-
-		if (lua_type(L, -1) == LUA_TNIL) {
-			lua_pop(L, 1);
-
-			new (L, name.c_str()) std::shared_ptr<T>(o);
-			
-			lua_pushvalue(L, -1);
-			lua_rawsetp(L, -3, o.get());
-		}
-
-		lua_replace(L, -2);
-
-		LUAE_STACK_CHECKEND(L, -1);
-	}
-
-	/**
-	 * Check if the object at index is suitable for cast to meta. Calls
-	 * luaL_error if not.
-	 *
-	 * @param L the Lua state
-	 * @param index the value index
-	 * @param meta the object name
-	 */
-	static void testShared(lua_State *L, int index, const char *meta);
-
-	/**
-	 * Get an object from Lua that was previously push with pushShared.
-	 *
-	 * @param L the Lua state
-	 * @param index the object index
-	 * @param meta the object metatable name
-	 * @return the object
-	 */
-	template <typename T>
-	static Ptr<T> getShared(lua_State *L, int index, const char *meta)
-	{
-		testShared(L, index, meta);
-		
-		return *static_cast<Ptr<T> *>(lua_touserdata(L, index));
-	}
-
-	/**
-	 * Delete the shared pointer at the given index. This function does
-	 * not check if the type is valid for performance reason. And because
-	 * it's usually called in __gc, there is no reason to check.
-	 *
-	 * Also return 0 the __gc method can directly call
-	 * return LuaeClass::deleteShared(...)
-	 *
-	 * @param L the Lua state
-	 * @param index the index
-	 * @return 0 for convenience
-	 */
-	template <typename T>
-	static int deleteShared(lua_State *L, int index)
-	{
-		LUAE_STACK_CHECKBEGIN(L);
-
-		static_cast<Ptr<T> *>(lua_touserdata(L, index))->~shared_ptr<T>();
-
-		LUAE_STACK_CHECKEQUALS(L);
-
-		return 0;
-	}
-};
-
-/* }}} */
-
-/* {{{ LuaeValue */
-
-/**
- * @class LuaeValue
- * @brief A fake variant for Lua values
- *
- * This class is primarly used for copying Lua values without checking
- * the types, useful to pass data.
- */
-class LuaeValue {
-private:
-	union {
-		lua_Number	 number;
-		bool		 boolean;
-	};
-
-	int type;
-	std::string str;
-	std::vector<std::pair<LuaeValue, LuaeValue>> table;
-
-public:
-	/**
-	 * Dump a value at the specific index.
-	 *
-	 * @param L the Lua state
-	 * @param index the value
-	 * @return a tree of values
-	 */
-	static LuaeValue copy(lua_State *L, int index);
-
-	/**
-	 * Push a value to a state.
-	 *
-	 * @param L the Lua state
-	 * @param value the value to push
-	 */
-	static void push(lua_State *L, const LuaeValue &value);
-
-	/**
-	 * Default constructor (type nil)
-	 */
-	LuaeValue();
-};
-
-/* }}} */
-
-/* {{{ Luae */
-
 /**
  * @class Luae
  * @brief Add lot of convenience for Lua
@@ -370,6 +44,9 @@
  */
 class Luae {
 private:
+	static constexpr const char *FieldRefs	= "__luae_refs";
+	static constexpr const char *FieldTop	= "__luae_topcheck";
+
 	/*
 	 * Wrapper for dofile and dostring.
 	 */
@@ -379,51 +56,16 @@
 	/**
 	 * Map from string to function.
 	 */
-	using Reg	= std::unordered_map<const char *, lua_CFunction>;
-
-	/**
-	 * @struct Convert
-	 * @brief Push or get values
-	 */
-	template <typename T>
-	struct Convert {
-		static const bool hasPush	= false;	//!< has push function
-		static const bool hasGet	= false;	//!< has get function
-		static const bool hasCheck	= false;	//!< has check function
-	};
+	using Reg = std::unordered_map<const char *, lua_CFunction>;
 
 	/**
-	 * @struct Iterator
-	 * @brief Wrap STL containers
-	 */
-	template <typename Type>
-	struct Iterator {
-		Type	begin;				//!< the beginning
-		Type	end;				//!< the end
-		Type	current;			//!< the current index
-
-		/**
-		 * Construct the iterator.
-		 *
-		 * @param begin the beginning
-		 * @param end the end
-		 */
-		Iterator(Type begin, Type end)
-			: begin(begin)
-			, end(end)
-			, current(begin)
-		{
-		}
-	};
-
-	/**
+	 * ## Userdata object
+	 *
 	 * Test if the object can be pushed as a userdata. If the object can
 	 * be pushed as a userdata, it must match the following requirements:
 	 *
 	 *	- Copy constructible
-	 *	- IsUserdata overload must have const char *MetatableName
-	 *
-	 * ## Userdata object
+	 *	- TypeInfo overload must have const char *name and inherit TypeUserdata
 	 *
 	 * The following example code allows the class Object to be pushed
 	 * and get as Lua userdata.
@@ -432,12 +74,10 @@
 	 * struct Object { };
 	 *
 	 * template <>
-	 * struct Luae::IsUserdata<Object> : std::true_type {
-	 * 	static const char *MetatableName;
+	 * struct Luae::TypeInfo<Object> : Luae::TypeUserdata {
+	 * 	static constexpr const char *name = "Object";
 	 * };
 	 *
-	 * const char *Luae::IsUserdata<Object>::MetatableName = "Object";
-	 *
 	 * int l_push(lua_State *L)
 	 * {
 	 * 	Luae::push(L, Object());
@@ -448,6 +88,7 @@
 	 * 	Object *o = Luae::get<Object>(L, 1);
 	 * }
 	 * @endcode
+	 *
 	 * @note You don't need to add the pointer type to the get template parameter
 	 *
 	 * ## Custom object
@@ -455,17 +96,15 @@
 	 * This other example can be used to push custom objects but not as
 	 * userdata. You can use this to push and read tables for instance.
 	 *
+	 * For this you must overload TypeInfo to the object and inherit to TypeCustom.
+	 *
 	 * @code
 	 * struct Point {
 	 * 	int x, y;
 	 * };
 	 *
 	 * template <>
-	 * struct Luae::Convert<Point> {
-	 * 	static const bool hasPush = true;
-	 * 	static const bool hasGet = true;
-	 * 	static const bool hasCheck = true;
-	 *
+	 * struct Luae::TypeInfo<Point> : Luae::TypeCustom {
 	 * 	static void push(lua_State *L, const Point &p)
 	 * 	{
 	 * 		lua_createtable(L, 0, 0);
@@ -509,20 +148,66 @@
 	 * 	Point p = Luae::get<Point>(L, 1);
 	 * }
 	 * @endcode
+	 *
 	 * @note Here you get a T and not a T *
 	 */
 	template <typename T>
-	struct IsUserdata : std::false_type { };
+	struct TypeInfo {
+		static const bool	isCustom = false;
+		static const bool	isUserdata = false;
+	};
+	
+	/**
+	 * Helpers for custom types. It is already overloaded for all standard
+	 * types :
+	 *	- int
+	 *	- bool
+	 *	- double
+	 *	- std::string
+	 *	- std::32string
+	 */
+	struct TypeCustom {
+		static const bool	canGet = true;
+		static const bool	canPush = true;
+		static const bool	canCheck = true;
+		static const bool	isCustom = true;
+		static const bool	isUserdata = false;
+	};
+
+	/**
+	 * Helper for userdata. It only require to set the name field
+	 * as the metatable name.
+	 */
+	struct TypeUserdata {
+		static const bool	isUserdata = true;
+		static const bool	isCustom = false;
+	};
 
 private:
 	template <typename T>
-	struct IsSharedUserdata : std::false_type { };
+	struct IsCustom {
+		static const bool value = TypeInfo<T>::isCustom;
+	};
+
+	template <typename T>
+	struct IsUserdata {
+		static const bool value = TypeInfo<T>::isUserdata;
+	};
+	
+	template <typename T>
+	struct IsSharedUserdata : std::false_type {};
 
 	template <typename T>
 	struct IsSharedUserdata<std::shared_ptr<T>> {
-		static const bool value = IsUserdata<T>::value;
+		static const bool value = TypeInfo<T>::isUserdata;
 	};
 
+	template <bool Cond, typename Type = void>
+	using EnableIf		= typename std::enable_if<Cond, Type>::type;
+
+	template <typename T>
+	using SharedType	= typename T::element_type;
+
 public:
 	/* -------------------------------------------------
 	 * Standard Lua API wrappers
@@ -610,6 +295,18 @@
 	}
 
 	/**
+	 * Create a table.
+	 *
+	 * @param L the Lua state
+	 * @param nr the number of array record
+	 * @param ns the number of sequence
+	 */
+	static inline void createtable(lua_State *L, int nr = 0, int ns = 0)
+	{
+		lua_createtable(L, nr, ns);
+	}
+
+	/**
 	 * Load and execute a file.
 	 *
 	 * @param L the Lua state
@@ -1190,6 +887,24 @@
 	 * ------------------------------------------------- */
 
 	/**
+	 * Call this prior to assertEnd.
+	 *
+	 * @param L the Lua state
+	 */
+	static void assertBegin(lua_State *L);
+
+	/**
+	 * Call this to check the stack size after asserBegin. The stack size
+	 * is automatically adjusted to the last size so the expected argument
+	 * can just be set to the real expected size just like if the stack size
+	 * were 0.
+	 *
+	 * @param L the Lua state
+	 * @param expected the stack size expected
+	 */
+	static void assertEnd(lua_State *L, int expected);
+
+	/**
 	 * Preload a library, it will be added to package.preload so the
 	 * user can successfully call require "name". In order to work, you need
 	 * to open luaopen_package and luaopen_base first.
@@ -1199,9 +914,7 @@
 	 * @param func the opening library
 	 * @see require
 	 */
-	static void preload(lua_State *L,
-			    const std::string &name,
-			    lua_CFunction func);
+	static void preload(lua_State *L, const std::string &name, lua_CFunction func);
 
 	/**
 	 * Load a library just like it was loaded with require.
@@ -1209,60 +922,71 @@
 	 * @param L the Lua state
 	 * @param name the module name
 	 * @param func the function
-	 * @param global store as global
 	 */
-	static void require(lua_State *L,
-			    const std::string &name,
-			    lua_CFunction func,
-			    bool global);
+	static void require(lua_State *L, const std::string &name, lua_CFunction func);
+
+	template <typename T>
+	static int push(lua_State *L,
+			 const T &value,
+			 EnableIf<IsCustom<T>::value, T> * = 0)
+	{
+		static_assert(TypeInfo<T>::canPush, "type not supported");
+
+		TypeInfo<T>::push(L, value);
+
+		return 1;
+	}
+
+	template <typename T>
+	static int push(lua_State *L,
+			 const T &value,
+			 EnableIf<IsUserdata<T>::value, T> * = 0)
+	{
+		new (L, TypeInfo<T>::name) T(value);
+
+		return 1;
+	}
 
-	/**
-	 * TODO: DOC
-	 *
-	 * @param L the Lua state
-	 * @param value the value
-	 */
 	template <typename T>
-	static void push(lua_State *L,
-			 const T &value,
-			 typename std::enable_if<!IsUserdata<T>::value, T>::type * = 0,
-			 typename std::enable_if<!IsSharedUserdata<T>::value, T>::type * = 0)
+	static int push(lua_State *L,
+			const std::shared_ptr<T> &value,
+			EnableIf<IsSharedUserdata<std::shared_ptr<T>>::value, T> * = 0)
 	{
-		static_assert(Convert<T>::hasPush, "type not supported");
+		assertBegin(L);
 
-		Convert<T>::push(L, value);
+		/*
+		 * If already in the registry use the same shared_ptr to get the same
+		 * pointer address within Lua. This let scripts using the object
+		 * as a table key for instance.
+		 */
+		getfield(L, LUA_REGISTRYINDEX, FieldRefs);
+		if (type(L, -1) == LUA_TNIL) {
+			pop(L);
+			createtable(L, 0, 0);
+			createtable(L, 0, 0);
+			pushfstring(L, "v");
+			setfield(L, -2, "__mode");
+			setmetatable(L, -2);
+			pushvalue(L, -1);
+			setfield(L, LUA_REGISTRYINDEX, FieldRefs);
+		}
+
+		rawget(L, -1, value.get());
+		if (type(L, -1) == LUA_TNIL) {
+			pop(L);
+			new (L, TypeInfo<T>::name) std::shared_ptr<T>(value);
+			pushvalue(L, -1);
+			rawset(L, -3, value.get());
+		}
+
+		// Remove refs table
+		remove(L, -2);
+
+		return 1;
 	}
 
 	/**
-	 * TODO: DOC
-	 *
-	 * @param L the Lua state
-	 * @param value the value
-	 */
-	template <typename T>
-	static void push(lua_State *L,
-			 const T &value,
-			 typename std::enable_if<IsUserdata<T>::value, T>::type * = 0)
-	{
-		new (L, IsUserdata<T>::MetatableName) T(value);
-	}
-
-	/**
-	 * TODO: DOC
-	 *
-	 * @param L the Lua state
-	 * @param value the value
-	 */
-	template <typename T, typename Type = typename T::element_type>
-	static void push(lua_State *L,
-			 const T &value,
-			 typename std::enable_if<IsSharedUserdata<T>::value>::type * = 0)
-	{
-		LuaeClass::pushShared<Type>(L, value, IsUserdata<Type>::MetatableName);
-	}
-
-	/**
-	 * Overload for string literals and arrays.
+	 * Overload for string literals.
 	 *
 	 * @param L the Lua state
 	 * @param s the string
@@ -1273,159 +997,50 @@
 		push<const char *>(L, s);
 	}
 
-	/**
-	 * Get the data, the type is not checked.
-	 *
-	 * @param L the Lua state
-	 * @param index the index
-	 * @return a T value
-	 */
 	template <typename T>
-	static T
-	get(lua_State *L,
-	    int index,
-	    typename std::enable_if<!IsUserdata<T>::value, T>::type * = 0,
-	    typename std::enable_if<!IsSharedUserdata<T>::value, T>::type * = 0)
+	static EnableIf<IsCustom<T>::value, T>
+	get(lua_State *L, int index)
 	{
-		static_assert(Convert<T>::hasGet, "type not supported");
+		static_assert(TypeInfo<T>::canGet, "type not supported");
 
-		return Convert<T>::get(L, index);
+		return TypeInfo<T>::get(L, index);
 	}
 
-	/**
-	 * Get a userdata object. The type is not checked and just cast.
-	 *
-	 * @param L the Lua state
-	 * @param index the index
-	 * @return a T * value
-	 */
 	template <typename T>
-	static T *
-	get(lua_State *L,
-	    int index,
-	    typename std::enable_if<IsUserdata<T>::value, T *>::type * = 0)
+	static EnableIf<IsUserdata<T>::value, T *>
+	get(lua_State *L, int index)
 	{
 		return Luae::toType<T *>(L, index);
 	}
-
-	/**
-	 * Get a shared pointer object created from LuaeClass. The type is not
-	 * checked.
-	 *
-	 * @param L the Lua state
-	 * @param index the index
-	 * @return a std::shared_ptr<>
-	 */
-	template <typename T, typename Type = typename T::element_type>
-	static std::shared_ptr<Type>
-	get(lua_State *L,
-	   int index,
-	   typename std::enable_if<IsSharedUserdata<T>::value, T>::type * = 0)
-	{
-		return LuaeClass::getShared<Type>(L, index);
-	}
-
-	/**
-	 * Check for a data. The type is checked.
-	 *
-	 * @param L the Lua state
-	 * @param index the index
-	 * @return a T value
-	 */
+	
 	template <typename T>
-	static T
-	check(lua_State *L,
-	      int index,
-	      typename std::enable_if<!IsUserdata<T>::value, T>::type * = 0,
-	      typename std::enable_if<!IsSharedUserdata<T>::value, T>::type * = 0)
+	static EnableIf<IsSharedUserdata<std::shared_ptr<T>>::value, std::shared_ptr<T>>
+	get(lua_State *L, int index)
 	{
-		static_assert(Convert<T>::hasCheck, "type not supported");
-
-		return Convert<T>::check(L, index);
+		return *Luae::toType<std::shared_ptr<T> *>(L, index);
 	}
+	
+	template <typename T>
+	static EnableIf<IsCustom<T>::value, T>
+	check(lua_State *L, int index)
+	{
+		static_assert(TypeInfo<T>::canCheck, "type not supported");
 
-	/**
-	 * Check for a userdata object.
-	 *
-	 * @param L the Lua state
-	 * @param index the index
-	 * @return a T * value
-	 */
-	template <typename T>
-	static T *
-	check(lua_State *L,
-	      int index,
-	      typename std::enable_if<IsUserdata<T>::value, T *>::type * = 0)
-	{
-		return Luae::toType<T *>(L, index, IsUserdata<T>::MetatableName);
+		return TypeInfo<T>::check(L, index);
 	}
 
-	/**
-	 * Check for a shared pointer object created from LuaeClass.
-	 *
-	 * @param L the Lua state
-	 * @param index the index
-	 * @return a std::shared_ptr<>
-	 */
-	template <typename T, typename Type = typename T::element_type>
-	static std::shared_ptr<Type>
-	check(lua_State *L,
-	      int index,
-	      typename std::enable_if<IsSharedUserdata<T>::value, T>::type * = 0)
+	template <typename T>
+	static EnableIf<IsUserdata<T>::value, T *>
+	check(lua_State *L, int index)
 	{
-		return LuaeClass::getShared<Type>(L, index, IsUserdata<Type>::MetatableName); 
+		return Luae::toType<T *>(L, index, TypeInfo<T>::name);
 	}
 
-	/**
-	 * Push an iterator function onto the stack. May be used by functions
-	 * calls or directly with __pairs.
-	 *
-	 * The container must at least have:
-	 *	value_type,
-	 *	const_iterator
-	 *
-	 * The value of the container must also be pushable with Luae::Convert.
-	 *
-	 * @param L the Lua state
-	 * @param container the container
-	 * @return 1
-	 */
-	template <typename Container,
-		  typename Converter = Convert<typename Container::value_type>>
-	static int pushIterator(lua_State *L, const Container &container)
+	template <typename T>
+	static EnableIf<IsSharedUserdata<T>::value, T>
+	check(lua_State *L, int index)
 	{
-		using ValueType		= typename Container::value_type;
-		using IteratorType	= typename Container::const_iterator;
-
-		LUAE_STACK_CHECKBEGIN(L);
-
-		new (L) Iterator<IteratorType>(container.cbegin(), container.cend());
-
-		lua_createtable(L, 0, 0);
-		lua_pushcfunction(L, [] (lua_State *L) -> int {
-			toType<Iterator<IteratorType> *>(L, 1)->~Iterator<IteratorType>();
-
-			return 0;
-		});
-		lua_setfield(L, -2, "__gc");
-		lua_setmetatable(L, -2);
-
-		// Push the iterator function
-		lua_pushcclosure(L, [] (lua_State *L) -> int {
-			auto it = toType<Iterator<IteratorType> *>(L, lua_upvalueindex(1));
-			auto top = lua_gettop(L);
-
-			if (it->current == it->end)
-				return 0;
-
-			Converter::push(L, *(it->current++));
-
-			return lua_gettop(L) - top;
-		}, 1);
-
-		LUAE_STACK_CHECKEND(L, -1);
-		
-		return 1;
+		return *Luae::toType<T *>(L, index, TypeInfo<SharedType<T>>::name);
 	}
 
 	/**
@@ -1462,8 +1077,9 @@
  * @brief Overload for nil.
  */
 template <>
-struct Luae::Convert<std::nullptr_t> {
-	static const bool hasPush	= true;	//!< push supported
+struct Luae::TypeInfo<std::nullptr_t> : Luae::TypeCustom {
+	static const bool canGet	= false;
+	static const bool canCheck	= false;
 
 	/**
 	 * Push nil.
@@ -1480,11 +1096,7 @@
  * @brief Overload for booleans.
  */
 template <>
-struct Luae::Convert<bool> {
-	static const bool hasPush	= true;	//!< push supported
-	static const bool hasGet	= true;	//!< get supported
-	static const bool hasCheck	= true;	//!< check supported
-
+struct Luae::TypeInfo<bool> : Luae::TypeCustom {
 	/**
 	 * Push the boolean value.
 	 *
@@ -1524,11 +1136,7 @@
  * @brief Overload for integers.
  */
 template <>
-struct Luae::Convert<int> {
-	static const bool hasPush	= true;	//!< push supported
-	static const bool hasGet	= true;	//!< get supported
-	static const bool hasCheck	= true;	//!< check supported
-
+struct Luae::TypeInfo<int> : Luae::TypeCustom {
 	/**
 	 * Push the integer value.
 	 *
@@ -1568,11 +1176,7 @@
  * @brief Overload for longs.
  */
 template <>
-struct Luae::Convert<long> {
-	static const bool hasPush	= true;	//!< push supported
-	static const bool hasGet	= true;	//!< get supported
-	static const bool hasCheck	= true;	//!< check supported
-
+struct Luae::TypeInfo<long> : Luae::TypeCustom {
 	/**
 	 * Push the integer value.
 	 *
@@ -1612,11 +1216,7 @@
  * @brief Overload for doubles.
  */
 template <>
-struct Luae::Convert<double> {
-	static const bool hasPush	= true;	//!< push supported
-	static const bool hasGet	= true;	//!< get supported
-	static const bool hasCheck	= true;	//!< check supported
-
+struct Luae::TypeInfo<double> : Luae::TypeCustom {
 	/**
 	 * Push the double value.
 	 *
@@ -1656,11 +1256,7 @@
  * @brief Overload for std::string.
  */
 template <>
-struct Luae::Convert<std::string> {
-	static const bool hasPush	= true;	//!< push supported
-	static const bool hasGet	= true;	//!< get supported
-	static const bool hasCheck	= true;	//!< check supported
-
+struct Luae::TypeInfo<std::string> : Luae::TypeCustom {
 	/**
 	 * Push the string value.
 	 *
@@ -1700,11 +1296,7 @@
  * @brief Overload for std::u32string.
  */
 template <>
-struct Luae::Convert<std::u32string> {
-	static const bool hasPush	= true;	//!< push supported
-	static const bool hasGet	= true;	//!< get supported
-	static const bool hasCheck	= true;	//!< check supported
-
+struct Luae::TypeInfo<std::u32string> : Luae::TypeCustom {
 	/**
 	 * Push the string value.
 	 *
@@ -1767,80 +1359,10 @@
 };
 
 /**
- * @brief Overload for string list
- */
-template <>
-struct Luae::Convert<std::vector<std::string>> {
-	static const bool hasPush	= true;	//!< push supported
-	static const bool hasGet	= true; //!< get supported
-	static const bool hasCheck	= true; //!< check supported
-
-	/**
-	 * Push a string list.
-	 *
-	 * @param L the Lua state
-	 * @param value the value
-	 */
-	static void push(lua_State *L, const std::vector<std::string> &value)
-	{
-		int i = 0;
-
-		lua_createtable(L, value.size(), 0);
-		for (const auto &s : value) {
-			lua_pushlstring(L, s.c_str(), s.length());
-			lua_rawseti(L, -2, ++i);
-		}
-	}
-
-	/**
-	 * Get a string list.
-	 *
-	 * @param L the Lua state
-	 * @param index the index
-	 * @return the list
-	 */
-	static std::vector<std::string> get(lua_State *L, int index)
-	{
-		std::vector<std::string> list;
-
-		if (index < 0)
-			-- index;
-
-		lua_pushnil(L);
-		while (lua_next(L, index)) { 
-			if (lua_type(L, -1) == LUA_TSTRING)
-				list.push_back(lua_tostring(L, -1));
-
-			lua_pop(L, 1);
-		}
-
-		return list;
-	}
-
-	/**
-	 * Check for a string list.
-	 *
-	 * @param L the Lua state
-	 * @param index the index
-	 * @return the list
-	 */
-	static std::vector<std::string> check(lua_State *L, int index)
-	{
-		luaL_checktype(L, index, LUA_TTABLE);
-
-		return get(L, index);
-	}
-};
-
-/**
  * @brief Overload for const char *
  */
 template <>
-struct Luae::Convert<const char *> {
-	static const bool hasPush	= true;	//!< push supported
-	static const bool hasGet	= true;	//!< get supported
-	static const bool hasCheck	= true;	//!< check supported
-
+struct Luae::TypeInfo<const char *> : Luae::TypeCustom {
 	/**
 	 * Push the string value.
 	 *
@@ -1876,244 +1398,6 @@
 	}
 };
 
-/* }}} */
-
-/* {{{ LuaeTable */
-
-/**
- * @class LuaeTable
- * @brief Some function for table manipulation
- *
- * Read, reference and get fields from tables.
- */
-class LuaeTable {
-public:
-	/**
-	 * The map function for \ref read
-	 */
-	using ReadFunction = std::function<void(lua_State *L, int tkey, int tvalue)>;
-
-	/**
-	 * Push a new table onto the stack.
-	 *
-	 * @param L the Lua state
-	 * @param nrec the optional number of entries as record
-	 * @param narr the optional number of entries as sequence
-	 */
-	static void create(lua_State *L, int nrec = 0, int narr = 0);
-
-	/**
-	 * Get a field of a specific type from a table. Specialized for the
-	 * types: int, double, bool and string.
-	 *
-	 * @param L the Lua state
-	 * @param idx the table index
-	 * @param name the field name
-	 * @return the converted type.
-	 */
-	template <typename T>
-	static T get(lua_State *L, int idx, const std::string &name)
-	{
-		LUAE_STACK_CHECKBEGIN(L);
-
-		lua_getfield(L, idx, name.c_str());
-		auto t = Luae::get<T>(L, -1);
-		lua_pop(L, 1);
-
-		LUAE_STACK_CHECKEQUALS(L);
-
-		return t;
-	}
-
-	/**
-	 * Set a table field. Specialized for the same fields as get.
-	 *
-	 * @param L the Lua state
-	 * @param idx the index
-	 * @param name the field name
-	 * @param value the value
-	 * @see get
-	 */
-	template <typename T>
-	static void set(lua_State *L, int idx, const std::string &name, const T &value)
-	{
-		LUAE_STACK_CHECKBEGIN(L);
-
-		Luae::push(L, value);
-		Luae::setfield(L, (idx < 0) ? --idx : idx, name);
-
-		LUAE_STACK_CHECKEQUALS(L);
-	}
-
-	/**
-	 * Overload for string literals.
-	 *
-	 * @param L the Lua state
-	 * @param idx the index
-	 * @param name the field name
-	 * @param s the string
-	 */
-	template <size_t N>
-	static void set(lua_State *L, int idx, const std::string &name, const char (&s)[N])
-	{
-		set<const char *>(L, idx, name, s);
-	}
-
-	/**
-	 * Require a field from a table.
-	 *
-	 * @param L the Lua state
-	 * @param idx the table index
-	 * @param name the field name
-	 * @return the value or call luaL_error
-	 */
-	template <typename T>
-	static T require(lua_State *L, int idx, const std::string &name)
-	{
-		LUAE_STACK_CHECKBEGIN(L);
-
-		lua_getfield(L, idx, name.c_str());
-
-		if (lua_type(L, -1) == LUA_TNIL)
-			luaL_error(L, "missing field `%s'", name.c_str());
-			// NOT REACHED
-
-		lua_pop(L, 1);
-		auto v = get<T>(L, idx, name);
-
-		LUAE_STACK_CHECKEQUALS(L);
-
-		return v;
-	}
-
-	/**
-	 * Check a table field.
-	 *
-	 * @param L the Lua state
-	 * @param idx the table index
-	 * @param name the field name
-	 * @return the type
-	 */
-	static int type(lua_State *L, int idx, const std::string &name);
-
-	/**
-	 * Read a table, the function func is called for each element in the
-	 * table. Parameter tkey is the Lua type of the key, parameter tvalue is
-	 * the Lua type of the value. The key is available at index -2 and the
-	 * value at index -1.
-	 *
-	 * <strong>Do not pop anything within the function.</strong>
-	 *
-	 * @param L the Lua state
-	 * @param idx the table index
-	 * @param func the function to call
-	 */
-	static void read(lua_State *L, int idx, ReadFunction func);
-
-	/**
-	 * Reference a field from a table at the index. The reference is created in
-	 * the registry only if type matches.
-	 *
-	 * @param L the Lua state
-	 * @param idx the table index
-	 * @param type the type requested
-	 * @param name the field name
-	 * @return the reference or LUA_REFNIL on problem
-	 */
-	static int ref(lua_State *L,
-		       int idx,
-		       int type,
-		       const std::string &name);
-};
-
-/* }}} */
-
-/* {{{ LuaeEnum */
-
-/**
- * @class LuaeEnum
- * @brief Binds and get enumeration
- *
- * Bind C/C++ enumeration as tables to Lua in the key-value form. Two
- * methods push and get are also available for enumeration flags.
- */
-class LuaeEnum {
-public:
-	/**
-	 * The definition of the enumeration
-	 */
-	using Def = std::unordered_map<const char *, int>;
-
-	/**
-	 * Bind the enumeration and keep it at the top of the stack.
-	 *
-	 * @param L the Lua state
-	 * @param def the definition
-	 */
-	static void create(lua_State *L, const Def &def);
-
-	/**
-	 * Set the enumeration values to an existing table.
-	 *
-	 * @param L the Lua state
-	 * @param def the definition
-	 * @param index the table index
-	 */
-	static void create(lua_State *L, const Def &def, int index);
-
-	/**
-	 * Create the enumeration table and set it to a table field.
-	 *
-	 * @param L the Lua state
-	 * @param def the definition
-	 * @param index the table index
-	 * @param name the field name to store the enumeration
-	 */
-	static void create(lua_State *L, const Def &def, int index, const std::string &name);
-
-	/**
-	 * Push the value enumeration as a table to Lua. This is used
-	 * as the OR replacement.
-	 *
-	 * The table is pushed in the following manner:
-	 *
-	 * t[i] = i
-	 * t[j] = j
-	 *
-	 * Where i and j are enumeration values so user can check which flag is enabled by
-	 * just testing the presence of the field.
-	 *
-	 * @param L the Lua state
-	 * @param def the definition
-	 * @param value the value
-	 */
-	static void push(lua_State *L, const Def &def, int value);
-
-	/**
-	 * Get the enumeration from Lua. Returns 0 if the value at the index
-	 * is not a table.
-	 *
-	 * This is used as the OR replacement.
-	 *
-	 * @param L the Lua state
-	 * @param index the value index
-	 * @return the value
-	 */
-	static int get(lua_State *L, int index);
-
-	/**
-	 * Require a enumeration from Lua. Calls luaL_error if the value at the given index
-	 * is not a table.
-	 *
-	 * @param L the Lua state
-	 * @param index the value index
-	 * @return the value
-	 */
-	static int require(lua_State *L, int index);
-};
-
-/* }}} */
-
 /**
  * Push a Lua userdata.
  *
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/LuaeClass.cpp	Fri May 09 17:12:25 2014 +0200
@@ -0,0 +1,104 @@
+/*
+ * LuaeClass.cpp -- Lua object management
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "LuaeClass.h"
+
+const char *LuaeClass::FieldName	= "__name";
+const char *LuaeClass::FieldParents	= "__parents";
+
+void LuaeClass::create(lua_State *L, const Def &def)
+{
+	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) {
+		for (auto m : def.metamethods) {
+			lua_pushcfunction(L, m.func);
+			lua_setfield(L, -2, m.name);
+		}
+	}
+
+	// Methods
+	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);
+}
+
+void LuaeClass::testShared(lua_State *L, int index, const char *meta)
+{
+	luaL_checktype(L, index, LUA_TUSERDATA);
+	if (!luaL_getmetafield(L, index, FieldName))
+		luaL_error(L, "invalid type cast");
+
+	// 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 cast");
+
+		lua_pushnil(L);
+		while (lua_next(L, -2) != 0) {
+			if (lua_type(L, -2) != LUA_TSTRING) {
+				lua_pop(L, 1);
+				continue;
+			}
+
+			auto tn = lua_tostring(L, -1);
+			if (std::string(tn) == std::string(meta))
+				found = true;
+
+			lua_pop(L, 1);
+		}
+
+		lua_pop(L, 1);
+	}
+
+	if (!found)
+		luaL_error(L, "invalid cast from `%s' to `%s'", name, meta);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/LuaeClass.h	Fri May 09 17:12:25 2014 +0200
@@ -0,0 +1,154 @@
+/*
+ * LuaeClass.h -- Lua object management
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _LUAE_CLASS_H_
+#define _LUAE_CLASS_H_
+
+#include <lua.hpp>
+
+/**
+ * @class LuaeClass
+ * @brief Support for object oriented programming between C++ and Lua
+ *
+ * This class provides functions for passing and retrieving objects from C++ and
+ * Lua.
+ */
+class LuaeClass {
+public:
+	/**
+	 * Methods for a class.
+	 */
+	using Methods	= std::vector<luaL_Reg>;
+
+	/**
+	 * Smart pointer for Luae objects.
+	 */
+	template <typename T>
+	using Ptr	= std::shared_ptr<T>;
+
+	/**
+	 * @struct Def
+	 * @brief Definition of a class
+	 */
+	struct Def {
+		std::string	name;		//!< metatable name
+		Methods		methods;	//!< methods
+		Methods		metamethods;	//!< metamethods
+		const Def	*parent;	//!< optional parent class
+	};
+
+	/**
+	 * The field stored in the object metatable about the object metatable
+	 * name.
+	 */
+	static const char *FieldName;
+
+	/**
+	 * The field that holds all parent classes. It is used to verify casts.
+	 */
+	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"
+	 * 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:
+	 *
+	 * 1. The user can use the userdata as table key
+	 * 2. A performance gain thanks to less allocations
+	 *
+	 * @param L the Lua state
+	 * @param o the object to push
+	 * @param name the object metatable name
+	 */
+	template <typename T>
+	static void pushShared(lua_State *L, Ptr<T> o, const std::string &name)
+	{
+		lua_getfield(L, LUA_REGISTRYINDEX, LuaeState::FieldRefs);
+		assert(lua_type(L, -1) == LUA_TTABLE);
+
+		lua_rawgetp(L, -1, o.get());
+
+		if (lua_type(L, -1) == LUA_TNIL) {
+			lua_pop(L, 1);
+
+			new (L, name.c_str()) std::shared_ptr<T>(o);
+			
+			lua_pushvalue(L, -1);
+			lua_rawsetp(L, -3, o.get());
+		}
+
+		lua_replace(L, -2);
+	}
+
+	/**
+	 * Check if the object at index is suitable for cast to meta. Calls
+	 * luaL_error if not.
+	 *
+	 * @param L the Lua state
+	 * @param index the value index
+	 * @param meta the object name
+	 */
+	static void testShared(lua_State *L, int index, const char *meta);
+
+	/**
+	 * Get an object from Lua that was previously push with pushShared.
+	 *
+	 * @param L the Lua state
+	 * @param index the object index
+	 * @param meta the object metatable name
+	 * @return the object
+	 */
+	template <typename T>
+	static Ptr<T> getShared(lua_State *L, int index, const char *meta)
+	{
+		testShared(L, index, meta);
+		
+		return *static_cast<Ptr<T> *>(lua_touserdata(L, index));
+	}
+
+	/**
+	 * Delete the shared pointer at the given index. This function does
+	 * not check if the type is valid for performance reason. And because
+	 * it's usually called in __gc, there is no reason to check.
+	 *
+	 * Also return 0 the __gc method can directly call
+	 * return LuaeClass::deleteShared(...)
+	 *
+	 * @param L the Lua state
+	 * @param index the index
+	 * @return 0 for convenience
+	 */
+	template <typename T>
+	static int deleteShared(lua_State *L, int index)
+	{
+		static_cast<Ptr<T> *>(lua_touserdata(L, index))->~shared_ptr<T>();
+
+		return 0;
+	}
+};
+
+#endif // !_LUAE_CLASS_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/LuaeEnum.cpp	Fri May 09 17:12:25 2014 +0200
@@ -0,0 +1,86 @@
+
+#include "LuaeEnum.h"
+
+void LuaeEnum::create(lua_State *L, const Def &def)
+{
+	LUAE_STACK_CHECKBEGIN(L);
+
+	lua_createtable(L, 0, 0);
+
+	for (auto p : def) {
+		lua_pushinteger(L, p.second);
+		lua_setfield(L, -2, p.first);
+	}
+
+	LUAE_STACK_CHECKEND(L, - 1);
+}
+
+void LuaeEnum::create(lua_State *L, const Def &def, int index)
+{
+	LUAE_STACK_CHECKBEGIN(L);
+
+	if (index < 0)
+		-- index;
+
+	for (auto p : def) {
+		lua_pushinteger(L, p.second);
+		lua_setfield(L, index, p.first);
+	}
+
+	LUAE_STACK_CHECKEQUALS(L);
+}
+
+void LuaeEnum::create(lua_State *L,
+		      const Def &def,
+		      int index,
+		      const std::string &name)
+{
+	LUAE_STACK_CHECKBEGIN(L);
+
+	create(L, def);
+
+	if (index < 0)
+		-- index;
+
+	lua_setfield(L, index, name.c_str());
+
+	LUAE_STACK_CHECKEQUALS(L);
+}
+
+void LuaeEnum::push(lua_State *L, const Def &def, int value)
+{
+	LUAE_STACK_CHECKBEGIN(L);
+	lua_createtable(L, 0, 0);
+
+	for (auto p : def) {
+		if (value & p.second) {
+			lua_pushinteger(L, p.second);
+			lua_setfield(L, -2, p.first);
+		}
+	}
+
+	LUAE_STACK_CHECKEND(L, - 1);
+}
+
+int LuaeEnum::get(lua_State *L, int index)
+{
+	int value = 0;
+
+	LUAE_STACK_CHECKBEGIN(L);
+	luaL_checktype(L, index, LUA_TTABLE);
+
+	if (index < 0)
+		-- index;
+
+	lua_pushnil(L);
+	while (lua_next(L, index)) {
+		if (lua_type(L, -1) == LUA_TNUMBER)
+			value |= lua_tointeger(L, -1);
+
+		lua_pop(L, 1);
+	}
+
+	LUAE_STACK_CHECKEQUALS(L);
+
+	return value;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/LuaeEnum.h	Fri May 09 17:12:25 2014 +0200
@@ -0,0 +1,91 @@
+/*
+ * LuaeEnum.h -- Lua enumeration helpers
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _LUAE_ENUM_H_
+#define _LUAE_ENUM_H_
+
+#include <lua.hpp>
+
+/**
+ * @class LuaeEnum
+ * @brief Binds and get enumeration
+ *
+ * Bind C/C++ enumeration as tables to Lua in the key-value form. Two
+ * methods push and get are also available for enumeration flags.
+ */
+class LuaeEnum {
+public:
+	/**
+	 * The definition of the enumeration
+	 */
+	using Def = std::unordered_map<const char *, int>;
+
+	/**
+	 * Bind the enumeration and keep it at the top of the stack.
+	 *
+	 * @param L the Lua state
+	 * @param def the definition
+	 */
+	static void create(lua_State *L, const Def &def);
+
+	/**
+	 * Set the enumeration values to an existing table.
+	 *
+	 * @param L the Lua state
+	 * @param def the definition
+	 * @param index the table index
+	 */
+	static void create(lua_State *L, const Def &def, int index);
+
+	/**
+	 * Create the enumeration table and set it to a table field.
+	 *
+	 * @param L the Lua state
+	 * @param def the definition
+	 * @param index the table index
+	 * @param name the field name to store the enumeration
+	 */
+	static void create(lua_State *L,
+			   const Def &def,
+			   int index,
+			   const std::string &name);
+
+	/**
+	 * Push the value enumeration as a table to Lua. This is used
+	 * as the OR replacement.
+	 *
+	 * @param L the Lua state
+	 * @param def the definition
+	 * @param value the value
+	 */
+	static void push(lua_State *L, const Def &def, int value);
+
+	/**
+	 * Get the enumeration from Lua. Raises an error if the
+	 * value at the index is not a table.
+	 *
+	 * This is used as the OR replacement.
+	 *
+	 * @param L the Lua state
+	 * @param index the value index
+	 * @return the value
+	 */
+	static int get(lua_State *L, int index);
+};
+
+#endif // !_LUAE_ENUM_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/LuaeState.cpp	Fri May 09 17:12:25 2014 +0200
@@ -0,0 +1,28 @@
+#include "LuaeState.h"
+
+LuaeState::LuaeState()
+{
+	m_state = Ptr(luaL_newstate());
+}
+
+LuaeState::LuaeState(lua_State *L)
+{
+	m_state = Ptr(L);
+}
+
+LuaeState::LuaeState(LuaeState &&state)
+{
+	m_state = std::move(state.m_state);
+}
+
+LuaeState &LuaeState::operator=(LuaeState &&state)
+{
+	m_state = std::move(state.m_state);
+
+	return *this;
+}
+
+LuaeState::operator lua_State*()
+{
+	return m_state.get();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/LuaeState.h	Fri May 09 17:12:25 2014 +0200
@@ -0,0 +1,91 @@
+/*
+ * LuaeState.h -- Lua RAII wrapper for lua_State
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _LUAE_STATE_H_
+#define _LUAE_STATE_H_
+
+#include <memory>
+
+#include <lua.hpp>
+
+/**
+ * @class LuaeState
+ * @brief Wrapper for lua_State
+ *
+ * This class automatically create a new Lua state and add implicit
+ * cast operator plus RAII destruction.
+ */
+class LuaeState {
+private:
+	struct Deleter {
+		void operator()(lua_State *L)
+		{
+			lua_close(L);
+		}
+	};
+
+	using Ptr = std::unique_ptr<lua_State, Deleter>;
+
+	Ptr m_state;
+
+public:
+	/**
+	 * Deleted copy constructor.
+	 */
+	LuaeState(const LuaeState &) = delete;
+
+	/**
+	 * Deleted copy assignment.
+	 */
+	LuaeState &operator=(const LuaeState &) = delete;
+
+	/**
+	 * Default constructor. Create a new state.
+	 */
+	LuaeState();
+
+	/**
+	 * Use the already created state.
+	 *
+	 * @param L the state to use
+	 */
+	LuaeState(lua_State *L);
+
+	/**
+	 * Move constructor.
+	 *
+	 * @param state the Lua state to move
+	 */
+	LuaeState(LuaeState &&state);
+
+	/**
+	 * Move assignment operator.
+	 *
+	 * @param state the Lua state to move
+	 */
+	LuaeState &operator=(LuaeState &&state);
+
+	/**
+	 * Implicit cast operator for convenient usage to C Lua API.
+	 *
+	 * @return the state as lua_State *
+	 */
+	operator lua_State*();
+};
+
+#endif // !_LUAE_STATE_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/LuaeTable.cpp	Fri May 09 17:12:25 2014 +0200
@@ -0,0 +1,76 @@
+/*
+ * LuaeTable.cpp -- Lua table helpers
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "LuaeTable.h"
+
+void LuaeTable::create(lua_State *L, int nrec, int narr)
+{
+	LUAE_STACK_CHECKBEGIN(L);
+
+	lua_createtable(L, nrec, narr);
+
+	LUAE_STACK_CHECKEND(L, - 1);
+}
+
+int LuaeTable::type(lua_State *L, int idx, const std::string &name)
+{
+	int type;
+
+	LUAE_STACK_CHECKBEGIN(L);
+
+	lua_getfield(L, idx, name.c_str());
+	type = lua_type(L, -1);
+	lua_pop(L, 1);
+
+	LUAE_STACK_CHECKEQUALS(L);
+
+	return type;
+}
+
+void LuaeTable::read(lua_State *L, int idx, ReadFunction func)
+{
+	LUAE_STACK_CHECKBEGIN(L);
+
+	lua_pushnil(L);
+
+	if (idx < 0)
+		--idx;
+
+	while (lua_next(L, idx)) {
+		func(L, lua_type(L, -2), lua_type(L, -1));
+		lua_pop(L, 1);
+	}
+
+	LUAE_STACK_CHECKEQUALS(L);
+}
+
+int LuaeTable::ref(lua_State *L, int idx, int type, const std::string &name)
+{
+	int ref = LUA_REFNIL;
+
+	lua_getfield(L, idx, name.c_str());
+
+	if (lua_type(L, -1) == type) {
+		lua_pushvalue(L, -1);
+		ref = luaL_ref(L, LUA_REGISTRYINDEX);
+	}
+
+	lua_pop(L, 1);
+
+	return ref;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/LuaeTable.h	Fri May 09 17:12:25 2014 +0200
@@ -0,0 +1,170 @@
+/*
+ * LuaeTable.h -- Lua table helpers
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _LUAE_TABLE_H_
+#define _LUAE_TABLE_H_
+
+#include <lua.hpp>
+
+/**
+ * @class LuaeTable
+ * @brief Some function for table manipulation
+ *
+ * Read, reference and get fields from tables.
+ */
+class LuaeTable {
+public:
+	/**
+	 * The map function for \ref read
+	 */
+	using ReadFunction = std::function<void(lua_State *L, int tkey, int tvalue)>;
+
+	/**
+	 * Push a new table onto the stack.
+	 *
+	 * @param L the Lua state
+	 * @param nrec the optional number of entries as record
+	 * @param narr the optional number of entries as sequence
+	 */
+	static void create(lua_State *L, int nrec = 0, int narr = 0);
+
+	/**
+	 * Get a field of a specific type from a table. Specialized for the
+	 * types: int, double, bool and string.
+	 *
+	 * @param L the Lua state
+	 * @param idx the table index
+	 * @param name the field name
+	 * @return the converted type.
+	 */
+	template <typename T>
+	static T get(lua_State *L, int idx, const std::string &name)
+	{
+		LUAE_STACK_CHECKBEGIN(L);
+
+		lua_getfield(L, idx, name.c_str());
+		auto t = Luae::get<T>(L, -1);
+		lua_pop(L, 1);
+
+		LUAE_STACK_CHECKEQUALS(L);
+
+		return t;
+	}
+
+	/**
+	 * Set a table field. Specialized for the same fields as get.
+	 *
+	 * @param L the Lua state
+	 * @param idx the index
+	 * @param name the field name
+	 * @param value the value
+	 * @see get
+	 */
+	template <typename T>
+	static void set(lua_State *L, int idx, const std::string &name, const T &value)
+	{
+		LUAE_STACK_CHECKBEGIN(L);
+
+		Luae::push(L, value);
+		Luae::setfield(L, (idx < 0) ? --idx : idx, name);
+
+		LUAE_STACK_CHECKEQUALS(L);
+	}
+
+	/**
+	 * Overload for string literals.
+	 *
+	 * @param L the Lua state
+	 * @param idx the index
+	 * @param name the field name
+	 * @param s the string
+	 */
+	template <size_t N>
+	static void set(lua_State *L, int idx, const std::string &name, const char (&s)[N])
+	{
+		set<const char *>(L, idx, name, s);
+	}
+
+	/**
+	 * Require a field from a table.
+	 *
+	 * @param L the Lua state
+	 * @param idx the table index
+	 * @param name the field name
+	 * @return the value or call luaL_error
+	 */
+	template <typename T>
+	static T require(lua_State *L, int idx, const std::string &name)
+	{
+		LUAE_STACK_CHECKBEGIN(L);
+
+		lua_getfield(L, idx, name.c_str());
+
+		if (lua_type(L, -1) == LUA_TNIL)
+			luaL_error(L, "missing field `%s'", name.c_str());
+			// NOT REACHED
+
+		lua_pop(L, 1);
+		auto v = get<T>(L, idx, name);
+
+		LUAE_STACK_CHECKEQUALS(L);
+
+		return v;
+	}
+
+	/**
+	 * Check a table field.
+	 *
+	 * @param L the Lua state
+	 * @param idx the table index
+	 * @param name the field name
+	 * @return the type
+	 */
+	static int type(lua_State *L, int idx, const std::string &name);
+
+	/**
+	 * Read a table, the function func is called for each element in the
+	 * table. Parameter tkey is the Lua type of the key, parameter tvalue is
+	 * the Lua type of the value. The key is available at index -2 and the
+	 * value at index -1.
+	 *
+	 * <strong>Do not pop anything within the function.</strong>
+	 *
+	 * @param L the Lua state
+	 * @param idx the table index
+	 * @param func the function to call
+	 */
+	static void read(lua_State *L, int idx, ReadFunction func);
+
+	/**
+	 * Reference a field from a table at the index. The reference is created in
+	 * the registry only if type matches.
+	 *
+	 * @param L the Lua state
+	 * @param idx the table index
+	 * @param type the type requested
+	 * @param name the field name
+	 * @return the reference or LUA_REFNIL on problem
+	 */
+	static int ref(lua_State *L,
+		       int idx,
+		       int type,
+		       const std::string &name);
+};
+
+#endif // !_LUAE_TABLE_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/LuaeVariant.cpp	Fri May 09 17:12:25 2014 +0200
@@ -0,0 +1,92 @@
+/*
+ * LuaeVariant.cpp -- Lua variant helper
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "LuaeVariant.h"
+
+LuaeVariant LuaeVariant::copy(lua_State *L, int index)
+{
+	LuaeVariant v;
+
+	v.type = lua_type(L, index);
+
+	switch (v.type) {
+	case LUA_TBOOLEAN:
+		v.boolean = lua_toboolean(L, index);
+		break;
+	case LUA_TNUMBER:
+		v.number = lua_tonumber(L, index);
+		break;
+	case LUA_TSTRING:
+		v.str = lua_tostring(L, index);
+		break;
+	case LUA_TTABLE:
+	{
+		if (index < 0)
+			-- index;
+
+		lua_pushnil(L);
+		while (lua_next(L, index)) {
+			v.table.push_back(std::make_pair(copy(L, -2), copy(L, -1)));
+			lua_pop(L, 1);
+		}
+
+		break;
+	}
+	default:
+		v.type = LUA_TNIL;
+		break;
+	}
+
+	return v;
+}
+
+void LuaeVariant::push(lua_State *L, const LuaeVariant &value)
+{
+	switch (value.type) {
+	case LUA_TBOOLEAN:
+		lua_pushboolean(L, value.boolean);
+		break;
+	case LUA_TSTRING:
+		lua_pushlstring(L,  value.str.c_str(), value.str.size());
+		break;
+	case LUA_TNUMBER:
+		lua_pushnumber(L, value.number);
+		break;
+	case LUA_TTABLE:
+	{
+		lua_createtable(L, 0, 0);
+
+		for (auto p : value.table) {
+			push(L, p.first);
+			push(L, p.second);
+
+			lua_settable(L, -3);
+		}
+		break;
+	}
+	default:
+		lua_pushnil(L);
+		break;
+	}
+}
+
+LuaeVariant::LuaeVariant()
+	: type(LUA_TNIL)
+{
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/LuaeVariant.h	Fri May 09 17:12:25 2014 +0200
@@ -0,0 +1,66 @@
+/*
+ * LuaeVariant.h -- Lua variant helper
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _LUAE_VARIANT_H_
+#define _LUAE_VARIANT_H_
+
+#include <lua.hpp>
+
+/**
+ * @class LuaeVariant
+ * @brief A fake variant for Lua values
+ *
+ * This class is primarly used for copying Lua values without checking
+ * the types, useful to pass data.
+ */
+class LuaeVariant {
+private:
+	union {
+		lua_Number	 number;
+		bool		 boolean;
+	};
+
+	int type;
+	std::string str;
+	std::vector<std::pair<LuaeVariant, LuaeVariant>> table;
+
+public:
+	/**
+	 * Dump a value at the specific index.
+	 *
+	 * @param L the Lua state
+	 * @param index the value
+	 * @return a tree of values
+	 */
+	static LuaeVariant copy(lua_State *L, int index);
+
+	/**
+	 * Push a value to a state.
+	 *
+	 * @param L the Lua state
+	 * @param value the value to push
+	 */
+	static void push(lua_State *L, const LuaeVariant &value);
+
+	/**
+	 * Default constructor (type nil)
+	 */
+	LuaeVariant();
+};
+
+#endif // !_LUAE_VARIANT_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/Tests/Luae/CMakeLists.txt	Fri May 09 17:12:25 2014 +0200
@@ -0,0 +1,41 @@
+#
+# CMakeLists.txt -- tests for Luae classes
+#
+# Copyright (c) 2014 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+find_package(Lua52 REQUIRED)
+
+set(
+	LUAE_SOURCES
+	${code_SOURCE_DIR}/C++/Luae.cpp
+	${code_SOURCE_DIR}/C++/Luae.h
+	${code_SOURCE_DIR}/C++/LuaeState.cpp
+	${code_SOURCE_DIR}/C++/LuaeState.h
+	TestLuae.cpp
+	TestLuae.h
+)
+
+define_test(luae "${LUAE_SOURCES}")
+target_include_directories(luae PRIVATE ${LUA52_INCLUDE_DIR})
+target_link_libraries(luae ${LUA52_LIBRARIES})
+
+add_custom_command(
+	TARGET luae
+	POST_BUILD
+	COMMENT "Copying Lua example files"
+	COMMAND
+		${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/scripts $<TARGET_FILE_DIR:luae>
+)
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/Tests/Luae/TestLuae.cpp	Fri May 09 17:12:25 2014 +0200
@@ -0,0 +1,418 @@
+/*
+ * TestLuae.cpp -- test the Luae class
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <cppunit/TextTestRunner.h>
+
+#include <Luae.h>
+#include <LuaeState.h>
+
+#include "TestLuae.h"
+
+/* --------------------------------------------------------
+ * Custom type Point
+ * -------------------------------------------------------- */
+
+struct Point {
+	int x;
+	int y;
+};
+
+template <>
+struct Luae::TypeInfo<Point> : Luae::TypeCustom {
+	static void push(lua_State *L, const Point &point)
+	{
+		lua_createtable(L, 0, 0);
+		lua_pushinteger(L, point.x);
+		lua_setfield(L, -2, "x");
+		lua_pushinteger(L, point.y);
+		lua_setfield(L, -2, "y");
+	}
+
+	static Point get(lua_State *L, int index)
+	{
+		Point p{0, 0};
+
+		if (lua_type(L, index) == LUA_TTABLE) {
+			lua_getfield(L, index, "x");
+			p.x = luaL_optint(L, -1, 0);
+			lua_pop(L, 1);
+			lua_getfield(L, index, "y");
+			p.y = luaL_optint(L, -1, 0);
+			lua_pop(L, 1);
+		}
+
+		return p;
+	}
+
+	static Point check(lua_State *L, int index)
+	{
+		luaL_checktype(L, index, LUA_TTABLE);
+
+		return get(L, index);
+	}
+};
+
+/* --------------------------------------------------------
+ * Userdata type Object
+ * -------------------------------------------------------- */
+
+struct Object {
+	std::string hello()
+	{
+		return "hello";
+	}
+};
+
+template <>
+struct Luae::TypeInfo<Object> : Luae::TypeUserdata {
+	static constexpr const char *name = "Object";
+};
+
+int l_hello(lua_State *L)
+{
+	return Luae::push(L, Luae::check<Object>(L, 1)->hello());
+}
+
+const Luae::Reg methods {
+	{ "hello",	l_hello		}
+};
+
+/* --------------------------------------------------------
+ * Userdata as shared_ptr Widget
+ * -------------------------------------------------------- */
+
+class Widget {
+private:
+	int		m_width;
+	int		m_height;
+	std::string	m_name;
+
+public:
+	Widget(int width, int height, const std::string &name)
+		: m_width(width)
+		, m_height(height)
+		, m_name(name)
+	{
+	}
+
+	int width() const
+	{
+		return m_width;
+	}
+
+	int height() const
+	{
+		return m_height;
+	}
+
+	const std::string &name() const
+	{
+		return m_name;
+	}
+};
+
+using WidgetPtr	= std::shared_ptr<Widget>;
+
+template <>
+struct Luae::TypeInfo<Widget> : Luae::TypeUserdata {
+	static constexpr const char *name = "Widget";
+};
+
+int l_width(lua_State *L)
+{
+	return Luae::push(L, Luae::check<WidgetPtr>(L, 1)->width());
+}
+
+int l_height(lua_State *L)
+{
+	return Luae::push(L, Luae::check<WidgetPtr>(L, 1)->height());
+}
+
+int l_name(lua_State *L)
+{
+	return Luae::push(L, Luae::check<WidgetPtr>(L, 1)->name());
+}
+
+const Luae::Reg widgetMethods {
+	{ "width",		l_width		},
+	{ "height",		l_height	},
+	{ "name",		l_name		}
+};
+
+/* --------------------------------------------------------
+ * Push function tests
+ * -------------------------------------------------------- */
+
+void TestLuae::pushPoint()
+{
+	LuaeState L;
+	Luae::openlibs(L);
+
+	try {
+		Luae::dofile(L, "push.lua");
+		Luae::getglobal(L, "pushPoint");
+		Luae::push(L, Point{10, 20});
+		Luae::pcall(L, 1, 0);
+	} catch (const std::runtime_error &error) {
+		CPPUNIT_ASSERT_MESSAGE("unexpected exception: " + std::string(error.what()), false);
+	}
+}
+
+void TestLuae::pushObject()
+{
+	LuaeState L;
+	Luae::openlibs(L);
+
+	// Object metatable
+	Luae::newmetatable(L, "Object");
+	Luae::newlib(L, methods);
+	Luae::setfield(L, -2, "__index");
+	Luae::pop(L);
+
+	try {
+		Luae::dofile(L, "push.lua");
+		Luae::getglobal(L, "pushObject");
+		Luae::push(L, Object());
+		Luae::pcall(L, 1, 0);
+	} catch (const std::runtime_error &error) {
+		CPPUNIT_ASSERT_MESSAGE("unexpected exception: " + std::string(error.what()), false);
+	}
+}
+
+void TestLuae::pushShared()
+{
+	LuaeState L;
+	Luae::openlibs(L);
+
+	// Widget metatable
+	Luae::newmetatable(L, "Widget");
+	Luae::newlib(L, widgetMethods);
+	Luae::setfield(L, -2, "__index");
+	Luae::pop(L);
+
+	try {
+		Luae::dofile(L, "push.lua");
+		Luae::getglobal(L, "pushShared");
+		Luae::push(L, std::make_shared<Widget>(100, 200, "Button"));
+		Luae::pcall(L, 1, 0);
+	} catch (const std::runtime_error &error) {
+		CPPUNIT_ASSERT_MESSAGE("unexpected exception: " + std::string(error.what()), false);
+	}
+}
+
+void TestLuae::pushSharedTwice()
+{
+	LuaeState L;
+	Luae::openlibs(L);
+
+	// Widget metatable
+	Luae::newmetatable(L, "Widget");
+	Luae::newlib(L, widgetMethods);
+	Luae::setfield(L, -2, "__index");
+	Luae::pop(L);
+
+	try {
+		auto widget = std::make_shared<Widget>(640, 480, "Screen");
+
+		Luae::dofile(L, "push.lua");
+		Luae::getglobal(L, "pushSharedTwice");
+		Luae::push(L, widget);
+		Luae::push(L, widget);
+		Luae::pcall(L, 2, 0);
+	} catch (const std::runtime_error &error) {
+		CPPUNIT_ASSERT_MESSAGE("unexpected exception: " + std::string(error.what()), false);
+	}
+}
+
+/* --------------------------------------------------------
+ * Other functions
+ * -------------------------------------------------------- */
+
+void TestLuae::preload()
+{
+	LuaeState L;
+	Luae::openlibs(L);
+
+	Luae::preload(L, "luae", [] (lua_State *L) -> int {
+		lua_createtable(L, 0, 0);
+		lua_pushstring(L, "1.0");
+		lua_setfield(L, -2, "version");
+		lua_pushstring(L, "Luae");
+		lua_setfield(L, -2, "name");
+
+		return 1;
+	});
+
+	try {
+		Luae::dofile(L, "loading.lua");
+		Luae::getglobal(L, "test");
+	} catch (const std::runtime_error &error) {
+		CPPUNIT_ASSERT_MESSAGE("unexpected exception: " + std::string(error.what()), false);
+	}
+}
+
+void TestLuae::require()
+{
+	LuaeState L;
+	Luae::openlibs(L);
+
+	Luae::require(L, "luae", [] (lua_State *L) -> int {
+		lua_createtable(L, 0, 0);
+		lua_pushstring(L, "1.0");
+		lua_setfield(L, -2, "version");
+		lua_pushstring(L, "Luae");
+		lua_setfield(L, -2, "name");
+
+		return 1;
+	});
+
+	try {
+		Luae::dofile(L, "loading.lua");
+		Luae::getglobal(L, "test");
+	} catch (const std::runtime_error &error) {
+		CPPUNIT_ASSERT_MESSAGE("unexpected exception: " + std::string(error.what()), false);
+	}
+}
+
+/* --------------------------------------------------------
+ * Standard types push / get / check
+ * -------------------------------------------------------- */
+
+void TestLuae::testbool()
+{
+	LuaeState L;
+	Luae::openlibs(L);
+
+	try {
+		Luae::dofile(L, "standard.lua");
+		Luae::getglobal(L, "testbool");
+		Luae::push(L, true);
+		Luae::pcall(L, 1, 1);
+		CPPUNIT_ASSERT_EQUAL(Luae::check<bool>(L, 1), false);
+	} catch (const std::runtime_error &error) {
+		CPPUNIT_ASSERT_MESSAGE("unexpected exception: " + std::string(error.what()), false);
+	}
+}
+
+void TestLuae::testdouble()
+{
+	LuaeState L;
+	Luae::openlibs(L);
+
+	try {
+		Luae::dofile(L, "standard.lua");
+		Luae::getglobal(L, "testdouble");
+		Luae::push(L, 10.0);
+		Luae::pcall(L, 1, 1);
+		CPPUNIT_ASSERT_EQUAL(Luae::check<double>(L, 1), -10.0);
+	} catch (const std::runtime_error &error) {
+		CPPUNIT_ASSERT_MESSAGE("unexpected exception: " + std::string(error.what()), false);
+	}
+}
+
+void TestLuae::testint()
+{
+	LuaeState L;
+	Luae::openlibs(L);
+
+	try {
+		Luae::dofile(L, "standard.lua");
+		Luae::getglobal(L, "testint");
+		Luae::push(L, 123);
+		Luae::pcall(L, 1, 1);
+		CPPUNIT_ASSERT_EQUAL(Luae::check<int>(L, 1), -123);
+	} catch (const std::runtime_error &error) {
+		CPPUNIT_ASSERT_MESSAGE("unexpected exception: " + std::string(error.what()), false);
+	}
+}
+
+void TestLuae::testlong()
+{
+	LuaeState L;
+	Luae::openlibs(L);
+
+	try {
+		Luae::dofile(L, "standard.lua");
+		Luae::getglobal(L, "testlong");
+		Luae::push(L, 9999L);
+		Luae::pcall(L, 1, 1);
+		CPPUNIT_ASSERT_EQUAL(Luae::check<long>(L, 1), -9999L);
+	} catch (const std::runtime_error &error) {
+		CPPUNIT_ASSERT_MESSAGE("unexpected exception: " + std::string(error.what()), false);
+	}
+}
+
+void TestLuae::testnil()
+{
+	LuaeState L;
+	Luae::openlibs(L);
+
+	try {
+		Luae::dofile(L, "standard.lua");
+		Luae::getglobal(L, "testnil");
+		Luae::push(L, nullptr);
+		Luae::pcall(L, 1, 1);
+		CPPUNIT_ASSERT_EQUAL(Luae::type(L, -1), LUA_TNIL);
+	} catch (const std::runtime_error &error) {
+		CPPUNIT_ASSERT_MESSAGE("unexpected exception: " + std::string(error.what()), false);
+	}
+}
+
+void TestLuae::teststring()
+{
+	LuaeState L;
+	Luae::openlibs(L);
+
+	try {
+		Luae::dofile(L, "standard.lua");
+		Luae::getglobal(L, "teststring");
+		Luae::push(L, "Hello");
+		Luae::pcall(L, 1, 1);
+		CPPUNIT_ASSERT_EQUAL(Luae::check<std::string>(L, 1), std::string("olleH"));
+	} catch (const std::runtime_error &error) {
+		CPPUNIT_ASSERT_MESSAGE("unexpected exception: " + std::string(error.what()), false);
+	}
+}
+
+void TestLuae::testustring()
+{
+	LuaeState L;
+	Luae::openlibs(L);
+
+	try {
+		std::u32string arg{'H', 'e', 'l', 'l', 'o'};
+		std::u32string expected{'o', 'l', 'l', 'e', 'H'};
+
+		Luae::dofile(L, "standard.lua");
+		Luae::getglobal(L, "testustring");
+		Luae::push(L, arg);
+		Luae::pcall(L, 1, 1);
+		CPPUNIT_ASSERT_MESSAGE("u32string failure", Luae::check<std::u32string>(L, 1) == expected);
+	} catch (const std::runtime_error &error) {
+		CPPUNIT_ASSERT_MESSAGE("unexpected exception: " + std::string(error.what()), false);
+	}
+}
+
+int main()
+{
+	CppUnit::TextTestRunner runnerText;
+
+	runnerText.addTest(TestLuae::suite());
+
+	return runnerText.run("", false) == 1 ? 0 : 1;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/Tests/Luae/TestLuae.h	Fri May 09 17:12:25 2014 +0200
@@ -0,0 +1,59 @@
+/*
+ * TestLuae.h -- test the Luae class
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _TEST_LUAE_H_
+#define _TEST_LUAE_H_
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestFixture.h>
+
+class TestLuae : public CppUnit::TestFixture {
+private:
+	CPPUNIT_TEST_SUITE(TestLuae);
+	CPPUNIT_TEST(pushPoint);
+	CPPUNIT_TEST(pushObject);
+	CPPUNIT_TEST(pushShared);
+	CPPUNIT_TEST(pushSharedTwice);
+	CPPUNIT_TEST(preload);
+	CPPUNIT_TEST(require);
+	CPPUNIT_TEST(testnil);
+	CPPUNIT_TEST(testbool);
+	CPPUNIT_TEST(testint);
+	CPPUNIT_TEST(testlong);
+	CPPUNIT_TEST(testdouble);
+	CPPUNIT_TEST(teststring);
+	CPPUNIT_TEST(testustring);
+	CPPUNIT_TEST_SUITE_END();
+
+public:
+	void pushPoint();
+	void pushObject();
+	void pushShared();
+	void pushSharedTwice();
+	void preload();
+	void require();
+	void testnil();
+	void testbool();
+	void testint();
+	void testlong();
+	void testdouble();
+	void teststring();
+	void testustring();
+};
+
+#endif // !_TEST_LUAE_H_
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/Tests/Luae/scripts/loading.lua	Fri May 09 17:12:25 2014 +0200
@@ -0,0 +1,10 @@
+--
+-- loading.lua -- preload and require functions
+--
+
+function test()
+	local luae = require "luae"
+
+	assert(luae.version == "1.0")
+	assert(luae.name == "Luae")
+end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/Tests/Luae/scripts/push.lua	Fri May 09 17:12:25 2014 +0200
@@ -0,0 +1,22 @@
+--
+-- push.lua -- test for push functions
+--
+
+function pushPoint(point)
+	assert(point.x == 10)
+	assert(point.y == 20)
+end
+
+function pushObject(object)
+	assert(object:hello() == "hello")
+end
+
+function pushShared(widget)
+	assert(widget:width() == 100)
+	assert(widget:height() == 200)
+	assert(widget:name() == "Button")
+end
+
+function pushSharedTwice(o1, o2)
+	assert(o1 == o2)
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/Tests/Luae/scripts/standard.lua	Fri May 09 17:12:25 2014 +0200
@@ -0,0 +1,55 @@
+--
+-- standard.lua -- standard types push / get / check
+--
+
+function testbool(v)
+	assert(v == true)
+
+	return false
+end
+
+function testdouble(v)
+	assert(v == 10.0)
+
+	return -10.0
+end
+
+function testint(v)
+	assert(v == 123)
+
+	return -123
+end
+
+function testlong(v)
+	assert(v == 9999)
+
+	return -9999
+end
+
+function testnil(v)
+	assert(type(v) == "nil")
+
+	return nil
+end
+
+function teststring(v)
+	assert(v == "Hello")
+
+	return "olleH"
+end
+
+function testustring(v)
+	assert(v[1] == string.byte('H'))
+	assert(v[2] == string.byte('e'))
+	assert(v[3] == string.byte('l'))
+	assert(v[4] == string.byte('l'))
+	assert(v[5] == string.byte('o'))
+
+	return {
+		string.byte('o'),
+		string.byte('l'),
+		string.byte('l'),
+		string.byte('e'),
+		string.byte('H')
+	}
+end
\ No newline at end of file
--- a/CMakeLists.txt	Fri May 09 09:15:52 2014 +0200
+++ b/CMakeLists.txt	Fri May 09 17:12:25 2014 +0200
@@ -75,10 +75,14 @@
 	add_subdirectory(C++/Tests/Hash)
 endif ()
 
+if (WITH_LUAE)
+	add_subdirectory(C++/Tests/Luae)
+endif ()
+
 if (WITH_PACK)
 	add_subdirectory(C++/Tests/Pack)
 endif ()
 
 if (WITH_PARSER)
 	add_subdirectory(C++/Tests/Parser)
-endif ()
+endif ()
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cmake/FindLua52.cmake	Fri May 09 17:12:25 2014 +0200
@@ -0,0 +1,80 @@
+# Locate Lua library
+# This module defines
+#  LUA52_FOUND, if false, do not try to link to Lua 
+#  LUA52_LIBRARIES
+#  LUA52_INCLUDE_DIR, where to find lua.h
+#  LUA52_VERSION_STRING, the version of Lua found (since CMake 2.8.8)
+#
+# Note that the expected include convention is
+#  #include "lua.h"
+# and not
+#  #include <lua/lua.h>
+# This is because, the lua location is not standardized and may exist
+# in locations other than lua/
+
+#=============================================================================
+# Copyright 2007-2009 Kitware, Inc.
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+#  License text for the above reference.)
+
+find_path(LUA52_INCLUDE_DIR lua.h
+	HINTS
+	$ENV{LUA_DIR}
+	PATH_SUFFIXES include/lua52 include/lua5.2 include/lua include
+	PATHS
+	~/Library/Frameworks
+	/Library/Frameworks
+	/sw # Fink
+	/opt/local # DarwinPorts
+	/opt/csw # Blastwave
+	/opt
+)
+
+find_library(LUA52_LIBRARY
+	NAMES lua52 lua5.2 lua-5.2 lua
+	HINTS
+	$ENV{LUA_DIR}
+	PATH_SUFFIXES lib64 lib
+	PATHS
+	~/Library/Frameworks
+	/Library/Frameworks
+	/sw
+	/opt/local
+	/opt/csw
+	/opt
+)
+
+if (LUA52_LIBRARY)
+	# include the math library for Unix
+	if (UNIX AND NOT APPLE)
+		FIND_LIBRARY(LUA52_MATH_LIBRARY m)
+		SET(LUA52_LIBRARIES "${LUA52_LIBRARY};${LUA52_MATH_LIBRARY}" CACHE STRING "Lua Libraries")
+	# For Windows and Mac, don't need to explicitly include the math library
+	else (UNIX AND NOT APPLE)
+		SET(LUA52_LIBRARIES "${LUA52_LIBRARY}" CACHE STRING "Lua Libraries")
+	endif (UNIX AND NOT APPLE)
+endif ()
+
+if (LUA52_INCLUDE_DIR AND EXISTS "${LUA52_INCLUDE_DIR}/lua.h")
+	file(STRINGS "${LUA52_INCLUDE_DIR}/lua.h" lua52_version_str REGEX "^#define[ \t]+LUA_RELEASE[ \t]+\"Lua .+\"")
+
+	string(REGEX REPLACE "^#define[ \t]+LUA_RELEASE[ \t]+\"Lua ([^\"]+)\".*" "\\1" LUA52_VERSION_STRING "${lua52_version_str}")
+	unset(lua52_version_str)
+endif()
+
+include(FindPackageHandleStandardArgs)
+# handle the QUIETLY and REQUIRED arguments and set LUA52_FOUND to TRUE if 
+# all listed variables are TRUE
+find_package_handle_standard_args(Lua52
+                                  REQUIRED_VARS LUA52_LIBRARIES LUA52_INCLUDE_DIR
+                                  VERSION_VAR LUA52_VERSION_STRING)
+
+mark_as_advanced(LUA52_INCLUDE_DIR LUA52_LIBRARIES LUA52_LIBRARY LUA52_MATH_LIBRARY)