class_rep.cpp.svn-base
来自「本人找过多个在linux下c++的lua5.1封装库,但很少.luabind已经」· SVN-BASE 代码 · 共 1,676 行 · 第 1/3 页
SVN-BASE
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; }#endifluabind::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 stackstd::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, keyint 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, valuebool 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 classint 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 + -
显示快捷键?