📄 class.hpp
字号:
// 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_HPP_INCLUDED
#define LUABIND_CLASS_HPP_INCLUDED
/*
ISSUES:
------------------------------------------------------
* solved for member functions, not application operator *
if we have a base class that defines a function a derived class must be able to
override that function (not just overload). Right now we just add the other overload
to the overloads list and will probably get an ambiguity. If we want to support this
each method_rep must include a vector of type_info pointers for each parameter.
Operators do not have this problem, since operators always have to have
it's own type as one of the arguments, no ambiguity can occur. Application
operator, on the other hand, would have this problem.
Properties cannot be overloaded, so they should always be overridden.
If this is to work for application operator, we really need to specify if an application
operator is const or not.
If one class registers two functions with the same name and the same
signature, there's currently no error. The last registered function will
be the one that's used.
How do we know which class registered the function? If the function was
defined by the base class, it is a legal operation, to override it.
we cannot look at the pointer offset, since it always will be zero for one of the bases.
TODO:
------------------------------------------------------
scopes
classes with the same name in different scopes will have the same (fully qualified) name.
finish smart pointer support
* make sure there are no bugs in the conversion from holder to const_holder
* the adopt policy should not be able to adopt pointers to held_types. This
must be prohibited.
* name_of_type must recognize holder_types and not return "custom"
support calling functions on lua threads (i.e. use lua_resume() instead of lua_pcall()).
document the new yield-policy
cache finalizers in the class_rep. For lua classes
we currently do a lookup each time we need to know if a lua class
has a finalizer.
static functions, this could be implemented by letting classes contain
other declarations (classes or functions)
document custom policies, custom converters
store the instance object for policies.
support the __concat metamethod. This is a bit tricky, since it cannot be
treated as a normal operator. It is a binary operator but we want to use the
__tostring implementation for both arguments.
*/
#include <luabind/config.hpp>
#include <string>
#include <map>
#include <vector>
#include <cassert>
#include <boost/static_assert.hpp>
#include <boost/type_traits.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_params_with_a_default.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/mpl/list.hpp>
#include <boost/mpl/apply.hpp>
#include <boost/mpl/lambda.hpp>
#include <boost/mpl/logical.hpp>
#include <boost/mpl/find_if.hpp>
#include <boost/mpl/apply_if.hpp>
#include <boost/mpl/logical.hpp>
#include <luabind/config.hpp>
#include <luabind/scope.hpp>
#include <luabind/detail/constructor.hpp>
#include <luabind/detail/call.hpp>
#include <luabind/detail/signature_match.hpp>
#include <luabind/detail/primitives.hpp>
#include <luabind/detail/property.hpp>
#include <luabind/detail/typetraits.hpp>
#include <luabind/detail/class_rep.hpp>
#include <luabind/detail/method_rep.hpp>
#include <luabind/detail/construct_rep.hpp>
#include <luabind/detail/object_rep.hpp>
#include <luabind/detail/operators.hpp>
#include <luabind/detail/calc_arity.hpp>
#include <luabind/detail/call_member.hpp>
#include <luabind/detail/enum_maker.hpp>
#include <luabind/detail/get_signature.hpp>
#include <luabind/detail/implicit_cast.hpp>
#include <luabind/detail/operator_id.hpp>
namespace luabind
{
namespace detail
{
struct unspecified {};
}
using detail::type;
template<class T, class X1 = detail::unspecified, class X2 = detail::unspecified, class X3 = detail::unspecified>
struct class_;
// TODO: this function will only be invoked if the user hasn't defined a correct overload
// maybe we should have a static assert in here?
inline detail::null_type* get_const_holder(...)
{
return 0;
}
namespace detail
{
template<BOOST_PP_ENUM_PARAMS(LUABIND_MAX_BASES, class A)>
double is_bases_helper(const bases<BOOST_PP_ENUM_PARAMS(LUABIND_MAX_BASES, A)>&);
#ifndef BOOST_MSVC
template<class T>
char is_bases_helper(const T&);
#else
char is_bases_helper(...);
#endif
template<class T>
struct is_bases
{
static const T& t;
BOOST_STATIC_CONSTANT(bool, value = sizeof(is_bases_helper(t)) == sizeof(double));
typedef boost::mpl::bool_<value> type;
BOOST_MPL_AUX_LAMBDA_SUPPORT(1,is_bases,(T))
};
double is_not_unspecified_helper(const unspecified*);
char is_not_unspecified_helper(...);
template<class T>
struct is_not_unspecified
{
BOOST_STATIC_CONSTANT(bool, value = sizeof(is_not_unspecified_helper(static_cast<T*>(0))) == sizeof(char));
typedef boost::mpl::bool_<value> type;
BOOST_MPL_AUX_LAMBDA_SUPPORT(1,is_not_unspecified,(T))
};
template<class Predicate>
struct get_predicate
{
typedef typename boost::mpl::and_<
Predicate
, is_not_unspecified<boost::mpl::_1>
> type;
};
template<class Parameters, class Predicate, class DefaultValue>
struct extract_parameter
{
typedef typename get_predicate<Predicate>::type pred;
typedef typename boost::mpl::find_if<Parameters, pred>::type iterator;
typedef typename boost::mpl::apply_if<boost::is_same<iterator, typename boost::mpl::end<Parameters>::type>
, boost::mpl::identity<DefaultValue>
, iterator
>::type type;
};
int function_dispatcher(lua_State* L);
// this should know about the smart pointer type.
// and should really do:
// get_pointer(*static_cast<SmartPointer*>(obj_ptr))
// to extract the held pointer.
template<class HeldType, class T, class F, class Policies>
struct function_callback_non_null : Policies
{
function_callback_non_null(F f_): f(f_) {}
inline int operator()(lua_State* L, void* obj_ptr)
{
HeldType& held_obj = *static_cast<HeldType*>(obj_ptr);
T* ptr = static_cast<T*>(luabind::get_pointer(held_obj));
return call(f, ptr, L, static_cast<Policies*>(this));
}
F f;
};
template<class T, class F, class Policies>
struct function_callback_null_type : Policies
{
function_callback_null_type(F f_): f(f_) {}
inline int operator()(lua_State* L, void* obj_ptr)
{
// std::cout << "HeldType: null_type\n";
T* ptr = static_cast<T*>(obj_ptr);
return call(f, ptr, L, static_cast<Policies*>(this));
}
F f;
};
template<class HeldType, class T, class F, class Policies>
struct function_callback_s
{
typedef typename
boost::mpl::if_<boost::is_same<HeldType,detail::null_type>
, function_callback_null_type<T,F,Policies>
, function_callback_non_null<HeldType,T,F,Policies>
>::type type;
};
template<class T, class F, class Policies>
struct match_function_callback_s
{
static inline int apply(lua_State* L)
{
object_rep* obj = static_cast<object_rep*>(lua_touserdata(L, 1));
F fptr = 0;
return match(fptr, L, obj->flags() & object_rep::constant, static_cast<Policies*>(0));
}
};
// prints the types of the values on the stack, in the
// range [start_index, lua_gettop()]
std::string stack_content_by_name(lua_State* L, int start_index);
struct create_class
{
static int stage1(lua_State* L);
static int stage2(lua_State* L);
};
template<class Type>
struct register_wrapped_type
{
template<class Signature, class Policies>
static void apply(detail::construct_rep::overload_t& o, const Signature*, const Policies*)
{
o.set_wrapped_constructor(
&detail::construct_wrapped_class<Type, Policies, Signature>::apply
);
}
};
template<>
struct register_wrapped_type<detail::null_type>
{
template<class Signature, class Policies>
static void apply(detail::construct_rep::overload_t&, const Signature*, const Policies*) {}
};
// if the class is held by a smart pointer, we need to be able to
// implicitly dereference the pointer when needed.
template<class UnderlyingT, class HeldT>
struct extract_underlying_type
{
static void* extract(void* ptr)
{
HeldT& held_obj = *reinterpret_cast<HeldT*>(ptr);
UnderlyingT* underlying_ptr = static_cast<UnderlyingT*>(get_pointer(held_obj));
return underlying_ptr;
}
};
template<class UnderlyingT, class HeldT>
struct extract_underlying_const_type
{
static const void* extract(void* ptr)
{
HeldT& held_obj = *reinterpret_cast<HeldT*>(ptr);
const UnderlyingT* underlying_ptr = static_cast<const UnderlyingT*>(get_pointer(held_obj));
return underlying_ptr;
}
};
template<class HeldType>
struct internal_holder_extractor
{
typedef void*(*extractor_fun)(void*);
template<class T>
static extractor_fun apply(detail::type<T>)
{
return &detail::extract_underlying_type<T, HeldType>::extract;
}
};
template<>
struct internal_holder_extractor<detail::null_type>
{
typedef void*(*extractor_fun)(void*);
template<class T>
static extractor_fun apply(detail::type<T>)
{
return 0;
}
};
template<class HeldType, class ConstHolderType>
struct convert_holder
{
static void apply(void* holder, void* target)
{
new(target) ConstHolderType(*reinterpret_cast<HeldType*>(holder));
};
};
template<class HeldType>
struct const_converter
{
typedef void(*converter_fun)(void*, void*);
template<class ConstHolderType>
static converter_fun apply(ConstHolderType*)
{
return &detail::convert_holder<HeldType, ConstHolderType>::apply;
}
};
template<>
struct const_converter<detail::null_type>
{
typedef void(*converter_fun)(void*, void*);
template<class T>
static converter_fun apply(T*)
{
return 0;
}
};
template<class HeldType>
struct internal_const_holder_extractor
{
typedef const void*(*extractor_fun)(void*);
template<class T>
static extractor_fun apply(detail::type<T>)
{
return get_extractor(detail::type<T>(), luabind::get_const_holder(static_cast<HeldType*>(0)));
}
private:
template<class T, class ConstHolderType>
static extractor_fun get_extractor(detail::type<T>, ConstHolderType*)
{
return &detail::extract_underlying_const_type<T, ConstHolderType>::extract;
}
};
template<>
struct internal_const_holder_extractor<detail::null_type>
{
typedef const void*(*extractor_fun)(void*);
template<class T>
static extractor_fun apply(detail::type<T>)
{
return 0;
}
};
// this is simply a selector that returns the type_info
// of the held type, or invalid_type_info if we don't have
// a held_type
template<class HeldType>
struct internal_holder_type
{
static LUABIND_TYPE_INFO apply()
{
return LUABIND_TYPEID(HeldType);
}
};
template<>
struct internal_holder_type<detail::null_type>
{
static LUABIND_TYPE_INFO apply()
{
return LUABIND_INVALID_TYPE_INFO;
}
};
// this is the actual held_type constructor
template<class HeldType, class T>
struct internal_construct_holder
{
static void apply(void* target, void* raw_pointer)
{
new(target) HeldType(static_cast<T*>(raw_pointer));
}
};
// the following two functions are the ones that returns
// a pointer to a held_type_constructor, or 0 if there
// is no held_type
template<class HeldType>
struct holder_constructor
{
typedef void(*constructor)(void*,void*);
template<class T>
static constructor apply(detail::type<T>)
{
return &internal_construct_holder<HeldType, T>::apply;
}
};
template<>
struct holder_constructor<detail::null_type>
{
typedef void(*constructor)(void*,void*);
template<class T>
static constructor apply(detail::type<T>)
{
return 0;
}
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -