⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 class_rep.cpp

📁 魔兽世界的私服源程序
💻 CPP
📖 第 1 页 / 共 3 页
字号:
// 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.

extern "C"
{
	#include "lua.h"
}

#include <luabind/luabind.hpp>
#include <utility>

using namespace luabind::detail;


#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*)
	, 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_holder_size(holder_size)
	, m_holder_alignment(holder_alignment)
	, m_name(name)
	, m_table_ref(LUA_NOREF)
	, 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");

	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 = detail::ref(L); // pop one of them

	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_holder_size(0)
	, m_holder_alignment(1)
	, m_class_type(lua_class)
	, m_destructor(0)
	, m_const_holder_destructor(0)
	, m_operator_cache(0)
{
#ifndef LUABIND_DONT_COPY_STRINGS
	m_strings.push_back(detail::dup_string(name));
	m_name = m_strings.back();
#else
	m_name = name;
#endif
	lua_newtable(L);
	m_table_ref = detail::ref(L);

	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 = detail::ref(L); // pop one of them

	m_instance_metatable = r->lua_instance();
}

luabind::detail::class_rep::~class_rep()
{
#ifndef LUABIND_DONT_COPY_STRINGS
	for (std::vector<char*>::iterator i = m_strings.begin(); 
			i != m_strings.end(); ++i)
	{
			delete[] *i;
	}
#endif
}

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);
}

int luabind::detail::class_rep::gettable(lua_State* L)
{
	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);

	if (key && !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;
	}

	std::map<const char*, method_rep, ltstr>::iterator i = m_methods.find(key);

	if (i != m_methods.end())
	{
		// the name is a method, return it
		lua_pushlightuserdata(L, &i->second);
		lua_pushcclosure(L, function_dispatcher, 1);
		return 1;
	}

	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
bool luabind::detail::class_rep::settable(lua_State* L)
{
	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);
	std::map<const char*, callback, ltstr>::iterator j = m_setters.find(key);
	if (j != m_setters.end())
	{
		// the name is a data member
		j->second.func(L, j->second.pointer_offset);
		return true;
	}

	return false; // false means that we don't have a member with the given name
}

 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)
	{
		// this block is needed to make sure the std::string is destructed before
		// lua_error() is called
#ifdef BOOST_MSVC
		{
			// msvc has a bug which deletes the string twice, that's
			// why we have to create it on the heap
			std::string* msg = new std::string("cannot set attribute '");
			*msg += obj->crep()->m_name;
			*msg += ".";
			*msg += lua_tostring(L, -2);
			*msg += "'";
			lua_pushstring(L, msg->c_str());
			delete msg;
		}
#else
		{
			std::string msg = "cannot set attribute '";
			msg += obj->crep()->m_name;
			msg += ".";
			msg += lua_tostring(L, -2);
			msg += "'";
			lua_pushstring(L, msg.c_str());
		}
#endif
		lua_error(L);
	}

