mirror of
https://github.com/boostorg/python.git
synced 2026-01-26 06:42:27 +00:00
boost.python.numpy - moved dtype::invoke_matching_template into separate header, added similar code for invocation based on dimensionality
This commit is contained in:
@@ -46,76 +46,8 @@ public:
|
||||
|
||||
BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(dtype, object);
|
||||
|
||||
template <typename Sequence, typename Function>
|
||||
void invoke_matching_template(Function f) const;
|
||||
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct add_pointer_meta {
|
||||
|
||||
template <typename T>
|
||||
struct apply {
|
||||
typedef typename boost::add_pointer<T>::type type;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
struct dtype_template_match_found {};
|
||||
|
||||
template <typename Function>
|
||||
struct dtype_template_invoker {
|
||||
|
||||
template <typename T>
|
||||
void operator()(T * x) const {
|
||||
if (dtype::get_builtin<T>() == m_dtype) {
|
||||
m_func.template apply<T>();
|
||||
throw dtype_template_match_found();
|
||||
}
|
||||
}
|
||||
|
||||
dtype_template_invoker(dtype const & dtype_, Function func) :
|
||||
m_dtype(dtype_), m_func(func) {}
|
||||
|
||||
private:
|
||||
dtype const & m_dtype;
|
||||
Function m_func;
|
||||
};
|
||||
|
||||
template <typename Function>
|
||||
struct dtype_template_invoker< boost::reference_wrapper<Function> > {
|
||||
|
||||
template <typename T>
|
||||
void operator()(T * x) const {
|
||||
if (dtype::get_builtin<T>() == m_dtype) {
|
||||
m_func.template apply<T>();
|
||||
throw dtype_template_match_found();
|
||||
}
|
||||
}
|
||||
|
||||
dtype_template_invoker(dtype const & dtype_, Function & func) :
|
||||
m_dtype(dtype_), m_func(func) {}
|
||||
|
||||
private:
|
||||
dtype const & m_dtype;
|
||||
Function & m_func;
|
||||
};
|
||||
|
||||
} // namespace boost::python::numpy::detail
|
||||
|
||||
template <typename Sequence, typename Function>
|
||||
void dtype::invoke_matching_template(Function f) const {
|
||||
detail::dtype_template_invoker<Function> invoker(*this, f);
|
||||
try {
|
||||
boost::mpl::for_each< Sequence, detail::add_pointer_meta >(invoker);
|
||||
} catch (detail::dtype_template_match_found &) {
|
||||
return;
|
||||
}
|
||||
PyErr_SetString(PyExc_TypeError, "numpy.dtype not found in template list.");
|
||||
throw_error_already_set();
|
||||
}
|
||||
|
||||
} // namespace boost::python::numpy
|
||||
|
||||
namespace converter {
|
||||
|
||||
175
boost/python/numpy/invoke_matching.hpp
Normal file
175
boost/python/numpy/invoke_matching.hpp
Normal file
@@ -0,0 +1,175 @@
|
||||
#ifndef BOOST_PYTHON_NUMPY_INVOKE_MATCHING_HPP_INCLUDED
|
||||
#define BOOST_PYTHON_NUMPY_INVOKE_MATCHING_HPP_INCLUDED
|
||||
|
||||
/**
|
||||
* @file boost/python/numpy/ndarray.hpp
|
||||
* @brief Object manager and various utilities for numpy.ndarray.
|
||||
*/
|
||||
|
||||
#include <boost/python/numpy/dtype.hpp>
|
||||
#include <boost/python/numpy/ndarray.hpp>
|
||||
|
||||
namespace boost { namespace python { namespace numpy {
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct add_pointer_meta {
|
||||
|
||||
template <typename T>
|
||||
struct apply {
|
||||
typedef typename boost::add_pointer<T>::type type;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
struct dtype_template_match_found {};
|
||||
struct nd_template_match_found {};
|
||||
|
||||
template <typename Function>
|
||||
struct dtype_template_invoker {
|
||||
|
||||
template <typename T>
|
||||
void operator()(T * x) const {
|
||||
if (dtype::get_builtin<T>() == m_dtype) {
|
||||
m_func.apply(x);
|
||||
throw dtype_template_match_found();
|
||||
}
|
||||
}
|
||||
|
||||
dtype_template_invoker(dtype const & dtype_, Function func) :
|
||||
m_dtype(dtype_), m_func(func) {}
|
||||
|
||||
private:
|
||||
dtype const & m_dtype;
|
||||
Function m_func;
|
||||
};
|
||||
|
||||
template <typename Function>
|
||||
struct dtype_template_invoker< boost::reference_wrapper<Function> > {
|
||||
|
||||
template <typename T>
|
||||
void operator()(T * x) const {
|
||||
if (dtype::get_builtin<T>() == m_dtype) {
|
||||
m_func.apply(x);
|
||||
throw dtype_template_match_found();
|
||||
}
|
||||
}
|
||||
|
||||
dtype_template_invoker(dtype const & dtype_, Function & func) :
|
||||
m_dtype(dtype_), m_func(func) {}
|
||||
|
||||
private:
|
||||
dtype const & m_dtype;
|
||||
Function & m_func;
|
||||
};
|
||||
|
||||
template <typename Function>
|
||||
struct nd_template_invoker {
|
||||
|
||||
template <typename T>
|
||||
void operator()(T * x) const {
|
||||
if (m_nd == T::value) {
|
||||
m_func.apply(x);
|
||||
throw nd_template_match_found();
|
||||
}
|
||||
}
|
||||
|
||||
nd_template_invoker(int nd, Function func) :
|
||||
m_nd(nd), m_func(func) {}
|
||||
|
||||
private:
|
||||
int m_nd;
|
||||
Function m_func;
|
||||
};
|
||||
|
||||
template <typename Function>
|
||||
struct nd_template_invoker< boost::reference_wrapper<Function> > {
|
||||
|
||||
template <typename T>
|
||||
void operator()(T * x) const {
|
||||
if (m_nd == T::value) {
|
||||
m_func.apply(x);
|
||||
throw nd_template_match_found();
|
||||
}
|
||||
}
|
||||
|
||||
nd_template_invoker(int nd, Function & func) :
|
||||
m_nd(nd), m_func(func) {}
|
||||
|
||||
private:
|
||||
int m_nd;
|
||||
Function & m_func;
|
||||
};
|
||||
|
||||
} // namespace boost::python::numpy::detail
|
||||
|
||||
template <typename Sequence, typename Function>
|
||||
void invoke_matching_nd(int nd, Function f) {
|
||||
detail::nd_template_invoker<Function> invoker(nd, f);
|
||||
try {
|
||||
boost::mpl::for_each< Sequence, detail::add_pointer_meta >(invoker);
|
||||
} catch (detail::nd_template_match_found &) {
|
||||
return;
|
||||
}
|
||||
PyErr_SetString(PyExc_TypeError, "number of dimensions not found in template list.");
|
||||
throw_error_already_set();
|
||||
}
|
||||
|
||||
template <typename Sequence, typename Function>
|
||||
void invoke_matching_dtype(dtype const & dtype_, Function f) {
|
||||
detail::dtype_template_invoker<Function> invoker(dtype_, f);
|
||||
try {
|
||||
boost::mpl::for_each< Sequence, detail::add_pointer_meta >(invoker);
|
||||
} catch (detail::dtype_template_match_found &) {
|
||||
return;
|
||||
}
|
||||
PyErr_SetString(PyExc_TypeError, "dtype not found in template list.");
|
||||
throw_error_already_set();
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename DimSequence, typename Function>
|
||||
struct array_template_invoker_wrapper {
|
||||
|
||||
template <typename T>
|
||||
void apply(T * x) const {
|
||||
invoke_matching_nd<DimSequence>(m_nd, m_func.nest(x));
|
||||
}
|
||||
|
||||
array_template_invoker_wrapper(int nd, Function func) :
|
||||
m_nd(nd), m_func(func) {}
|
||||
|
||||
private:
|
||||
int m_nd;
|
||||
Function m_func;
|
||||
};
|
||||
|
||||
template <typename DimSequence, typename Function>
|
||||
struct array_template_invoker_wrapper< DimSequence, boost::reference_wrapper<Function> > {
|
||||
|
||||
template <typename T>
|
||||
void apply(T * x) const {
|
||||
invoke_matching_nd<DimSequence>(m_nd, m_func.nest(x));
|
||||
}
|
||||
|
||||
array_template_invoker_wrapper(int nd, Function & func) :
|
||||
m_nd(nd), m_func(func) {}
|
||||
|
||||
private:
|
||||
int m_nd;
|
||||
Function & m_func;
|
||||
};
|
||||
|
||||
} // namespace boost::python::numpy::detail
|
||||
|
||||
template <typename TypeSequence, typename DimSequence, typename Function>
|
||||
void invoke_matching_array(ndarray const & array_, Function f) {
|
||||
detail::array_template_invoker_wrapper<DimSequence,Function> wrapper(array_.get_nd(), f);
|
||||
invoke_matching_dtype<TypeSequence>(array_.get_dtype(), wrapper);
|
||||
}
|
||||
|
||||
|
||||
}}} // namespace boost::python::numpy
|
||||
|
||||
#endif // !BOOST_PYTHON_NUMPY_INVOKE_MATCHING_HPP_INCLUDED
|
||||
@@ -275,7 +275,6 @@ inline ndarray::bitflag operator&(ndarray::bitflag a, ndarray::bitflag b) {
|
||||
return ndarray::bitflag(int(a) & int(b));
|
||||
}
|
||||
|
||||
|
||||
} // namespace boost::python::numpy
|
||||
|
||||
namespace converter {
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <boost/python/numpy/scalars.hpp>
|
||||
#include <boost/python/numpy/matrix.hpp>
|
||||
#include <boost/python/numpy/ufunc.hpp>
|
||||
#include <boost/python/numpy/invoke_matching.hpp>
|
||||
|
||||
namespace boost { namespace python {
|
||||
namespace numpy {
|
||||
|
||||
@@ -6,12 +6,16 @@ class TestTemplates(unittest.TestCase):
|
||||
|
||||
def testTemplates(self):
|
||||
for dtype in (numpy.int16, numpy.int32, numpy.float32, numpy.complex128):
|
||||
a1 = numpy.zeros((12,), dtype=dtype)
|
||||
a2 = numpy.arange(12, dtype=dtype)
|
||||
templates_mod.fill(a1)
|
||||
self.assert_((a1 == a2).all())
|
||||
v = numpy.arange(12, dtype=dtype)
|
||||
for shape in ((12,), (4, 3), (2, 6)):
|
||||
a1 = numpy.zeros(shape, dtype=dtype)
|
||||
a2 = v.reshape(a1.shape)
|
||||
templates_mod.fill(a1)
|
||||
self.assert_((a1 == a2).all())
|
||||
a1 = numpy.zeros((12,), dtype=numpy.float64)
|
||||
self.assertRaises(TypeError, templates_mod.fill, a1)
|
||||
a1 = numpy.zeros((12,2,3), dtype=numpy.float32)
|
||||
self.assertRaises(TypeError, templates_mod.fill, a1)
|
||||
|
||||
if __name__=="__main__":
|
||||
unittest.main()
|
||||
|
||||
@@ -1,21 +1,48 @@
|
||||
#include <boost/python/numpy/numpy.hpp>
|
||||
#include <boost/mpl/vector.hpp>
|
||||
#include <boost/mpl/vector_c.hpp>
|
||||
|
||||
namespace bp = boost::python;
|
||||
|
||||
struct ArrayFiller {
|
||||
|
||||
typedef boost::mpl::vector< short, int, float, std::complex<double> > Sequence;
|
||||
typedef boost::mpl::vector< short, int, float, std::complex<double> > TypeSequence;
|
||||
typedef boost::mpl::vector_c< int, 1, 2 > DimSequence;
|
||||
|
||||
template <typename T>
|
||||
void apply() const {
|
||||
char * p = argument.get_data();
|
||||
int stride = argument.strides(0);
|
||||
int size = argument.shape(0);
|
||||
for (int n = 0; n != size; ++n, p += stride) {
|
||||
*reinterpret_cast<T*>(p) = static_cast<T>(n);
|
||||
struct nested {
|
||||
|
||||
void apply(boost::mpl::integral_c<int,1> * ) const {
|
||||
char * p = argument.get_data();
|
||||
int stride = argument.strides(0);
|
||||
int size = argument.shape(0);
|
||||
for (int n = 0; n != size; ++n, p += stride) {
|
||||
*reinterpret_cast<T*>(p) = static_cast<T>(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void apply(boost::mpl::integral_c<int,2> * ) const {
|
||||
char * row_p = argument.get_data();
|
||||
int row_stride = argument.strides(0);
|
||||
int col_stride = argument.strides(1);
|
||||
int rows = argument.shape(0);
|
||||
int cols = argument.shape(1);
|
||||
int i = 0;
|
||||
for (int n = 0; n != rows; ++n, row_p += row_stride) {
|
||||
char * col_p = row_p;
|
||||
for (int m = 0; m != cols; ++i, ++m, col_p += col_stride) {
|
||||
*reinterpret_cast<T*>(col_p) = static_cast<T>(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
explicit nested(bp::numpy::ndarray const & arg) : argument(arg) {}
|
||||
|
||||
bp::numpy::ndarray argument;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
nested<T> nest(T *) const { return nested<T>(argument); }
|
||||
|
||||
bp::numpy::ndarray argument;
|
||||
|
||||
@@ -25,7 +52,7 @@ struct ArrayFiller {
|
||||
|
||||
void fill(bp::numpy::ndarray const & arg) {
|
||||
ArrayFiller filler(arg);
|
||||
arg.get_dtype().invoke_matching_template< ArrayFiller::Sequence >(filler);
|
||||
bp::numpy::invoke_matching_array< ArrayFiller::TypeSequence, ArrayFiller::DimSequence >(arg, filler);
|
||||
}
|
||||
|
||||
BOOST_PYTHON_MODULE(templates_mod) {
|
||||
|
||||
Reference in New Issue
Block a user