changeset 193:258087829c66

Replace Luae
author David Demelier <markand@malikania.fr>
date Wed, 27 Nov 2013 11:34:02 +0100
parents 1c2788f9f55f
children 9fc5f917872b
files C++/Luae.cpp C++/Luae.h Luae.cpp Luae.h
diffstat 4 files changed, 349 insertions(+), 998 deletions(-) [+]
line wrap: on
line diff
--- a/C++/Luae.cpp	Wed Nov 27 11:26:26 2013 +0100
+++ b/C++/Luae.cpp	Wed Nov 27 11:34:02 2013 +0100
@@ -1,7 +1,7 @@
 /*
- * Luae.cpp -- Lua helpers and such
+ * Lua.cpp -- Lua helpers and such
  *
- * Copyright (c) 2011, 2012, 2013 David Demelier <markand@malikania.fr>
+ * Copyright (c) 2013 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
@@ -18,98 +18,116 @@
 
 #include "Luae.h"
 
-void LuaeClass::createClass(lua_State *L, const LuaObject &cls)
+namespace irccd {
+
+LuaState::LuaState()
 {
-	LUA_STACK_CHECKBEGIN(L);
+	m_state = Ptr(luaL_newstate());
+}
+
+LuaState::LuaState(lua_State *L)
+{
+	m_state = Ptr(L);
+}
 
-	// Already registered?
-	if (luaL_newmetatable(L, cls.name) == 0)
-		return;
+LuaState::LuaState(LuaState &&state)
+{
+	m_state = std::move(state.m_state);
+}
 
-	// Add it's "name" field
-	lua_pushstring(L, cls.name);
-	lua_setfield(L, -2, LUAE_CLASS_FIELDNAME);
+LuaState &LuaState::operator=(LuaState &&state)
+{
+	m_state = std::move(state.m_state);
 
-	// Create a list of parent for a faster cast
-	lua_createtable(L, 0, 0);
+	return *this;
+}
+
+LuaState::operator lua_State*()
+{
+	return m_state.get();
+}
 
-	int i = 0;
-	for (auto p = cls.parent; p != nullptr; p = p->parent) {
-		lua_pushstring(L, p->name);
-		lua_rawseti(L, -2, ++i);
-	}
-	lua_setfield(L, -2, LUAE_CLASS_FIELDPARENTS);
+LuaValue LuaValue::copy(lua_State *L, int index)
+{
+	LuaValue v;
+
+	v.type = lua_type(L, index);
 
-	// Metamethods
-	if (cls.metamethods.size() > 0)
-		luaL_setfuncs(L, cls.metamethods.data(), 0);
+	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:
+	{
+		LuaValue k;
 
-	// Methods
-	lua_createtable(L, 0, 0);
+		if (index < 0)
+			-- index;
 
-	if (cls.methods.size() > 0) {
-		luaL_setfuncs(L, cls.methods.data(), 0);
+		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;
 	}
 
-	/*
-	 * Add a metatable to this __index table so that if
-	 * a method is not found it use the parent table recursively
-	 */
-	if (cls.parent) {
-		// 1. Get the parent 
-		luaL_getmetatable(L, cls.parent->name);
-		assert(lua_type(L, -1) != LUA_TNIL);
-
-		// 2. Create an anonymous metatable
-		lua_createtable(L, 1, 1);
-
-		// 3. Get the __index field from this metatable
-		lua_getfield(L, -2, "__index");
-		assert(lua_type(L, -1) != LUA_TNIL);
-		lua_setfield(L, -2, "__index");
-		lua_setmetatable(L, -3);
-		lua_pop(L, 1);
-	}
-
-	lua_setfield(L, -2, "__index");
-
-	// Pop that metatable
-	lua_pop(L, 1);
-
-	LUA_STACK_CHECKEQUALS(L);
+	return v;
 }
 
-/* --------------------------------------------------------
- * Luae public methods
- * -------------------------------------------------------- */
-
-void Luae::createEnum(lua_State *L, const LuaEnum *enumeration)
+void LuaValue::push(lua_State *L, const LuaValue &value)
 {
-	lua_createtable(L, 0, 0);
+	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 (int i = 0; enumeration[i].name != nullptr; ++i) {
-		lua_pushinteger(L, enumeration[i].value);
-		lua_setfield(L, -2, enumeration[i].name);
+		for (auto p : value.table) {
+			LuaValue::push(L, p.first);
+			LuaValue::push(L, p.second);
+
+			lua_settable(L, -3);
+		}
+		break;
+	}
+	default:
+		lua_pushnil(L);
+		break;
 	}
 }
 
-void Luae::createLibrary(lua_State *L, const luaL_Reg *functions)
+LuaValue::LuaValue()
+	: type(LUA_TNIL)
 {
-	LUA_STACK_CHECKBEGIN(L);
-
-	lua_createtable(L, 0, 0);
-	luaL_setfuncs(L, functions, 0);
-
-	LUA_STACK_CHECKEND(L, - 1);
 }
 
 template <>
-bool Luae::getField(lua_State *L, int idx, const std::string & name)
+bool Luae::getField(lua_State *L, int idx, const std::string &name)
 {
 	bool value = false;
 
 	lua_getfield(L, idx, name.c_str());
-	if (lua_type(L, idx) == LUA_TBOOLEAN)
+	if (lua_type(L, -1) == LUA_TBOOLEAN)
 		value = lua_toboolean(L, -1) == 1;
 	lua_pop(L, 1);
 
@@ -117,12 +135,12 @@
 }
 
 template <>
-double Luae::getField(lua_State *L, int idx, const std::string & name)
+double Luae::getField(lua_State *L, int idx, const std::string &name)
 {
 	double value = 0;
 
 	lua_getfield(L, idx, name.c_str());
-	if (lua_type(L, idx) == LUA_TNUMBER)
+	if (lua_type(L, -1) == LUA_TNUMBER)
 		value = lua_tonumber(L, -1);
 	lua_pop(L, 1);
 
@@ -130,12 +148,12 @@
 }
 
 template <>
-int Luae::getField(lua_State *L, int idx, const std::string & name)
+int Luae::getField(lua_State *L, int idx, const std::string &name)
 {
 	int value = 0;
 
 	lua_getfield(L, idx, name.c_str());
-	if (lua_type(L, idx) == LUA_TNUMBER)
+	if (lua_type(L, -1) == LUA_TNUMBER)
 		value = lua_tointeger(L, -1);
 	lua_pop(L, 1);
 
@@ -143,19 +161,34 @@
 }
 
 template <>
-std::string Luae::getField(lua_State *L, int idx, const std::string & name)
+std::string Luae::getField(lua_State *L, int idx, const std::string &name)
 {
 	std::string value;
 
 	lua_getfield(L, idx, name.c_str());
-	if (lua_type(L, idx) == LUA_TSTRING)
+	if (lua_type(L, -1) == LUA_TSTRING)
 		value = lua_tostring(L, -1);
 	lua_pop(L, 1);
 
 	return value;
 }
 
-void Luae::preload(lua_State *L, const std::string & name, lua_CFunction func)
+int Luae::typeField(lua_State *L, int idx, const std::string &name)
+{
+	int type;
+
+	LUA_STACK_CHECKBEGIN(L);
+
+	lua_getfield(L, idx, name.c_str());
+	type = lua_type(L, -1);
+	lua_pop(L, 1);
+
+	LUA_STACK_CHECKEQUALS(L);
+
+	return type;
+}
+
+void Luae::preload(lua_State *L, const std::string &name, lua_CFunction func)
 {
 	LUA_STACK_CHECKBEGIN(L);
 
@@ -170,6 +203,8 @@
 
 void Luae::readTable(lua_State *L, int idx, ReadFunction func)
 {
+	LUA_STACK_CHECKBEGIN(L);
+
 	lua_pushnil(L);
 
 	if (idx < 0)
@@ -180,10 +215,10 @@
 		lua_pop(L, 1);
 	}
 
-	lua_pop(L, 1);
+	LUA_STACK_CHECKEQUALS(L);
 }
 
-int Luae::referenceField(lua_State *L, int idx, int type, const std::string & name)
+int Luae::referenceField(lua_State *L, int idx, int type, const std::string &name)
 {
 	int ref = LUA_REFNIL;
 
@@ -199,7 +234,7 @@
 	return ref;
 }
 
-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, bool global)
 {
 	LUA_STACK_CHECKBEGIN(L);
 
@@ -209,6 +244,18 @@
 	LUA_STACK_CHECKEQUALS(L);
 }
 
