------------------------------------------------------------ revno: 3718 committer: Anton Gladky <[email protected]> timestamp: Wed 2013-10-16 07:58:05 +0200 message: Update numpy_boost.hpp from svn. modified: lib/pyutil/README lib/pyutil/numpy_boost.hpp
-- lp:yade https://code.launchpad.net/~yade-pkg/yade/git-trunk Your team Yade developers is subscribed to branch lp:yade. To unsubscribe from this branch go to https://code.launchpad.net/~yade-pkg/yade/git-trunk/+edit-subscription
=== modified file 'lib/pyutil/README' --- lib/pyutil/README 2010-01-01 15:21:30 +0000 +++ lib/pyutil/README 2013-10-16 05:58:05 +0000 @@ -1,2 +1,2 @@ numpy_boost.cpp: - http://code.google.com/p/numpy-boost/source/checkout (svn rev 2) + http://code.google.com/p/numpy-boost/source/checkout (svn rev 9) === modified file 'lib/pyutil/numpy_boost.hpp' --- lib/pyutil/numpy_boost.hpp 2010-01-21 07:53:17 +0000 +++ lib/pyutil/numpy_boost.hpp 2013-10-16 05:58:05 +0000 @@ -1,5 +1,5 @@ /* -Copyright (c) 2008, Michael Droettboom +Copyright (c) 2012, Michael Droettboom All rights reserved. Licensed under the BSD license. @@ -33,10 +33,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* - Documentation to come -*/ - #ifndef __NUMPY_BOOST_HPP__ #define __NUMPY_BOOST_HPP__ @@ -44,10 +40,15 @@ #include <numpy/arrayobject.h> #include <boost/multi_array.hpp> #include <boost/cstdint.hpp> +#include <boost/python.hpp> #include <complex> #include <algorithm> -namespace numpy_boost_detail { +/* numpy_type_map<T> + + Provides a mapping from C++ datatypes to Numpy type + numbers. */ +namespace detail { template<class T> class numpy_type_map { public: @@ -94,42 +95,87 @@ const int numpy_type_map<boost::int64_t>::typenum = NPY_INT64; template<> - const int numpy_type_map<boost::uint64_t>::typenum = NPY_INT64; + const int numpy_type_map<boost::uint64_t>::typenum = NPY_UINT64; } -class numpy_boost_exception : public std::exception { +class python_exception : public std::exception { }; +/* An array that acts like a boost::multi_array, but is backed by the + memory of a Numpy array. Provides nice C++ interface to a Numpy + array without any copying of the data. + + It may be constructed one of two ways: + + 1) With an existing Numpy array. The boost::multi_array will + then have the data, dimensions and strides of the Numpy array. + + 2) With a list of dimensions, in which case a new contiguous + Numpy array will be created and the new boost::array will + point to it. + + */ template<class T, int NDims> class numpy_boost : public boost::multi_array_ref<T, NDims> { public: - typedef numpy_boost<T, NDims> self_type; + typedef numpy_boost<T, NDims> self_type; typedef boost::multi_array_ref<T, NDims> super; - typedef typename super::size_type size_type; - typedef T* TPtr; + typedef typename super::size_type size_type; + typedef T* TPtr; private: PyArrayObject* array; - void init_from_array(PyArrayObject* a) { + void init_from_array(PyArrayObject* a) throw() { + /* Upon calling init_from_array, a should already have been + incref'd for ownership by this object. */ + + /* Store a reference to the Numpy array so we can DECREF it in the + destructor. */ array = a; + + /* Point the boost::array at the Numpy array data. + + We don't need to worry about free'ing this pointer, because it + will always point to memory allocated as part of the data of a + Numpy array. That memory is managed by Python reference + counting. */ super::base_ = (TPtr)PyArray_DATA(a); - // It would seem like we would want to choose C or Fortran - // ordering here based on the flags in the Numpy array. However, - // those flags are purely informational, the actually information - // about storage order is recorded in the strides. + /* Set the storage order. + + It would seem like we would want to choose C or Fortran + ordering here based on the flags in the Numpy array. However, + those flags are purely informational, the actually information + about storage order is recorded in the strides. */ super::storage_ = boost::c_storage_order(); + /* Copy the dimensions from the Numpy array to the boost::array. */ boost::detail::multi_array::copy_n(PyArray_DIMS(a), NDims, super::extent_list_.begin()); + + /* Copy the strides from the Numpy array to the boost::array. + + Numpy strides are in bytes. boost::array strides are in + elements, so we need to divide. */ for (size_t i = 0; i < NDims; ++i) { super::stride_list_[i] = PyArray_STRIDE(a, i) / sizeof(T); } + + /* index_base_list_ stores the bases of the indices in each + dimension. Since we want C-style and Numpy-style zero-based + indexing, just fill it with zeros. */ std::fill_n(super::index_base_list_.begin(), NDims, 0); + + /* We don't want any additional offsets. If they exist, Numpy has + already handled that for us when calculating the data pointer + and strides. */ super::origin_offset_ = 0; super::directional_offset_ = 0; + + /* Calculate the number of elements. This has nothing to do with + memory layout. */ super::num_elements_ = std::accumulate(super::extent_list_.begin(), super::extent_list_.end(), size_type(1), @@ -137,32 +183,35 @@ } public: - numpy_boost(PyObject* obj) : - super(NULL, std::vector<boost::uint32_t>(NDims, 0)), + /* Construct from an existing Numpy array */ + numpy_boost(PyObject* obj) throw () : + super(NULL, std::vector<typename super::index>(NDims, 0)), array(NULL) { PyArrayObject* a; - a = (PyArrayObject*)PyArray_FromObject(obj, numpy_boost_detail::numpy_type_map<T>::typenum, NDims, NDims); + a = (PyArrayObject*)PyArray_FromObject( + obj, detail::numpy_type_map<T>::typenum, NDims, NDims); if (a == NULL) { - // TODO: Extract Python exception - throw numpy_boost_exception(); + throw boost::python::error_already_set(); } init_from_array(a); } - numpy_boost(const self_type &other) : - super(NULL, std::vector<boost::uint32_t>(NDims, 0)), + /* Copy constructor */ + numpy_boost(const self_type &other) throw() : + super(NULL, std::vector<typename super::index>(NDims, 0)), array(NULL) { Py_INCREF(other.array); init_from_array(other.array); } + /* Construct a new array based on the given dimensions */ template<class ExtentsList> - explicit numpy_boost(const ExtentsList& extents) : - super(NULL, std::vector<boost::uint32_t>(NDims, 0)), + explicit numpy_boost(const ExtentsList& extents) throw () : + super(NULL, std::vector<typename super::index>(NDims, 0)), array(NULL) { npy_intp shape[NDims]; @@ -170,28 +219,32 @@ boost::detail::multi_array::copy_n(extents, NDims, shape); - a = (PyArrayObject*)PyArray_SimpleNew(NDims, shape, numpy_boost_detail::numpy_type_map<T>::typenum); + a = (PyArrayObject*)PyArray_SimpleNew( + NDims, shape, detail::numpy_type_map<T>::typenum); if (a == NULL) { - // TODO: Extract Python exception - throw numpy_boost_exception(); + throw boost::python::error_already_set(); } init_from_array(a); } + /* Destructor */ ~numpy_boost() { - Py_DECREF(array); + /* Dereference the numpy array. */ + Py_XDECREF(array); } - void operator=(const self_type &other) { - Py_DECREF(array); + /* Assignment operator */ + void operator=(const self_type &other) throw() { Py_INCREF(other.array); + Py_DECREF(array); init_from_array(other.array); } + /* Return the underlying Numpy array object. [Borrowed + reference] */ PyObject* - py_ptr() { - Py_INCREF(array); + py_ptr() const throw() { return (PyObject*)array; } };
_______________________________________________ Mailing list: https://launchpad.net/~yade-dev Post to : [email protected] Unsubscribe : https://launchpad.net/~yade-dev More help : https://help.launchpad.net/ListHelp