#endif

	return 0;
}


 int luabind::detail::class_rep::operator_dispatcher(lua_State* L)
{
	int id = static_cast<int>(lua_tonumber(L, lua_upvalueindex(1)));

	int operand_id = 0;

	object_rep* operand[2];
	for (int i = 0; i < 2; ++i)
		operand[i] = detail::is_class_object(L, i + 1);

	// we cannot compare the types here, we have to compare the pointers of the class_reps
	// since all lua-classes have the same type (LUABIND_INVALID_TYPE_INFO)
	if (operand[0] && operand[1])
		if (operand[0]->crep() == operand[1]->crep()) operand[1] = 0;

	std::vector<operator_callback>* overloads[2];
	for (int i = 0; i < 2; ++i)
		if (operand[i]) overloads[i] = &operand[i]->crep()->m_operators[id]; else overloads[i] = 0;

	std::size_t num_overloads[2];
	for (int i = 0; i < 2; ++i)
		if (overloads[i]) num_overloads[i] = overloads[i]->size(); else num_overloads[i] = 0;

	for (int i = 0; i < 2; ++i)
		if (operand[i] && operand[i]->crep()->get_class_type() == class_rep::lua_class)
		{
/*			// if this is a lua class we have to
			// look in its table to see if there's
			// any overload of this operator
			detail::getref(L, operand[i]->crep()->table_ref());
			lua_pushstring(L, get_operator_name(id));
			lua_rawget(L, -2);
			// if we have tha operator, set num_overloads to 1
			if (lua_isfunction(L, -1)) num_overloads[i] = 1;
			lua_pop(L, 2);*/
			
			if (operand[i]->crep()->has_operator_in_lua(L, id))
				num_overloads[i] = 1;
		}

	bool ambiguous = false;
	int match_index = -1;
	int min_match = std::numeric_limits<int>::max();

#ifdef LUABIND_NO_ERROR_CHECKING

	if (num_overloads[0] == 1 && num_overloads[1] == 0)
	{
		operand_id = 0;
		match_index = 0;
	}
	else if (num_overloads[0] == 0 && num_overloads[1] == 1)
	{
		operand_id = 1;
		match_index = 0;
	}
	else
	{

#endif

		int num_params = lua_gettop(L);

		// have look at the right operand.
		// if the right operand is a class and
		// not the same class as this, we have to
		// try to match it's operators too	
		for (int i = 0; i < 2; ++i)
		{
			if (num_overloads[i])
			{
				if (operand[i]->crep()->get_class_type() == class_rep::lua_class)
				{
					// if this is a lua class
					// and num_overloads is > 0
					// it means that it has implemented
					// this operator. Set match_index to
					// 0 to signal that this operand has
					// an overload, but leave the min_match
					// at int-max to mark it as a last resort
					operand_id = i;
					if (match_index == -1) match_index = 0;
				}
				else if (find_best_match(
					L
					, &overloads[i]->front()
					, overloads[i]->size()
					, sizeof(operator_callback)
					, ambiguous
					, min_match
					, match_index
					, num_params))
				{
					operand_id = i;
				}
			}
		}


#ifdef LUABIND_NO_ERROR_CHECKING

	}

#else

	if (match_index == -1)
	{
		// this block is needed to make sure the std::string is destructed before
		// lua_error() is called
		{
			std::string msg = "no operator ";
			msg += get_operator_symbol(id);
			msg += " matched the arguments (";
			msg += stack_content_by_name(L, 1);
			msg += ")\ncandidates are:\n";

			for (int i = 0; i < 2; ++i)
			{
				if (overloads[i])
				{
					msg += get_overload_signatures(
							L
							, overloads[i]->begin()
							, overloads[i]->end()
							, get_operator_symbol(id));
				}
				else
				{
					// if num_overloads is > 0 it would mean that this is
					// a lua class with this operator overloaded. And if
					// that's the case, it should always match (and if an
					// operator matches, we never come here).
					assert(num_overloads[i] == 0 && "internal error");
				}
			}

			lua_pushstring(L, msg.c_str());
		}
		lua_error(L);
	}
	else if (ambiguous)
	{
		// this block is needed to make sure the std::string is destructed before
		// lua_error() is called
		{
			std::string msg = "call of overloaded operator ";
			msg += get_operator_symbol(id);
			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;
			if (overloads[0])
				find_exact_match(L, &overloads[0]->front(), overloads[0]->size(), sizeof(operator_callback), min_match, num_params, candidates);

			if (overloads[1])
				find_exact_match(L, &overloads[1]->front(), overloads[1]->size(), sizeof(operator_callback), min_match, num_params, candidates);

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

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

#endif

	if (operand[operand_id]->crep()->get_class_type() == class_rep::lua_class)
	{
		detail::getref(L, operand[operand_id]->crep()->table_ref());
		lua_pushstring(L, get_operator_name(id));
		lua_rawget(L, -2);
		lua_insert(L, -4); // move the function to the bottom
		lua_pop(L, 1); // remove the table
		lua_call(L, 2, 1);
		return 1;
	}
	else
	{
		return (*overloads[operand_id])[match_index].call(L);
	}
}

// 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)
	{
		// this block is needed to make sure the std::string is destructed before
		// lua_error() is called
		{
			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)
	{

⌨️ 快捷键说明

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