2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-26 18:52:26 +00:00

Preparation for delivering nicely-formatted error messages in

Boost.Python.  The major change is that, instead of being
boost::function2<PyObject*,PyObject*,PyObject*>, py_function is now a
runtime-polymorphic wrapper for compile-time polymorphic
behavior (just like function) of our own which carries more
information/behaviors.  In particular, you can retrieve an array of
c-strings describing the types in the function signature.
Additionally, the minimum and maximum arity are stored in the
py_function object instead of in the 'function' object which wraps it.

* data_members.hpp -

     Adjustments for the new py_function.  Workarounds for CodeWarrior
     Pro 8.3 bugs in function template argument deduction with
     pointers-to-members.

* has_back_reference.hpp, test/back_reference.cpp,
  test/select_holder.cpp -

     Updated to follow the metafunction protocol

* init.hpp, detail/defaults_gen.hpp -

     Make Keywords a more-specific type in function signatures to
     prevent string literals that show up as char[N] from binding to
     the wrong argument (at least Intel 7.1 for Windows does this).

* make_function.hpp -

     Adjustments for the new py_function.  Arities are now computed
     by caller<>.

* opaque_pointer_converter.hpp, type_id.hpp -

     Use BOOST_NO_EXPLICIT_FUNCTION_TEMPLATE_ARGUMENTS facilities;
     generate specializations that all compilers can handle.

* raw_function.hpp -

     Adjustments for the new py_function.

* caller.hpp -

     Added arity and signature type name reporting.

* detail/config.hpp

     Enable __declspec(dllexport) for Cygwin, thereby fixing the
     recent horrible Cygwin linking problems.


* detail/msvc_typeinfo.hpp -

     Always pass boost::type<T>* explicitly, thereby working around
     incompatible notions of how to specialize function templates with
     default arguments on various compilers.

*   object/function.hpp
  , object/function_handle.hpp
  , object/function_object.hpp
  , object/function_object.cpp

     Adjustments for the new py_function.  Arities are carried by
     py_function.

* object/iterator.hpp, object/iterator.cpp

     Adjustments for the new py_function; we have to compute a
     signature of types to construct it with.

* object/py_function.hpp

     Removed dependency on boost::function; see the comment at the
     top of this entry for more details.

* object/select_holder.hpp

     Clean up to more closely follow MPL idioms.

* test/Jamfile -

     Adjust the embedding test for the new Cygwin use of declspec.
     Update bases and pointee tests with missing properties.

* test/input_iterator.cpp -

     Updates for the new iterator adaptors.

* test/opaque.py -

     Add Python encoding comment to suppress PendinDeprecationWarning
     with recent Python builds.

* test/str.cpp

     Pass a Python long instead of a float to string.expandtabs,
     suppressing a PendinDeprecationWarning with recent Python builds.

* libs/utility/counting_iterator_example.cpp

     Borland workaround

* libs/utility/indirect_iterator_example.cpp

     const-correctness fix.

*


[SVN r19247]
This commit is contained in:
Dave Abrahams
2003-07-22 00:06:41 +00:00
parent 817dcd37e0
commit d4e06ac436
25 changed files with 521 additions and 202 deletions

View File

