class_rep.cpp
来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 1,676 行 · 第 1/3 页
CPP
1,676 行
// can only be reached if an exception was thrown
lua_error(L);
#endif
}
return 0;
}
int luabind::detail::class_rep::lua_settable_dispatcher(lua_State* L)
{
class_rep* crep = static_cast<class_rep*>(lua_touserdata(L, 1));
// get first table
crep->get_table(L);
// copy key, value
lua_pushvalue(L, -3);
lua_pushvalue(L, -3);
lua_rawset(L, -3);
// pop table
lua_pop(L, 1);
// get default table
crep->get_default_table(L);
lua_replace(L, 1);
lua_rawset(L, -3);
crep->m_operator_cache = 0; // invalidate cache
return 0;
}
int luabind::detail::class_rep::construct_lua_class_callback(lua_State* L)
{
class_rep* crep = static_cast<class_rep*>(lua_touserdata(L, 1));
int args = lua_gettop(L);
// lua stack: crep <arguments>
lua_newtable(L);
detail::lua_reference ref;
ref.set(L);
bool has_bases = !crep->bases().empty();
if (has_bases)
{
lua_pushstring(L, "super");
lua_pushvalue(L, 1); // crep
}
// lua stack: crep <arguments> "super" crep
// or
// lua stack: crep <arguments>
// if we have a baseclass we set the flag to say that the super has not yet been called
// we will use this flag later to check that it actually was called from __init()
int flags = object_rep::lua_class | object_rep::owner | (has_bases ? object_rep::call_super : 0);
// void* obj_ptr = lua_newuserdata(L, sizeof(object_rep));
void* obj_ptr;
void* held_storage;
boost::tie(obj_ptr, held_storage) = crep->allocate(L);
(new(obj_ptr) object_rep(crep, flags, ref))->set_object(held_storage);
detail::getref(L, crep->metatable_ref());
lua_setmetatable(L, -2);
// lua stack: crep <arguments> "super" crep obj_ptr
// or
// lua stack: crep <arguments> obj_ptr
if (has_bases) lua_pushvalue(L, -1); // obj_ptr
lua_replace(L, 1); // obj_ptr
// lua stack: obj_ptr <arguments> "super" crep obj_ptr
// or
// lua stack: obj_ptr <arguments>
if (has_bases)
{
lua_pushcclosure(L, super_callback, 2);
// lua stack: crep <arguments> "super" function
lua_settable(L, LUA_GLOBALSINDEX);
}
// lua stack: crep <arguments>
lua_pushvalue(L, 1);
lua_insert(L, 1);
crep->get_table(L);
lua_pushstring(L, "__init");
lua_gettable(L, -2);
#ifndef LUABIND_NO_ERROR_CHECKING
// TODO: should this be a run-time error?
// maybe the default behavior should be to just call
// the base calss' constructor. We should register
// the super callback funktion as __init
if (!lua_isfunction(L, -1))
{
{
std::string msg = crep->name();
msg += ":__init is not defined";
lua_pushstring(L, msg.c_str());
}
lua_error(L);
}
#endif
lua_insert(L, 2); // function first on stack
lua_pop(L, 1);
// TODO: lua_call may invoke longjump! make sure we don't have any memory leaks!
// we don't have any stack objects here
lua_call(L, args, 0);
#ifndef LUABIND_NO_ERROR_CHECKING
object_rep* obj = static_cast<object_rep*>(obj_ptr);
if (obj->flags() & object_rep::call_super)
{
lua_pushstring(L, "derived class must call super on base");
lua_error(L);
}
#endif
return 1;
}
// called from the metamethod for __index
// obj is the object pointer
int luabind::detail::class_rep::lua_class_gettable(lua_State* L)
{
object_rep* obj = static_cast<object_rep*>(lua_touserdata(L, 1));
class_rep* crep = obj->crep();
#ifndef LUABIND_NO_ERROR_CHECKING
if (obj->flags() & object_rep::call_super)
{
lua_pushstring(L, "derived class must call super on base");
lua_error(L);
}
#endif
// we have to ignore the first argument since this may point to
// a method that is not present in this class (but in a subclass)
// BUG: This might catch members called "__ok\0foobar"
const char* key = lua_tostring(L, 2);
if (key && !std::strcmp(key, "__ok"))
{
class_rep* crep = obj->crep();
void* p = crep->extractor() ? crep->extractor()(obj->ptr())
: obj->ptr();
lua_pushboolean(L, p != 0);
return 1;
}
// first look in the instance's table
detail::lua_reference const& tbl = obj->get_lua_table();
assert(tbl.is_valid());
tbl.get(L);
lua_pushvalue(L, 2);
lua_gettable(L, -2);
if (!lua_isnil(L, -1))
{
lua_remove(L, -2); // remove table
return 1;
}
lua_pop(L, 2);
// then look in the class' table
crep->get_table(L);
lua_pushvalue(L, 2);
lua_gettable(L, -2);
if (!lua_isnil(L, -1))
{
lua_remove(L, -2); // more table
return 1;
}
lua_pop(L, 2);
if (lua_isnil(L, 2))
{
lua_pushnil(L);
return 1;
}
std::map<const char*, class_rep::callback, ltstr>::iterator j = crep->m_getters.find(key);
if (j != crep->m_getters.end())
{
// the name is a data member
return j->second.func(L, j->second.pointer_offset);
}
lua_pushnil(L);
return 1;
}
// called from the metamethod for __newindex
// obj is the object pointer
int luabind::detail::class_rep::lua_class_settable(lua_State* L)
{
object_rep* obj = static_cast<object_rep*>(lua_touserdata(L, 1));
class_rep* crep = obj->crep();
#ifndef LUABIND_NO_ERROR_CHECKING
if (obj->flags() & object_rep::call_super)
{
// this block makes sure the std::string is destructed
// before lua_error is called
{
std::string msg = "derived class '";
msg += crep->name();
msg += "'must call super on base";
lua_pushstring(L, msg.c_str());
}
lua_error(L);
}
#endif
// we have to ignore the first argument since this may point to
// a method that is not present in this class (but in a subclass)
// BUG: This will not work with keys with extra nulls in them
const char* key = lua_tostring(L, 2);
std::map<const char*, class_rep::callback, ltstr>::iterator j = crep->m_setters.find(key);
// if the strlen(key) is not the true length,
// it means that the member-name contains
// extra nulls. luabind does not support such
// names as member names. So, use the lua
// table as fall-back
if (j == crep->m_setters.end()
|| std::strlen(key) != lua_strlen(L, 2))
{
std::map<const char*, class_rep::callback, ltstr>::iterator k = crep->m_getters.find(key);
#ifndef LUABIND_NO_ERROR_CHECKING
if (k != crep->m_getters.end())
{
{
std::string msg = "cannot set property '";
msg += crep->name();
msg += ".";
msg += key;
msg += "', because it's read only";
lua_pushstring(L, msg.c_str());
}
lua_error(L);
}
#endif
detail::lua_reference const& tbl = obj->get_lua_table();
assert(tbl.is_valid());
tbl.get(L);
lua_replace(L, 1);
lua_settable(L, 1);
}
else
{
// the name is a data member
j->second.func(L, j->second.pointer_offset);
}
return 0;
}
/*
stack:
1: class_rep
2: member name
*/
int luabind::detail::class_rep::static_class_gettable(lua_State* L)
{
class_rep* crep = static_cast<class_rep*>(lua_touserdata(L, 1));
// look in the static function table
crep->get_default_table(L);
lua_pushvalue(L, 2);
lua_gettable(L, -2);
if (!lua_isnil(L, -1)) return 1;
else lua_pop(L, 2);
const char* key = lua_tostring(L, 2);
if (std::strlen(key) != lua_strlen(L, 2))
{
lua_pushnil(L);
return 1;
}
std::map<const char*, int, ltstr>::const_iterator j = crep->m_static_constants.find(key);
if (j != crep->m_static_constants.end())
{
lua_pushnumber(L, j->second);
return 1;
}
#ifndef LUABIND_NO_ERROR_CHECKING
{
std::string msg = "no static '";
msg += key;
msg += "' in class '";
msg += crep->name();
msg += "'";
lua_pushstring(L, msg.c_str());
}
lua_error(L);
#endif
lua_pushnil(L);
return 1;
}
bool luabind::detail::is_class_rep(lua_State* L, int index)
{
if (lua_getmetatable(L, index) == 0) return false;
lua_pushstring(L, "__luabind_classrep");
lua_gettable(L, -2);
if (lua_toboolean(L, -1))
{
lua_pop(L, 2);
return true;
}
lua_pop(L, 2);
return false;
}
void luabind::detail::finalize(lua_State* L, class_rep* crep)
{
if (crep->get_class_type() != class_rep::lua_class) return;
// lua_pushvalue(L, -1); // copy the object ref
crep->get_table(L);
lua_pushstring(L, "__finalize");
lua_gettable(L, -2);
lua_remove(L, -2);
if (lua_isnil(L, -1))
{
lua_pop(L, 1);
}
else
{
lua_pushvalue(L, -2);
lua_call(L, 1, 0);
}
for (std::vector<class_rep::base_info>::const_iterator
i = crep->bases().begin(); i != crep->bases().end(); ++i)
{
if (i->base) finalize(L, i->base);
}
}
void* luabind::detail::class_rep::convert_to(
LUABIND_TYPE_INFO target_type
, const object_rep* obj
, void* target_memory) const
{
// TODO: since this is a member function, we don't have to use the accesor functions for
// the types and the extractor
assert(obj == 0 || obj->crep() == this);
int steps = 0;
int offset = 0;
if (!(LUABIND_TYPE_INFO_EQUAL(holder_type(), target_type))
&& !(LUABIND_TYPE_INFO_EQUAL(const_holder_type(), target_type)))
{
steps = implicit_cast(this, target_type, offset);
}
// should never be called with a type that can't be cast
assert((steps >= 0) && "internal error, please report");
if (LUABIND_TYPE_INFO_EQUAL(target_type, holder_type()))
{
if (obj == 0)
{
// we are trying to convert nil to a holder type
m_default_construct_holder(target_memory);
return target_memory;
}
// if the type we are trying to convert to is the holder_type
// it means that his crep has a holder_type (since it would have
// been invalid otherwise, and T cannot be invalid). It also means
// that we need no conversion, since the holder_type is what the
// object points to.
return obj->ptr();
}
if (LUABIND_TYPE_INFO_EQUAL(target_type, const_holder_type()))
{
if (obj == 0)
{
// we are trying to convert nil to a const holder type
m_default_construct_const_holder(target_memory);
return target_memory;
}
if (obj->flags() & object_rep::constant)
{
// we are holding a constant
return obj->ptr();
}
else
{
// we are holding a non-constant, we need to convert it
// to a const_holder.
m_const_converter(obj->ptr(), target_memory);
return target_memory;
}
}
void* raw_pointer;
if (has_holder())
{
assert(obj);
// this means that we have a holder type where the
// raw-pointer needs to be extracted
raw_pointer = extractor()(obj->ptr());
}
else
{
if (obj == 0) raw_pointer = 0;
else raw_pointer = obj->ptr();
}
return static_cast<char*>(raw_pointer) + offset;
}
void luabind::detail::class_rep::cache_operators(lua_State* L)
{
m_operator_cache = 0x1;
for (int i = 0; i < number_of_operators; ++i)
{
get_table(L);
lua_pushstring(L, get_operator_name(i));
lua_rawget(L, -2);
if (lua_isfunction(L, -1)) m_operator_cache |= 1 << (i + 1);
lua_pop(L, 2);
}
}
bool luabind::detail::class_rep::has_operator_in_lua(lua_State* L, int id)
{
if ((m_operator_cache & 0x1) == 0)
cache_operators(L);
const int mask = 1 << (id + 1);
return (m_operator_cache & mask) != 0;
}
// this will merge all overloads of fun into the list of
// overloads in this class
void luabind::detail::class_rep::add_method(luabind::detail::method_rep const& fun)
{
typedef std::list<detail::method_rep> methods_t;
methods_t::iterator m = std::find_if(
m_methods.begin()
, m_methods.end()
, method_name(fun.name));
if (m == m_methods.end())
{
m_methods.push_back(method_rep());
m = m_methods.end();
std::advance(m, -1);
m->name = fun.name;
}
m->crep = this;
typedef std::vector<detail::overload_rep> overloads_t;
for (overloads_t::const_iterator j = fun.overloads().begin();
j != fun.overloads().end(); ++j)
{
detail::overload_rep o = *j;
m->add_overload(o);
}
}
// this function will add all the overloads in method rep to
// this class' lua tables. If there already are overloads with this
// name, thses will simply be appended to the overload list
void luabind::detail::class_rep::register_methods(lua_State* L)
{
LUABIND_CHECK_STACK(L);
// insert the function in the normal member table
// and in the default member table
m_default_table.push(L);
m_table.push(L);
// pops the tables
detail::stack_pop pop_tables(L, 2);
for (std::list<method_rep>::const_iterator m = m_methods.begin();
m != m_methods.end(); ++m)
{
// create the function closure in m_table
lua_pushstring(L, m->name);
lua_pushlightuserdata(L, const_cast<void*>((const void*)&(*m)));
lua_pushboolean(L, 0);
lua_pushlightuserdata(L, reinterpret_cast<void*>(0x1337));
lua_pushcclosure(L, function_dispatcher, 3);
lua_settable(L, -3);
// create the function closure in m_default_table
lua_pushstring(L, m->name);
lua_pushlightuserdata(L, const_cast<void*>((const void*)&(*m)));
lua_pushboolean(L, 1);
lua_pushlightuserdata(L, reinterpret_cast<void*>(0x1337));
lua_pushcclosure(L, function_dispatcher, 3);
lua_settable(L, -4);
}
}
const class_rep::property_map& luabind::detail::class_rep::properties() const
{
return m_getters;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?