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

📄 class_rep_scope.hpp

📁 魔兽世界的私服源程序
💻 HPP
📖 第 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.


#ifndef LUABIND_CLASS_REP_HPP_INCLUDED
#define LUABIND_CLASS_REP_HPP_INCLUDED

//#include <cstdlib>

#include <boost/limits.hpp>
#include <boost/preprocessor/repetition/enum_params_with_a_default.hpp>

#include <luabind/config.hpp>
#include <luabind/detail/object_rep.hpp>
#include <luabind/detail/construct_rep.hpp>
#include <luabind/detail/method_rep.hpp>
#include <luabind/detail/garbage_collector.hpp>
#include <luabind/detail/operator_id.hpp>
#include <luabind/detail/signature_match.hpp>
#include <luabind/detail/class_registry.hpp>
#include <luabind/detail/find_best_match.hpp>
#include <luabind/detail/get_overload_signature.hpp>
#include <luabind/detail/error.hpp>

namespace luabind
{

	template<BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(LUABIND_MAX_BASES, class A, detail::null_type)>
	struct bases {};
	typedef bases<detail::null_type> no_bases;

	struct class_base;

}

namespace luabind { namespace detail
{
	std::string stack_content_by_name(lua_State* L, int start_index);
	int construct_lua_class_callback(lua_State* L);

	// this is class-specific information, poor man's vtable
	// this is allocated statically (removed by the compiler)
	// a pointer to this structure is stored in the lua tables'
	// metatable with the name __classrep
	// it is used when matching parameters to function calls
	// to determine possible implicit casts
	// it is also used when finding the best match for overloaded
	// methods
	class class_rep
	{
	friend struct luabind::class_base;
	friend int super_callback(lua_State*);
//TODO: avoid the lua-prefix
	friend int lua_class_gettable(lua_State*);
	friend int lua_class_settable(lua_State*);
	friend int static_class_gettable(lua_State*);
	public:

		enum class_type
		{
			cpp_class = 0,
			lua_class = 1
		};

		// destructor is a lua callback function that is hooked as garbage collector event on every instance
		// of this class (including those that is not owned by lua). It gets an object_rep as argument
		// on the lua stack. It should delete the object pointed to by object_rep::ptr if object_pre::flags
		// is object_rep::owner (which means that lua owns the object)

		// EXPECTS THE TOP VALUE ON THE LUA STACK TO
		// BE THE USER DATA WHERE THIS CLASS IS BEING
		// INSTANTIATED!
		class_rep(LUABIND_TYPE_INFO t, const char* name, lua_State* L, void(*destructor)(void*), LUABIND_TYPE_INFO held_t, void*(*extractor)(void*))
			: m_type(t)
			, m_held_type(held_t)
			, m_extract_underlying_fun(extractor)
			, m_name(name)
			, m_class_type(cpp_class)
			, m_destructor(destructor)
		{

			// TODO: don't we need to copy the name?
			class_registry* r = class_registry::get_registry(L);
			assert((r->cpp_class() != LUA_NOREF) && "you must call luabind::open()"); // 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();
		}

		// used when creating a lua class
		// EXPECTS THE TOP VALUE ON THE LUA STACK TO
		// BE THE USER DATA WHERE THIS CLASS IS BEING
		// INSTANTIATED!
		class_rep(lua_State* L, const char* name)
			: m_type(LUABIND_TYPEID(int))
			, m_held_type(0)
			, m_extract_underlying_fun(0)
			, m_name(name)
			, m_class_type(lua_class)
		{
			// TODO: don't we need to copy the name?
			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()"); // 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();
		}

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


		// called from the metamethod for __index
		// the object pointer is passed on the lua stack
		int gettable(lua_State* L)
		{
			if (lua_isnil(L, 2))
			{
				lua_pushnil(L);
				return 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);
			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 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
		}

		// this is called as __index metamethod on every instance of this class
		static int 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
		static int 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;
		}

		static int 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);

			if (operand[0] && operand[1])
				if (LUABIND_TYPE_INFO_EQUAL(operand[0]->crep()->type(), operand[1]->crep()->type())) 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;

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

//			std::cout << "operator_dispatcher\n";
//			std::cout << "num overloads: " << num_overloads[0] + num_overloads[1] << "\n";
//			std::cout << "operator: " << id << "\n";

#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);
				if (overloads[0])
				{
					if (find_best_match(L, overloads[0]->begin(), overloads[0]->end(), ambiguous, min_match, match_index, num_params))
						operand_id = 0;
				}

				// 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	

				if (overloads[1])
				{
					if(find_best_match(L, overloads[1]->begin(), overloads[1]->end(), ambiguous, min_match, match_index, num_params))
						operand_id = 1;
				}

#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";

					if (overloads[0])
						msg += get_overload_signatures(L, overloads[0]->begin(), overloads[0]->end(), get_operator_symbol(id));

					if (overloads[1])
						msg += get_overload_signatures(L, overloads[1]->begin(), overloads[1]->end(), get_operator_symbol(id));
					
					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<operator_callback> candidates;
					if (overloads[0])
						find_exact_match(L, overloads[0]->begin(), overloads[0]->end(), min_match, num_params, candidates);

					if (overloads[1])
						find_exact_match(L, overloads[1]->begin(), overloads[1]->end(), min_match, num_params, candidates);

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


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

#endif

			return (*overloads[operand_id])[match_index].call(L);
		}


		// this is called as metamethod __call on the class_rep.
		static int 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.begin(), rep->overloads.end(), 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)
			{
				// this block is needed to make sure the std::string is destructed before
				// lua_error() is called
				{
					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<construct_rep::overload_t> candidates;
					find_exact_match(L, rep->overloads.begin(), rep->overloads.end(), min_match, num_params, candidates);
					msg += get_overload_signatures(L, candidates.begin(), candidates.end(), crep->name());

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

#endif

#ifndef LUABIND_NO_EXCEPTIONS

			try
			{

#endif

				void* object_ptr = rep->overloads[match_index].construct(L);

				void* obj_rep = lua_newuserdata(L, sizeof(object_rep));
				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 std::exception& e)
			{
				lua_pushstring(L, e.what());
			}
			catch(const char* s)
			{
				lua_pushstring(L, s);
			}
			catch(...)
			{
				{

⌨️ 快捷键说明

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