@@ -20,20 +20,40 @@
# include <boost/python/detail/indirect_traits.hpp>
# include <boost/python/detail/not_specified.hpp>
# include <boost/type_traits/transform_traits.hpp>
# include <boost/type_traits/add_const.hpp>
# include <boost/type_traits/add_reference.hpp>
# include <boost/type_traits/is_same.hpp>
# include <boost/type_traits/is_member_pointer.hpp>
# include <boost/mpl/apply_if.hpp>
# include <boost/mpl/if.hpp>
# include <boost/mpl/vector/vector10.hpp>
# include <boost/bind.hpp>
# include <boost/detail/workaround.hpp>
namespace boost { namespace python {
//
// This file defines the make_getter and make_setter function
// families, which are responsible for turning pointers, references,
// and pointers-to-data-members into callable Python objects which
// can be used for attribute access on wrapped classes.
//
namespace detail
{
//
// Raw Getter and Setter function generators. These class templates
// generate static functions which can be bound together with
// policies and wrapped to generate the python callable objects
// mentioned above.
//
//
// Generates get and set functions for access through
// pointers-to-data-members
//
template <class Data, class Class, class Policies>
struct member
{
@@ -74,6 +94,12 @@ namespace detail
}
};
//
// Generates get and set functions for access through ordinary
// pointers. These are generally used to wrap static data members,
// but can also be used to expose namespace-scope data as class
// attributes.
//
template <class Data, class Policies>
struct datum
{
@@ -108,6 +134,17 @@ namespace detail
}
};
//
// Helper metafunction for determining the default CallPolicy to use
// for attribute access. If T is a [reference to a] class type X
// whose conversion to python would normally produce a new copy of X
// in a wrapped X class instance (as opposed to types such as
// std::string, which are converted to native Python types, and
// smart pointer types which produce a wrapped class instance of the
// pointee type), to-python conversions will attempt to produce an
// object which refers to the original C++ object, rather than a
// copy. See default_member_getter_policy for rationale.
//
template <class T>
struct default_getter_by_ref
: mpl::and_<
@@ -123,6 +160,9 @@ namespace detail
{
};
// Metafunction computing the default CallPolicy to use for reading
// data members
//
// If it's a regular class type (not an object manager or other
// type for which we have to_python specializations, use
// return_internal_reference so that we can do things like
@@ -130,82 +170,124 @@ namespace detail
// and get the right result.
template <class T>
struct default_member_getter_policy
: mpl::if_<
default_getter_by_ref<T>
, return_internal_reference<>
, return_value_policy<return_by_value>
>
: mpl::if_<
default_getter_by_ref<T>
, return_internal_reference<>
, return_value_policy<return_by_value>
>
{};
// Metafunction computing the default CallPolicy to use for reading
// non-member data.
template <class T>
struct default_datum_getter_policy
: mpl::if_<
default_getter_by_ref<T>
, return_value_policy<reference_existing_object>
, return_value_policy<return_by_value>
>
: mpl::if_<
default_getter_by_ref<T>
, return_value_policy<reference_existing_object>
, return_value_policy<return_by_value>
>
{};
//
// make_getter helper function family -- These helpers to
// boost::python::make_getter are used to dispatch behavior. The
// third argument is a workaround for a CWPro8 partial ordering bug
// with pointers to data members. It should be convertible to
// mpl::true_ iff the first argument is a pointer-to-member, and
// mpl::false_ otherwise. The fourth argument is for compilers
// which don't support partial ordering at all and should always be
// passed 0L.
//
// Handle non-member pointers with policies
template <class D, class Policies>
inline object make_getter(D* p, Policies const& policies, int)
inline object make_getter(D* d, Policies const& policies, mpl::false_, int)
{
return objects::function_object(
objects::py_function(
::boost::bind(
&detail::datum<D,Policies>::get, p, _1, _2
&detail::datum<D,Policies>::get, d, _1, _2
, policies)
, 0);
, mpl::vector1<D>()
)
);
}
// Handle non-member pointers without policies
template <class D>
inline object make_getter(D* p, not_specified, long)
inline object make_getter(D* d, not_specified, mpl::false_, long)
{
typedef typename default_datum_getter_policy<D>::type policies;
return make_getter(p, policies(), 0L);
return detail::make_getter(d, policies(), mpl::false_(), 0);
}
// Handle pointers-to-members with policies
template <class C, class D, class Policies>
inline object make_getter(D C::*pm, Policies const& policies, int)
inline object make_getter(D C::*pm, Policies const& policies, mpl::true_, int)
{
return objects::function_object(
objects::py_function(
::boost::bind(
&detail::member<D,C,Policies>::get, pm, _1, _2
, policies)
, 1);
, mpl::vector2<D, C const*>()
)
);
}
// Handle pointers-to-members without policies
template <class C, class D>
inline object make_getter(D C::*pm, not_specified, long)
inline object make_getter(D C::*pm, not_specified, mpl::true_, long)
{
typedef typename default_member_getter_policy<D>::type policies;
return make_getter(pm, policies(), 0L);
}
template <class D, class Policies>
inline object make_getter(D& d, Policies const& policies, ...)
{
return detail::make_getter(&d, policies, 0L);
return detail::make_getter(pm, policies(), mpl::true_(), 0);
}
// Handle references
template <class D, class P>
inline object make_getter(D& d, P& p, mpl::false_, ...)
{
// Just dispatch to the handler for pointer types.
return detail::make_getter(&d, p, mpl::false_(), 0L);
}
//
// make_setter helper function family -- These helpers to
// boost::python::make_setter are used to dispatch behavior. The
// third argument is for compilers which don't support partial
// ordering at all and should always be passed 0.
//
// Handle non-member pointers
template <class D, class Policies>
inline object make_setter(D* p, Policies const& policies, long)
inline object make_setter(D* p, Policies const& policies, int)
{
return objects::function_object(
::boost::bind(
&detail::datum<D,Policies>::set, p, _1, _2
, policies)
, 1);
objects::py_function(
::boost::bind(
&detail::datum<D,Policies>::set, p, _1, _2
, policies)
, mpl::vector2<void, D const&>()
)
);
}
// Handle pointers-to-members
template <class C, class D, class Policies>
inline object make_setter(D C::*pm, Policies const& policies, long)
inline object make_setter(D C::*pm, Policies const& policies, int)
{
return objects::function_object(
::boost::bind(
&detail::member<D,C,Policies>::set, pm, _1, _2
, policies)
, 2);
objects::py_function(
::boost::bind(
&detail::member<D,C,Policies>::set, pm, _1, _2
, policies)
, mpl::vector3<void, C*, D const&>()
)
);
}
// Handle references
template <class D, class Policies>
inline object make_setter(D& x, Policies const& policies, ...)
{
@@ -213,55 +295,71 @@ namespace detail
}
}
//
// make_getter function family -- build a callable object which
// retrieves data through the first argument and is appropriate for
// use as the `get' function in Python properties . The second,
// policies argument, is optional. We need both D& and D const&
// overloads in order be able to handle rvalues.
//
template <class D, class Policies>
inline object make_getter(D& d, Policies const& policies)
{
return detail::make_getter(d, policies, 0L);
return detail::make_getter(d, policies, is_member_pointer<D>(), 0L);
}
template <class D, class Policies>
inline object make_getter(D const& d, Policies const& policies)
{
return detail::make_getter(d, policies, 0L);
return detail::make_getter(d, policies, is_member_pointer<D>(), 0L);
}
template <class D>
inline object make_getter(D& x)
{
return detail::make_getter(x, detail::not_specified(), 0L);
detail::not_specified policy;
return detail::make_getter(x, policy, is_member_pointer<D>(), 0L);
}
# if !(BOOST_WORKAROUND(BOOST_MSVC, <= 1300) || BOOST_WORKAROUND(__EDG_VERSION__, <= 238))
# if !BOOST_WORKAROUND(__EDG_VERSION__, <= 238) && !BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
template <class D>
inline object make_getter(D const& x)
inline object make_getter(D const& d)
{
return detail::make_getter(x, detail::not_specified(), 0L);
detail::not_specified policy;
return detail::make_getter(d, policy, is_member_pointer<D>(), 0L);
}
# endif
# endif
//
// make_setter function family -- build a callable object which
// writes data through the first argument and is appropriate for
// use as the `set' function in Python properties . The second,
// policies argument, is optional. We need both D& and D const&
// overloads in order be able to handle rvalues.
//
template <class D, class Policies>
inline object make_setter(D& x, Policies const& policies)
{
return detail::make_setter(x, policies, 0L);
return detail::make_setter(x, policies, 0);
}
template <class D, class Policies>
inline object make_setter(D const& x, Policies const& policies)
{
return detail::make_setter(x, policies, 0L);
return detail::make_setter(x, policies, 0);
}
template <class D>
inline object make_setter(D& x)
{
return detail::make_setter(x, default_call_policies(), 0L);
return detail::make_setter(x, default_call_policies(), 0);
}
# if !(BOOST_WORKAROUND(BOOST_MSVC, <= 1300) || BOOST_WORKAROUND(__EDG_VERSION__, <= 238))
template <class D>
inline object make_setter(D const& x)
{
return detail::make_setter(x, default_call_policies(), 0L);
return detail::make_setter(x, default_call_policies(), 0);
}
# endif

