2
Copyright (c) 2008, Michael Droettboom
5
Licensed under the BSD license.
7
Redistribution and use in source and binary forms, with or without
8
modification, are permitted provided that the following conditions are
11
* Redistributions of source code must retain the above copyright
12
notice, this list of conditions and the following disclaimer.
14
* Redistributions in binary form must reproduce the above
15
copyright notice, this list of conditions and the following
16
disclaimer in the documentation and/or other materials provided
17
with the distribution.
19
* The names of its contributors may not be used to endorse or
20
promote products derived from this software without specific
21
prior written permission.
23
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40
#ifndef __NUMPY_BOOST_HPP__
41
#define __NUMPY_BOOST_HPP__
44
#include <numpy/arrayobject.h>
45
#include <boost/multi_array.hpp>
46
#include <boost/cstdint.hpp>
50
namespace numpy_boost_detail {
52
class numpy_type_map {
54
static const int typenum;
58
const int numpy_type_map<float>::typenum = NPY_FLOAT;
61
const int numpy_type_map<std::complex<float> >::typenum = NPY_CFLOAT;
64
const int numpy_type_map<double>::typenum = NPY_DOUBLE;
67
const int numpy_type_map<std::complex<double> >::typenum = NPY_CDOUBLE;
70
const int numpy_type_map<long double>::typenum = NPY_LONGDOUBLE;
73
const int numpy_type_map<std::complex<long double> >::typenum = NPY_CLONGDOUBLE;
76
const int numpy_type_map<boost::int8_t>::typenum = NPY_INT8;
79
const int numpy_type_map<boost::uint8_t>::typenum = NPY_UINT8;
82
const int numpy_type_map<boost::int16_t>::typenum = NPY_INT16;
85
const int numpy_type_map<boost::uint16_t>::typenum = NPY_UINT16;
88
const int numpy_type_map<boost::int32_t>::typenum = NPY_INT32;
91
const int numpy_type_map<boost::uint32_t>::typenum = NPY_UINT32;
94
const int numpy_type_map<boost::int64_t>::typenum = NPY_INT64;
97
const int numpy_type_map<boost::uint64_t>::typenum = NPY_INT64;
100
class numpy_boost_exception : public std::exception {
104
template<class T, int NDims>
105
class numpy_boost : public boost::multi_array_ref<T, NDims>
108
typedef numpy_boost<T, NDims> self_type;
109
typedef boost::multi_array_ref<T, NDims> super;
110
typedef typename super::size_type size_type;
114
PyArrayObject* array;
116
void init_from_array(PyArrayObject* a) {
118
super::base_ = (TPtr)PyArray_DATA(a);
120
// It would seem like we would want to choose C or Fortran
121
// ordering here based on the flags in the Numpy array. However,
122
// those flags are purely informational, the actually information
123
// about storage order is recorded in the strides.
124
super::storage_ = boost::c_storage_order();
126
boost::detail::multi_array::copy_n(PyArray_DIMS(a), NDims, super::extent_list_.begin());
127
for (size_t i = 0; i < NDims; ++i) {
128
super::stride_list_[i] = PyArray_STRIDE(a, i) / sizeof(T);
130
std::fill_n(super::index_base_list_.begin(), NDims, 0);
131
super::origin_offset_ = 0;
132
super::directional_offset_ = 0;
133
super::num_elements_ = std::accumulate(super::extent_list_.begin(),
134
super::extent_list_.end(),
136
std::multiplies<size_type>());
140
numpy_boost(PyObject* obj) :
141
super(NULL, std::vector<boost::uint32_t>(NDims, 0)),
146
a = (PyArrayObject*)PyArray_FromObject(obj, numpy_boost_detail::numpy_type_map<T>::typenum, NDims, NDims);
148
// TODO: Extract Python exception
149
throw numpy_boost_exception();
155
numpy_boost(const self_type &other) :
156
super(NULL, std::vector<boost::uint32_t>(NDims, 0)),
159
Py_INCREF(other.array);
160
init_from_array(other.array);
163
template<class ExtentsList>
164
explicit numpy_boost(const ExtentsList& extents) :
165
super(NULL, std::vector<boost::uint32_t>(NDims, 0)),
168
npy_intp shape[NDims];
171
boost::detail::multi_array::copy_n(extents, NDims, shape);
173
a = (PyArrayObject*)PyArray_SimpleNew(NDims, shape, numpy_boost_detail::numpy_type_map<T>::typenum);
175
// TODO: Extract Python exception
176
throw numpy_boost_exception();
186
void operator=(const self_type &other) {
188
Py_INCREF(other.array);
189
init_from_array(other.array);
195
return (PyObject*)array;