2 // SPDX-License-Identifier: BSD-3-Clause
3 // Copyright Contributors to the OpenEXR Project.
8 #ifndef _PyImathFixedArray2D_h_
9 #define _PyImathFixedArray2D_h_
11 #define BOOST_BIND_GLOBAL_PLACEHOLDERS
12 #include <boost/python.hpp>
13 #include <boost/operators.hpp>
14 #include <boost/shared_array.hpp>
15 #include <boost/any.hpp>
18 #include "PyImathFixedArray.h"
19 #include "PyImathOperators.h"
27 IMATH_NAMESPACE::Vec2<size_t> _length;
28 IMATH_NAMESPACE::Vec2<size_t> _stride;
29 size_t _size; //flattened size of the array
31 // this handle optionally stores a shared_array to allocated array data
32 // so that everything is freed properly on exit.
37 FixedArray2D(T *ptr, Py_ssize_t lengthX, Py_ssize_t lengthY, Py_ssize_t strideX = 1)
38 : _ptr(ptr), _length(lengthX, lengthY), _stride(strideX, lengthX), _handle()
40 if (lengthX < 0 || lengthY < 0)
41 throw std::domain_error("Fixed array 2d lengths must be non-negative");
43 throw std::domain_error("Fixed array 2d strides must be positive");
45 //std::cout << "fixed array external construct" << std::endl;
49 FixedArray2D(T *ptr, Py_ssize_t lengthX, Py_ssize_t lengthY, Py_ssize_t strideX, Py_ssize_t strideY)
50 : _ptr(ptr), _length(lengthX, lengthY), _stride(strideX, strideY), _handle()
52 if (lengthX < 0 || lengthY < 0)
53 throw std::domain_error("Fixed array 2d lengths must be non-negative");
54 if (strideX <= 0 || strideY < 0)
55 throw std::domain_error("Fixed array 2d strides must be positive");
57 //std::cout << "fixed array external construct" << std::endl;
61 FixedArray2D(T *ptr, Py_ssize_t lengthX, Py_ssize_t lengthY, Py_ssize_t strideX, Py_ssize_t strideY, boost::any handle)
62 : _ptr(ptr), _length(lengthX, lengthY), _stride(strideX, strideY), _handle(handle)
65 //std::cout << "fixed array external construct with handle" << std::endl;
69 explicit FixedArray2D(Py_ssize_t lengthX, Py_ssize_t lengthY)
70 : _ptr(0), _length(lengthX, lengthY), _stride(1, lengthX), _handle()
72 if (lengthX < 0 || lengthY < 0)
73 throw std::domain_error("Fixed array 2d lengths must be non-negative");
75 T tmp = FixedArrayDefaultValue<T>::value();
76 boost::shared_array<T> a(new T[_size]);
77 for (size_t i=0; i<_size; ++i) a[i] = tmp;
82 explicit FixedArray2D(const IMATH_NAMESPACE::V2i& length)
83 : _ptr(0), _length(length), _stride(1, length.x), _handle()
85 if (length.x < 0 || length.y < 0)
86 throw std::domain_error("Fixed array 2d lengths must be non-negative");
88 T tmp = FixedArrayDefaultValue<T>::value();
89 boost::shared_array<T> a(new T[_size]);
90 for (size_t i=0; i<_size; ++i) a[i] = tmp;
95 FixedArray2D(const T &initialValue, Py_ssize_t lengthX, Py_ssize_t lengthY)
96 : _ptr(0), _length(lengthX, lengthY), _stride(1, lengthX), _handle()
98 if (lengthX < 0 || lengthY < 0)
99 throw std::domain_error("Fixed array 2d lengths must be non-negative");
101 boost::shared_array<T> a(new T[_size]);
102 for (size_t i=0; i<_size; ++i) a[i] = initialValue;
106 void initializeSize()
108 _size = _length.x*_length.y;
112 explicit FixedArray2D(const FixedArray2D<S> &other)
113 : _ptr(0), _length(other.len()), _stride(1, other.len().x), _handle()
116 boost::shared_array<T> a(new T[_size]);
118 for (size_t j = 0; j < _length.y; ++j)
119 for (size_t i = 0; i < _length.x; ++i)
120 a[z++] = T(other(i,j));
125 FixedArray2D(const FixedArray2D &other)
126 : _ptr(other._ptr), _length(other._length), _stride(other._stride), _size(other._size), _handle(other._handle)
128 //std::cout << "fixed array copy consturct construct" << std::endl;
133 operator = (const FixedArray2D &other)
135 if (&other == this) return *this;
137 //std::cout << "fixed array assign" << std::endl;
140 _length = other._length;
141 _stride = other._stride;
142 _handle = other._handle;
144 _size = _length.x*_length.y;
151 //std::cout << "fixed array delete" << std::endl;
154 const boost::any & handle() { return _handle; }
156 size_t canonical_index(Py_ssize_t index, size_t length) const
158 if (index < 0) index += length;
159 if ((size_t) index >= length || index < 0) {
160 PyErr_SetString(PyExc_IndexError, "Index out of range");
161 boost::python::throw_error_already_set();
166 void extract_slice_indices(PyObject *index, size_t length, size_t &start, size_t &end, Py_ssize_t &step, size_t &slicelength) const
168 if (PySlice_Check(index)) {
169 #if PY_MAJOR_VERSION > 2
170 PyObject *slice = index;
172 PySliceObject *slice = reinterpret_cast<PySliceObject *>(index);
175 if (PySlice_GetIndicesEx(slice,length,&s,&e,&step,&sl) == -1) {
176 boost::python::throw_error_already_set();
178 if (s < 0 || e < 0 || sl < 0) {
179 throw std::domain_error("Slice extraction produced invalid start, end, or length indices");
184 } else if (PyInt_Check(index)) {
185 size_t i = canonical_index(PyInt_AsSsize_t(index), length);
186 start = i; end = i+1; step = 1; slicelength = 1;
188 PyErr_SetString(PyExc_TypeError, "Object is not a slice");
189 boost::python::throw_error_already_set();
191 //std::cout << "Slice indices are " << start << " " << end << " " << step << " " << slicelength << std::endl;
194 // return_internal_reference doesn't seem to work with non-class types
195 typedef typename boost::mpl::if_<boost::is_class<T>,T&,T>::type get_type;
196 // get_type getitem(Py_ssize_t index) const { return _ptr[canonical_index(index)*_stride]; }
197 //FIXME: const does not work here with at least IMATH_NAMESPACE::Color4, why it works for V3fArray?
198 get_type getitem(Py_ssize_t i, Py_ssize_t j) //const
200 return (*this)(canonical_index(i, _length.x), canonical_index(j, _length.y));
203 //FIXME: anyway to seperate 2:3,4:5 from 2,4? we'd like to return int for the second one, and also 1d array for 2, 4:5 or 2:3, 4
204 FixedArray2D getslice(PyObject *index) const
206 if (PyTuple_Check(index) && PyTuple_Size(index) == 2)
208 size_t startx=0, endx=0, slicelengthx=0;
209 size_t starty=0, endy=0, slicelengthy=0;
212 extract_slice_indices(PyTuple_GetItem(index, 0),_length.x,startx,endx,stepx,slicelengthx);
213 extract_slice_indices(PyTuple_GetItem(index, 1),_length.y,starty,endy,stepy,slicelengthy);
214 FixedArray2D f(slicelengthx, slicelengthy);
215 for (size_t j=0,z=0; j<slicelengthy; j++)
216 for (size_t i=0; i<slicelengthx; ++i)
217 f._ptr[z++] = (*this)(startx+i*stepx, starty+j*stepy);
222 PyErr_SetString(PyExc_TypeError, "Slice syntax error");
223 boost::python::throw_error_already_set();
225 return FixedArray2D(0,0);
228 //FIXME: for 2D array, cannot reduce the size, or maybe returning 1D array?
229 FixedArray2D getslice_mask(const FixedArray2D<int> &mask) const
231 // size_t len = match_dimension(mask);
232 // size_t slicelength = 0;
233 // for (size_t i=0; i<len; ++i) if (mask[i]) slicelength++;
234 // FixedArray2D f(slicelength, _length.y);
235 // for (size_t i=0,z=0; i<len; ++i) {
237 // for (size_t j = 0; j < _length.y; j++)
238 // f._ptr[z++] = (*this)(i,j);
242 IMATH_NAMESPACE::Vec2<size_t> len = match_dimension(mask);
244 for (size_t j=0; j<len.y; j++)
245 for (size_t i=0; i<len.x; i++)
247 f(i,j) = (*this)(i,j);
251 // void setitem(const boost::python::tuple& index, const T &data)
253 // Py_ssize_t i = boost::python::extract<Py_ssize_t>(index[0]);
254 // Py_ssize_t j = boost::python::extract<Py_ssize_t>(index[1]);
255 // (*this)(i,j) = data;
258 setitem_scalar(PyObject *index, const T &data)
260 if (!PyTuple_Check(index) || PyTuple_Size(index) != 2)
262 PyErr_SetString(PyExc_TypeError, "Slice syntax error");
263 boost::python::throw_error_already_set();
266 size_t startx=0, endx=0, slicelengthx=0;
267 size_t starty=0, endy=0, slicelengthy=0;
270 extract_slice_indices(PyTuple_GetItem(index, 0),_length.x,startx,endx,stepx,slicelengthx);
271 extract_slice_indices(PyTuple_GetItem(index, 1),_length.y,starty,endy,stepy,slicelengthy);
272 for (size_t j=0; j<slicelengthy; j++)
273 for (size_t i=0; i<slicelengthx; ++i)
274 (*this)(startx+i*stepx, starty+j*stepy) = data;
278 setitem_scalar_mask(const FixedArray2D<int> &mask, const T &data)
280 IMATH_NAMESPACE::Vec2<size_t> len = match_dimension(mask);
281 for (size_t j = 0; j < len.y; j++)
282 for (size_t i=0; i<len.x; ++i)
288 setitem_vector(PyObject *index, const FixedArray2D &data)
291 size_t startx=0, endx=0, slicelengthx=0;
292 size_t starty=0, endy=0, slicelengthy=0;
295 extract_slice_indices(PyTuple_GetItem(index, 0),_length.x,startx,endx,stepx,slicelengthx);
296 extract_slice_indices(PyTuple_GetItem(index, 1),_length.y,starty,endy,stepy,slicelengthy);
297 // we have a valid range of indices
298 if (data.len() != IMATH_NAMESPACE::Vec2<size_t>(slicelengthx, slicelengthy)) {
299 PyErr_SetString(PyExc_IndexError, "Dimensions of source do not match destination");
300 boost::python::throw_error_already_set();
302 for (size_t i=0; i<slicelengthx; ++i)
303 for (size_t j=0; j<slicelengthy; ++j)
304 (*this)(startx+i*stepx, starty+j*stepy) = data(i,j);
308 setitem_vector_mask(const FixedArray2D<int> &mask, const FixedArray2D &data)
310 IMATH_NAMESPACE::Vec2<size_t> len = match_dimension(mask);
311 if (data.len() == len) {
312 for (size_t j = 0; j < len.y; j++)
313 for (size_t i=0; i<len.x; ++i)
315 (*this)(i,j) = data(i,j);
317 PyErr_SetString(PyExc_IndexError, "Dimensions of source data do not match destination");
318 boost::python::throw_error_already_set();
323 setitem_array1d_mask(const FixedArray2D<int> &mask, const FixedArray<T> &data)
325 IMATH_NAMESPACE::Vec2<size_t> len = match_dimension(mask);
326 if ((size_t) data.len() == len.x*len.y) {
327 for (size_t j = 0, z = 0; j < len.y; j++)
328 for (size_t i=0; i<len.x; ++i, ++z)
330 (*this)(i,j) = data[z];
333 for (size_t j = 0, z = 0; j < len.y; j++)
334 for (size_t i=0; i<len.x; ++i, ++z)
335 if (mask(i,j)) count++;
337 if ((size_t) data.len() != count) {
338 PyErr_SetString(PyExc_IndexError, "Dimensions of source data do not match destination either masked or unmasked");
339 boost::python::throw_error_already_set();
342 for (size_t j = 0, z = 0; j < len.y; j++)
343 for (size_t i=0; i<len.x; ++i)
345 (*this)(i,j) = data[z++];
350 setitem_array1d(PyObject *index, const FixedArray<T> &data)
353 size_t startx=0, endx=0, slicelengthx=0;
354 size_t starty=0, endy=0, slicelengthy=0;
357 extract_slice_indices(PyTuple_GetItem(index, 0),_length.x,startx,endx,stepx,slicelengthx);
358 extract_slice_indices(PyTuple_GetItem(index, 1),_length.y,starty,endy,stepy,slicelengthy);
359 // we have a valid range of indices
360 if ((size_t) data.len() != slicelengthx*slicelengthy) {
361 PyErr_SetString(PyExc_IndexError, "Dimensions of source data do not match destination");
362 boost::python::throw_error_already_set();
364 for (size_t j=0, z=0; j<slicelengthy; ++j)
365 for (size_t i=0; i<slicelengthx; ++i, ++z)
366 (*this)(startx+i*stepx, starty+j*stepy) = data[z];
369 IMATH_NAMESPACE::Vec2<size_t> len() const { return _length; }
370 IMATH_NAMESPACE::Vec2<size_t> stride() const { return _stride; }
371 T & operator () (size_t i, size_t j) { return _ptr[_stride.x*(j*_stride.y + i)]; }
372 const T & operator () (size_t i, size_t j) const { return _ptr[_stride.x*(j*_stride.y + i)]; }
373 size_t totalLen() const { return _size; }
374 boost::python::tuple size() const
376 return boost::python::make_tuple(_length.x, _length.y);
379 static boost::python::class_<FixedArray2D<T> > register_(const char *name, const char *doc)
381 // a little tricky, but here we go - class types return internal references
382 // but fundemental types just get copied. this typedef sets up the appropriate
383 // call policy for each type.
384 typedef typename boost::mpl::if_<
386 boost::python::return_internal_reference<>,
387 boost::python::default_call_policies>::type call_policy;
389 boost::python::class_<FixedArray2D<T> > c(name,doc, boost::python::init<size_t, size_t>(
390 "construct an array of the specified length initialized to the default value for the type"));
392 .def(boost::python::init<const FixedArray2D<T> &>("construct an array with the same values as the given array"))
393 .def(boost::python::init<const T &,size_t,size_t>("construct an array of the specified length initialized to the specified default value"))
394 .def("__getitem__", &FixedArray2D<T>::getslice)
395 .def("__getitem__", &FixedArray2D<T>::getslice_mask)
396 // .def("__getitem__", &FixedArray2D<T>::getitem, call_policy())
397 .def("item", &FixedArray2D<T>::getitem, call_policy())
398 // .def("__setitem__", &FixedArray2D<T>::setitem)
399 .def("__setitem__", &FixedArray2D<T>::setitem_scalar)
400 .def("__setitem__", &FixedArray2D<T>::setitem_scalar_mask)
401 .def("__setitem__", &FixedArray2D<T>::setitem_vector)
402 .def("__setitem__", &FixedArray2D<T>::setitem_vector_mask)
403 .def("__setitem__", &FixedArray2D<T>::setitem_array1d)
404 .def("__setitem__", &FixedArray2D<T>::setitem_array1d_mask)
405 .def("__len__",&FixedArray2D<T>::totalLen)
406 .def("size",&FixedArray2D<T>::size)
407 .def("ifelse",&FixedArray2D<T>::ifelse_scalar)
408 .def("ifelse",&FixedArray2D<T>::ifelse_vector)
413 // template <class T2>
414 // size_t match_dimension(const FixedArray<T2> &a1) const
416 // if (_length.x != a1.len()) {
417 // PyErr_SetString(PyExc_IndexError, "Dimensions of source do not match destination");
418 // boost::python::throw_error_already_set();
424 IMATH_NAMESPACE::Vec2<size_t> match_dimension(const FixedArray2D<T2> &a1) const
426 if (len() != a1.len()) {
427 PyErr_SetString(PyExc_IndexError, "Dimensions of source do not match destination");
428 boost::python::throw_error_already_set();
433 FixedArray2D<T> ifelse_vector(const FixedArray2D<int> &choice, const FixedArray2D<T> &other) {
434 IMATH_NAMESPACE::Vec2<size_t> len = match_dimension(choice);
435 match_dimension(other);
436 FixedArray2D<T> tmp(len); // should use default construction but V3f doens't initialize
437 for (size_t j = 0; j < len.y; ++j)
438 for (size_t i = 0; i < len.x; ++i)
439 tmp(i,j) = choice(i,j) ? (*this)(i,j) : other(i,j);
443 FixedArray2D<T> ifelse_scalar(const FixedArray2D<int> &choice, const T &other) {
444 IMATH_NAMESPACE::Vec2<size_t> len = match_dimension(choice);
445 FixedArray2D<T> tmp(len); // should use default construction but V3f doens't initialize
446 for (size_t j = 0; j < len.y; ++j)
447 for (size_t i = 0; i < len.x; ++i)
448 tmp(i,j) = choice(i,j) ? (*this)(i,j) : other;
454 // unary operation application
455 template <template <class,class> class Op, class T1, class Ret>
456 FixedArray2D<Ret> apply_array2d_unary_op(const FixedArray2D<T1> &a1)
458 IMATH_NAMESPACE::Vec2<size_t> len = a1.len();
459 FixedArray2D<Ret> retval(len.x,len.y);
460 for (size_t j=0; j<len.y; ++j) {
461 for (size_t i=0;i<len.x;++i) {
462 retval(i,j) = Op<T1,Ret>::apply(a1(i,j));
468 // binary operation application
469 template <template <class,class,class> class Op, class T1, class T2, class Ret>
470 FixedArray2D<Ret> apply_array2d_array2d_binary_op(const FixedArray2D<T1> &a1, const FixedArray2D<T2> &a2)
472 IMATH_NAMESPACE::Vec2<size_t> len = a1.match_dimension(a2);
473 FixedArray2D<Ret> retval(len.x,len.y);
474 for (size_t j=0; j<len.y; ++j) {
475 for (size_t i=0;i<len.x;++i) {
476 retval(i,j) = Op<T1,T2,Ret>::apply(a1(i,j),a2(i,j));
482 template <template <class,class,class> class Op, class T1, class T2, class Ret>
483 FixedArray2D<Ret> apply_array2d_scalar_binary_op(const FixedArray2D<T1> &a1, const T2 &a2)
485 IMATH_NAMESPACE::Vec2<size_t> len = a1.len();
486 FixedArray2D<Ret> retval(len.x,len.y);
487 for (size_t j=0; j<len.y; ++j) {
488 for (size_t i=0;i<len.x;++i) {
489 retval(i,j) = Op<T1,T2,Ret>::apply(a1(i,j),a2);
495 template <template <class,class,class> class Op, class T1, class T2, class Ret>
496 FixedArray2D<Ret> apply_array2d_scalar_binary_rop(const FixedArray2D<T1> &a1, const T2 &a2)
498 IMATH_NAMESPACE::Vec2<size_t> len = a1.len();
499 FixedArray2D<Ret> retval(len.x,len.y);
500 for (size_t j=0; j<len.y; ++j) {
501 for (size_t i=0;i<len.x;++i) {
502 retval(i,j) = Op<T2,T1,Ret>::apply(a2,a1(i,j));
508 // in-place binary operation application
509 template <template <class,class> class Op, class T1, class T2>
510 FixedArray2D<T1> & apply_array2d_array2d_ibinary_op(FixedArray2D<T1> &a1, const FixedArray2D<T2> &a2)
512 IMATH_NAMESPACE::Vec2<size_t> len = a1.match_dimension(a2);
513 for (size_t j=0; j<len.y; ++j) {
514 for (size_t i=0;i<len.x;++i) {
515 Op<T1,T2>::apply(a1(i,j),a2(i,j));
521 // in-place binary operation application
522 template <template <class,class> class Op, class T1, class T2>
523 FixedArray2D<T1> & apply_array2d_scalar_ibinary_op(FixedArray2D<T1> &a1, const T2 &a2)
525 IMATH_NAMESPACE::Vec2<size_t> len = a1.len();
526 for (size_t j=0; j<len.y; ++j) {
527 for (size_t i=0;i<len.x;++i) {
528 Op<T1,T2>::apply(a1(i,j),a2);
535 // PyObject* PyNumber_Add( PyObject *o1, PyObject *o2)
536 template <class T> static FixedArray2D<T> operator + (const FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_binary_op<op_add,T,T,T>(a0,a1); }
537 template <class T> static FixedArray2D<T> operator + (const FixedArray2D<T> &a0, const T &v1) { return apply_array2d_scalar_binary_op<op_add,T,T,T>(a0,v1); }
538 template <class T> static FixedArray2D<T> operator + (const T &v1, const FixedArray2D<T> &a0) { return a0+v1; }
540 // PyObject* PyNumber_Subtract( PyObject *o1, PyObject *o2)
541 template <class T> static FixedArray2D<T> operator - (const FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_binary_op<op_sub,T,T,T>(a0,a1); }
542 template <class T> static FixedArray2D<T> operator - (const FixedArray2D<T> &a0, const T &v1) { return apply_array2d_scalar_binary_op<op_sub,T,T,T>(a0,v1); }
543 template <class T> static FixedArray2D<T> operator - (const T &v1, const FixedArray2D<T> &a0) { return apply_array2d_scalar_binary_op<op_rsub,T,T,T>(a0,v1); }
545 // PyObject* PyNumber_Multiply( PyObject *o1, PyObject *o2)
546 template <class T> static FixedArray2D<T> operator * (const FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_binary_op<op_mul,T,T,T>(a0,a1); }
547 template <class T> static FixedArray2D<T> operator * (const FixedArray2D<T> &a0, const T &v1) { return apply_array2d_scalar_binary_op<op_mul,T,T,T>(a0,v1); }
548 template <class T> static FixedArray2D<T> operator * (const T &v1, const FixedArray2D<T> &a0) { return a0*v1; }
550 // PyObject* PyNumber_Divide( PyObject *o1, PyObject *o2)
551 template <class T> static FixedArray2D<T> operator / (const FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_binary_op<op_div,T,T,T>(a0,a1); }
552 template <class T> static FixedArray2D<T> operator / (const FixedArray2D<T> &a0, const T &v1) { return apply_array2d_scalar_binary_op<op_div,T,T,T>(a0,v1); }
553 // no reversed scalar/array2d divide - no meaning
555 // PyObject* PyNumber_FloorDivide( PyObject *o1, PyObject *o2)
556 // PyObject* PyNumber_TrueDivide( PyObject *o1, PyObject *o2)
557 // PyObject* PyNumber_Remainder( PyObject *o1, PyObject *o2)
558 template <class T> static FixedArray2D<T> operator % (const FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_binary_op<op_mod,T,T,T>(a0,a1); }
559 template <class T> static FixedArray2D<T> operator % (const FixedArray2D<T> &a0, const T &v1) { return apply_array2d_scalar_binary_op<op_mod,T,T,T>(a0,v1); }
560 // no reversed scalar%array2d remainder - no meaning
562 // PyObject* PyNumber_Divmod( PyObject *o1, PyObject *o2)
564 // PyObject* PyNumber_Power( PyObject *o1, PyObject *o2, PyObject *o3)
565 template <class T> static FixedArray2D<T> pow_array2d_array2d (const FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_binary_op<op_pow,T,T,T>(a0,a1); }
566 template <class T> static FixedArray2D<T> pow_array2d_scalar (const FixedArray2D<T> &a0, const T &v1) { return apply_array2d_scalar_binary_op<op_pow,T,T,T>(a0,v1); }
567 // no reversed scalar/array2d pow - no meaning
569 // PyObject* PyNumber_Negative( PyObject *o)
570 template <class T> static FixedArray2D<T> operator - (const FixedArray2D<T> &a0) { return apply_array2d_unary_op<op_neg,T,T>(a0); }
572 // PyObject* PyNumber_Positive( PyObject *o)
574 // PyObject* PyNumber_Absolute( PyObject *o)
575 template <class T> static FixedArray2D<T> abs (const FixedArray2D<T> &a0) { return apply_array2d_unary_op<op_abs,T,T>(a0); }
577 // PyObject* PyNumber_Invert( PyObject *o)
578 template <class T> static FixedArray2D<T> operator ~ (const FixedArray2D<T> &a0) { return apply_array2d_unary_op<op_inverse,T,T>(a0); }
580 // PyObject* PyNumber_Lshift( PyObject *o1, PyObject *o2)
581 template <class T> static FixedArray2D<T> operator << (const FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_binary_op<op_lshift,T,T,T>(a0,a1); }
582 template <class T> static FixedArray2D<T> operator << (const FixedArray2D<T> &a0, const T &v1) { return apply_array2d_scalar_binary_op<op_lshift,T,T,T>(a0,v1); }
585 // PyObject* PyNumber_Rshift( PyObject *o1, PyObject *o2)
586 template <class T> static FixedArray2D<T> operator >> (const FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_binary_op<op_rshift,T,T,T>(a0,a1); }
587 template <class T> static FixedArray2D<T> operator >> (const FixedArray2D<T> &a0, const T &v1) { return apply_array2d_scalar_binary_op<op_rshift,T,T,T>(a0,v1); }
590 // PyObject* PyNumber_And( PyObject *o1, PyObject *o2)
591 template <class T> static FixedArray2D<T> operator & (const FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_binary_op<op_bitand,T,T,T>(a0,a1); }
592 template <class T> static FixedArray2D<T> operator & (const FixedArray2D<T> &a0, const T &v1) { return apply_array2d_scalar_binary_op<op_bitand,T,T,T>(a0,v1); }
593 template <class T> static FixedArray2D<T> operator & (const T &v1, const FixedArray2D<T> &a0) { return a0&v1; }
595 // PyObject* PyNumber_Xor( PyObject *o1, PyObject *o2)
596 template <class T> static FixedArray2D<T> operator ^ (const FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_binary_op<op_xor,T,T,T>(a0,a1); }
597 template <class T> static FixedArray2D<T> operator ^ (const FixedArray2D<T> &a0, const T &v1) { return apply_array2d_scalar_binary_op<op_xor,T,T,T>(a0,v1); }
598 template <class T> static FixedArray2D<T> operator ^ (const T &v1, const FixedArray2D<T> &a0) { return a0^v1; }
600 // PyObject* PyNumber_Or( PyObject *o1, PyObject *o2)
601 template <class T> static FixedArray2D<T> operator | (const FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_binary_op<op_bitor,T,T,T>(a0,a1); }
602 template <class T> static FixedArray2D<T> operator | (const FixedArray2D<T> &a0, const T &v1) { return apply_array2d_scalar_binary_op<op_bitor,T,T,T>(a0,v1); }
603 template <class T> static FixedArray2D<T> operator | (const T &v1, const FixedArray2D<T> &a0) { return a0|v1; }
606 // PyObject* PyNumber_InPlaceAdd( PyObject *o1, PyObject *o2)
607 template <class T> static FixedArray2D<T> & operator += (FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_ibinary_op<op_iadd,T,T>(a0,a1); }
608 template <class T> static FixedArray2D<T> & operator += (FixedArray2D<T> &a0, const T &v1) { return apply_array2d_scalar_ibinary_op<op_iadd,T,T>(a0,v1); }
610 // PyObject* PyNumber_InPlaceSubtract( PyObject *o1, PyObject *o2)
611 template <class T> static FixedArray2D<T> & operator -= (FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_ibinary_op<op_isub,T,T>(a0,a1); }
612 template <class T> static FixedArray2D<T> & operator -= (FixedArray2D<T> &a0, const T &v1) { return apply_array2d_scalar_ibinary_op<op_isub,T,T>(a0,v1); }
614 // PyObject* PyNumber_InPlaceMultiply( PyObject *o1, PyObject *o2)
615 template <class T> static FixedArray2D<T> & operator *= (FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_ibinary_op<op_imul,T,T>(a0,a1); }
616 template <class T> static FixedArray2D<T> & operator *= (FixedArray2D<T> &a0, const T &v1) { return apply_array2d_scalar_ibinary_op<op_imul,T,T>(a0,v1); }
618 // PyObject* PyNumber_InPlaceDivide( PyObject *o1, PyObject *o2)
619 template <class T> static FixedArray2D<T> & operator /= (FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_ibinary_op<op_idiv,T,T>(a0,a1); }
620 template <class T> static FixedArray2D<T> & operator /= (FixedArray2D<T> &a0, const T &v1) { return apply_array2d_scalar_ibinary_op<op_idiv,T,T>(a0,v1); }
622 // PyObject* PyNumber_InPlaceFloorDivide( PyObject *o1, PyObject *o2)
625 // PyObject* PyNumber_InPlaceTrueDivide( PyObject *o1, PyObject *o2)
628 // PyObject* PyNumber_InPlaceRemainder( PyObject *o1, PyObject *o2)
629 template <class T> static FixedArray2D<T> & operator %= (FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_ibinary_op<op_imod,T,T>(a0,a1); }
630 template <class T> static FixedArray2D<T> & operator %= (FixedArray2D<T> &a0, const T &v1) { return apply_array2d_scalar_ibinary_op<op_imod,T,T>(a0,v1); }
632 // PyObject* PyNumber_InPlacePower( PyObject *o1, PyObject *o2, PyObject *o3)
633 template <class T> static FixedArray2D<T> & ipow_array2d_array2d (FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_ibinary_op<op_ipow,T,T>(a0,a1); }
634 template <class T> static FixedArray2D<T> & ipow_array2d_scalar (FixedArray2D<T> &a0, const T &v1) { return apply_array2d_scalar_ibinary_op<op_ipow,T,T>(a0,v1); }
636 // PyObject* PyNumber_InPlaceLshift( PyObject *o1, PyObject *o2)
637 template <class T> static FixedArray2D<T> & operator <<= (FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_ibinary_op<op_ilshift,T,T>(a0,a1); }
638 template <class T> static FixedArray2D<T> & operator <<= (FixedArray2D<T> &a0, const T &v1) { return apply_array2d_scalar_ibinary_op<op_ilshift,T,T>(a0,v1); }
640 // PyObject* PyNumber_InPlaceRshift( PyObject *o1, PyObject *o2)
641 template <class T> static FixedArray2D<T> & operator >>= (FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_ibinary_op<op_irshift,T,T>(a0,a1); }
642 template <class T> static FixedArray2D<T> & operator >>= (FixedArray2D<T> &a0, const T &v1) { return apply_array2d_scalar_ibinary_op<op_irshift,T,T>(a0,v1); }
644 // PyObject* PyNumber_InPlaceAnd( PyObject *o1, PyObject *o2)
645 template <class T> static FixedArray2D<T> & operator &= (FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_ibinary_op<op_ibitand,T,T>(a0,a1); }
646 template <class T> static FixedArray2D<T> & operator &= (FixedArray2D<T> &a0, const T &v1) { return apply_array2d_scalar_ibinary_op<op_ibitand,T,T>(a0,v1); }
648 // PyObject* PyNumber_InPlaceXor( PyObject *o1, PyObject *o2)
649 template <class T> static FixedArray2D<T> & operator ^= (FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_ibinary_op<op_ixor,T,T>(a0,a1); }
650 template <class T> static FixedArray2D<T> & operator ^= (FixedArray2D<T> &a0, const T &v1) { return apply_array2d_scalar_ibinary_op<op_ixor,T,T>(a0,v1); }
652 // PyObject* PyNumber_InPlaceOr( PyObject *o1, PyObject *o2)
653 template <class T> static FixedArray2D<T> & operator |= (FixedArray2D<T> &a0, const FixedArray2D<T> &a1) { return apply_array2d_array2d_ibinary_op<op_ibitor,T,T>(a0,a1); }
654 template <class T> static FixedArray2D<T> & operator |= (FixedArray2D<T> &a0, const T &v1) { return apply_array2d_scalar_ibinary_op<op_ibitor,T,T>(a0,v1); }
657 static void add_arithmetic_math_functions(boost::python::class_<FixedArray2D<T> > &c) {
658 using namespace boost::python;
660 .def("__add__",&apply_array2d_array2d_binary_op<op_add,T,T,T>)
661 .def("__add__",&apply_array2d_scalar_binary_op<op_add,T,T,T>)
662 .def("__radd__",&apply_array2d_scalar_binary_rop<op_add,T,T,T>)
663 .def("__sub__",&apply_array2d_array2d_binary_op<op_sub,T,T,T>)
664 .def("__sub__",&apply_array2d_scalar_binary_op<op_sub,T,T,T>)
665 .def("__rsub__",&apply_array2d_scalar_binary_op<op_rsub,T,T,T>)
666 .def("__mul__",&apply_array2d_array2d_binary_op<op_mul,T,T,T>)
667 .def("__mul__",&apply_array2d_scalar_binary_op<op_mul,T,T,T>)
668 .def("__rmul__",&apply_array2d_scalar_binary_rop<op_mul,T,T,T>)
669 .def("__div__",&apply_array2d_array2d_binary_op<op_div,T,T,T>)
670 .def("__div__",&apply_array2d_scalar_binary_op<op_div,T,T,T>)
671 .def("__truediv__",&apply_array2d_array2d_binary_op<op_div,T,T,T>)
672 .def("__truediv__",&apply_array2d_scalar_binary_op<op_div,T,T,T>)
673 .def("__neg__",&apply_array2d_unary_op<op_neg,T,T>)
674 .def("__iadd__",&apply_array2d_array2d_ibinary_op<op_iadd,T,T>,return_internal_reference<>())
675 .def("__iadd__",&apply_array2d_scalar_ibinary_op<op_iadd,T,T>,return_internal_reference<>())
676 .def("__isub__",&apply_array2d_array2d_ibinary_op<op_isub,T,T>,return_internal_reference<>())
677 .def("__isub__",&apply_array2d_scalar_ibinary_op<op_isub,T,T>,return_internal_reference<>())
678 .def("__imul__",&apply_array2d_array2d_ibinary_op<op_imul,T,T>,return_internal_reference<>())
679 .def("__imul__",&apply_array2d_scalar_ibinary_op<op_imul,T,T>,return_internal_reference<>())
680 .def("__idiv__",&apply_array2d_array2d_ibinary_op<op_idiv,T,T>,return_internal_reference<>())
681 .def("__idiv__",&apply_array2d_scalar_ibinary_op<op_idiv,T,T>,return_internal_reference<>())
682 .def("__itruediv__",&apply_array2d_array2d_ibinary_op<op_idiv,T,T>,return_internal_reference<>())
683 .def("__itruediv__",&apply_array2d_scalar_ibinary_op<op_idiv,T,T>,return_internal_reference<>())
689 static void add_pow_math_functions(boost::python::class_<FixedArray2D<T> > &c) {
690 using namespace boost::python;
692 .def("__pow__",&apply_array2d_array2d_binary_op<op_pow,T,T,T>)
693 .def("__pow__",&apply_array2d_scalar_binary_op<op_pow,T,T,T>)
694 .def("__rpow__",&apply_array2d_scalar_binary_rop<op_rpow,T,T,T>)
695 .def("__ipow__",&apply_array2d_array2d_ibinary_op<op_ipow,T,T>,return_internal_reference<>())
696 .def("__ipow__",&apply_array2d_scalar_ibinary_op<op_ipow,T,T>,return_internal_reference<>())
701 static void add_mod_math_functions(boost::python::class_<FixedArray2D<T> > &c) {
702 using namespace boost::python;
704 .def("__mod__",&apply_array2d_array2d_binary_op<op_mod,T,T,T>)
705 .def("__mod__",&apply_array2d_scalar_binary_op<op_mod,T,T,T>)
706 .def("__imod__",&apply_array2d_array2d_ibinary_op<op_imod,T,T>,return_internal_reference<>())
707 .def("__imod__",&apply_array2d_scalar_ibinary_op<op_imod,T,T>,return_internal_reference<>())
712 static void add_shift_math_functions(boost::python::class_<FixedArray2D<T> > &c) {
713 using namespace boost::python;
715 .def("__lshift__",&apply_array2d_array2d_binary_op<op_lshift,T,T,T>)
716 .def("__lshift__",&apply_array2d_scalar_binary_op<op_lshift,T,T,T>)
717 .def("__ilshift__",&apply_array2d_array2d_ibinary_op<op_ilshift,T,T>,return_internal_reference<>())
718 .def("__ilshift__",&apply_array2d_scalar_ibinary_op<op_ilshift,T,T>,return_internal_reference<>())
719 .def("__rshift__",&apply_array2d_array2d_binary_op<op_rshift,T,T,T>)
720 .def("__rshift__",&apply_array2d_scalar_binary_op<op_rshift,T,T,T>)
721 .def("__irshift__",&apply_array2d_array2d_ibinary_op<op_irshift,T,T>,return_internal_reference<>())
722 .def("__irshift__",&apply_array2d_scalar_ibinary_op<op_irshift,T,T>,return_internal_reference<>())
727 static void add_bitwise_math_functions(boost::python::class_<FixedArray2D<T> > &c) {
728 using namespace boost::python;
730 .def("__and__",&apply_array2d_array2d_binary_op<op_bitand,T,T,T>)
731 .def("__and__",&apply_array2d_scalar_binary_op<op_bitand,T,T,T>)
732 .def("__iand__",&apply_array2d_array2d_ibinary_op<op_ibitand,T,T>,return_internal_reference<>())
733 .def("__iand__",&apply_array2d_scalar_ibinary_op<op_ibitand,T,T>,return_internal_reference<>())
734 .def("__or__",&apply_array2d_array2d_binary_op<op_bitor,T,T,T>)
735 .def("__or__",&apply_array2d_scalar_binary_op<op_bitor,T,T,T>)
736 .def("__ior__",&apply_array2d_array2d_ibinary_op<op_ibitor,T,T>,return_internal_reference<>())
737 .def("__ior__",&apply_array2d_scalar_ibinary_op<op_ibitor,T,T>,return_internal_reference<>())
738 .def("__xor__",&apply_array2d_array2d_binary_op<op_xor,T,T,T>)
739 .def("__xor__",&apply_array2d_scalar_binary_op<op_xor,T,T,T>)
740 .def("__ixor__",&apply_array2d_array2d_ibinary_op<op_ixor,T,T>,return_internal_reference<>())
741 .def("__ixor__",&apply_array2d_scalar_ibinary_op<op_ixor,T,T>,return_internal_reference<>())
746 static void add_comparison_functions(boost::python::class_<FixedArray2D<T> > &c) {
747 using namespace boost::python;
749 .def("__eq__",&apply_array2d_array2d_binary_op<op_eq,T,T,int>)
750 .def("__eq__",&apply_array2d_scalar_binary_op<op_eq,T,T,int>)
751 .def("__ne__",&apply_array2d_array2d_binary_op<op_ne,T,T,int>)
752 .def("__ne__",&apply_array2d_scalar_binary_op<op_ne,T,T,int>)
757 static void add_ordered_comparison_functions(boost::python::class_<FixedArray2D<T> > &c) {
758 using namespace boost::python;
760 .def("__lt__",&apply_array2d_array2d_binary_op<op_lt,T,T,int>)
761 .def("__lt__",&apply_array2d_scalar_binary_op<op_lt,T,T,int>)
762 .def("__gt__",&apply_array2d_array2d_binary_op<op_gt,T,T,int>)
763 .def("__gt__",&apply_array2d_scalar_binary_op<op_gt,T,T,int>)
764 .def("__le__",&apply_array2d_array2d_binary_op<op_le,T,T,int>)
765 .def("__le__",&apply_array2d_scalar_binary_op<op_le,T,T,int>)
766 .def("__ge__",&apply_array2d_array2d_binary_op<op_ge,T,T,int>)
767 .def("__ge__",&apply_array2d_scalar_binary_op<op_ge,T,T,int>)
771 template <class S,class T>
772 static void add_explicit_construction_from_type(boost::python::class_<FixedArray2D<T> > &c) {
773 using namespace boost::python;
774 c.def(boost::python::init<FixedArray2D<S> >("copy contents of other array into this one"));