View File

@@ -14,6 +14,7 @@
# include <boost/mpl/apply.hpp>
# include <boost/mpl/if.hpp>
# include <boost/mpl/size.hpp>
# include <boost/mpl/at.hpp>
# include <boost/type_traits/is_same.hpp>
# include <boost/python/detail/preprocessor.hpp>
@@ -25,7 +26,9 @@
# include <boost/preprocessor/dec.hpp>
# include <boost/preprocessor/if.hpp>
# include <boost/python/type_id.hpp>
# include <boost/python/detail/invoke.hpp>
# include <boost/python/detail/signature.hpp>
namespace boost { namespace python { namespace detail {
@@ -58,15 +61,18 @@ struct select_result_converter
template <unsigned> struct caller_arity;
template <class F, class ConverterGenerators, class CallPolicies, class Sig>
struct caller;
# define BOOST_PYTHON_NEXT(init,name,n) \
typedef BOOST_PP_IF(n,typename BOOST_PP_CAT(name,BOOST_PP_DEC(n)) ::next, init) name##n;
# define BOOST_PYTHON_ARG_CONVERTER(n) \
BOOST_PYTHON_NEXT(typename first::next, arg_iter,n) \
BOOST_PYTHON_NEXT(ConverterGenerators, conv_iter,n) \
typedef typename apply_iter1<conv_iter##n,arg_iter##n>::type c_t##n; \
c_t##n c##n(PyTuple_GET_ITEM(args_, n)); \
if (!c##n.convertible()) \
# define BOOST_PYTHON_ARG_CONVERTER(n) \
BOOST_PYTHON_NEXT(typename first::next, arg_iter,n) \
BOOST_PYTHON_NEXT(ConverterGenerators, conv_iter,n) \
typedef typename apply_iter1<conv_iter##n,arg_iter##n>::type c_t##n; \
c_t##n c##n(PyTuple_GET_ITEM(args_, n)); \
if (!c##n.convertible()) \
return 0;
# define BOOST_PP_ITERATION_PARAMS_1 \
@@ -119,8 +125,8 @@ struct caller
typedef PyObject* result_type;
caller(F f, CallPolicies p) : base(f,p) {}
};
};
}}} // namespace boost::python::detail
@@ -163,6 +169,14 @@ struct caller_arity<N>
return m_data.second().postcall(args_, result);
}
static unsigned min_arity() { return N; }
static char const*const* type_names()
{
return signature<Sig>::type_names();
}
private:
compressed_pair<F,Policies> m_data;
};

View File

@@ -71,7 +71,7 @@
# define BOOST_PYTHON_NO_TEMPLATE_EXPORT
#endif
#if defined(BOOST_PYTHON_DYNAMIC_LIB) && defined(_WIN32) || defined(__CYGWIN__)
#if defined(BOOST_PYTHON_DYNAMIC_LIB) && (defined(_WIN32) || defined(__CYGWIN__))
# if defined(BOOST_PYTHON_SOURCE)
# define BOOST_PYTHON_DECL __declspec(dllexport)
# define BOOST_PYTHON_BUILD_DLL

View File

