2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-30 20:12:37 +00:00

Overhauled how builtin dtype objects are accessed for better consistency, added converters for array scalars.

This commit is contained in:
Jim Bosch
2012-05-13 13:03:10 -04:00
parent ab2225bcbd
commit 28a9fab278
7 changed files with 280 additions and 82 deletions

View File

@@ -1,58 +1,78 @@
#define BOOST_NUMPY_INTERNAL
#include <boost/numpy/internal.hpp>
#define NUMPY_DTYPE_TRAITS_BUILTIN(ctype,code) \
template <> struct dtype_traits<ctype> \
{ \
static dtype get() \
{ \
return dtype(python::detail::new_reference \
(reinterpret_cast<PyObject*>(PyArray_DescrFromType(code)))); \
} \
}; \
template dtype dtype::get_builtin<ctype>()
#define DTYPE_FROM_CODE(code) \
dtype(python::detail::new_reference(reinterpret_cast<PyObject*>(PyArray_DescrFromType(code))))
#define NUMPY_DTYPE_TRAITS_COMPLEX(creal, ctype, code) \
template <> struct dtype_traits< std::complex<creal> > \
{ \
static dtype get() \
{ \
if (sizeof(ctype) != sizeof(std::complex<creal>)) \
{ \
PyErr_SetString(PyExc_TypeError, "Cannot reinterpret std::complex<T> as T[2]"); \
python::throw_error_already_set(); \
} \
return dtype(python::detail::new_reference \
(reinterpret_cast<PyObject*>(PyArray_DescrFromType(code)))); \
} \
}; \
template dtype dtype::get_builtin< std::complex<creal> >()
#define BUILTIN_INT_DTYPE(bits) \
template <> struct builtin_int_dtype< bits, false > { \
static dtype get() { return DTYPE_FROM_CODE(NPY_INT ## bits); } \
}; \
template <> struct builtin_int_dtype< bits, true > { \
static dtype get() { return DTYPE_FROM_CODE(NPY_UINT ## bits); } \
}; \
template dtype get_int_dtype< bits, false >(); \
template dtype get_int_dtype< bits, true >()
namespace boost
{
namespace python
{
namespace converter
{
#define BUILTIN_FLOAT_DTYPE(bits) \
template <> struct builtin_float_dtype< bits > { \
static dtype get() { return DTYPE_FROM_CODE(NPY_FLOAT ## bits); } \
}; \
template dtype get_float_dtype< bits >()
#define BUILTIN_COMPLEX_DTYPE(bits) \
template <> struct builtin_complex_dtype< bits > { \
static dtype get() { return DTYPE_FROM_CODE(NPY_COMPLEX ## bits); } \
}; \
template dtype get_complex_dtype< bits >()
namespace boost { namespace python { namespace converter {
NUMPY_OBJECT_MANAGER_TRAITS_IMPL(PyArrayDescr_Type, numpy::dtype)
} // namespace boost::python::converter
} // namespace boost::python
}}} // namespace boost::python::converter
namespace numpy
{
namespace boost { namespace numpy {
template <typename T> struct dtype_traits;
namespace detail {
python::detail::new_reference dtype::convert(python::object const & arg, bool align)
{
dtype builtin_dtype<bool,true>::get() { return DTYPE_FROM_CODE(NPY_BOOL); }
template <int bits, bool isUnsigned> struct builtin_int_dtype;
template <int bits> struct builtin_float_dtype;
template <int bits> struct builtin_complex_dtype;
template <int bits, bool isUnsigned> dtype get_int_dtype() {
return builtin_int_dtype<bits,isUnsigned>::get();
}
template <int bits> dtype get_float_dtype() { return builtin_float_dtype<bits>::get(); }
template <int bits> dtype get_complex_dtype() { return builtin_complex_dtype<bits>::get(); }
BUILTIN_INT_DTYPE(8);
BUILTIN_INT_DTYPE(16);
BUILTIN_INT_DTYPE(32);
BUILTIN_INT_DTYPE(64);
BUILTIN_FLOAT_DTYPE(32);
BUILTIN_FLOAT_DTYPE(64);
BUILTIN_COMPLEX_DTYPE(64);
BUILTIN_COMPLEX_DTYPE(128);
#if NPY_BITSOF_LONGDOUBLE > NPY_BITSOF_DOUBLE
template <> struct builtin_float_dtype< NPY_BITSOF_LONGDOUBLE > {
static dtype get() { return DTYPE_FROM_CODE(NPY_LONGDOUBLE); }
};
template dtype get_float_dtype< NPY_BITSOF_LONGDOUBLE >();
template <> struct builtin_complex_dtype< 2 * NPY_BITSOF_LONGDOUBLE > {
static dtype get() { return DTYPE_FROM_CODE(NPY_CLONGDOUBLE); }
};
template dtype get_complex_dtype< 2 * NPY_BITSOF_LONGDOUBLE >();
#endif
} // namespace detail
python::detail::new_reference dtype::convert(python::object const & arg, bool align) {
PyArray_Descr* obj=NULL;
if (align)
{
if (align) {
if (PyArray_DescrAlignConverter(arg.ptr(), &obj) < 0)
python::throw_error_already_set();
}
else
{
} else {
if (PyArray_DescrConverter(arg.ptr(), &obj) < 0)
python::throw_error_already_set();
}
@@ -61,28 +81,72 @@ python::detail::new_reference dtype::convert(python::object const & arg, bool al
int dtype::get_itemsize() const { return reinterpret_cast<PyArray_Descr*>(ptr())->elsize;}
template <typename T>
dtype dtype::get_builtin() { return dtype_traits<T>::get(); }
namespace {
NUMPY_DTYPE_TRAITS_BUILTIN(bool, NPY_BOOL);
NUMPY_DTYPE_TRAITS_BUILTIN(npy_ubyte, NPY_UBYTE);
NUMPY_DTYPE_TRAITS_BUILTIN(npy_byte, NPY_BYTE);
NUMPY_DTYPE_TRAITS_BUILTIN(npy_ushort, NPY_USHORT);
NUMPY_DTYPE_TRAITS_BUILTIN(npy_short, NPY_SHORT);
NUMPY_DTYPE_TRAITS_BUILTIN(npy_uint, NPY_UINT);
NUMPY_DTYPE_TRAITS_BUILTIN(npy_int, NPY_INT);
NUMPY_DTYPE_TRAITS_BUILTIN(npy_ulong, NPY_ULONG);
NUMPY_DTYPE_TRAITS_BUILTIN(npy_long, NPY_LONG);
NUMPY_DTYPE_TRAITS_BUILTIN(npy_longlong, NPY_LONGLONG);
NUMPY_DTYPE_TRAITS_BUILTIN(npy_float, NPY_FLOAT);
NUMPY_DTYPE_TRAITS_BUILTIN(npy_double, NPY_DOUBLE);
NUMPY_DTYPE_TRAITS_BUILTIN(npy_longdouble, NPY_LONGDOUBLE);
NUMPY_DTYPE_TRAITS_BUILTIN(npy_cfloat, NPY_CFLOAT);
NUMPY_DTYPE_TRAITS_BUILTIN(npy_cdouble, NPY_CDOUBLE);
NUMPY_DTYPE_TRAITS_BUILTIN(npy_clongdouble, NPY_CLONGDOUBLE);
NUMPY_DTYPE_TRAITS_COMPLEX(float, npy_cfloat, NPY_CFLOAT);
NUMPY_DTYPE_TRAITS_COMPLEX(double, npy_cdouble, NPY_CDOUBLE);
NUMPY_DTYPE_TRAITS_COMPLEX(long double, npy_clongdouble, NPY_CLONGDOUBLE);
namespace pyconv = boost::python::converter;
template <typename T>
class array_scalar_converter {
public:
static PyTypeObject const * get_pytype() {
// This implementation depends on the fact that get_builtin returns pointers to objects
// NumPy has declared statically, and that the typeobj member also refers to a static
// object. That means we don't need to do any reference counting.
// In fact, I'm somewhat concerned that increasing the reference count of any of these
// might cause leaks, because I don't think Boost.Python ever decrements it, but it's
// probably a moot point if everything is actually static.
return reinterpret_cast<PyArray_Descr*>(dtype::get_builtin<T>().ptr())->typeobj;
}
static void * convertible(PyObject * obj) {
if (obj->ob_type == get_pytype()) {
return obj;
} else {
return 0;
}
}
static void convert(PyObject * obj, pyconv::rvalue_from_python_stage1_data* data) {
void * storage = reinterpret_cast<pyconv::rvalue_from_python_storage<T>*>(data)->storage.bytes;
// We assume std::complex is a "standard layout" here and elsewhere; not guaranteed by
// C++03 standard, but true in every known implementation (and guaranteed by C++11).
PyArray_ScalarAsCtype(obj, reinterpret_cast<T*>(storage));
data->convertible = storage;
}
static void declare() {
pyconv::registry::push_back(
&convertible, &convert, python::type_id<T>()
#ifndef BOOST_PYTHON_NO_PY_SIGNATURES
, &get_pytype
#endif
);
}
};
} // anonymous
void dtype::register_scalar_converters() {
array_scalar_converter<bool>::declare();
array_scalar_converter<npy_uint8>::declare();
array_scalar_converter<npy_int8>::declare();
array_scalar_converter<npy_uint16>::declare();
array_scalar_converter<npy_int16>::declare();
array_scalar_converter<npy_uint32>::declare();
array_scalar_converter<npy_int32>::declare();
array_scalar_converter<npy_uint64>::declare();
array_scalar_converter<npy_int64>::declare();
array_scalar_converter<float>::declare();
array_scalar_converter<double>::declare();
array_scalar_converter< std::complex<float> >::declare();
array_scalar_converter< std::complex<double> >::declare();
#if NPY_BITSOF_LONGDOUBLE > NPY_BITSOF_DOUBLE
array_scalar_converter<long double>::declare();
array_scalar_converter< std::complex<long double> >::declare();
#endif
}
} // namespace boost::numpy
} // namespace boost

View File

@@ -1,15 +1,18 @@
#define BOOST_NUMPY_INTERNAL_MAIN
#include <boost/numpy/internal.hpp>
#include <boost/numpy/dtype.hpp>
namespace boost
{
namespace numpy
{
void initialize()
void initialize(bool register_scalar_converters)
{
import_array();
import_ufunc();
if (register_scalar_converters)
dtype::register_scalar_converters();
}
}