📄 object.hpp
字号:
// Copyright (c) 2003 Daniel Wallin and Arvid Norberg
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
// OR OTHER DEALINGS IN THE SOFTWARE.
#if !BOOST_PP_IS_ITERATING
#ifndef LUABIND_OBJECT_HPP_INCLUDED
#define LUABIND_OBJECT_HPP_INCLUDED
#include <iterator>
#include <luabind/config.hpp>
#include <luabind/detail/error.hpp>
#include <boost/preprocessor/repeat.hpp>
#include <boost/preprocessor/iteration/iterate.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#include <boost/tuple/tuple.hpp>
namespace luabind
{
// below are some considerations that haven't been implemented
//
//
// object might need to be able to store values temporarily
// without knowing about a lua_State.
//
// globals["f"] = function(&f);
//
// Creates the need for this, since function() doesn't know
// about the state and thus can't return a fully initialized
// object.
//
// Current solution is to allow for objects to store a pointer
// to a commiter-object. This object has a virtual method which
// converts it's value to the lua_State.
//
// This has some serious issues. For example, how would
// two 'pseude-initialized' objects be able to compare?
//
// Perhaps attempting to perform operations on non-intialised
// objects could throw?
//
// Perhaps we could perform some not-so-smart comparisions? like:
//
// template<class T>
// struct commiter : base_commiter
// {
// commiter(const T& v): val(v), base_commiter(typeid(T)) {}
//
// virtual bool compare(void* rhs)
// {
// T* other = static_cast<T*>(rhs);
// return val == *other;
// }
//
// T val;
// };
//
// This would at least allow for the most intuitive use.. like:
//
// object a = 5;
// object b = 5;
//
// return a == b;
//
// However, comparing an initialized object with a non-initialized
// would always return false. Is this ok? Better to disallow it?
// the current implementation does not have commiters, all objects
// knows about the lua_State* or is uninitialized.
class object;
namespace detail
{
class proxy_object;
class proxy_raw_object;
class proxy_array_object;
template<class T>
void convert_to_lua(lua_State*, const T&);
template<int Index, class T, class Policies>
void convert_to_lua_p(lua_State*, const T&, const Policies&);
template<int Index>
struct push_args_from_tuple
{
template<class H, class T, class Policies>
inline static void apply(lua_State* L, const boost::tuples::cons<H, T>& x, const Policies& p)
{
convert_to_lua_p<Index>(L, *x.get_head(), p);
push_args_from_tuple<Index+1>::apply(L, x.get_tail(), p);
}
template<class H, class T>
inline static void apply(lua_State* L, const boost::tuples::cons<H, T>& x)
{
convert_to_lua(L, *x.get_head());
push_args_from_tuple<Index+1>::apply(L, x.get_tail());
}
template<class Policies>
inline static void apply(lua_State*, const boost::tuples::null_type&, const Policies&) {};
inline static void apply(lua_State*, const boost::tuples::null_type&) {};
};
template<class Tuple>
class proxy_caller
{
friend class luabind::object;
public:
proxy_caller(luabind::object* o, const Tuple args)
: m_obj(o)
, m_args(args)
, m_called(false)
{
}
proxy_caller(const detail::proxy_caller<Tuple>& rhs)
: m_obj(rhs.m_obj)
, m_args(rhs.m_args)
, m_called(rhs.m_called)
{
rhs.m_called = true;
}
~proxy_caller();
operator luabind::object();
#if defined(BOOST_MSVC) && (BOOST_MSVC <= 1300)
#define LUABIND_SEMICOLON
#else
#define LUABIND_SEMICOLON ;
#endif
template<class Policies>
luabind::object operator[](const Policies& p) LUABIND_SEMICOLON
#if defined(BOOST_MSVC) && (BOOST_MSVC <= 1300)
{
m_called = true;
lua_State* L = m_obj->lua_state();
m_obj->pushvalue();
detail::push_args_from_tuple<1>::apply(L, m_args, p);
if (lua_pcall(L, boost::tuples::length<Tuple>::value, 1, 0))
{
#ifndef LUABIND_NO_EXCEPTIONS
throw error(L);
#else
error_callback_fun e = detail::error_callback::get().err;
if (e) e(L);
assert(0 && "the lua function threw an error and exceptions are disabled."
"if you want to handle this error use luabind::set_error_callback()");
std::terminate();
#endif
}
int ref = detail::ref(L);
return luabind::object(m_obj->lua_state(), ref, true/*luabind::object::reference()*/);
}
#endif
#undef LUABIND_SEMICOLON
private:
luabind::object* m_obj;
Tuple m_args;
mutable bool m_called;
};
struct stack_pop
{
stack_pop(lua_State* L, int n)
: m_state(L)
, m_n(n)
{
}
~stack_pop()
{
lua_pop(m_state, m_n);
}
private:
lua_State* m_state;
int m_n;
};
class proxy_object
{
friend class luabind::object;
friend class luabind::detail::proxy_array_object;
friend class luabind::detail::proxy_raw_object;
// template<class T> friend T object_cast(const proxy_object& obj);
public:
template<class T>
proxy_object& operator=(const T& val)
{
//std::cout << "proxy assigment\n";
lua_State* L = m_obj->m_state;
m_obj->pushvalue();
detail::getref(L, m_key_ref);
detail::convert_to_lua(L, val);
lua_settable(L, -3);
// pop table
lua_pop(L, 1);
return *this;
}
proxy_object& operator=(const object& p);
proxy_object& operator=(const proxy_object& p);
proxy_object& operator=(const proxy_raw_object& p);
proxy_object& operator=(const proxy_array_object& p);
void swap(const proxy_object& rhs);
operator luabind::object();
int type() const
{
pushvalue();
detail::stack_pop p(lua_state(), 1);
return lua_type(lua_state(), -1);
}
#define LUABIND_PROXY_RAW_AT_BODY \
{ \
lua_State* L = lua_state(); \
pushvalue(); \
detail::convert_to_lua(L, key); \
lua_rawget(L, -2); \
int ref = detail::ref(L); \
lua_pop(L, 1); \
return object(L, ref, true); \
}
#if defined(BOOST_MSVC) && (BOOST_MSVC <= 1300)
template<class T>
inline object raw_at(const T& key)
LUABIND_PROXY_RAW_AT_BODY
#else
template<class T>
inline object raw_at(const T& key);
#endif
#define LUABIND_PROXY_AT_BODY \
{ \
lua_State* L = lua_state(); \
pushvalue(); \
detail::convert_to_lua(L, key); \
lua_gettable(L, -2); \
int ref = detail::ref(L); \
lua_pop(L, 1); \
return object(L, ref, true); \
}
#if defined(BOOST_MSVC) && (BOOST_MSVC <= 1300)
template<class T>
inline object at(const T& key)
LUABIND_PROXY_AT_BODY
#else
template<class T>
inline object at(const T& key);
#endif
inline bool is_valid() const { return true; }
lua_State* lua_state() const;
void pushvalue() const;
void set() const;
// this is a safe substitute for an implicit converter to bool
typedef void (proxy_object::*member_ptr)() const;
operator member_ptr() const
{
if (is_valid()) return &proxy_object::dummy;
return 0;
}
private:
void dummy() const {}
proxy_object(luabind::object* o, int key)
: m_obj(o)
, m_key_ref(key)
{
}
luabind::object* m_obj;
int m_key_ref;
};
class proxy_raw_object
{
friend class luabind::object;
friend class luabind::detail::proxy_array_object;
friend class luabind::detail::proxy_object;
// template<class T> friend T luabind::object_cast(const proxy_object& obj);
public:
template<class T>
proxy_raw_object& operator=(const T& val)
{
//std::cout << "proxy assigment\n";
lua_State* L = m_obj->m_state;
m_obj->pushvalue();
detail::getref(L, m_key_ref);
detail::convert_to_lua(L, val);
lua_rawset(L, -3);
// pop table
lua_pop(L, 1);
return *this;
}
proxy_raw_object& operator=(const object& p);
proxy_raw_object& operator=(const proxy_object& p);
proxy_raw_object& operator=(const proxy_raw_object& p);
proxy_raw_object& operator=(const proxy_array_object& p);
void swap(const proxy_raw_object& rhs);
operator luabind::object();
int type() const
{
pushvalue();
detail::stack_pop p(lua_state(), 1);
return lua_type(lua_state(), -1);
}
#if defined(BOOST_MSVC) && (BOOST_MSVC <= 1300)
template<class T>
inline object raw_at(const T& key)
LUABIND_PROXY_RAW_AT_BODY
#else
template<class T>
inline object raw_at(const T& key);
#endif
#if defined(BOOST_MSVC) && (BOOST_MSVC <= 1300)
template<class T>
inline object at(const T& key)
LUABIND_PROXY_AT_BODY
#else
template<class T>
inline object at(const T& key);
#endif
inline bool is_valid() const { return true; }
lua_State* lua_state() const;
void pushvalue() const;
void set() const;
// this is a safe substitute for an implicit converter to bool
typedef void (proxy_raw_object::*member_ptr)() const;
operator member_ptr() const
{
if (is_valid()) return &proxy_raw_object::dummy;
return 0;
}
private:
void dummy() const {}
proxy_raw_object(luabind::object* o, int key)
: m_obj(o)
, m_key_ref(key)
{
}
luabind::object* m_obj;
int m_key_ref;
};
class proxy_array_object
{
friend class luabind::object;
friend class luabind::detail::proxy_object;
friend class luabind::detail::proxy_raw_object;
// template<class T> friend T object_cast(const proxy_array_object& obj);
public:
template<class T>
proxy_array_object& operator=(const T& val)
{
//std::cout << "array proxy assigment\n";
lua_State* L = m_obj->m_state;
m_obj->pushvalue();
detail::convert_to_lua(L, val);
lua_rawseti(L, -2, m_key);
// pops the table
lua_pop(L, 1);
return *this;
}
proxy_array_object& operator=(const object& p);
proxy_array_object& operator=(const proxy_object& p);
proxy_array_object& operator=(const proxy_raw_object& p);
proxy_array_object& operator=(const proxy_array_object& p);
void swap(const proxy_array_object& rhs);
operator luabind::object();
int type() const
{
pushvalue();
detail::stack_pop p(lua_state(), 1);
return lua_type(lua_state(), -1);
}
#define LUABIND_PROXY_ARRAY_RAW_AT_BODY \
{ \
pushvalue(); \
detail::convert_to_lua(m_state, key); \
lua_rawget(m_state, -2); \
int ref = detail::ref(m_state); \
lua_pop(m_state, 1); \
return object(m_state, ref, true); \
}
#define LUABIND_PROXY_ARRAY_AT_BODY \
{ \
pushvalue(); \
detail::convert_to_lua(m_state, key); \
lua_gettable(m_state, -2); \
int ref = detail::ref(m_state); \
lua_pop(m_state, 1); \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -