class_rep.cpp

来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 1,676 行 · 第 1/3 页

CPP
1,676
字号
	}

	// we can only reach this line if an exception was thrown
	lua_error(L);
	return 0; // will never be reached

#endif

}

/*
	the functions dispatcher assumes the following:

	upvalues:
	1: method_rep* method, points to the method_rep that this dispatcher is to call
	2: boolean force_static, is true if this is to be a static call
       and false if it is a normal call (= virtual if possible).

	stack:
	1: object_rep* self, points to the object the call is being made on
*/

int luabind::detail::class_rep::function_dispatcher(lua_State* L)
{
#ifndef NDEBUG

/*	lua_Debug tmp_;
	assert(lua_getinfo(L, "u", &tmp_));
	assert(tmp_.nups == 2);*/
	assert(lua_type(L, lua_upvalueindex(1)) == LUA_TLIGHTUSERDATA);
	assert(lua_type(L, lua_upvalueindex(2)) == LUA_TBOOLEAN);
	assert(lua_type(L, lua_upvalueindex(3)) == LUA_TLIGHTUSERDATA);
	assert(lua_touserdata(L, lua_upvalueindex(3)) == reinterpret_cast<void*>(0x1337));



//	assert(lua_type(L, 1) == LUA_TUSERDATA);

#endif

	method_rep* rep = static_cast<method_rep*>(lua_touserdata(L, lua_upvalueindex(1)));
	int force_static_call = lua_toboolean(L, lua_upvalueindex(2));

	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(overload_rep), ambiguous, min_match, match_index, num_params);

#ifdef LUABIND_NO_ERROR_CHECKING

	}

#else

	if (!found)
	{
		{
			std::string msg = "no overload of  '";
			msg += rep->crep->name();
			msg += ":";
			msg += rep->name;
			msg += "' matched the arguments (";
			msg += stack_content_by_name(L, 1);
			msg += ")\ncandidates are:\n";

			std::string function_name;
			function_name += rep->crep->name();
			function_name += ":";
			function_name += rep->name;

			msg += get_overload_signatures(L, rep->overloads().begin()
				, rep->overloads().end(), function_name);

			lua_pushstring(L, msg.c_str());
		}
		lua_error(L);
	}
	else if (ambiguous)
	{
		{
			std::string msg = "call of overloaded  '";
			msg += rep->crep->name();
			msg += ":";
			msg += rep->name;
			msg += "(";
			msg += stack_content_by_name(L, 1);
			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(overload_rep), min_match, num_params, candidates);

			std::string function_name;
			function_name += rep->crep->name();
			function_name += ":";
			function_name += rep->name;

			msg += get_overload_signatures_candidates(L, candidates.begin()
				, candidates.end(), function_name);

			lua_pushstring(L, msg.c_str());
		}
		lua_error(L);
	}

#endif

#ifndef LUABIND_NO_EXCEPTIONS

	try
	{

#endif

		const overload_rep& o = rep->overloads()[match_index];

        if (force_static_call && !o.has_static())
		{
			lua_pushstring(L, "pure virtual function called");
        }
		else
		{
	        return o.call(L, force_static_call != 0);
		}

#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 = rep->crep->name();
		msg += ":";
		msg += rep->name;
		msg += "() threw an exception";
		lua_pushstring(L, msg.c_str());
	}

#endif

	// we can only reach this line if an error occured
	lua_error(L);
	return 0; // will never be reached
}

#ifndef NDEBUG

#ifndef BOOST_NO_STRINGSTREAM
#include <sstream>
#else
#include <strstream>
#endif

namespace
{
	std::string to_string(luabind::object const& o)
	{
		using namespace luabind;
		if (type(o) == LUA_TSTRING) return object_cast<std::string>(o);
		lua_State* L = o.interpreter();
		LUABIND_CHECK_STACK(L);

#ifdef BOOST_NO_STRINGSTREAM
		std::strstream s;
#else
		std::stringstream s;
#endif

		if (type(o) == LUA_TNUMBER)
		{
			s << object_cast<float>(o);
			return s.str();
		}

		s << "<" << lua_typename(L, type(o)) << ">";
#ifdef BOOST_NO_STRINGSTREAM
		s << std::ends;
#endif
		return s.str();
	}


	std::string member_to_string(luabind::object const& e)
	{
#if !defined(LUABIND_NO_ERROR_CHECKING)
        using namespace luabind;
		lua_State* L = e.interpreter();
		LUABIND_CHECK_STACK(L);

		if (type(e) == LUA_TFUNCTION)
		{
			e.push(L);
			detail::stack_pop p(L, 1);

			{
				if (lua_getupvalue(L, -1, 3) == 0) return to_string(e);
				detail::stack_pop p2(L, 1);
				if (lua_touserdata(L, -1) != reinterpret_cast<void*>(0x1337)) return to_string(e);
			}

#ifdef BOOST_NO_STRINGSTREAM
			std::strstream s;
#else
			std::stringstream s;
#endif
			{
				lua_getupvalue(L, -1, 2);
				detail::stack_pop p2(L, 1);
				int b = lua_toboolean(L, -1);
				s << "<c++ function";
				if (b) s << " (default)";
				s << "> ";
			}

			{
				lua_getupvalue(L, -1, 1);
				detail::stack_pop p2(L, 1);
				method_rep* m = static_cast<method_rep*>(lua_touserdata(L, -1));
				s << m << "\n";
				for (std::vector<overload_rep>::const_iterator i = m->overloads().begin();
					i != m->overloads().end(); ++i)
				{
					std::string str;
					i->get_signature(L, str);
					s << "   " << str << "\n";
				}
			}
#ifdef BOOST_NO_STRINGSTREAM
			s << std::ends;
#endif
			return s.str();
		}

        return to_string(e);
#else
        return "";
#endif
	}
}

std::string luabind::detail::class_rep::class_info_string(lua_State* L) const
{
#ifdef BOOST_NO_STRINGSTREAM
	std::strstream ret;
#else
	std::stringstream ret;
#endif

	ret << "CLASS: " << m_name << "\n";

	ret << "dynamic dispatch functions:\n------------------\n";

	for (luabind::iterator i(m_table), end; i != end; ++i)
	{
		luabind::object e = *i;
		ret << "  " << to_string(i.key()) << ": " << member_to_string(e) << "\n";
	}

	ret << "default implementations:\n------------------\n";

	for (luabind::iterator i(m_default_table), end; i != end; ++i)
	{
		luabind::object e = *i;
		ret << "  " << to_string(i.key()) << ": " << member_to_string(e) << "\n";
	}
#ifdef BOOST_NO_STRINGSTREAM
	ret << std::ends;
#endif
	return ret.str();
}
#endif

void luabind::detail::class_rep::add_base_class(const luabind::detail::class_rep::base_info& binfo)
{
	// If you hit this assert you are deriving from a type that is not registered
	// in lua. That is, in the class_<> you are giving a baseclass that isn't registered.
	// Please note that if you don't need to have access to the base class or the
	// conversion from the derived class to the base class, you don't need
	// to tell luabind that it derives.
	assert(binfo.base && "You cannot derive from an unregistered type");

	class_rep* bcrep = binfo.base;

	// import all functions from the base
	typedef std::list<detail::method_rep> methods_t;

	for (methods_t::const_iterator i = bcrep->m_methods.begin();
		i != bcrep->m_methods.end(); ++i)
    {
		add_method(*i);
    }

	// import all getters from the base
	for (std::map<const char*, callback, ltstr>::const_iterator i = bcrep->m_getters.begin(); 
			i != bcrep->m_getters.end(); ++i)
	{
		callback& m = m_getters[i->first];
		m.pointer_offset = i->second.pointer_offset + binfo.pointer_offset;
		m.func = i->second.func;

#ifndef LUABIND_NO_ERROR_CHECKING
		m.match = i->second.match;
		m.sig = i->second.sig;
#endif
	}

	// import all setters from the base
	for (std::map<const char*, callback, ltstr>::const_iterator i = bcrep->m_setters.begin(); 
			i != bcrep->m_setters.end(); ++i)
	{
		callback& m = m_setters[i->first];
		m.pointer_offset = i->second.pointer_offset + binfo.pointer_offset;
		m.func = i->second.func;

#ifndef LUABIND_NO_ERROR_CHECKING
		m.match = i->second.match;
		m.sig = i->second.sig;
#endif
	}

	// import all static constants
	for (std::map<const char*, int, ltstr>::const_iterator i = bcrep->m_static_constants.begin(); 
			i != bcrep->m_static_constants.end(); ++i)
	{
		int& v = m_static_constants[i->first];
		v = i->second;
	}

	// import all operators
	for (int i = 0; i < number_of_operators; ++i)
	{
		for (std::vector<operator_callback>::const_iterator j = bcrep->m_operators[i].begin(); 
				j != bcrep->m_operators[i].end(); ++j)
			m_operators[i].push_back(*j);
	}

	// also, save the baseclass info to be used for typecasts
	m_bases.push_back(binfo);
}

int luabind::detail::class_rep::super_callback(lua_State* L)
{
	int args = lua_gettop(L);
		
	object_rep* obj = static_cast<object_rep*>(lua_touserdata(L, lua_upvalueindex(2)));
	class_rep* crep = static_cast<class_rep*>(lua_touserdata(L, lua_upvalueindex(1)));
	class_rep* base = crep->bases()[0].base;

	if (base->get_class_type() == class_rep::lua_class)
	{
		if (base->bases().empty())
		{
			obj->set_flags(obj->flags() & ~object_rep::call_super);

			lua_pushstring(L, "super");
			lua_pushnil(L);
			lua_settable(L, LUA_GLOBALSINDEX);
		}
		else
		{
			lua_pushstring(L, "super");
			lua_pushlightuserdata(L, base);
			lua_pushvalue(L, lua_upvalueindex(2));
			lua_pushcclosure(L, super_callback, 2);
			lua_settable(L, LUA_GLOBALSINDEX);
		}

		base->get_table(L);
		lua_pushstring(L, "__init");
		lua_gettable(L, -2);
		lua_insert(L, 1);
		lua_pop(L, 1);

		lua_pushvalue(L, lua_upvalueindex(2));
		lua_insert(L, 2);

		lua_call(L, args + 1, 0);

		// TODO: instead of clearing the global variable "super"
		// store it temporarily in the registry. maybe we should
		// have some kind of warning if the super global is used?
		lua_pushstring(L, "super");
		lua_pushnil(L);
		lua_settable(L, LUA_GLOBALSINDEX);
	}
	else
	{
		obj->set_flags(obj->flags() & ~object_rep::call_super);

		// we need to push some garbage at index 1 to make the construction work
		lua_pushboolean(L, 1);
		lua_insert(L, 1);

		construct_rep* rep = &base->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 += base->m_name;
				msg += "' matched the arguments (";
				msg += stack_content_by_name(L, 2);
				msg += ")";
				lua_pushstring(L, msg.c_str());
			}
			lua_error(L);
		}
		else if (ambiguous)
		{
			{
				std::string msg = "call of overloaded constructor '";
				msg += base->m_name;
				msg +=  "(";
				msg += stack_content_by_name(L, 2);
				msg += ")' is ambiguous";
				lua_pushstring(L, msg.c_str());
			}
			lua_error(L);
		}

			// TODO: should this be a warning or something?
/*
			// since the derived class is a lua class
			// it may have reimplemented virtual functions
			// therefore, we have to instantiate the Basewrapper
			// if there is no basewrapper, throw a run-time error
			if (!rep->overloads[match_index].has_wrapped_construct())
			{
				{
					std::string msg = "Cannot derive from C++ class '";
					msg += base->name();
					msg += "'. It does not have a wrapped type";
					lua_pushstring(L, msg.c_str());
				}
				lua_error(L);
			}
*/
#endif

#ifndef LUABIND_NO_EXCEPTIONS

		try
		{

#endif
			lua_pushvalue(L, lua_upvalueindex(2));
			weak_ref backref(L, -1);
			lua_pop(L, 1);

			void* storage_ptr = obj->ptr();		

			if (!rep->overloads[match_index].has_wrapped_construct())
			{
				// if the type doesn't have a wrapped type, use the ordinary constructor
				void* instance = rep->overloads[match_index].construct(L, backref);

				if (crep->has_holder())
				{
					crep->m_construct_holder(storage_ptr, instance);
				}
				else
				{
					obj->set_object(instance);
				}
			}
			else
			{
				// get reference to lua object
/*				lua_pushvalue(L, lua_upvalueindex(2));
				detail::lua_reference ref;
				ref.set(L);
				void* instance = rep->overloads[match_index].construct_wrapped(L, ref);*/

				void* instance = rep->overloads[match_index].construct_wrapped(L, backref);

				if (crep->has_holder())
				{
					crep->m_construct_holder(storage_ptr, instance);			
				}
				else
				{
					obj->set_object(instance);
				}
			}
			// TODO: is the wrapped type destructed correctly?
			// it should, since the destructor is either the wrapped type's
			// destructor or the base type's destructor, depending on wether
			// the type has a wrapped type or not.
			obj->set_destructor(base->destructor());
			return 0;

#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 = base->m_name;
			msg += "() threw an exception";
			lua_pushstring(L, msg.c_str());
		}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?