@@ -27,6 +27,7 @@
#include <boost/mpl/begin_end.hpp>
#include <boost/mpl/next.hpp>
#include <boost/mpl/apply.hpp>
#include <cstddef>
namespace boost { namespace python {
@@ -203,26 +204,26 @@ namespace detail
}; \
};
#define BOOST_PYTHON_OVERLOAD_CONSTRUCTORS(fstubs_name, n_args, n_dflts) \
fstubs_name(char const* doc = 0) \
: ::boost::python::detail::overloads_common<fstubs_name>(doc) {} \
template <class Keywords> \
fstubs_name(char const* doc, Keywords const& keywords) \
: ::boost::python::detail::overloads_common<fstubs_name>( \
doc, keywords.range()) \
{ \
typedef typename ::boost::python::detail:: \
error::more_keywords_than_function_arguments< \
Keywords::size,n_args>::too_many_keywords assertion; \
} \
template <class Keywords> \
fstubs_name(Keywords const& keywords, char const* doc = 0) \
: ::boost::python::detail::overloads_common<fstubs_name>( \
doc, keywords.range()) \
{ \
typedef typename ::boost::python::detail:: \
error::more_keywords_than_function_arguments< \
Keywords::size,n_args>::too_many_keywords assertion; \
#define BOOST_PYTHON_OVERLOAD_CONSTRUCTORS(fstubs_name, n_args, n_dflts) \
fstubs_name(char const* doc = 0) \
: ::boost::python::detail::overloads_common<fstubs_name>(doc) {} \
template <std::size_t N> \
fstubs_name(char const* doc, ::boost::python::detail::keywords<N> const& keywords) \
: ::boost::python::detail::overloads_common<fstubs_name>( \
doc, keywords.range()) \
{ \
typedef typename ::boost::python::detail:: \
error::more_keywords_than_function_arguments< \
N,n_args>::too_many_keywords assertion; \
} \
template <std::size_t N> \
fstubs_name(::boost::python::detail::keywords<N> const& keywords, char const* doc = 0) \
: ::boost::python::detail::overloads_common<fstubs_name>( \
doc, keywords.range()) \
{ \
typedef typename ::boost::python::detail:: \
error::more_keywords_than_function_arguments< \
N,n_args>::too_many_keywords assertion; \
}
# if defined(BOOST_NO_VOID_RETURNS)

View File

@@ -49,17 +49,24 @@ template< typename T > T&(* is_ref_tester1(type<T>) )(type<T>) { return 0; }
inline char BOOST_TT_DECL is_ref_tester1(...) { return 0; }
template <class T>
inline typeinfo msvc_typeid(boost::type<T>* = 0)
inline typeinfo msvc_typeid(boost::type<T>*)
{
return detail::typeid_ref(
(boost::type<T>*)0, detail::is_ref_tester1(type<T>())
);
}
template <>
inline typeinfo msvc_typeid<void>(boost::type<void>*)
{
return typeid(void);
}
# ifndef NDEBUG
inline typeinfo assert_array_typeid_compiles()
{
return msvc_typeid<char const[3]>(), msvc_typeid<char[3]>();
return msvc_typeid((boost::type<char const[3]>*)0)
, msvc_typeid((boost::type<char[3]>*)0);
}
# endif

View File

@@ -7,6 +7,7 @@
# define HAS_BACK_REFERENCE_DWA2002323_HPP
# include <boost/python/detail/prefix.hpp>
# include <boost/mpl/bool.hpp>
namespace boost { namespace python {
@@ -14,8 +15,8 @@ namespace boost { namespace python {
// contains a back-reference to its owning PyObject*
template <class T>
struct has_back_reference
: mpl::false_
{
BOOST_STATIC_CONSTANT(bool, value = false);
};

View File

@@ -203,22 +203,22 @@ class init : public init_base<init<BOOST_PYTHON_OVERLOAD_ARGS> >
: base(doc_)
{
}
template <class Keywords>
init(char const* doc_, Keywords const& kw)
: base(doc_, std::make_pair(kw.base(), kw.base() + Keywords::size))
{
typedef typename detail::error::more_keywords_than_init_arguments<
Keywords::size, n_arguments::value
>::too_many_keywords assertion;
}
template <class Keywords>
init(Keywords const& kw, char const* doc_ = 0)
template <std::size_t N>
init(char const* doc_, detail::keywords<N> const& kw)
: base(doc_, kw.range())
{
typedef typename detail::error::more_keywords_than_init_arguments<
Keywords::size, n_arguments::value
N, n_arguments::value
>::too_many_keywords assertion;
}
template <std::size_t N>
init(detail::keywords<N> const& kw, char const* doc_ = 0)
: base(doc_, kw.range())
{
typedef typename detail::error::more_keywords_than_init_arguments<
N, n_arguments::value
>::too_many_keywords assertion;
}

View File

@@ -37,7 +37,7 @@ namespace detail
{
return objects::function_object(
detail::caller<F,ConverterGenerators,CallPolicies,Sig>(f, p)
, mpl::size<Sig>::value - 1);
);
}
// As above, except that it accepts argument keywords. NumKeywords
@@ -62,8 +62,7 @@ namespace detail
return objects::function_object(
detail::caller<F,ConverterGenerators,CallPolicies,Sig>(f, p)
, arity
, kw);
, kw);
}
}

View File

@@ -19,8 +19,6 @@ struct BOOST_PYTHON_DECL function : PyObject
{
function(
py_function const&
, unsigned min_arity
, unsigned max_arity
, python::detail::keyword const* names_and_defaults
, unsigned num_keywords);
@@ -48,8 +46,6 @@ struct BOOST_PYTHON_DECL function : PyObject
private: // data members
py_function m_fn;
unsigned m_min_arity;
unsigned m_max_arity;
handle<function> m_overloads;
object m_name;
object m_doc;

View File

@@ -14,7 +14,7 @@
namespace boost { namespace python { namespace objects {
BOOST_PYTHON_DECL handle<> function_handle_impl(py_function const& f, unsigned min_args, unsigned max_args = 0);
BOOST_PYTHON_DECL handle<> function_handle_impl(py_function const& f);
// Just like function_object, but returns a handle<> instead. Using
// this for arg_to_python<> allows us to break a circular dependency
@@ -26,9 +26,11 @@ inline handle<> function_handle(F const& f, Signature)
return objects::function_handle_impl(
python::detail::caller<
F,python::detail::args_from_python,default_call_policies,Signature>(
f, default_call_policies())
, n_arguments, n_arguments);
F,python::detail::args_from_python,default_call_policies,Signature
>(
f, default_call_policies()
)
);
}
// Just like make_function, but returns a handle<> intead. Same

View File

@@ -17,15 +17,13 @@ namespace objects
{
BOOST_PYTHON_DECL api::object function_object(
py_function const& f
, unsigned min_arity, unsigned max_arity
, python::detail::keyword_range const&);
BOOST_PYTHON_DECL api::object function_object(
py_function const& f
, unsigned arity
, python::detail::keyword_range const&);
BOOST_PYTHON_DECL api::object function_object(py_function const& f, unsigned arity);
BOOST_PYTHON_DECL api::object function_object(py_function const& f);
// Add an attribute to the name_space with the given name. If it is
// a Boost.Python function object

View File

@@ -16,12 +16,15 @@
# include <boost/type.hpp>
# include <boost/python/arg_from_python.hpp>
# include <boost/mpl/apply.hpp>
# include <boost/mpl/vector/vector10.hpp>
# include <boost/bind.hpp>
# include <boost/bind/protect.hpp>
# include <boost/python/detail/raw_pyobject.hpp>
# include <boost/type_traits/add_reference.hpp>
# include <boost/type_traits/add_const.hpp>
# include <boost/detail/iterator.hpp>
namespace boost { namespace python { namespace objects {
// CallPolicies for the next() method of iterators. We don't want
@@ -118,8 +121,18 @@ namespace detail
// Make a callable object which can be used as the iterator's next() function.
object next_function =
objects::function_object(
py_function(
bind(&detail::iterator_next<Iterator,NextPolicies>::execute, _1, _2, policies)
, 1);
, mpl::vector2<
# if defined BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
object
# else
typename boost::detail::iterator_traits<Iterator>::value_type
# endif
, Iterator
>()
)
);
return class_<range_>(name, no_init)
.def("__iter__", identity_function())
@@ -164,16 +177,25 @@ namespace detail
template <class NextPolicies, class Target, class Iterator, class Accessor1, class Accessor2>
inline object make_iterator_function(
Accessor1 const& get_start, Accessor2 const& get_finish, Iterator const& (*)(), boost::type<Target>*, NextPolicies*, int)
Accessor1 const& get_start
, Accessor2 const& get_finish
, Iterator const& (*)()
, boost::type<Target>*
, NextPolicies*
, int
)
{
return
objects::function_object(
boost::bind(
&make_iterator_help<
Target,Iterator,Accessor1,Accessor2,NextPolicies
>::create
, get_start, get_finish, _1, _2)
, 1 );
py_function(
boost::bind(
&make_iterator_help<
Target,Iterator,Accessor1,Accessor2,NextPolicies
>::create
, get_start, get_finish, _1, _2)
, mpl::vector2<object, Target>()
)
);
}
template <class NextPolicies, class Target, class Iterator, class Accessor1, class Accessor2>

View File

@@ -5,7 +5,11 @@
// to its suitability for any purpose.
#ifndef PY_FUNCTION_DWA200286_HPP
# define PY_FUNCTION_DWA200286_HPP
# include <boost/function/function2.hpp>
# include <boost/python/detail/signature.hpp>
# include <boost/detail/workaround.hpp>
# include <boost/mpl/size.hpp>
# include <memory>
namespace boost { namespace python { namespace objects {
@@ -13,9 +17,142 @@ namespace boost { namespace python { namespace objects {
// function signature:
//
// PyObject* (PyObject* args, PyObject* keywords)
//
// We use boost::function to avoid generating lots of virtual tables
typedef boost::function2<PyObject*, PyObject*, PyObject*> py_function;
struct BOOST_PYTHON_DECL py_function_impl_base
{
virtual ~py_function_impl_base();
virtual PyObject* operator()(PyObject*, PyObject*) = 0;
virtual unsigned min_arity() const = 0;
virtual unsigned max_arity() const;
virtual char const* const* type_names() const = 0;
};
template <class Caller>
struct caller_py_function_impl : py_function_impl_base
{
caller_py_function_impl(Caller const& caller)
: m_caller(caller)
{}
PyObject* operator()(PyObject* args, PyObject* kw)
{
return m_caller(args, kw);
}
virtual unsigned min_arity() const
{
return m_caller.min_arity();
}
virtual char const* const* type_names() const
{
return m_caller.type_names();
}
private:
Caller m_caller;
};
template <class Caller, class Sig>
struct signature_py_function_impl : py_function_impl_base
{
signature_py_function_impl(Caller const& caller)
: m_caller(caller)
{}
PyObject* operator()(PyObject* args, PyObject* kw)
{
return m_caller(args, kw);
}
virtual unsigned min_arity() const
{
return mpl::size<Sig>::value - 1;
}
virtual char const* const* type_names() const
{
return python::detail::signature<Sig>::type_names();
}
private:
Caller m_caller;
};
template <class Caller, class Sig>
struct full_py_function_impl : py_function_impl_base
{
full_py_function_impl(Caller const& caller, unsigned min_arity, unsigned max_arity)
: m_caller(caller)
, m_min_arity(min_arity)
, m_max_arity(max_arity > min_arity ? max_arity : min_arity)
{}
PyObject* operator()(PyObject* args, PyObject* kw)
{
return m_caller(args, kw);
}
virtual unsigned min_arity() const
{
return m_min_arity;
}
virtual unsigned max_arity() const
{
return m_max_arity;
}
virtual char const* const* type_names() const
{
return python::detail::signature<Sig>::type_names();
}
private:
Caller m_caller;
unsigned m_min_arity;
unsigned m_max_arity;
};
struct py_function
{
template <class Caller>
py_function(Caller const& caller)
: m_impl(new caller_py_function_impl<Caller>(caller))
{}
template <class Caller, class Sig>
py_function(Caller const& caller, Sig)
: m_impl(new signature_py_function_impl<Caller, Sig>(caller))
{}
template <class Caller, class Sig>
py_function(Caller const& caller, Sig, int min_arity, int max_arity = 0)
: m_impl(new full_py_function_impl<Caller, Sig>(caller, min_arity, max_arity))
{}
py_function(py_function const& rhs)
: m_impl(rhs.m_impl)
{}
PyObject* operator()(PyObject* args, PyObject* kw) const
{
return (*m_impl)(args, kw);
}
unsigned min_arity() const
{
return m_impl->min_arity();
}
unsigned max_arity() const
{
return m_impl->max_arity();
}
private:
mutable std::auto_ptr<py_function_impl_base> m_impl;
};
}}} // namespace boost::python::objects

View File

@@ -21,6 +21,7 @@
# include <boost/mpl/bool.hpp>
# include <boost/mpl/if.hpp>
# include <boost/mpl/or.hpp>
# include <boost/mpl/not.hpp>
# include <boost/type_traits/same_traits.hpp>
# include <boost/type_traits/is_base_and_derived.hpp>
@@ -49,7 +50,7 @@ namespace detail
// constructor. Normally this means U is a virtual function
// dispatcher subclass for T.
template <class T, class U>
void check_default_constructible(T*, U*, mpl::bool_<true>)
void check_default_constructible(T*, U*, mpl::true_)
{
python::detail::force_instantiate(
sizeof(specify_init_arguments_or_no_init_for_class_<T>(U((::PyObject*)0)))
@@ -59,7 +60,7 @@ namespace detail
// Handles the "normal" case where T is held directly and
// has_back_reference<T> is not specialized.
template <class T>
void check_default_constructible(T*, T*, mpl::bool_<false>)
void check_default_constructible(T*, T*, mpl::false_)
{
python::detail::force_instantiate(
sizeof(specify_init_arguments_or_no_init_for_class_<T>(T()))
@@ -90,17 +91,22 @@ namespace detail
template <class T, class Held>
struct select_value_holder
{
BOOST_STATIC_CONSTANT(bool, back_ref = (!is_same<T,Held>::value) | has_back_reference<T>::value);
private:
typedef mpl::or_<
mpl::not_<is_same<T,Held> >
, has_back_reference<T>
> use_back_ref;
public:
static void assert_default_constructible()
{
detail::check_default_constructible((T*)0,(Held*)0,mpl::bool_<back_ref>());
detail::check_default_constructible((T*)0,(Held*)0, use_back_ref());
}
typedef typename mpl::if_c<
back_ref
, value_holder_back_reference<T,Held>
, value_holder<T>
typedef typename mpl::if_<
use_back_ref
, value_holder_back_reference<T,Held>
, value_holder<T>
>::type type;
static inline void register_() {}
@@ -111,23 +117,28 @@ namespace detail
template <class T,class Ptr>
struct select_pointer_holder
{
typedef typename python::pointee<Ptr>::type pointee;
BOOST_STATIC_CONSTANT(bool, back_ref = (!is_same<T,pointee>::value) | has_back_reference<T>::value);
private:
typedef typename python::pointee<Ptr>::type wrapper;
typedef mpl::or_<
mpl::not_<is_same<T,wrapper> >
, has_back_reference<T>
> use_back_ref;
public:
static void assert_default_constructible()
{
detail::check_default_constructible((T*)0,(pointee*)0,mpl::bool_<back_ref>());
detail::check_default_constructible((T*)0,(wrapper*)0, use_back_ref());
}
typedef typename mpl::if_c<
back_ref
typedef typename mpl::if_<
use_back_ref
, pointer_holder_back_reference<Ptr,T>
, pointer_holder<Ptr,T>
>::type type;
static inline void register_()
{
select_pointer_holder::register_(mpl::bool_<back_ref>());
select_pointer_holder::register_(use_back_ref());
}
static type* get() { return 0; }

View File

@@ -113,22 +113,24 @@ PyTypeObject opaque_pointer_converter<Pointer>::type_object =
::boost::python::detail::dealloc
};
}} // namespace boost::python
# ifdef BOOST_MSVC
# ifdef BOOST_MSVC
// MSC works without this workaround, but needs another one ...
# define BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(Pointee) \
BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION(Pointee)
# else
# define BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(Pointee) \
namespace boost { namespace python { \
template<> \
inline type_info type_id(boost::type<Pointee>*) { \
return type_info (typeid (Pointee *)); \
} \
template<> \
inline type_info type_id( \
boost::type<const volatile Pointee &>*) { \
return type_info (typeid (Pointee *)); \
} \
# define BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(Pointee) \
BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION(Pointee)
# else
# define BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(Pointee) \
namespace boost { namespace python { \
template<> \
inline type_info type_id<Pointee>(BOOST_PYTHON_EXPLICIT_TT_DEF(Pointee)) \
{ \
return type_info (typeid (Pointee *)); \
} \
template<> \
inline type_info type_id<const volatile Pointee&>( \
BOOST_PYTHON_EXPLICIT_TT_DEF(const volatile Pointee&)) \
{ \
return type_info (typeid (Pointee *)); \
} \
}}
# endif
# endif
# endif // OPAQUE_POINTER_CONVERTER_HPP_

View File

@@ -11,7 +11,9 @@
# include <boost/python/tuple.hpp>
# include <boost/python/dict.hpp>
# include <boost/python/object/py_function.hpp>
# include <boost/mpl/vector/vector10.hpp>
# include <boost/limits.hpp>
# include <cstddef>
namespace boost { namespace python {
@@ -31,17 +33,25 @@ namespace detail
).ptr()
);
}
private:
F f;
};
object BOOST_PYTHON_DECL make_raw_function(objects::py_function, std::size_t min_args);
object BOOST_PYTHON_DECL make_raw_function(objects::py_function);
}
template <class F>
object raw_function(F f, std::size_t min_args = 0)
{
return detail::make_raw_function(detail::raw_dispatcher<F>(f), min_args);
return detail::make_raw_function(
objects::py_function(
detail::raw_dispatcher<F>(f)
, mpl::vector1<PyObject*>()
, min_args
, std::numeric_limits<unsigned>::max()
)
);
}
}} // namespace boost::python

View File

@@ -57,14 +57,20 @@ struct type_info : private totally_ordered<type_info>
base_id_t m_base_type;
};
# ifdef BOOST_NO_EXPLICIT_FUNCTION_TEMPLATE_ARGUMENTS
# define BOOST_PYTHON_EXPLICIT_TT_DEF(T) ::boost::type<T>*
# else
# define BOOST_PYTHON_EXPLICIT_TT_DEF(T)
# endif
template <class T>
inline type_info type_id(boost::type<T>* = 0)
inline type_info type_id(BOOST_EXPLICIT_TEMPLATE_TYPE(T))
{
return type_info(
# if (!defined(BOOST_MSVC) || BOOST_MSVC > 1300) && (!defined(BOOST_INTEL_CXX_VERSION) || BOOST_INTEL_CXX_VERSION > 700)
typeid(T)
# else // strip the decoration which msvc and Intel mistakenly leave in
python::detail::msvc_typeid<T>()
python::detail::msvc_typeid((boost::type<T>*)0)
# endif
);
}
@@ -76,11 +82,11 @@ inline type_info type_id(boost::type<T>* = 0)
// down into template instantiations. Explicit specialization stops
// that from taking hold.
# define BOOST_PYTHON_SIGNED_INTEGRAL_TYPE_ID(T) \
template <> \
inline type_info type_id<T>(boost::type<T>*) \
{ \
return type_info(typeid(T)); \
# define BOOST_PYTHON_SIGNED_INTEGRAL_TYPE_ID(T) \
template <> \
inline type_info type_id<T>(BOOST_PYTHON_EXPLICIT_TT_DEF(T)) \
{ \
return type_info(typeid(T)); \
}
BOOST_PYTHON_SIGNED_INTEGRAL_TYPE_ID(short)

View File

@@ -14,33 +14,42 @@
#include <boost/python/refcount.hpp>
#include <boost/python/extract.hpp>
#include <boost/python/detail/signature.hpp>
#include <boost/mpl/vector/vector10.hpp>
#include <boost/bind.hpp>
#include <algorithm>
#include <cstring>
namespace boost { namespace python { namespace objects {
py_function_impl_base::~py_function_impl_base()
{
}
unsigned py_function_impl_base::max_arity() const
{
return this->min_arity();
}
extern PyTypeObject function_type;
function::function(
py_function const& implementation
, unsigned min_arity
, unsigned max_arity
, python::detail::keyword const* names_and_defaults
, unsigned num_keywords
)
: m_fn(implementation)
, m_min_arity(min_arity)
// was using std::max here, but a problem with MinGW-2.95 and
// our <boost/numeric/...> directory prevents it.
, m_max_arity(max_arity > min_arity ? max_arity : min_arity)
{
if (names_and_defaults != 0)
{
unsigned keyword_offset
= m_max_arity > num_keywords ? m_max_arity - num_keywords : 0;
unsigned int max_arity = m_fn.max_arity();
unsigned int keyword_offset
= max_arity > num_keywords ? max_arity - num_keywords : 0;
unsigned tuple_size = num_keywords ? m_max_arity : 0;
unsigned tuple_size = num_keywords ? max_arity : 0;
m_arg_names = object(handle<>(PyTuple_New(tuple_size)));
if (num_keywords != 0)
@@ -86,7 +95,8 @@ PyObject* function::call(PyObject* args, PyObject* keywords) const
do
{
// Check for a plausible number of arguments
if (total_args >= f->m_min_arity && total_args <= f->m_max_arity)
if (total_args >= f->m_fn.min_arity()
&& total_args <= f->m_fn.max_arity())
{
// This will be the args that actually get passed
handle<> args2(allow_null(borrowed(args)));
@@ -242,7 +252,7 @@ namespace
}
// Something for the end of the chain of binary operators
PyObject* not_implemented_impl(PyObject*, PyObject*)
PyObject* not_implemented(PyObject*, PyObject*)
{
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
@@ -250,9 +260,11 @@ namespace
handle<function> not_implemented_function()
{
static object keeper(
function_object(&not_implemented_impl, 2, 3
, python::detail::keyword_range())
function_object(
py_function(&not_implemented, mpl::vector1<void>(), 2)
, python::detail::keyword_range())
);
return handle<function>(borrowed(downcast<function>(keeper.ptr())));
}
@@ -478,48 +490,38 @@ PyTypeObject function_type = {
};
object function_object(
py_function const& f, unsigned min_arity, unsigned max_arity
py_function const& f
, python::detail::keyword_range const& keywords)
{
return python::object(
python::detail::new_non_null_reference(
new function(
f, min_arity, max_arity, keywords.first, keywords.second - keywords.first)));
f, keywords.first, keywords.second - keywords.first)));
}
object function_object(
py_function const& f
, unsigned arity
, python::detail::keyword_range const& kw)
object function_object(py_function const& f)
{
return function_object(f, arity, arity, kw);
}
object function_object(py_function const& f, unsigned arity)
{
return function_object(f, arity, arity, python::detail::keyword_range());
return function_object(f, python::detail::keyword_range());
}
handle<> function_handle_impl(py_function const& f, unsigned min_arity, unsigned max_arity)
handle<> function_handle_impl(py_function const& f)
{
return python::handle<>(
allow_null(
new function(f, min_arity, max_arity, 0, 0)));
new function(f, 0, 0)));
}
}
namespace detail
{
object BOOST_PYTHON_DECL make_raw_function(objects::py_function f, std::size_t min_args)
object BOOST_PYTHON_DECL make_raw_function(objects::py_function f)
{
static keyword k;
return objects::function_object(
f
, min_args
, std::numeric_limits<std::size_t>::max()
, keyword_range(&k,&k));
}
}

View File

@@ -7,19 +7,27 @@
#include <boost/python/object/iterator_core.hpp>
#include <boost/python/object/function_object.hpp>
#include <boost/bind.hpp>
#include <boost/mpl/vector/vector10.hpp>
namespace boost { namespace python { namespace objects {
static PyObject* identity(PyObject* args_, PyObject*)
namespace
{
PyObject* x = PyTuple_GET_ITEM(args_,0);
Py_INCREF(x);
return x;
PyObject* identity(PyObject* args_, PyObject*)
{
PyObject* x = PyTuple_GET_ITEM(args_,0);
Py_INCREF(x);
return x;
}
}
BOOST_PYTHON_DECL object const& identity_function()
{
static object result(function_object(&identity, 1));
static object result(
function_object(
py_function(&identity, mpl::vector2<PyObject*,PyObject*>())
)
);
return result;
}

View File

@@ -61,6 +61,7 @@ run ../test/embedding.cpp <lib>../build/boost_python
: # requirements
$(PYTHON_PROPERTIES)
<define>BOOST_PYTHON_STATIC_LIB
<define>BOOST_PYTHON_STATIC_MODULE
<library-path>$(PYTHON_LIB_PATH)
<$(gcc-compilers)><debug-python><library-path>$(CYGWIN_PYTHON_DEBUG_DLL_PATH)
<$(gcc-compilers)><*><library-path>$(CYGWIN_PYTHON_DLL_PATH)
@@ -151,9 +152,9 @@ run indirect_traits_test.cpp ;
run destroy_test.cpp ;
run pointer_type_id_test.cpp <lib>../../test/build/boost_test_exec_monitor : : : $(UNIT_TEST_PROPERTIES) ;
run member_function_cast.cpp ;
run bases.cpp ;
run bases.cpp : : : $(UNIT_TEST_PROPERTIES) ;
run if_else.cpp ;
run pointee.cpp ;
run pointee.cpp : : : $(UNIT_TEST_PROPERTIES) ;
run result.cpp ;
compile string_literal.cpp ;

View File

@@ -14,6 +14,7 @@
#include <cassert>
#include <boost/python/copy_const_reference.hpp>
#include <boost/python/return_value_policy.hpp>
#include <boost/mpl/bool.hpp>
// This test shows that a class can be wrapped "as itself" but also
// acquire a back-reference iff has_back_reference<> is appropriately
@@ -64,14 +65,14 @@ namespace boost { namespace python
{
template <>
struct has_back_reference<Y>
: mpl::true_
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
template <>
struct has_back_reference<Z>
: mpl::true_
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
}}

View File

@@ -7,7 +7,7 @@
#include <boost/python/def.hpp>
#include <boost/python/class.hpp>
#include <boost/python/iterator.hpp>
#include <boost/iterator_adaptors.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <list>
using namespace boost::python;
@@ -21,7 +21,7 @@ struct doubler
int operator()(int x) const { return x * 2; }
};
typedef boost::transform_iterator_generator<doubler, list_int::iterator>::type doubling_iterator;
typedef boost::transform_iterator<doubler, list_int::iterator> doubling_iterator;
typedef std::pair<doubling_iterator,doubling_iterator> list_range2;
list_range2 range2(list_int& x)

View File

@@ -1,8 +1,10 @@
# -*- coding: iso-latin-1 -*-
# Copyright Gottfried Ganßauge 2003. Permission to copy, use,
# modify, sell and distribute this software is granted provided this
# copyright notice appears in all copies. This software is provided
# "as is" without express or implied warranty, and with no claim as
# to its suitability for any purpose.
"""
>>> from opaque_ext import *
>>> #

View File

@@ -9,6 +9,7 @@
#include <boost/static_assert.hpp>
#include <boost/type_traits/same_traits.hpp>
#include <boost/function/function0.hpp>
#include <boost/mpl/bool.hpp>
#include <memory>
#define BOOST_INCLUDE_MAIN
@@ -24,8 +25,8 @@ namespace boost { namespace python
// specialization
template <>
struct has_back_reference<BR>
: mpl::true_
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
}} // namespace boost::python

View File

@@ -38,7 +38,7 @@ void work_with_string(object print)
str tabstr("\t\ttab\tdemo\t!");
print(tabstr.expandtabs());
print(tabstr.expandtabs(4));
print(tabstr.expandtabs(7.9));
print(tabstr.expandtabs(7L));
print("operators");
print( str("part1") + str("part2") );