struct Nil
{
};
class LuaRef
{
private:
class Proxy;
friend struct Stack <Proxy>;
class StackPop
{
public:
StackPop (lua_State* L, int count)
: m_L (L)
, m_count (count)
{
}
~StackPop ()
{
lua_pop (m_L, m_count);
}
private:
lua_State* m_L;
int m_count;
};
class Proxy
{
private:
lua_State* m_L;
int m_tableRef;
int m_keyRef;
public:
Proxy (lua_State* L, int tableRef)
: m_L (L)
, m_tableRef (tableRef)
, m_keyRef (luaL_ref (L, LUA_REGISTRYINDEX))
{
}
Proxy (Proxy const& other)
: m_L (other.m_L)
, m_tableRef (other.m_tableRef)
{
assert (0);
lua_rawgeti (m_L, LUA_REGISTRYINDEX, other.m_keyRef);
m_keyRef = luaL_ref (m_L, LUA_REGISTRYINDEX);
}
~Proxy ()
{
luaL_unref (m_L, LUA_REGISTRYINDEX, m_keyRef);
}
int createRef () const
{
push (m_L);
return luaL_ref (m_L, LUA_REGISTRYINDEX);
}
template <class T>
Proxy& operator= (T v)
{
StackPop p (m_L, 1);
lua_rawgeti (m_L, LUA_REGISTRYINDEX, m_tableRef);
lua_rawgeti (m_L, LUA_REGISTRYINDEX, m_keyRef);
Stack <T>::push (m_L, v);
lua_rawset (m_L, -3);
return *this;
}
template <class T>
Proxy& rawset (T v)
{
StackPop p (m_L, 1);
lua_rawgeti (m_L, LUA_REGISTRYINDEX, m_tableRef);
lua_rawgeti (m_L, LUA_REGISTRYINDEX, m_keyRef);
Stack <T>::push (m_L, v);
lua_settable (m_L, -3);
return *this;
}
lua_State* state () const
{
return m_L;
}
void push (lua_State* L) const
{
assert (equalstates (L, m_L));
lua_rawgeti (L, LUA_REGISTRYINDEX, m_tableRef);
lua_rawgeti (L, LUA_REGISTRYINDEX, m_keyRef);
lua_gettable (L, -2);
lua_remove (L, -2); }
int type () const
{
int result;
push (m_L);
result = lua_type (m_L, -1);
lua_pop (m_L, 1);
return result;
}
inline bool isNil () const { return type () == LUA_TNIL; }
inline bool isNumber () const { return type () == LUA_TNUMBER; }
inline bool isString () const { return type () == LUA_TSTRING; }
inline bool isTable () const { return type () == LUA_TTABLE; }
inline bool isFunction () const { return type () == LUA_TFUNCTION; }
inline bool isUserdata () const { return type () == LUA_TUSERDATA; }
inline bool isThread () const { return type () == LUA_TTHREAD; }
inline bool isLightUserdata () const { return type () == LUA_TLIGHTUSERDATA; }
template <class T>
T cast () const
{
StackPop p (m_L, 1);
push (m_L);
return Stack <T>::get (m_L, lua_gettop (m_L));
}
template <class T>
inline operator T () const
{
return cast <T> ();
}
template <class T>
bool operator== (T rhs) const
{
StackPop p (m_L, 2);
push (m_L);
Stack <T>::push (m_L, rhs);
return lua_compare (m_L, -2, -1, LUA_OPEQ) == 1;
}
template <class T>
bool operator< (T rhs) const
{
StackPop p (m_L, 2);
push (m_L);
Stack <T>::push (m_L, rhs);
return lua_compare (m_L, -2, -1, LUA_OPLT) == 1;
}
template <class T>
bool operator<= (T rhs) const
{
StackPop p (m_L, 2);
push (m_L);
Stack <T>::push (m_L, rhs);
return lua_compare (m_L, -2, -1, LUA_OPLE) == 1;
}
template <class T>
bool operator> (T rhs) const
{
StackPop p (m_L, 2);
push (m_L);
Stack <T>::push (m_L, rhs);
return lua_compare (m_L, -1, -2, LUA_OPLT) == 1;
}
template <class T>
bool operator>= (T rhs) const
{
StackPop p (m_L, 2);
push (m_L);
Stack <T>::push (m_L, rhs);
return lua_compare (m_L, -1, -2, LUA_OPLE) == 1;
}
template <class T>
bool rawequal (T rhs) const
{
StackPop p (m_L, 2);
push (m_L);
Stack <T>::push (m_L, rhs);
return lua_rawequal (m_L, -1, -2) == 1;
}
template <class T>
Proxy operator[] (T key) const
{
return LuaRef (*this) [key];
}
template <class T>
LuaRef rawget (T key) const
{
StackPop (m_L, 1);
push (m_L);
Stack <T>::push (m_L, key);
lua_rawget (m_L, -2);
return LuaRef (m_L, FromStack ());
}
template <class T>
void append (T v) const
{
push (m_L);
Stack <T>::push (m_L, v);
luaL_ref (m_L, -2);
lua_pop (m_L, 1);
}
int length () const
{
StackPop p (m_L, 1);
push (m_L);
return get_length (m_L, -1);
}
LuaRef const operator() () const
{
push (m_L);
LuaException::pcall (m_L, 0, 1);
return LuaRef (m_L, FromStack ());
}
template <class P1>
LuaRef const operator() (P1 p1) const
{
push (m_L);
Stack <P1>::push (m_L, p1);
LuaException::pcall (m_L, 1, 1);
return LuaRef (m_L, FromStack ());
}
template <class P1, class P2>
LuaRef const operator() (P1 p1, P2 p2) const
{
push (m_L);
Stack <P1>::push (m_L, p1);
Stack <P2>::push (m_L, p2);
LuaException::pcall (m_L, 2, 1);
return LuaRef (m_L, FromStack ());
}
template <class P1, class P2, class P3>
LuaRef const operator() (P1 p1, P2 p2, P3 p3) const
{
push (m_L);
Stack <P1>::push (m_L, p1);
Stack <P2>::push (m_L, p2);
Stack <P3>::push (m_L, p3);
LuaException::pcall (m_L, 3, 1);
return LuaRef (m_L, FromStack ());
}
template <class P1, class P2, class P3, class P4>
LuaRef const operator() (P1 p1, P2 p2, P3 p3, P4 p4) const
{
push (m_L);
Stack <P1>::push (m_L, p1);
Stack <P2>::push (m_L, p2);
Stack <P3>::push (m_L, p3);
Stack <P4>::push (m_L, p4);
LuaException::pcall (m_L, 4, 1);
return LuaRef (m_L, FromStack ());
}
template <class P1, class P2, class P3, class P4, class P5>
LuaRef const operator() (P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) const
{
push (m_L);
Stack <P1>::push (m_L, p1);
Stack <P2>::push (m_L, p2);
Stack <P3>::push (m_L, p3);
Stack <P4>::push (m_L, p4);
Stack <P5>::push (m_L, p5);
LuaException::pcall (m_L, 5, 1);
return LuaRef (m_L, FromStack ());
}
template <class P1, class P2, class P3, class P4, class P5, class P6>
LuaRef const operator() (P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) const
{
push (m_L);
Stack <P1>::push (m_L, p1);
Stack <P2>::push (m_L, p2);
Stack <P3>::push (m_L, p3);
Stack <P4>::push (m_L, p4);
Stack <P5>::push (m_L, p5);
Stack <P6>::push (m_L, p6);
LuaException::pcall (m_L, 6, 1);
return LuaRef (m_L, FromStack ());
}
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7>
LuaRef const operator() (P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) const
{
push (m_L);
Stack <P1>::push (m_L, p1);
Stack <P2>::push (m_L, p2);
Stack <P3>::push (m_L, p3);
Stack <P4>::push (m_L, p4);
Stack <P5>::push (m_L, p5);
Stack <P6>::push (m_L, p6);
Stack <P7>::push (m_L, p7);
LuaException::pcall (m_L, 7, 1);
return LuaRef (m_L, FromStack ());
}
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8>
LuaRef const operator() (P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) const
{
push (m_L);
Stack <P1>::push (m_L, p1);
Stack <P2>::push (m_L, p2);
Stack <P3>::push (m_L, p3);
Stack <P4>::push (m_L, p4);
Stack <P5>::push (m_L, p5);
Stack <P6>::push (m_L, p6);
Stack <P7>::push (m_L, p7);
Stack <P8>::push (m_L, p8);
LuaException::pcall (m_L, 8, 1);
return LuaRef (m_L, FromStack ());
}
};
private:
friend struct Stack <LuaRef>;
struct FromStack { };
LuaRef (lua_State* L, FromStack)
: m_L (L)
{
m_ref = luaL_ref (m_L, LUA_REGISTRYINDEX);
}
LuaRef (lua_State* L, int index, FromStack)
: m_L (L)
{
lua_pushvalue (m_L, index);
m_ref = luaL_ref (m_L, LUA_REGISTRYINDEX);
}
template <class T>
LuaRef (T)
{
}
int createRef () const
{
if (m_ref != LUA_REFNIL)
{
push (m_L);
return luaL_ref (m_L, LUA_REGISTRYINDEX);
}
else
{
return LUA_REFNIL;
}
}
public:
LuaRef (lua_State* L)
: m_L (L)
, m_ref (LUA_REFNIL)
{
}
template <class T>
LuaRef (lua_State* L, T v)
: m_L (L)
{
Stack <T>::push (m_L, v);
m_ref = luaL_ref (m_L, LUA_REGISTRYINDEX);
}
LuaRef (Proxy const& v)
: m_L (v.state ())
, m_ref (v.createRef ())
{
}
LuaRef (LuaRef const& other)
: m_L (other.m_L)
, m_ref (other.createRef ())
{
}
~LuaRef ()
{
luaL_unref (m_L, LUA_REGISTRYINDEX, m_ref);
}
static LuaRef fromStack (lua_State* L, int index)
{
lua_pushvalue (L, index);
return LuaRef (L, FromStack ());
}
static LuaRef newTable (lua_State* L)
{
lua_newtable (L);
return LuaRef (L, FromStack ());
}
static LuaRef getGlobal (lua_State *L, char const* name)
{
lua_getglobal (L, name);
return LuaRef (L, FromStack ());
}
template <class T>
LuaRef& operator= (T rhs)
{
luaL_unref (m_L, LUA_REGISTRYINDEX, m_ref);
Stack <T>::push (m_L, rhs);
m_ref = luaL_ref (m_L, LUA_REGISTRYINDEX);
return *this;
}
LuaRef& operator= (LuaRef const& rhs)
{
luaL_unref (m_L, LUA_REGISTRYINDEX, m_ref);
rhs.push (m_L);
m_L = rhs.state ();
m_ref = luaL_ref (m_L, LUA_REGISTRYINDEX);
return *this;
}
std::string tostring() const
{
lua_getglobal (m_L, "tostring");
push (m_L);
lua_call (m_L, 1, 1);
const char* str = lua_tostring(m_L, 1);
lua_pop(m_L, 1);
return std::string(str);
}
void print (std::ostream& os) const
{
switch (type ())
{
case LUA_TNIL:
os << "nil";
break;
case LUA_TNUMBER:
os << cast <lua_Number> ();
break;
case LUA_TBOOLEAN:
os << (cast <bool> () ? "true" : "false");
break;
case LUA_TSTRING:
os << '"' << cast <std::string> () << '"';
break;
case LUA_TTABLE:
os << "table: " << tostring();
break;
case LUA_TFUNCTION:
os << "function: " << tostring();
break;
case LUA_TUSERDATA:
os << "userdata: " << tostring();
break;
case LUA_TTHREAD:
os << "thread: " << tostring();
break;
case LUA_TLIGHTUSERDATA:
os << "lightuserdata: " << tostring();
break;
default:
os << "unknown";
break;
}
}
lua_State* state () const
{
return m_L;
}
void push (lua_State* L) const
{
assert (equalstates (L, m_L));
lua_rawgeti (L, LUA_REGISTRYINDEX, m_ref);
}
void pop (lua_State* L)
{
assert (equalstates (L, m_L));
luaL_unref (m_L, LUA_REGISTRYINDEX, m_ref);
m_ref = luaL_ref (m_L, LUA_REGISTRYINDEX);
}
int type () const
{
int result;
if (m_ref != LUA_REFNIL)
{
push (m_L);
result = lua_type (m_L, -1);
lua_pop (m_L, 1);
}
else
{
result = LUA_TNIL;
}
return result;
}
inline bool isNil () const { return type () == LUA_TNIL; }
inline bool isNumber () const { return type () == LUA_TNUMBER; }
inline bool isString () const { return type () == LUA_TSTRING; }
inline bool isTable () const { return type () == LUA_TTABLE; }
inline bool isFunction () const { return type () == LUA_TFUNCTION; }
inline bool isUserdata () const { return type () == LUA_TUSERDATA; }
inline bool isThread () const { return type () == LUA_TTHREAD; }
inline bool isLightUserdata () const { return type () == LUA_TLIGHTUSERDATA; }
template <class T>
T cast () const
{
StackPop p (m_L, 1);
push (m_L);
return Stack <T>::get (m_L, lua_gettop (m_L));
}
template <class T>
inline operator T () const
{
return cast <T> ();
}
template <class T>
bool operator== (T rhs) const
{
StackPop p (m_L, 2);
push (m_L);
Stack <T>::push (m_L, rhs);
return lua_compare (m_L, -2, -1, LUA_OPEQ) == 1;
}
template <class T>
bool operator< (T rhs) const
{
StackPop p (m_L, 2);
push (m_L);
Stack <T>::push (m_L, rhs);
return lua_compare (m_L, -2, -1, LUA_OPLT) == 1;
}
template <class T>
bool operator<= (T rhs) const
{
StackPop p (m_L, 2);
push (m_L);
Stack <T>::push (m_L, rhs);
return lua_compare (m_L, -2, -1, LUA_OPLE) == 1;
}
template <class T>
bool operator> (T rhs) const
{
StackPop p (m_L, 2);
push (m_L);
Stack <T>::push (m_L, rhs);
return lua_compare (m_L, -1, -2, LUA_OPLT) == 1;
}
template <class T>
bool operator>= (T rhs) const
{
StackPop p (m_L, 2);
push (m_L);
Stack <T>::push (m_L, rhs);
return lua_compare (m_L, -1, -2, LUA_OPLE) == 1;
}
template <class T>
bool rawequal (T rhs) const
{
StackPop p (m_L, 2);
push (m_L);
Stack <T>::push (m_L, rhs);
return lua_rawequal (m_L, -1, -2) == 1;
}
template <class T>
void append (T v) const
{
push (m_L);
Stack <T>::push (m_L, v);
luaL_ref (m_L, -2);
lua_pop (m_L, 1);
}
int length () const
{
StackPop p (m_L, 1);
push (m_L);
return get_length (m_L, -1);
}
template <class T>
Proxy operator[] (T key) const
{
Stack <T>::push (m_L, key);
return Proxy (m_L, m_ref);
}
LuaRef const operator() () const
{
push (m_L);
LuaException::pcall (m_L, 0, 1);
return LuaRef (m_L, FromStack ());
}
template <class P1>
LuaRef const operator() (P1 p1) const
{
push (m_L);
Stack <P1>::push (m_L, p1);
LuaException::pcall (m_L, 1, 1);
return LuaRef (m_L, FromStack ());
}
template <class P1, class P2>
LuaRef const operator() (P1 p1, P2 p2) const
{
push (m_L);
Stack <P1>::push (m_L, p1);
Stack <P2>::push (m_L, p2);
LuaException::pcall (m_L, 2, 1);
return LuaRef (m_L, FromStack ());
}
template <class P1, class P2, class P3>
LuaRef const operator() (P1 p1, P2 p2, P3 p3) const
{
push (m_L);
Stack <P1>::push (m_L, p1);
Stack <P2>::push (m_L, p2);
Stack <P3>::push (m_L, p3);
LuaException::pcall (m_L, 3, 1);
return LuaRef (m_L, FromStack ());
}
template <class P1, class P2, class P3, class P4>
LuaRef const operator() (P1 p1, P2 p2, P3 p3, P4 p4) const
{
push (m_L);
Stack <P1>::push (m_L, p1);
Stack <P2>::push (m_L, p2);
Stack <P3>::push (m_L, p3);
Stack <P4>::push (m_L, p4);
LuaException::pcall (m_L, 4, 1);
return LuaRef (m_L, FromStack ());
}
template <class P1, class P2, class P3, class P4, class P5>
LuaRef const operator() (P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) const
{
push (m_L);
Stack <P1>::push (m_L, p1);
Stack <P2>::push (m_L, p2);
Stack <P3>::push (m_L, p3);
Stack <P4>::push (m_L, p4);
Stack <P5>::push (m_L, p5);
LuaException::pcall (m_L, 5, 1);
return LuaRef (m_L, FromStack ());
}
template <class P1, class P2, class P3, class P4, class P5, class P6>
LuaRef const operator() (P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) const
{
push (m_L);
Stack <P1>::push (m_L, p1);
Stack <P2>::push (m_L, p2);
Stack <P3>::push (m_L, p3);
Stack <P4>::push (m_L, p4);
Stack <P5>::push (m_L, p5);
Stack <P6>::push (m_L, p6);
LuaException::pcall (m_L, 6, 1);
return LuaRef (m_L, FromStack ());
}
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7>
LuaRef const operator() (P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) const
{
push (m_L);
Stack <P1>::push (m_L, p1);
Stack <P2>::push (m_L, p2);
Stack <P3>::push (m_L, p3);
Stack <P4>::push (m_L, p4);
Stack <P5>::push (m_L, p5);
Stack <P6>::push (m_L, p6);
Stack <P7>::push (m_L, p7);
LuaException::pcall (m_L, 7, 1);
return LuaRef (m_L, FromStack ());
}
template <class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8>
LuaRef const operator() (P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) const
{
push (m_L);
Stack <P1>::push (m_L, p1);
Stack <P2>::push (m_L, p2);
Stack <P3>::push (m_L, p3);
Stack <P4>::push (m_L, p4);
Stack <P5>::push (m_L, p5);
Stack <P6>::push (m_L, p6);
Stack <P7>::push (m_L, p7);
Stack <P8>::push (m_L, p8);
LuaException::pcall (m_L, 8, 1);
return LuaRef (m_L, FromStack ());
}
private:
lua_State* m_L;
int m_ref;
};
template <>
struct Stack <Nil>
{
public:
static inline void push (lua_State* L, Nil)
{
lua_pushnil (L);
}
};
template <>
struct Stack <LuaRef>
{
public:
static inline void push (lua_State* L, LuaRef const& v)
{
v.push (L);
}
static inline LuaRef get (lua_State* L, int index)
{
return LuaRef (L, index, LuaRef::FromStack ());
}
};
template <>
struct Stack <LuaRef::Proxy>
{
public:
static inline void push (lua_State* L, LuaRef::Proxy const& v)
{
v.push (L);
}
};
inline LuaRef newTable (lua_State* L)
{
return LuaRef::newTable (L);
}
inline LuaRef getGlobal (lua_State *L, char const* name)
{
return LuaRef::getGlobal (L, name);
}
inline std::ostream& operator<< (std::ostream& os, LuaRef const& ref)
{
ref.print (os);
return os;
}
template<class T>
inline T LuaRef_cast(LuaRef const& lr)
{
return lr.cast<T>();
}