+void Luae::initRegistry(lua_State *L)
+{
+	lua_createtable(L, 0, 0);
+	lua_createtable(L, 0, 1);
+	lua_pushstring(L, "v");
+	lua_setfield(L, -2, "__mode");
+	lua_setmetatable(L, -2);
+	lua_setfield(L, LUA_REGISTRYINDEX, "refs");
+}
+
+} // !irccd
+
 void * operator new(size_t size, lua_State *L)
 {
 	return lua_newuserdata(L, size);
--- a/C++/Luae.h	Wed Nov 27 11:26:26 2013 +0100
+++ b/C++/Luae.h	Wed Nov 27 11:34:02 2013 +0100
@@ -1,7 +1,7 @@
 /*
- * Luae.h -- Lua helpers and such
+ * Lua.h -- Lua helpers and such
  *
- * Copyright (c) 2011, 2012, 2013 David Demelier <markand@malikania.fr>
+ * Copyright (c) 2013 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
@@ -16,226 +16,129 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#ifndef _LUAE_H_
-#define _LUAE_H_
-
-/**
- * @file Luae.h
- * @brief Lua extended API
- * @author David Demelier
- *
- * Object oriented abstraction, common functions and such.
- */
+#ifndef _LUA_H_
+#define _LUA_H_
 
 #include <cassert>
-#include <cstring>
-#include <exception>
 #include <functional>
 #include <memory>
-#include <sstream>
-#include <stdexcept>
 #include <string>
-#include <unordered_map>
-#include <utility>
 #include <vector>
 
 #include <lua.hpp>
 
-#define LUAE_CLASS_FIELDNAME		"__name"
-#define LUAE_CLASS_FIELDPARENTS		"__parents"
-
-#if !defined(NDEBUG)
-
-#define LUA_STACK_CHECKBEGIN(L)						\
-	int __topstack = lua_gettop((L))
-
-#define LUA_STACK_CHECKEQUALS(L)					\
-	assert(lua_gettop((L)) == __topstack)
-
-#define LUA_STACK_CHECKEND(L, cond)					\
-	assert(lua_gettop((L)) cond == __topstack)
-
-#else
-
-#define LUA_STACK_CHECKBEGIN(L)
-#define LUA_STACK_CHECKEQUALS(L)
-#define LUA_STACK_CHECKEND(L, cond)
-
-#endif
+namespace irccd {
 
 /**
- * @enum LuaEnum
- * @brief A class to bind C enums
+ * @class LuaState
+ * @brief Wrapper for lua_State
  *
- * Used as a static array, binds C enum with the function Luae::createEnum().
- */
-struct LuaEnum {
-	const char	*name;
-	int		value;
-};
-
-/**
- * @struct LuaDeleter
- * @brief Deletor for lua_State
- *
- * Just delete the Lua state at the end of ownership.
+ * This class automatically create a new Lua state and add implicit
+ * cast operator plus RAII destruction.
  */
-struct LuaDeleter {
-	void operator()(lua_State *L) {
-		lua_close(L);
-	}
-};
+class LuaState {
+private:
+	struct Deleter {
+		void operator()(lua_State *L)
+		{
+			lua_close(L);
+		}
+	};
+
+	using Ptr = std::unique_ptr<lua_State, Deleter>;
+
+	Ptr m_state;
+
+public:
+	LuaState(const LuaState &) = delete;
+	LuaState &operator=(const LuaState &) = delete;
+
+	/**
+	 * Default constructor. Create a new state.
+	 */
+	LuaState();
 
-/**
- * @struct LuaObject
- * @brief Lua class binding definition
- *
- * Define a Lua class (single inheritance only).
- */
-struct LuaObject {
-	const LuaObject	*parent;
-	const char	*name;
-	std::vector<luaL_Reg> methods;
-	std::vector<luaL_Reg> metamethods;
+	/**
+	 * Use the already created state.
+	 *
+	 * @param L the state to use
+	 */
+	LuaState(lua_State *L);
+
+	/**
+	 * Move constructor.
+	 *
+	 * @param state the Lua state to move
+	 */
+	LuaState(LuaState &&state);
+
+	/**
+	 * Move assignment operator.
+	 *
+	 * @param state the Lua state to move
+	 */
+	LuaState &operator=(LuaState &&state);
+
+	/**
+	 * Implicit cast operator for convenient usage to C Lua API.
+	 *
+	 * @return the state as lua_State *
+	 */
+	operator lua_State*();
 };
 
 /**
- * A lua_State owner with its own deleter.
+ * @class LuaValue
+ * @brief A fake variant for Lua values
+ *
+ * This class is primarly used for copying Lua values without checking
+ * the types, useful to pass data.
  */
-typedef std::unique_ptr<lua_State, LuaDeleter> LuaState;
+class LuaValue {
+private:
+	union {
+		lua_Number	 number;
+		bool		 boolean;
+	};
 
-/**
- * @class Luae
- * @brief Functions to initialize object oriented Lua classes
- *
- * Provide multiple inheritance and such.
- */
-class LuaeClass {
+	int type;
+	std::string str;
+	std::vector<std::pair<LuaValue, LuaValue>> table;
+
 public:
 	/**
-	 * @param L the Lua state
-	 * @param name the class name
-	 */
-	static void createClass(lua_State *L, const LuaObject &cls);
-
-	/**
-	 * Push a object to Lua, the object must have been declared with
-	 * createClass before.
-	 *
-	 * @param L the Lua state
-	 * @param cls the class description
-	 * @param object the object to push
-	 * @see createClass
-	 */
-	template <class T>
-	static void pushObject(lua_State *L,
-			       const LuaObject &cls,
-			       std::shared_ptr<T> object)
-	{
-		new (L, cls.name) std::shared_ptr<T>(object);
-	}
-
-	/**
-	 * Get an object from Lua. The object must have been declared with
-	 * createClass before.
+	 * Dump a value at the specific index.
 	 *
 	 * @param L the Lua state
-	 * @param cls the class description
-	 * @param index the object index
-	 * @return the value or throw a luaL_error
+	 * @param index the value
+	 * @return a tree of values
 	 */
-	template <class T>
-	static std::shared_ptr<T> getObject(lua_State *L, const LuaObject &cls, int index)
-	{
-		LUA_STACK_CHECKBEGIN(L);
-
-		const char *name;
-		bool found = false;
-
-		/*
-		 * Get the metafield __name to check if it's a correct object.
-		 */
-		luaL_checktype(L, index, LUA_TUSERDATA);
-		if (!luaL_getmetafield(L, index, LUAE_CLASS_FIELDNAME))
-			luaL_error(L, "invalid object");
-			// NOT REACHED
-
-		name = lua_tostring(L, -1);
-		lua_pop(L, 1);
-
-		/*
-		 * Check if that cast is allowed.
-		 */
-		found = strcmp(name, cls.name) == 0;
-		if (!luaL_getmetafield(L, index, LUAE_CLASS_FIELDPARENTS))
-			luaL_error(L, "invalid object");
-			// NOT REACHED
-
-		lua_pushnil(L);
-		while (lua_next(L, -2) && !found) {
-			auto t = lua_tostring(L, -1);
-			found = strcmp(cls.name, t) == 0;
-			lua_pop(L, 1);
-		}
-		lua_pop(L, 1);
-
-		if (!found)
-			luaL_error(L, "invalid cast from %s to %s", name, cls.name);
-			// NOT REACHED
-
-		return *static_cast<const std::shared_ptr<T> *>(lua_topointer(L, index));
-	}
+	static LuaValue copy(lua_State *L, int index);
 
 	/**
-	 * Delete an object from Lua. The object must have been declared with
-	 * createClass before.
-	 *
-	 * This function is an helper for your __gc metamethods.
+	 * Push a value to a state.
 	 *
 	 * @param L the Lua state
-	 * @param cls the class description
-	 * @param index the object index
-	 * @return 0
+	 * @param value the value to push
 	 */
-	template <class T>
-	static int deleteObject(lua_State *L, const LuaObject &cls, int index)
-	{
-		std::shared_ptr<T> *ptr = static_cast<std::shared_ptr<T> *>(luaL_checkudata(L, index, cls.name));
+	static void push(lua_State *L, const LuaValue &value);
 
-		ptr->~shared_ptr<T>();
-
-		return 0;
-	}
+	/**
+	 * Default constructor (type nil)
+	 */
+	LuaValue();
 };
 
 /**
  * @class Luae
- * @brief Lua extended API
+ * @brief Add lot of convenience for Lua
  *
- * Provide some useful functions and multiple inheritance abstraction.
+ * This class adds lot of functions for Lua and C++.
  */
-class Luae {
-public:
-	typedef std::function<void(lua_State *L, int tkey, int tvalue)> ReadFunction;
-
+class Luae
+{
 public:
-	/**
-	 * Bind an enumeration as a table into Lua. This function pushes a new table
-	 * mapped by the keys to their value.
-	 *
-	 * @param L the Lua state
-	 * @param enumeration the values to bind
-	 */
-	static void createEnum(lua_State *L, const LuaEnum *enumeration);
-
-	/**
-	 * Create a library table and pushes it onto the stack.
-	 *
-	 * @param L the Lua state
-	 * @param functions the functions
-	 */
-	static void createLibrary(lua_State *L,
-				  const luaL_Reg *functions);
+	using ReadFunction = std::function<void(lua_State *L, int tkey, int tvalue)>;
 
 	/**
 	 * Get a field of a specific type from a table. Specialized for the
@@ -247,7 +150,39 @@
 	 * @return the converted type.
 	 */
 	template <typename T>
-	static T getField(lua_State *L, int idx, const std::string & name);
+	static T getField(lua_State *L, int idx, const std::string &name);
+
+	/**
+	 * 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 requireField(lua_State *L, int idx, const std::string &name)
+	{
+		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);
+
+		return getField<T>(L, idx, name);
+	}
+
+	/**
+	 * Check a table field.
+	 *
+	 * @param L the Lua state
+	 * @param idx the table index
+	 * @param name the field name
+	 * @return the type
+	 */
+	static int typeField(lua_State *L, int idx, const std::string &name);
 
 	/**
 	 * Read a table, the function func is called for each element in the
@@ -274,7 +209,7 @@
 	 * @see require
 	 */
 	static void preload(lua_State *L,
-			    const std::string & name,
+			    const std::string &name,
 			    lua_CFunction func);
 
 	/**
@@ -290,7 +225,7 @@
 	static int referenceField(lua_State *L,
 				  int idx,
 				  int type,
-				  const std::string & name);
+				  const std::string &name);
 
 	/**
 	 * Load a library just like it was loaded with require.
@@ -301,111 +236,123 @@
 	 * @param global store as global
 	 */
 	static void require(lua_State *L,
-			    const std::string & name,
+			    const std::string &name,
 			    lua_CFunction func,
 			    bool global);
 
 	/**
-	 * Convert a new-placement created type to the requested template.
+	 * Initialize the registry for shared objects.
+	 *
+	 * @param L the Lua state
+	 */
+	static void initRegistry(lua_State *L);
+
+	/**
+	 * 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,
+			std::shared_ptr<T> o,
+			const std::string &name)
+	{
+		lua_getfield(L, LUA_REGISTRYINDEX, "refs");
+		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);
+	}
+
+	/**
+	 * 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 std::shared_ptr<T> getShared(lua_State *L, int index, const char *meta)
+	{
+		using Ptr = std::shared_ptr<T>;
+		
+		Ptr *ptr = static_cast<Ptr *>(luaL_checkudata(L, index, meta));
+		
+		return *ptr;
+	}
+
+	/**
+	 * Convert a new placement made object, without testing if its a real
+	 * object.
 	 *
 	 * @param L the Lua state
 	 * @param idx the object index
-	 * @param metaname which metatable
-	 * @return the type
+	 * @return the converted object
+	 */
+	template<class T>
+	static T toType(lua_State *L, int idx)
+	{
+		return reinterpret_cast<T>(lua_touserdata(L, idx));
+	}
+
+	/**
+	 * Convert a class created with new placement.
+	 *
+	 * @param L the Lua state
+	 * @param idx the value index
+	 * @param metaname the metatable name
+	 * @return the converted object
 	 */
 	template <typename T>
 	static T toType(lua_State *L, int idx, const char *metaname)
 	{
 		return reinterpret_cast<T>(luaL_checkudata(L, idx, metaname));
 	}
-
-	/**
-	 * Get a table field from a specific allowed range.
-	 *
-	 * @param L the Lua state
-	 * @param idx the value index
-	 * @param name the field name
-	 * @param min the minimum
-	 * @param max the maximum
-	 * @return the converted value
-	 * @throw NotValidScript on failure
-	 */
-	template <typename T>
-	static T getRanged(lua_State *L,
-			   int idx,
-			   const char *name,
-			   int min,
-			   int max,
-			   int def)
-	{
-		LUA_STACK_CHECKBEGIN(L);
-
-		T ret;
-
-		lua_getfield(L, idx, name);
-		if (lua_type(L, -1) == LUA_TNUMBER) {
-			int i = lua_tonumber(L, -1);
-	
-			ret = (i < min || i > max) ? def : static_cast<T>(i);
-		} else {
-			ret = def;
-		}
-
-		lua_pop(L, 1);
-
-		LUA_STACK_CHECKEQUALS(L);
-
-		return ret;
-	}
-
-	template <typename T>
-	static T requireRanged(lua_State *L,
-			       int idx,
-			       const char *name,
-			       int min,
-			       int max)
-	{
-		LUA_STACK_CHECKBEGIN(L);
-
-		lua_getfield(L, idx, name);
-		if (lua_type(L, -1) != LUA_TNUMBER) {
-			std::ostringstream oss;
-			lua_pop(L, 1);
-
-			oss << "field `" << name;
-			oss << "': is not a number";
-
-			throw std::invalid_argument(oss.str());
-		}
-
-		int i = lua_tonumber(L, -1);
-
-		lua_pop(L, 1);
-		if (i < min || i > max) {
-			std::ostringstream oss;
-
-			oss << "field `" << name;
-			oss << "': is out of range [" << min;
-			oss << ", " << max << "] expected ";
-			oss << " got: " << i;
-
-			throw std::invalid_argument(oss.str());
-		}
-
-		LUA_STACK_CHECKEQUALS(L);
-
-		return static_cast<T>(i);
-	}
 };
 
-void * operator new(size_t size, lua_State *L);
+#if !defined(NDEBUG)
+
+#define LUA_STACK_CHECKBEGIN(L)						\
+	int __topstack = lua_gettop((L))
 
-void * operator new(size_t size, lua_State *L, const char *metaname);
+#define LUA_STACK_CHECKEQUALS(L)					\
+	assert(lua_gettop((L)) == __topstack)
+
+#define LUA_STACK_CHECKEND(L, cond)					\
+	assert(lua_gettop((L)) cond == __topstack)
 
-/*
- * Delete operators are just present to avoid some warnings, Lua does garbage
- * collection so these functions just do nothing.
- */
+#else
+
+#define LUA_STACK_CHECKBEGIN(L)
+#define LUA_STACK_CHECKEQUALS(L)
+#define LUA_STACK_CHECKEND(L, cond)
+
+#endif
+
+} // !irccd
+
+void *operator new(size_t size, lua_State *L);
+
+void *operator new(size_t size, lua_State *L, const char *metaname);
 
 void operator delete(void *ptr, lua_State *L);
 
--- a/Luae.cpp	Wed Nov 27 11:26:26 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,282 +0,0 @@
-/*
- * Lua.cpp -- Lua helpers and such
- *
- * Copyright (c) 2013 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 "Luae.h"
-
-namespace irccd {
-
-LuaState::LuaState()
-{
-	m_state = Ptr(luaL_newstate());
-}
-
-LuaState::LuaState(lua_State *L)
-{
-	m_state = Ptr(L);
-}
-
-LuaState::LuaState(LuaState &&state)
-{
-	m_state = std::move(state.m_state);
-}
-
-LuaState &LuaState::operator=(LuaState &&state)
-{
-	m_state = std::move(state.m_state);
-
-	return *this;
-}
-
-LuaState::operator lua_State*()
-{
-	return m_state.get();
-}
-
-LuaValue LuaValue::copy(lua_State *L, int index)
-{
-	LuaValue 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:
-	{
-		LuaValue k;
-
-		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 LuaValue::push(lua_State *L, const LuaValue &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) {
-			LuaValue::push(L, p.first);
-			LuaValue::push(L, p.second);
-
-			lua_settable(L, -3);
-		}
-		break;
-	}
-	default:
-		lua_pushnil(L);
-		break;
-	}
-}
-
-LuaValue::LuaValue()
-	: type(LUA_TNIL)
-{
-}
-
-template <>
-bool Luae::getField(lua_State *L, int idx, const std::string &name)
-{
-	bool value = false;
-
-	lua_getfield(L, idx, name.c_str());
-	if (lua_type(L, -1) == LUA_TBOOLEAN)
-		value = lua_toboolean(L, -1) == 1;
-	lua_pop(L, 1);
-
-	return value;
-}
-
-template <>
-double Luae::getField(lua_State *L, int idx, const std::string &name)
-{
-	double value = 0;
-
-	lua_getfield(L, idx, name.c_str());
-	if (lua_type(L, -1) == LUA_TNUMBER)
-		value = lua_tonumber(L, -1);
-	lua_pop(L, 1);
-
-	return value;
-}
-
-template <>
-int Luae::getField(lua_State *L, int idx, const std::string &name)
-{
-	int value = 0;
-
-	lua_getfield(L, idx, name.c_str());
-	if (lua_type(L, -1) == LUA_TNUMBER)
-		value = lua_tointeger(L, -1);
-	lua_pop(L, 1);
-
-	return value;
-}
-
-template <>
-std::string Luae::getField(lua_State *L, int idx, const std::string &name)
-{
-	std::string value;
-
-	lua_getfield(L, idx, name.c_str());
-	if (lua_type(L, -1) == LUA_TSTRING)
-		value = lua_tostring(L, -1);
-	lua_pop(L, 1);
-
-	return value;
-}
-
-int Luae::typeField(lua_State *L, int idx, const std::string &name)
-{
-	int type;
-
-	LUA_STACK_CHECKBEGIN(L);
-
-	lua_getfield(L, idx, name.c_str());
-	type = lua_type(L, -1);
-	lua_pop(L, 1);
-
-	LUA_STACK_CHECKEQUALS(L);
-
-	return type;
-}
-
-void Luae::preload(lua_State *L, const std::string &name, lua_CFunction func)
-{
-	LUA_STACK_CHECKBEGIN(L);
-
-	lua_getglobal(L, "package");
-	lua_getfield(L, -1, "preload");
-	lua_pushcfunction(L, func);
-	lua_setfield(L, -2, name.c_str());
-	lua_pop(L, 2);
-
-	LUA_STACK_CHECKEQUALS(L);
-}
-
-void Luae::readTable(lua_State *L, int idx, ReadFunction func)
-{
-	LUA_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);
-	}
-
-	LUA_STACK_CHECKEQUALS(L);
-}
-
-int Luae::referenceField(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;
-}
-
-void Luae::require(lua_State *L, const std::string &name, lua_CFunction func, bool global)
-{
-	LUA_STACK_CHECKBEGIN(L);
-
-	luaL_requiref(L, name.c_str(), func, global);
-	lua_pop(L, 1);
-
-	LUA_STACK_CHECKEQUALS(L);
-}
-
-void Luae::initRegistry(lua_State *L)
-{
-	lua_createtable(L, 0, 0);
-	lua_createtable(L, 0, 1);
-	lua_pushstring(L, "v");
-	lua_setfield(L, -2, "__mode");
-	lua_setmetatable(L, -2);
-	lua_setfield(L, LUA_REGISTRYINDEX, "refs");
-}
-
-} // !irccd
-
-void * operator new(size_t size, lua_State *L)
-{
-	return lua_newuserdata(L, size);
-}
-
-void * operator new(size_t size, lua_State *L, const char *metaname)
-{
-	void *object;
-
-	object = lua_newuserdata(L, size);
-	luaL_setmetatable(L, metaname);
-
-	return object;
-}
-
-void operator delete(void *, lua_State *)
-{
-}
-
-void operator delete(void *, lua_State *L, const char *)
-{
-	lua_pushnil(L);
-	lua_setmetatable(L, -2);
-}
--- a/Luae.h	Wed Nov 27 11:26:26 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,361 +0,0 @@
-/*
- * Lua.h -- Lua helpers and such
- *
- * Copyright (c) 2013 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 _LUA_H_
-#define _LUA_H_
-
-#include <cassert>
-#include <functional>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <lua.hpp>
-
-namespace irccd {
-
-/**
- * @class LuaState
- * @brief Wrapper for lua_State
- *
- * This class automatically create a new Lua state and add implicit
- * cast operator plus RAII destruction.
- */
-class LuaState {
-private:
-	struct Deleter {
-		void operator()(lua_State *L)
-		{
-			lua_close(L);
-		}
-	};
-
-	using Ptr = std::unique_ptr<lua_State, Deleter>;
-
-	Ptr m_state;
-
-public:
-	LuaState(const LuaState &) = delete;
-	LuaState &operator=(const LuaState &) = delete;
-
-	/**
-	 * Default constructor. Create a new state.
-	 */
-	LuaState();
-
-	/**
-	 * Use the already created state.
-	 *
-	 * @param L the state to use
-	 */
-	LuaState(lua_State *L);
-
-	/**
-	 * Move constructor.
-	 *
-	 * @param state the Lua state to move
-	 */
-	LuaState(LuaState &&state);
-
-	/**
-	 * Move assignment operator.
-	 *
-	 * @param state the Lua state to move
-	 */
-	LuaState &operator=(LuaState &&state);
-
-	/**
-	 * Implicit cast operator for convenient usage to C Lua API.
-	 *
-	 * @return the state as lua_State *
-	 */
-	operator lua_State*();
-};
-
-/**
- * @class LuaValue
- * @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 LuaValue {
-private:
-	union {
-		lua_Number	 number;
-		bool		 boolean;
-	};
-
-	int type;
-	std::string str;
-	std::vector<std::pair<LuaValue, LuaValue>> table;
-
-public:
-	/**
-	 * Dump a value at the specific index.
-	 *
-	 * @param L the Lua state
-	 * @param index the value
-	 * @return a tree of values
-	 */
-	static LuaValue 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 LuaValue &value);
-
-	/**
-	 * Default constructor (type nil)
-	 */
-	LuaValue();
-};
-
-/**
- * @class Luae
- * @brief Add lot of convenience for Lua
- *
- * This class adds lot of functions for Lua and C++.
- */
-class Luae
-{
-public:
-	using ReadFunction = std::function<void(lua_State *L, int tkey, int tvalue)>;
-
-	/**
-	 * 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 getField(lua_State *L, int idx, const std::string &name);
-
-	/**
-	 * 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 requireField(lua_State *L, int idx, const std::string &name)
-	{
-		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);
-
-		return getField<T>(L, idx, name);
-	}
-
-	/**
-	 * Check a table field.
-	 *
-	 * @param L the Lua state
-	 * @param idx the table index
-	 * @param name the field name
-	 * @return the type
-	 */
-	static int typeField(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 readTable(lua_State *L, int idx, ReadFunction func);
-
-	/**
-	 * 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.
-	 *
-	 * @param L the Lua state
-	 * @param name the module name
-	 * @param func the opening library
-	 * @see require
-	 */
-	static void preload(lua_State *L,
-			    const std::string &name,
-			    lua_CFunction 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 referenceField(lua_State *L,
-				  int idx,
-				  int type,
-				  const std::string &name);
-
-	/**
-	 * Load a library just like it was loaded with require.
-	 *
-	 * @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);
-
-	/**
-	 * Initialize the registry for shared objects.
-	 *
-	 * @param L the Lua state
-	 */
-	static void initRegistry(lua_State *L);
-
-	/**
-	 * 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,
-			std::shared_ptr<T> o,
-			const std::string &name)
-	{
-		lua_getfield(L, LUA_REGISTRYINDEX, "refs");
-		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);
-	}
-
-	/**
-	 * 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 std::shared_ptr<T> getShared(lua_State *L, int index, const char *meta)
-	{
-		using Ptr = std::shared_ptr<T>;
-		
-		Ptr *ptr = static_cast<Ptr *>(luaL_checkudata(L, index, meta));
-		
-		return *ptr;
-	}
-
-	/**
-	 * Convert a new placement made object, without testing if its a real
-	 * object.
-	 *
-	 * @param L the Lua state
-	 * @param idx the object index
-	 * @return the converted object
-	 */
-	template<class T>
-	static T toType(lua_State *L, int idx)
-	{
-		return reinterpret_cast<T>(lua_touserdata(L, idx));
-	}
-
-	/**
-	 * Convert a class created with new placement.
-	 *
-	 * @param L the Lua state
-	 * @param idx the value index
-	 * @param metaname the metatable name
-	 * @return the converted object
-	 */
-	template <typename T>
-	static T toType(lua_State *L, int idx, const char *metaname)
-	{
-		return reinterpret_cast<T>(luaL_checkudata(L, idx, metaname));
-	}
-};
-
-#if !defined(NDEBUG)
-
-#define LUA_STACK_CHECKBEGIN(L)						\
-	int __topstack = lua_gettop((L))
-
-#define LUA_STACK_CHECKEQUALS(L)					\
-	assert(lua_gettop((L)) == __topstack)
-
-#define LUA_STACK_CHECKEND(L, cond)					\
-	assert(lua_gettop((L)) cond == __topstack)
-
-#else
-
-#define LUA_STACK_CHECKBEGIN(L)
-#define LUA_STACK_CHECKEQUALS(L)
-#define LUA_STACK_CHECKEND(L, cond)
-
-#endif
-
-} // !irccd
-
-void *operator new(size_t size, lua_State *L);
-
-void *operator new(size_t size, lua_State *L, const char *metaname);
-
-void operator delete(void *ptr, lua_State *L);
-
-void operator delete(void *ptr, lua_State *L, const char *metaname);
-
-#endif // !_LUA_H_