diff --git a/include/boost/python/detail/target.hpp b/include/boost/python/detail/target.hpp new file mode 100644 index 00000000..e0c693dd --- /dev/null +++ b/include/boost/python/detail/target.hpp @@ -0,0 +1,89 @@ +// Copyright David Abrahams 2002. 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. +#ifndef TARGET_DWA2002513_HPP +# define TARGET_DWA2002513_HPP + +# include + +namespace boost { namespace python { namespace detail { + +// +// target(x) - deduce the type of the first argument when bind(x) is +// invoked. +// + +// functions +template +boost::type* target(R (*)(Target)) { return 0; } + +template +boost::type* target(R (*)(Target, A1)) { return 0; } + +template +boost::type* target(R (*)(Target, A1, A2)) { return 0; } + +template +boost::type* target(R (*)(Target, A1, A2, A3)) { return 0; } + +// data member pointers +template +boost::type* target(R (Target::*)) { return 0; } + +// member Functions +template +boost::type* target(R (Target::*)()) { return 0; } + +template +boost::type* target(R (Target::*)(A1)) { return 0; } + +template +boost::type* target(R (Target::*)(A1,A2)) { return 0; } + +template +boost::type* target(R (Target::*)(A1,A2,A3)) { return 0; } + +// const member functions +template +boost::type* target(R (Target::*)() const) { return 0; } + +template +boost::type* target(R (Target::*)(A1) const) { return 0; } + +template +boost::type* target(R (Target::*)(A1,A2) const) { return 0; } + +template +boost::type* target(R (Target::*)(A1,A2,A3) const) { return 0; } + +// volatile member functions +template +boost::type* target(R (Target::*)() volatile) { return 0; } + +template +boost::type* target(R (Target::*)(A1) volatile) { return 0; } + +template +boost::type* target(R (Target::*)(A1,A2) volatile) { return 0; } + +template +boost::type* target(R (Target::*)(A1,A2,A3) volatile) { return 0; } + +// const volatile member functions +template +boost::type* target(R (Target::*)() const volatile) { return 0; } + +template +boost::type* target(R (Target::*)(A1) const volatile) { return 0; } + +template +boost::type* target(R (Target::*)(A1,A2) const volatile) { return 0; } + +template +boost::type* target(R (Target::*)(A1,A2,A3) const volatile) { return 0; } + +}}} // namespace boost::python::detail + +#endif // TARGET_DWA2002513_HPP diff --git a/include/boost/python/iterator.hpp b/include/boost/python/iterator.hpp new file mode 100644 index 00000000..0f1e8eeb --- /dev/null +++ b/include/boost/python/iterator.hpp @@ -0,0 +1,114 @@ +// Copyright David Abrahams 2002. 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. +#ifndef ITERATOR_DWA2002512_HPP +# define ITERATOR_DWA2002512_HPP + +# include +# include +# include +# include + +namespace boost { namespace python { + +namespace detail +{ + // Adds an additional layer of binding to + // objects::make_iterator(...), which allows us to pass member + // function and member data pointers. + template + inline ref make_iterator( + Accessor1 get_start, Accessor2 get_finish, NextPolicies* = 0, boost::type* target = 0) + { + return objects::make_iterator_function( + boost::protect(boost::bind(get_start, _1)) + , boost::protect(boost::bind(get_finish, _1)) + , (NextPolicies*)0 + , target); + } + + // Guts of template class iterators<>, below. + template + struct iterators_impl + { + template + struct apply + { + typedef typename T::iterator iterator; + static iterator begin(T& x) { return x.begin(); } + static iterator end(T& x) { return x.end(); } + }; + }; + + template <> + struct iterators_impl + { + template + struct apply + { + typedef typename T::const_iterator iterator; + static iterator begin(T& x) { return x.begin(); } + static iterator end(T& x) { return x.end(); } + }; + }; +} + +// An "ordinary function generator" which contains static begin(x) and +// end(x) functions that invoke T::begin() and T::end(), respectively. +template +struct iterators + : detail::iterators_impl< + boost::is_const::value + >::template apply +{ +}; + +// Create an iterator-building function which uses the given +// accessors. Deduce the Target type from the accessors. The iterator +// returns copies of the inderlying elements. +template +ref range(Accessor1 start, Accessor2 finish) +{ + return detail::make_iterator(start, finish, (objects::default_iterator_call_policies*)0, detail::target(start)); +} + +// Create an iterator-building function which uses the given accessors +// and next() policies. Deduce the Target type. +template +ref range(Accessor1 start, Accessor2 finish, NextPolicies* = 0) +{ + return detail::make_iterator(start, finish, (NextPolicies*)0, detail::target(start)); +} + +// Create an iterator-building function which uses the given accessors +// and next() policies, operating on the given Target type +template +ref range(Accessor1 start, Accessor2 finish, NextPolicies* = 0, boost::type* = 0) +{ + typedef typename add_reference::type target; + return detail::make_iterator(start, finish, (NextPolicies*)0, + (boost::type*)0); +} + +// A Python callable object which produces an iterator traversing +// [x.begin(), x.end()), where x is an instance of the Container +// type. NextPolicies are used as the CallPolicies for the iterator's +// next() function. +template +struct iterator : ref +{ + iterator() + : ref( + range( + &iterators::begin, &iterators::end + )) + { + } +}; + +}} // namespace boost::python + +#endif // ITERATOR_DWA2002512_HPP diff --git a/include/boost/python/object/iterator.hpp b/include/boost/python/object/iterator.hpp new file mode 100644 index 00000000..3207d1d4 --- /dev/null +++ b/include/boost/python/object/iterator.hpp @@ -0,0 +1,211 @@ +// Copyright David Abrahams 2002. 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. +#ifndef ITERATOR_DWA2002510_HPP +# define ITERATOR_DWA2002510_HPP + +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + +namespace boost { namespace python { namespace objects { + +// CallPolicies for the next() method of iterators. We don't want +// users to have to explicitly specify that the references returned by +// iterators are copied, so we just replace the result_converter from +// the default_iterator_call_policies with a permissive one which +// always copies the result. +struct default_iterator_call_policies + : default_call_policies +{ + struct result_converter + { + template + struct apply + { + typedef to_python_value type; + }; + }; +}; + +// Instantiations of these are wrapped to produce Python iterators. +template +struct iterator_range +{ + iterator_range(ref sequence, Iterator start, Iterator finish); + + ref m_sequence; // Keeps the sequence alive while iterating. + Iterator m_start; + Iterator m_finish; +}; + +namespace detail +{ + // Guts of the iterator's next() function. We can't just wrap an + // ordinary function because we don't neccessarily know the result + // type of dereferencing the iterator. This also saves us from + // throwing C++ exceptions to indicate end-of-sequence. + template + struct iterator_next + { + static PyObject* execute(PyObject* args_, PyObject* kw, Policies const& policies) + { + typedef iterator_range range_; + + PyObject* py_self = PyTuple_GET_ITEM(args_, 0); + from_python c0(py_self); + range_* self = c0(py_self); + + // Done iterating? + if (self->m_start == self->m_finish) + { + objects::set_stop_iteration_error(); + return 0; + } + + // note: precall happens before we can check for the result + // converter in this case, to ensure it happens before the + // iterator is dereferenced. However, the arity is 1 so + // there's not much risk that this will amount to anything. + if (!policies.precall(args_)) return 0; + + PyObject* result = iterator_next::convert_result(*self->m_start); + ++self->m_start; + + return policies.postcall(args_, result); + } + private: + // Convert the result of dereferencing the iterator. Dispatched + // here because we can't neccessarily get the value_type of the + // iterator without PTS. This way, we deduce the value type by + // dereferencing. + template + static PyObject* convert_result(ValueType& x) + { + typedef typename Policies::result_converter result_converter; + typename mpl::apply1::type cr; + if (!cr.convertible()) return 0; + + return cr(x); + } + }; + + // Get a Python class which contains the given iterator and + // policies, creating it if neccessary. Requires: NextPolicies is + // default-constructible. + template + ref demand_iterator_class(char const* name, Iterator* = 0, NextPolicies const& policies = NextPolicies()) + { + typedef iterator_range range_; + + // Check the registry. If one is already registered, return it. + ref result( + objects::registered_class_object(converter::undecorated_type_id())); + + if (result.get() == 0) + { + // Make a callable object which can be used as the iterator's next() function. + ref next_function( + new objects::function( + objects::py_function( + bind(&detail::iterator_next::execute, _1, _2, policies)) + , 1)); + + result = class_(name) + .def("__iter__", identity_function()) + .setattr("next", next_function) + .object(); + + } + return result; + } + + // This class template acts as a generator for an ordinary function + // which builds a Python iterator. + template + struct make_iterator_help + { + // Extract an object x of the Target type from the first Python + // argument, and invoke get_start(x)/get_finish(x) to produce + // iterators, which are used to construct a new iterator_range<> + // object that gets wrapped into a Python iterator. + static PyObject* create( + Accessor1 const& get_start, Accessor2 const& get_finish + , PyObject* args_, PyObject* /*kw*/) + { + // Make sure the Python class is instantiated. + demand_iterator_class("iterator"); + + to_python_value > cr; + + // This check is probably redundant, since we ensure the + // type is registered above. + if (!cr.convertible()) + return 0; + + // Extract x from the first argument + PyObject* arg0 = PyTuple_GET_ITEM(args_, 0); + from_python c0(arg0); + if (!c0.convertible()) return 0; + typename from_python::result_type x = c0(arg0); + + // Build and convert the iterator_range<>. + return cr( + iterator_range( + ref(arg0, ref::increment_count) + , get_start(x), get_finish(x))); + } + }; +} + +// Create a Python callable object which accepts a single argument +// convertible to the C++ Target type and returns a Python +// iterator. The Python iterator uses get_start(x) and get_finish(x) +// (where x is an instance of Target) to produce begin and end +// iterators for the range, and an instance of NextPolicies is used as +// CallPolicies for the Python iterator's next() function. +template +inline ref make_iterator_function( + Accessor1 const& get_start, Accessor2 const& get_finish + , NextPolicies* , boost::type*) +{ + typedef typename Accessor1::result_type result_type; + + return ref( + new objects::function( + objects::py_function( + boost::bind( + &detail::make_iterator_help< + Target,result_type,Accessor1,Accessor2,NextPolicies + >::create + , get_start, get_finish, _1, _2) + ) + ,1 )); +} + +// +// implementation +// +template +inline iterator_range::iterator_range( + ref sequence, Iterator start, Iterator finish) + : m_sequence(sequence), m_start(start), m_finish(finish) +{ +} + +}}} // namespace boost::python::objects + +#endif // ITERATOR_DWA2002510_HPP diff --git a/include/boost/python/object/iterator_core.hpp b/include/boost/python/object/iterator_core.hpp new file mode 100644 index 00000000..dee87050 --- /dev/null +++ b/include/boost/python/object/iterator_core.hpp @@ -0,0 +1,18 @@ +// Copyright David Abrahams 2002. 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. +#ifndef ITERATOR_CORE_DWA2002512_HPP +# define ITERATOR_CORE_DWA2002512_HPP + +# include + +namespace boost { namespace python { namespace objects { + +BOOST_PYTHON_DECL ref identity_function(); +BOOST_PYTHON_DECL void set_stop_iteration_error(); + +}}} // namespace boost::python::object + +#endif // ITERATOR_CORE_DWA2002512_HPP diff --git a/test/minimal.cpp b/test/minimal.cpp new file mode 100644 index 00000000..07bbb394 --- /dev/null +++ b/test/minimal.cpp @@ -0,0 +1,13 @@ +// Copyright David Abrahams 2002. 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. +#include + +BOOST_PYTHON_MODULE_INIT(minimal_ext) +{ + boost::python::module m("minimal_ext"); +} + +#include "module_tail.cpp" diff --git a/test/minimal.py b/test/minimal.py new file mode 100644 index 00000000..fe5788f5 --- /dev/null +++ b/test/minimal.py @@ -0,0 +1,2 @@ +import minimal_ext +