casacore
PycArrayComCC.h
Go to the documentation of this file.
1 //# PycArrayCom.h: Common code to convert an Array to/from a Python array
2 //# Copyright (C) 2006
3 //# Associated Universities, Inc. Washington DC, USA.
4 //#
5 //# This library is free software; you can redistribute it and/or modify it
6 //# under the terms of the GNU Library General Public License as published by
7 //# the Free Software Foundation; either version 2 of the License, or (at your
8 //# option) any later version.
9 //#
10 //# This library is distributed in the hope that it will be useful, but WITHOUT
11 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
13 //# License for more details.
14 //#
15 //# You should have received a copy of the GNU Library General Public License
16 //# along with this library; if not, write to the Free Software Foundation,
17 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
18 //#
19 //# Correspondence concerning AIPS++ should be addressed as follows:
20 //# Internet email: aips2-request@nrao.edu.
21 //# Postal address: AIPS++ Project Office
22 //# National Radio Astronomy Observatory
23 //# 520 Edgemont Road
24 //# Charlottesville, VA 22903-2475 USA
25 //#
26 //# $Id: PycArrayComCC.h,v 1.3 2006/11/20 23:58:17 gvandiep Exp $
27 
28 #if PY_MAJOR_VERSION >= 3
29 #define IS_PY3K
30 #endif
31 
32 
33  Bool PycArrayCheck (PyObject* obj_ptr)
34  {
35  if (!PyArray_API) {
36  if (!isImported()) return False;
37  loadAPI();
38  }
39  return PyArray_Check (obj_ptr);
40  }
41 
43  {
44  using namespace boost::python;
45  // PySys_GetObject uses char* instead of const char*, so use a cast.
46  const char* modStr = "modules";
47  PyObject* mods = PySys_GetObject(const_cast<char*>(modStr));
48  dict d = extract<dict>(mods)();
49  return d.has_key(PYC_USE_PYARRAY);
50  }
51 
52  void loadAPI()
53  {
54  if (!PyArray_API) {
55  if (!importArray() || !PyArray_API) {
56  throw AipsError ("PycArray: failed to load the " PYC_USE_PYARRAY
57  " API");
58  }
59  }
60  }
61 
62 
63  template <typename T> struct TypeConvTraits {
64  typedef T casa_type;
65  typedef void* python_type;
66  static NPY_TYPES pyType()
67  { throw AipsError ("PycArray: unknown casa type"); }
68  };
69  template <> struct TypeConvTraits<casacore::Bool> {
71  typedef npy_bool python_type;
72  static NPY_TYPES pyType() { return NPY_BOOL; }
73  };
74  template <> struct TypeConvTraits<casacore::uChar> {
76  typedef npy_uint16 python_type; // Note: numarray uInt8 is Bool
77  static NPY_TYPES pyType() { return NPY_UINT16; }
78  };
79  template <> struct TypeConvTraits<casacore::Short> {
81  typedef npy_int16 python_type;
82  static NPY_TYPES pyType() { return NPY_INT16; }
83  };
84  template <> struct TypeConvTraits<casacore::uShort> {
86  typedef npy_uint16 python_type;
87  static NPY_TYPES pyType() { return NPY_UINT16; }
88  };
89  template <> struct TypeConvTraits<casacore::Int> {
91  typedef npy_int32 python_type;
92  static NPY_TYPES pyType() { return NPY_INT32; }
93  };
94  template <> struct TypeConvTraits<casacore::uInt> {
96  typedef npy_uint32 python_type;
97  static NPY_TYPES pyType() { return NPY_UINT32; }
98  };
99  template <> struct TypeConvTraits<casacore::Int64> {
101  typedef npy_int64 python_type;
102  static NPY_TYPES pyType() { return NPY_INT64; }
103  };
104  template <> struct TypeConvTraits<casacore::uInt64> {
106  typedef npy_uint64 python_type;
107  static NPY_TYPES pyType() { return NPY_UINT64; }
108  };
109  template <> struct TypeConvTraits<casacore::Float> {
111  typedef npy_float32 python_type;
112  static NPY_TYPES pyType() { return NPY_FLOAT32; }
113  };
114  template <> struct TypeConvTraits<casacore::Double> {
116  typedef npy_float64 python_type;
117  static NPY_TYPES pyType() { return NPY_FLOAT64; }
118  };
119  template <> struct TypeConvTraits<casacore::Complex> {
121  typedef npy_complex64 python_type;
122  static NPY_TYPES pyType() { return NPY_COMPLEX64; }
123  };
124  template <> struct TypeConvTraits<casacore::DComplex> {
126  typedef npy_complex128 python_type;
127  static NPY_TYPES pyType() { return NPY_COMPLEX128; }
128  };
129  template <> struct TypeConvTraits<casacore::String> {
131  typedef ::PyObject* python_type;
132  static NPY_TYPES pyType() { return NPY_OBJECT; }
133  };
134  // This one is only used to convert numpy BYTE and SBYTE to casa short.
135  // There is no back conversion, so an exception is thrown.
136  template <> struct TypeConvTraits<casacore::Char> {
138  typedef npy_int8 python_type;
139  static NPY_TYPES pyType()
140  { throw AipsError ("PycArray: unknown casa type"); }
141  };
142 
143 
144  template <typename T>
145  void ArrayCopy<T>::toPy (void* to, const T* from, uInt nr)
146  {
147  if (sizeof(T) == sizeof(typename TypeConvTraits<T>::python_type)) {
148  ::memcpy (to, from, nr*sizeof(T));
149  } else {
150  typename TypeConvTraits<T>::python_type* dst =
151  static_cast<typename TypeConvTraits<T>::python_type*>(to);
152  for (uInt i=0; i<nr; i++) {
153  dst[i] = from[i];
154  }
155  }
156  }
157  template <typename T>
158  void ArrayCopy<T>::fromPy (T* to, const void* from, uInt nr)
159  {
160  if (sizeof(T) == sizeof(typename TypeConvTraits<T>::python_type)) {
161  ::memcpy (to, from, nr*sizeof(T));
162  } else {
163  const typename TypeConvTraits<T>::python_type* src =
164  static_cast<const typename TypeConvTraits<T>::python_type*>(from);
165  for (uInt i=0; i<nr; i++) {
166  to[i] = src[i];
167  }
168  }
169  }
170  template <typename T>
171  Array<T> ArrayCopy<T>::toArray (const IPosition& shape,
172  void* data, bool copy)
173  {
174  // If the python array was contiguous, etc., we can directly use
175  // its data because the Array used is only temporary.
176  // However, if a copy of the Python array was made in PycArray.cc,
177  // we cannot do that because the Python copy is out of scope when
178  // the Array object gets used.
179  if (!copy) {
180  if (sizeof(T) == sizeof(typename TypeConvTraits<T>::python_type)) {
181  return Array<T> (shape, static_cast<T*>(data), SHARE);
182  }
183  }
184  Array<T> arr(shape);
185  fromPy (arr.data(), data, arr.size());
186  return arr;
187  }
188 
189 
190  void ArrayCopy<Complex>::toPy (void* to, const Complex* from, uInt nr)
191  {
192  if (sizeof(Complex) != sizeof(TypeConvTraits<Complex>::python_type)) {
193  throw AipsError("PycArray: size of Complex data type mismatches");
194  }
195  ::memcpy (to, from, nr*sizeof(Complex));
196  }
197  void ArrayCopy<Complex>::fromPy (Complex* to, const void* from, uInt nr)
198  {
199  if (sizeof(Complex) != sizeof(TypeConvTraits<Complex>::python_type)) {
200  throw AipsError("PycArray: size of Complex data type mismatches");
201  }
202  ::memcpy (to, from, nr*sizeof(Complex));
203  }
204  Array<Complex> ArrayCopy<Complex>::toArray (const IPosition& shape,
205  void* data, bool copy)
206  {
207  if (!copy) {
208  if (sizeof(Complex) == sizeof(TypeConvTraits<Complex>::python_type)) {
209  return Array<Complex> (shape, static_cast<Complex*>(data), SHARE);
210  }
211  }
212  Array<Complex> arr(shape);
213  fromPy (arr.data(), data, arr.size());
214  return arr;
215  }
216 
217 
218  void ArrayCopy<DComplex>::toPy (void* to, const DComplex* from, uInt nr)
219  {
220  if (sizeof(DComplex) != sizeof(TypeConvTraits<DComplex>::python_type)) {
221  throw AipsError("PycArray: size of DComplex data type mismatches");
222  }
223  ::memcpy (to, from, nr*sizeof(DComplex));
224  }
225  void ArrayCopy<DComplex>::fromPy (DComplex* to, const void* from, uInt nr)
226  {
227  if (sizeof(DComplex) != sizeof(TypeConvTraits<DComplex>::python_type)) {
228  throw AipsError("PycArray: size of DComplex data type mismatches");
229  }
230  ::memcpy (to, from, nr*sizeof(DComplex));
231  }
232  Array<DComplex> ArrayCopy<DComplex>::toArray (const IPosition& shape,
233  void* data, bool copy)
234  {
235  if (!copy) {
236  if (sizeof(DComplex) == sizeof(TypeConvTraits<DComplex>::python_type)) {
237  return Array<DComplex> (shape, static_cast<DComplex*>(data), SHARE);
238  }
239  }
240  Array<DComplex> arr(shape);
241  fromPy (arr.data(), data, arr.size());
242  return arr;
243  }
244 
245 
246  void ArrayCopy<String>::toPy (void* to, const String* from, uInt nr)
247  {
248  PyObject** dst = static_cast<PyObject**>(to);
249  for (uInt i=0; i<nr; i++) {
250 #ifdef IS_PY3K
251  dst[i] = PyUnicode_FromString(from[i].chars());
252 #else
253  dst[i] = PyString_FromString(from[i].chars());
254 #endif
255  }
256  }
257  void ArrayCopy<String>::fromPy (String* to, const void* from, uInt nr)
258  {
259  using namespace boost::python;
260  PyObject** src = (PyObject**)from;
261  for (uInt i=0; i<nr; i++) {
262  handle<> py_elem_hdl(src[i]);
263  object py_elem_obj(py_elem_hdl);
264  extract<std::string> elem_proxy(py_elem_obj);
265  to[i] = elem_proxy();
266  }
267  }
268  Array<String> ArrayCopy<String>::toArray (const IPosition& shape,
269  void* data, bool)
270  {
271  Array<String> arr(shape);
272  fromPy (arr.data(), data, arr.size());
273  return arr;
274  }
275 
276  ValueHolder makeArray (PyObject* obj_ptr, Bool copyData)
277  {
278  if (! PycArrayCheck(obj_ptr)) {
279  throw AipsError ("PycArray: python object is not an array");
280  }
281  PyArrayObject* po = (PyArrayObject*)obj_ptr;
282  boost::python::object obj;
283  bool docopy = copyData; // copy data if wanted or needed
284  if (! PyArray_ISCONTIGUOUS(po)
285  || ! PyArray_ISALIGNED(po)
286  || PyArray_ISBYTESWAPPED(po)) {
287  boost::python::handle<> py_hdl(obj_ptr);
288  boost::python::object py_obj(py_hdl);
289  // incr refcount, because ~object decrements it
290  boost::python::incref(obj_ptr);
291  po = (PyArrayObject*)PyArray_FromArray(po, NULL,
292  NPY_ARRAY_NOTSWAPPED
293  | NPY_ARRAY_C_CONTIGUOUS
294  | NPY_ARRAY_ALIGNED);
295  docopy = true;
296  }
297  // Swap axes, because Casacore has row minor and Python row major order.
298  // A scalar is treated as a vector with length 1.
299  int nd = PyArray_NDIM(po);
300  IPosition shp(1, 1);
301  if (nd > 0) {
302  shp.resize (nd);
303  for (int i=0; i<nd; i++) {
304  shp[i] = PyArray_DIMS(po)[nd-i-1];
305  }
306  }
307  // Assert array is contiguous now.
308  // If the array is empty, numarray still sees it as non-contiguous.
309  if (shp.product() > 0) {
310  AlwaysAssert (PyArray_ISCONTIGUOUS(po), AipsError);
311  AlwaysAssert (PyArray_ISALIGNED(po), AipsError);
312  AlwaysAssert (!PyArray_ISBYTESWAPPED(po), AipsError);
313  }
314  // Create the correct array.
315  switch (PyArray_TYPE(po)) {
316  case NPY_BOOL:
317  return ValueHolder (ArrayCopy<Bool>::toArray(shp, PyArray_DATA(po), docopy));
318  case NPY_INT16:
319  return ValueHolder (ArrayCopy<Short>::toArray(shp, PyArray_DATA(po), docopy));
320  case NPY_UINT16:
321  return ValueHolder (ArrayCopy<uShort>::toArray(shp, PyArray_DATA(po), docopy));
322  case NPY_INT32:
323  return ValueHolder (ArrayCopy<Int>::toArray(shp, PyArray_DATA(po), docopy));
324  case NPY_UINT32:
325  return ValueHolder (ArrayCopy<uInt>::toArray(shp, PyArray_DATA(po), docopy));
326  case NPY_INT64:
327  return ValueHolder (ArrayCopy<Int64>::toArray(shp, PyArray_DATA(po), docopy));
328  case NPY_FLOAT32:
329  return ValueHolder (ArrayCopy<Float>::toArray(shp, PyArray_DATA(po), docopy));
330  case NPY_FLOAT64:
331  return ValueHolder (ArrayCopy<Double>::toArray(shp, PyArray_DATA(po), docopy));
332  case NPY_COMPLEX64:
333  return ValueHolder (ArrayCopy<Complex>::toArray(shp, PyArray_DATA(po), docopy));
334  case NPY_COMPLEX128:
335  return ValueHolder (ArrayCopy<DComplex>::toArray(shp, PyArray_DATA(po), docopy));
336  case NPY_OBJECT:
337  return ValueHolder (ArrayCopy<String>::toArray(shp, PyArray_DATA(po), docopy));
338  default:
339  // Some types can be the same as other types, so they cannot
340  // be used in the switch (compiler complains).
341  // This is true for BYTE and SBYTE which can equal to BOOL in numarray.
342  // Similarly for STRING which exists for numpy and is set to
343  // INT for numarray.
344  if (PyArray_TYPE(po) == NPY_UINT64) {
345  Array<uInt64> arr = ArrayCopy<uInt64>::toArray(shp, PyArray_DATA(po), False);
346  Array<Int64> res(arr.shape());
347  convertArray (res, arr);
348  return ValueHolder(res);
349  } else if (PyArray_TYPE(po) == NPY_INT8) {
350  Array<Char> arr = ArrayCopy<Char>::toArray(shp, PyArray_DATA(po), False);
351  Array<Short> res(arr.shape());
352  convertArray (res, arr);
353  return ValueHolder(res);
354  } else if (PyArray_TYPE(po) == NPY_UINT8) {
355  // Copy using Char, because uChar is mapped to Short in the Traits.
356  Array<Char> arr = ArrayCopy<Char>::toArray(shp, PyArray_DATA(po), False);
357  Array<Short> res(arr.shape());
358  void* varr = &arr;
359  Array<uChar>* uarr = static_cast<Array<uChar>*>(varr);
360  convertArray (res, *uarr);
361  return ValueHolder(res);
362  } else if (PyArray_TYPE(po) == NPY_STRING) {
363  int slen = 0;
364  if (nd > 0) {
365  slen = PyArray_STRIDES(po)[nd-1];
366  }
367  return ValueHolder (ArrayCopyStr_toArray(shp, PyArray_DATA(po), slen));
368  }
369  break;
370  }
371  throw AipsError ("PycArray: unknown python array data type");
372  }
373 
374 
375  // Instantiate the various templates.
376  template struct ArrayCopy<Bool>;
377  template struct ArrayCopy<Char>;
378  template struct ArrayCopy<uChar>;
379  template struct ArrayCopy<Short>;
380  template struct ArrayCopy<uShort>;
381  template struct ArrayCopy<Int>;
382  template struct ArrayCopy<uInt>;
383  template struct ArrayCopy<Int64>;
384  template struct ArrayCopy<uInt64>;
385  template struct ArrayCopy<Float>;
386  template struct ArrayCopy<Double>;
387 
388  template boost::python::object makePyArrayObject
389  (casacore::Array<Bool> const& arr);
390  template boost::python::object makePyArrayObject
391  (casacore::Array<uChar> const& arr);
392  template boost::python::object makePyArrayObject
393  (casacore::Array<Short> const& arr);
394  template boost::python::object makePyArrayObject
395  (casacore::Array<uShort> const& arr);
396  template boost::python::object makePyArrayObject
397  (casacore::Array<Int> const& arr);
398  template boost::python::object makePyArrayObject
399  (casacore::Array<uInt> const& arr);
400  template boost::python::object makePyArrayObject
401  (casacore::Array<Int64> const& arr);
402  template boost::python::object makePyArrayObject
403  (casacore::Array<Float> const& arr);
404  template boost::python::object makePyArrayObject
405  (casacore::Array<Double> const& arr);
406  template boost::python::object makePyArrayObject
407  (casacore::Array<Complex> const& arr);
408  template boost::python::object makePyArrayObject
409  (casacore::Array<DComplex> const& arr);
static void fromPy(T *to, const void *from, uInt nr)
long long Int64
Define the extra non-standard types used by Casacore (like proposed uSize, Size)
Definition: aipsxtype.h:38
int Int
Definition: aipstype.h:47
StatsData< AccumType > copy(const StatsData< AccumType > &stats)
Bool PycArrayCheck(PyObject *obj_ptr)
A class to convert an Array to/from Python objects.
Definition: PycArrayComCC.h:33
unsigned long long uInt64
Definition: aipsxtype.h:39
void loadAPI()
Definition: PycArrayComCC.h:52
unsigned char uChar
Definition: aipstype.h:44
Bool isImported()
Check if the API is or can be imported.
Definition: PycArrayComCC.h:42
void * python_type
Definition: PycArrayComCC.h:65
Copy/convert the array data as needed.
Definition: PycArrayComH.h:48
char Char
Definition: aipstype.h:43
short Short
Definition: aipstype.h:45
static void toPy(void *to, const T *from, uInt nr)
ValueHolder makeArray(PyObject *obj_ptr, Bool copyData)
Convert the python array to a Casacore array in the ValueHolder.
double Double
Definition: aipstype.h:52
static NPY_TYPES pyType()
Definition: PycArrayComCC.h:66
template boost::python::object makePyArrayObject(casacore::Array< Bool > const &arr)
#define AlwaysAssert(expr, exception)
These marcos are provided for use instead of simply using the constructors of assert_ to allow additi...
Definition: Assert.h:157
bool Bool
Define the standard types used by Casacore.
Definition: aipstype.h:39
#define PYC_USE_PYARRAY
Definition: PycArrayNP.h:42
float Float
Definition: aipstype.h:51
const Bool False
Definition: aipstype.h:41
TableExprNode shape(const TableExprNode &array)
Function operating on any scalar or array resulting in a Double array containing the shape...
Definition: ExprNode.h:2015
static Array< T > toArray(const IPosition &shape, void *data, bool copy)
Base class for all Casacore library errors.
Definition: Error.h:135
Share means that the Array will just use the pointer (no copy), however the Array will NOT delete it ...
Definition: ArrayBase.h:64
Bool importArray()
Array< String > ArrayCopyStr_toArray(const IPosition &shape, void *data, uInt slen)
String: the storage and methods of handling collections of characters.
Definition: String.h:223
this file contains all the compiler specific defines
Definition: mainpage.dox:28
unsigned int uInt
Definition: aipstype.h:48
unsigned short uShort
Definition: aipstype.h:46