Interface slices between python and c++
I now have some experience using boost::python with vector_indexing_suite to expose std::vector objects to python. Using this, it is easy to expose c++ algorithms written for stl-style iterators. Consider an algorithm F1: template<typename it_t> void F1 (it_t start, it_t end); We can do: template<typename cont> void wrap_f1 (cont c) { F1 (c.begin(), c.end()); } and then expose wrap_f1<vector<double> >, for example. But now, suppose we want to apply algorithm F1 to a *slice* of a vector? I noticed that in boost.cvs, there is "slice.hpp". AFAICT, vector_indexing_suite is not using it, though. OK, so my question is, what is a "good" approach to this? I would add, I think this must be a very common issue.
I think I may have answered my own question. We can make a vector, and also a vector_slice object. Some sample code is below. One thing I still need to figure out, is I know I need to increment refcnt of vector when creating vector_slice, but I don't yet know how to do it. A vector_slice object has usual c++ iterator protocol, so I can pass it to a generic c++ algorithm without having to write a new wrapper. (The same wrapper that works for vector also works for vector_slice.) Comments? example: python Python 2.3.3 (#1, May 7 2004, 10:31:40) [GCC 3.3.3 20040412 (Red Hat Linux 3.3.3-7)] on linux2 Type "help", "copyright", "credits" or "license" for more information.
from vector import * v=IVec(10) for i in xrange(0,10): ... v[i]=i ... IVecSliceTimesIntInplace (IVec_slice (v, slice (0,4)), 2) [e for e in v] [0, 2, 4, 6, 4, 5, 6, 7, 8, 9]
vector.cc: #include <boost/python/class.hpp> #include <boost/python/init.hpp> #include <boost/python/module.hpp> #include <boost/python/def.hpp> #include <boost/python/operators.hpp> #include <boost/python/suite/indexing/vector_indexing_suite.hpp> #include <boost/python/slice.hpp> #include <string> #include <vector> #include <complex> #include <iostream> #include <numeric> #include <iterator> #include <boost/type_traits.hpp> #include "mismatch.H" typedef std::complex<double> Complex; typedef std::complex<int> ComplexI; using namespace boost::python; template<typename in1_cont_t, typename in2_cont_t, typename out_cont_t> inline void add_vector_wrapper (in1_cont_t in1, in2_cont_t in2, out_cont_t out) { typedef typename boost::remove_reference<in1_cont_t>::type::const_iterator it1_t; typedef typename boost::remove_reference<in2_cont_t>::type::const_iterator it2_t; typedef typename boost::remove_reference<out_cont_t>::type::iterator it3_t; if (in1.size() != in2.size() || in1.size() != out.size()) throw size_mismatch(); it1_t it1 = in1.begin(); it2_t it2 = in2.begin(); it3_t it3 = out.begin(); for ( ; it1 != in1.end(); it1++, it2++, it3++) *it3 = *it1 + *it2; } template<typename in1_cont_t, typename scale_t, typename out_cont_t> inline void times_vector_scalar_wrapper (in1_cont_t in1, scale_t scale, out_cont_t out) { typedef typename boost::remove_reference<in1_cont_t>::type::const_iterator it1_t; typedef typename boost::remove_reference<out_cont_t>::type::iterator it2_t; if (in1.size() != out.size()) throw size_mismatch(); it1_t it1 = in1.begin(); it2_t it2 = out.begin(); for ( ; it1 != in1.end(); it1++, it2++) *it2 = *it1 * scale; } template<typename in1_cont_t, typename scale_t> inline void times_vector_scalar_inplace_wrapper (in1_cont_t in1, scale_t scale) { typedef typename boost::remove_reference<in1_cont_t>::type::iterator it1_t; it1_t it1 = in1.begin(); for ( ; it1 != in1.end(); it1++) *it1 *= scale; } template<typename T> struct vector_slice { typedef typename std::vector<T>::iterator iterator; typedef typename std::vector<T>::const_iterator const_iterator; std::vector<T>& v; boost::python::slice s; vector_slice (std::vector<T>& _v, boost::python::slice _s) : v (_v), s (_s) {} iterator begin() { return v.begin() + extract<long>(s.start()); } iterator end() { return v.begin() + extract<long>(s.stop()); } const_iterator begin() const { return v.begin() + extract<long>(s.start()); } const_iterator end() const { return v.begin() + extract<long>(s.stop()); } size_t size() const { return (s.step() == object()) ? extract<long>(s.stop()) - extract<long>(s.start()) : (extract<long>(s.stop()) - extract<long>(s.start()))/extract<long>(s.step()); } }; BOOST_PYTHON_MODULE(vector) { class_<std::vector<double> >("DVec") .def(init<size_t>()) .def(init<const std::vector<double>&>()) .def("size", &std::vector<double>::size) .def("resize", (void (std::vector<double>::*)(size_t, const double&) )&std::vector<double>::resize) .def("resize", (void (std::vector<double>::* (size_t) )&std::vector<double>::resize) .def(vector_indexing_suite<std::vector<double> >()) ; class_<std::vector<Complex> >("CVec") .def(init<size_t>()) .def(init<const std::vector<Complex>&>()) .def("size", &std::vector<Complex>::size) .def("resize", (void (std::vector<Complex>::*)(size_t, const Complex&) )&std::vector<Complex>::resize) .def("resize", (void (std::vector<Complex>::* (size_t) )&std::vector<Complex>::resize) .def(vector_indexing_suite<std::vector<Complex>, true >()) ; class_<ComplexI >("CInt") .def(init<int,int>()) .def ("real", &ComplexI::real) .def ("imag", &ComplexI::imag) ; class_<std::vector<ComplexI > >("CIntVec") .def(init<size_t>()) .def(init<const std::vector<ComplexI>&>()) .def("size", &std::vector<ComplexI>::size) .def("resize", (void (std::vector<ComplexI>::*)(size_t, const ComplexI&) )&std::vector<ComplexI>::resize) .def("resize", (void (std::vector<ComplexI>::* (size_t) )&std::vector<ComplexI>::resize) .def(vector_indexing_suite<std::vector<ComplexI >, true >()) ; class_<std::vector<int> >("IVec") .def(init<size_t>()) .def(init<const std::vector<int>&>()) .def("size", &std::vector<int>::size) .def("resize", (void (std::vector<int>::*)(size_t, const int&) )&std::vector<int>::resize) .def("resize", (void (std::vector<int>::* (size_t) )&std::vector<int>::resize) .def(vector_indexing_suite<std::vector<int> >()) ; class_<vector_slice<int> > ("IVec_slice", init<std::vector<int>&, boost::python::slice>()) ; def ("AddCVec", &add_vector_wrapper<std::vector<Complex>const&, std::vector<Complex>const&, std::vector<Complex>&>); def ("CVecTimesdouble", ×_vector_scalar_wrapper<std::vector<Complex>const&, double, std::vector<Complex>&>); def ("CVecTimesComplex", ×_vector_scalar_wrapper<std::vector<Complex>const&, Complex, std::vector<Complex>&>); def ("IVecSliceTimesInt", ×_vector_scalar_wrapper<vector_slice<int>const&, int, std::vector<int>&>); def ("IVecSliceTimesIntInplace", ×_vector_scalar_inplace_wrapper<vector_slice<int>&, int>); }
participants (1)
-
Neal D. Becker