← Back to team overview

yade-dev team mailing list archive

[Branch ~yade-pkg/yade/git-trunk] Rev 3718: Update numpy_boost.hpp from svn.

 

------------------------------------------------------------
revno: 3718
committer: Anton Gladky <gladky.anton@xxxxxxxxx>
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;
   }
 };