class_rep.cpp
来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 1,676 行 · 第 1/3 页
CPP
1,676 行
// 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.
#include <luabind/lua_include.hpp>
#include <luabind/detail/stack_utils.hpp>
#include <luabind/luabind.hpp>
#include <utility>
using namespace luabind::detail;
namespace luabind { namespace detail
{
struct method_name
{
method_name(char const* n): name(n) {}
bool operator()(method_rep const& o) const
{ return std::strcmp(o.name, name) == 0; }
char const* name;
};
}}
#ifndef LUABIND_NO_ERROR_CHECKING
std::string luabind::detail::get_overload_signatures_candidates(
lua_State* L
, std::vector<const overload_rep_base*>::iterator start
, std::vector<const overload_rep_base*>::iterator end
, std::string name)
{
std::string s;
for (; start != end; ++start)
{
s += name;
(*start)->get_signature(L, s);
s += "\n";
}
return s;
}
#endif
luabind::detail::class_rep::class_rep(LUABIND_TYPE_INFO type
, const char* name
, lua_State* L
, void(*destructor)(void*)
, void(*const_holder_destructor)(void*)
, LUABIND_TYPE_INFO holder_type
, LUABIND_TYPE_INFO const_holder_type
, void*(*extractor)(void*)
, const void*(*const_extractor)(void*)
, void(*const_converter)(void*,void*)
, void(*construct_holder)(void*,void*)
, void(*construct_const_holder)(void*,void*)
, void(*default_construct_holder)(void*)
, void(*default_construct_const_holder)(void*)
, void(*adopt_fun)(void*)
, int holder_size
, int holder_alignment)
: m_type(type)
, m_holder_type(holder_type)
, m_const_holder_type(const_holder_type)
, m_extractor(extractor)
, m_const_extractor(const_extractor)
, m_const_converter(const_converter)
, m_construct_holder(construct_holder)
, m_construct_const_holder(construct_const_holder)
, m_default_construct_holder(default_construct_holder)
, m_default_construct_const_holder(default_construct_const_holder)
, m_adopt_fun(adopt_fun)
, m_holder_size(holder_size)
, m_holder_alignment(holder_alignment)
, m_name(name)
, m_class_type(cpp_class)
, m_destructor(destructor)
, m_const_holder_destructor(const_holder_destructor)
, m_operator_cache(0)
{
assert(m_holder_alignment >= 1 && "internal error");
lua_newtable(L);
handle(L, -1).swap(m_table);
lua_newtable(L);
handle(L, -1).swap(m_default_table);
lua_pop(L, 2);
class_registry* r = class_registry::get_registry(L);
assert((r->cpp_class() != LUA_NOREF) && "you must call luabind::open()");
detail::getref(L, r->cpp_class());
lua_setmetatable(L, -2);
lua_pushvalue(L, -1); // duplicate our user data
m_self_ref.set(L);
m_instance_metatable = r->cpp_instance();
}
luabind::detail::class_rep::class_rep(lua_State* L, const char* name)
: m_type(LUABIND_INVALID_TYPE_INFO)
, m_holder_type(LUABIND_INVALID_TYPE_INFO)
, m_const_holder_type(LUABIND_INVALID_TYPE_INFO)
, m_extractor(0)
, m_const_extractor(0)
, m_const_converter(0)
, m_construct_holder(0)
, m_construct_const_holder(0)
, m_default_construct_holder(0)
, m_default_construct_const_holder(0)
, m_adopt_fun(0)
, m_holder_size(0)
, m_holder_alignment(1)
, m_name(name)
, m_class_type(lua_class)
, m_destructor(0)
, m_const_holder_destructor(0)
, m_operator_cache(0)
{
lua_newtable(L);
handle(L, -1).swap(m_table);
lua_newtable(L);
handle(L, -1).swap(m_default_table);
lua_pop(L, 2);
class_registry* r = class_registry::get_registry(L);
assert((r->cpp_class() != LUA_NOREF) && "you must call luabind::open()");
detail::getref(L, r->lua_class());
lua_setmetatable(L, -2);
lua_pushvalue(L, -1); // duplicate our user data
m_self_ref.set(L);
m_instance_metatable = r->lua_instance();
}
luabind::detail::class_rep::~class_rep()
{
}
// leaves object on lua stack
std::pair<void*,void*>
luabind::detail::class_rep::allocate(lua_State* L) const
{
const int overlap = sizeof(object_rep)&(m_holder_alignment-1);
const int padding = overlap==0?0:m_holder_alignment-overlap;
const int size = sizeof(object_rep) + padding + m_holder_size;
char* mem = static_cast<char*>(lua_newuserdata(L, size));
char* ptr = mem + sizeof(object_rep) + padding;
return std::pair<void*,void*>(mem,ptr);
}
/*
#include <iostream>
namespace
{
void dump_stack(lua_State* L)
{
for (int i = 1; i <= lua_gettop(L); ++i)
{
int t = lua_type(L, i);
switch (t)
{
case LUA_TNUMBER:
std::cout << "[" << i << "] number: " << lua_tonumber(L, i) << "\n";
break;
case LUA_TSTRING:
std::cout << "[" << i << "] string: " << lua_tostring(L, i) << "\n";
break;
case LUA_TUSERDATA:
std::cout << "[" << i << "] userdata: " << lua_touserdata(L, i) << "\n";
break;
case LUA_TTABLE:
std::cout << "[" << i << "] table:\n";
break;
case LUA_TNIL:
std::cout << "[" << i << "] nil:\n";
break;
}
}
}
}
*/
void luabind::detail::class_rep::adopt(bool const_obj, void* obj)
{
if (m_adopt_fun == 0) return;
if (m_extractor)
{
assert(m_const_extractor);
if (const_obj)
m_adopt_fun(const_cast<void*>(m_const_extractor(obj)));
else
m_adopt_fun(m_extractor(obj));
}
else
{
m_adopt_fun(obj);
}
}
// lua stack: userdata, key
int luabind::detail::class_rep::gettable(lua_State* L)
{
// if key is nil, return nil
if (lua_isnil(L, 2))
{
lua_pushnil(L);
return 1;
}
object_rep* obj = static_cast<object_rep*>(lua_touserdata(L, 1));
// 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)
const char* key = lua_tostring(L, 2);
#ifndef LUABIND_NO_ERROR_CHECKING
if (std::strlen(key) != lua_strlen(L, 2))
{
{
std::string msg("luabind does not support "
"member names with extra nulls:\n");
msg += std::string(lua_tostring(L, 2), lua_strlen(L, 2));
lua_pushstring(L, msg.c_str());
}
lua_error(L);
}
#endif
// special case to see if this is a null-pointer
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();
if (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 for this member
obj->crep()->get_table(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);
std::map<const char*, callback, ltstr>::iterator j = m_getters.find(key);
if (j != 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
// the object pointer is passed on the lua stack
// lua stack: userdata, key, value
bool luabind::detail::class_rep::settable(lua_State* L)
{
// if the key is 'nil' fail
if (lua_isnil(L, 2)) return false;
// 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)
const char* key = lua_tostring(L, 2);
if (std::strlen(key) == lua_strlen(L, 2))
{
std::map<const char*, callback, ltstr>::iterator j = m_setters.find(key);
if (j != m_setters.end())
{
// the name is a data member
#ifndef LUABIND_NO_ERROR_CHECKING
if (j->second.match(L, 3) < 0)
{
std::string msg("the attribute '");
msg += m_name;
msg += ".";
msg += key;
msg += "' is of type: ";
j->second.sig(L, msg);
msg += "\nand does not match: (";
msg += stack_content_by_name(L, 3);
msg += ")";
lua_pushstring(L, msg.c_str());
return false;
}
#endif
j->second.func(L, j->second.pointer_offset);
return true;
}
if (m_getters.find(key) != m_getters.end())
{
// this means that we have a getter but no
// setter for an attribute. We will then fail
// because that attribute is read-only
std::string msg("the attribute '");
msg += m_name;
msg += ".";
msg += key;
msg += "' is read only";
lua_pushstring(L, msg.c_str());
return false;
}
}
// set the attribute to the object's table
object_rep* obj = static_cast<object_rep*>(lua_touserdata(L, 1));
detail::lua_reference& tbl = obj->get_lua_table();
if (!tbl.is_valid())
{
// this is the first time we are trying to add
// a member to this instance, create the table.
lua_newtable(L);
lua_pushvalue(L, -1);
tbl.set(L);
}
else
{
tbl.get(L);
}
lua_pushvalue(L, 2);
lua_pushvalue(L, 3);
lua_settable(L, 4);
lua_pop(L, 3);
return true;
}
int class_rep::gettable_dispatcher(lua_State* L)
{
object_rep* obj = static_cast<object_rep*>(lua_touserdata(L, 1));
return obj->crep()->gettable(L);
}
// this is called as __newindex metamethod on every instance of this class
int luabind::detail::class_rep::settable_dispatcher(lua_State* L)
{
object_rep* obj = static_cast<object_rep*>(lua_touserdata(L, 1));
bool success = obj->crep()->settable(L);
#ifndef LUABIND_NO_ERROR_CHECKING
if (!success)
{
// class_rep::settable() will leave
// error message on the stack in case
// of failure
lua_error(L);
}
#endif
return 0;
}
int luabind::detail::class_rep::operator_dispatcher(lua_State* L)
{
for (int i = 0; i < 2; ++i)
{
if (is_class_object(L, 1 + i))
{
int nargs = lua_gettop(L);
lua_pushvalue(L, lua_upvalueindex(1));
lua_gettable(L, 1 + i);
if (lua_isnil(L, -1))
{
lua_pop(L, 1);
continue;
}
lua_insert(L, 1); // move the function to the bottom
nargs = lua_toboolean(L, lua_upvalueindex(2)) ? 1 : nargs;
if (lua_toboolean(L, lua_upvalueindex(2))) // remove trailing nil
lua_remove(L, 3);
lua_call(L, nargs, 1);
return 1;
}
}
lua_pop(L, lua_gettop(L));
lua_pushstring(L, "No such operator defined");
lua_error(L);
return 0;
}
// this is called as metamethod __call on the class_rep.
int luabind::detail::class_rep::constructor_dispatcher(lua_State* L)
{
class_rep* crep = static_cast<class_rep*>(lua_touserdata(L, 1));
construct_rep* rep = &crep->m_constructor;
bool ambiguous = false;
int match_index = -1;
int min_match = std::numeric_limits<int>::max();
bool found;
#ifdef LUABIND_NO_ERROR_CHECKING
if (rep->overloads.size() == 1)
{
match_index = 0;
}
else
{
#endif
int num_params = lua_gettop(L) - 1;
found = find_best_match(L, &rep->overloads.front(), rep->overloads.size(), sizeof(construct_rep::overload_t), ambiguous, min_match, match_index, num_params);
#ifdef LUABIND_NO_ERROR_CHECKING
}
#else
if (!found)
{
{
std::string msg("no constructor of '");
msg += crep->name();
msg += "' matched the arguments (";
msg += stack_content_by_name(L, 2);
msg += ")\n candidates are:\n";
msg += get_overload_signatures(L, rep->overloads.begin(), rep->overloads.end(), crep->name());
lua_pushstring(L, msg.c_str());
}
lua_error(L);
}
else if (ambiguous)
{
{
std::string msg("call of overloaded constructor '");
msg += crep->m_name;
msg += "(";
msg += stack_content_by_name(L, 2);
msg += ")' is ambiguous\nnone of the overloads have a best conversion:\n";
std::vector<const overload_rep_base*> candidates;
find_exact_match(L, &rep->overloads.front(), rep->overloads.size(), sizeof(construct_rep::overload_t), min_match, num_params, candidates);
msg += get_overload_signatures_candidates(L, candidates.begin(), candidates.end(), crep->name());
lua_pushstring(L, msg.c_str());
}
lua_error(L);
}
#endif
#ifndef LUABIND_NO_EXCEPTIONS
try
{
#endif
void* obj_rep;
void* held;
boost::tie(obj_rep,held) = crep->allocate(L);
weak_ref backref(L, -1);
void* object_ptr = rep->overloads[match_index].construct(L, backref);
if (crep->has_holder())
{
crep->m_construct_holder(held, object_ptr);
object_ptr = held;
}
new(obj_rep) object_rep(object_ptr, crep, object_rep::owner, crep->destructor());
detail::getref(L, crep->m_instance_metatable);
lua_setmetatable(L, -2);
return 1;
#ifndef LUABIND_NO_EXCEPTIONS
}
catch(const error&)
{
}
catch(const std::exception& e)
{
lua_pushstring(L, e.what());
}
catch(const char* s)
{
lua_pushstring(L, s);
}
catch(...)
{
{
std::string msg = crep->name();
msg += "() threw an exception";
lua_pushstring(L, msg.c_str());
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?