HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PyImathFixedArray.h
Go to the documentation of this file.
1 //
2 // SPDX-License-Identifier: BSD-3-Clause
3 // Copyright Contributors to the OpenEXR Project.
4 //
5 
6 // clang-format off
7 
8 #ifndef _PyImathFixedArray_h_
9 #define _PyImathFixedArray_h_
10 
11 #define HBOOST_BIND_GLOBAL_PLACEHOLDERS
12 #include <hboost/python.hpp>
13 #include <hboost/operators.hpp>
14 #include <hboost/shared_array.hpp>
15 #include <hboost/any.hpp>
16 #include <iostream>
17 #include "PyImathUtil.h"
18 #include "ImathVec.h"
19 
20 //
21 // Note: when PyImath from the v2 release of OpenEXR depended on Iex,
22 // the PY_IMATH_LEAVE/RETURN_PYTHON macros bracketed calls that
23 // enabled/disabled float-point exceptions via via the MathExcOn
24 // class. This was a compile-time option based on the setting of
25 // PYIMATH_ENABLE_EXCEPTIONS. This behavior is now deprecated, hence
26 // the empty macros.
27 //
28 
29 #define PY_IMATH_LEAVE_PYTHON PyImath::PyReleaseLock pyunlock;
30 #define PY_IMATH_RETURN_PYTHON
31 
32 namespace PyImath {
33 
34 namespace {
35 
36 //
37 // Utility classes used for converting array members to hboost python objects.
38 //
39 
40 template <class T>
41 struct ReturnReference
42 {
43  static hboost::python::object applyReadOnly (const T& val)
44  {
46  return hboost::python::object(hboost::python::handle<>(converter(val)));
47  }
48 
49  static hboost::python::object applyWritable (T& val)
50  {
52  return hboost::python::object(hboost::python::handle<>(converter(val)));
53  }
54 
55  static bool isReferenceWrap () { return true; }
56 };
57 
58 template <class T>
59 struct ReturnByValue
60 {
61  static hboost::python::object applyReadOnly (const T& val)
62  {
64  return hboost::python::object(hboost::python::handle<>(converter(val)));
65  }
66 
67  static hboost::python::object applyWritable (T& val)
68  {
69  return applyReadOnly (val);
70  }
71 
72  static bool isReferenceWrap () { return false; }
73 };
74 
75 } // namespace
76 
77 //
78 // Utility class for a runtime-specified fixed length array type in python
79 //
80 template <class T>
82 {
83  static T value();
84 };
85 
87 
88 template <class T>
90 {
91  T * _ptr;
92  size_t _length;
93  size_t _stride;
94  bool _writable;
95 
96  // this handle optionally stores a shared_array to allocated array data
97  // so that everything is freed properly on exit.
98  hboost::any _handle;
99 
100  hboost::shared_array<size_t> _indices; // non-NULL iff I'm a masked reference
101  size_t _unmaskedLength;
102 
103 
104  public:
105  typedef T BaseType;
106 
107  FixedArray(T *ptr, Py_ssize_t length, Py_ssize_t stride = 1, bool writable = true)
108  : _ptr(ptr), _length(length), _stride(stride), _writable(writable),
109  _handle(), _unmaskedLength(0)
110  {
111  if (length < 0)
112  {
113  throw std::domain_error ("Fixed array length must be non-negative");
114  }
115  if (stride <= 0)
116  {
117  throw std::domain_error ("Fixed array stride must be positive");
118  }
119  // nothing
120  }
121 
122  FixedArray(T *ptr, Py_ssize_t length, Py_ssize_t stride,
123  hboost::any handle, bool writable = true)
124  : _ptr(ptr), _length(length), _stride(stride), _writable(writable),
125  _handle(handle), _unmaskedLength(0)
126  {
127  if (_length < 0)
128  {
129  throw std::domain_error("Fixed array length must be non-negative");
130  }
131  if (stride <= 0)
132  {
133  throw std::domain_error("Fixed array stride must be positive");
134  }
135  // nothing
136  }
137 
138  FixedArray(const T *ptr, Py_ssize_t length, Py_ssize_t stride = 1)
139  : _ptr(const_cast<T *>(ptr)), _length(length), _stride(stride),
140  _writable(false), _handle(), _unmaskedLength(0)
141  {
142  if (length < 0)
143  {
144  throw std::logic_error("Fixed array length must be non-negative");
145  }
146  if (stride <= 0)
147  {
148  throw std::logic_error("Fixed array stride must be positive");
149  }
150  // nothing
151  }
152 
153  FixedArray(const T *ptr, Py_ssize_t length, Py_ssize_t stride, hboost::any handle)
154  : _ptr(const_cast<T *>(ptr)), _length(length), _stride(stride), _writable(false),
155  _handle(handle), _unmaskedLength(0)
156  {
157  if (_length < 0)
158  {
159  throw std::logic_error("Fixed array length must be non-negative");
160  }
161  if (stride <= 0)
162  {
163  throw std::logic_error("Fixed array stride must be positive");
164  }
165  // nothing
166  }
167 
168  explicit FixedArray(Py_ssize_t length)
169  : _ptr(0), _length(length), _stride(1), _writable(true),
170  _handle(), _unmaskedLength(0)
171  {
172  if (_length < 0) {
173  throw std::domain_error("Fixed array length must be non-negative");
174  }
175  hboost::shared_array<T> a(new T[length]);
177  for (Py_ssize_t i=0; i<length; ++i) a[i] = tmp;
178  _handle = a;
179  _ptr = a.get();
180  }
181 
183  : _ptr(0), _length(length), _stride(1), _writable(true),
184  _handle(), _unmaskedLength(0)
185  {
186  if (_length < 0) {
187  throw std::domain_error("Fixed array length must be non-negative");
188  }
189  hboost::shared_array<T> a(new T[length]);
190  _handle = a;
191  _ptr = a.get();
192  }
193 
194  FixedArray(const T &initialValue, Py_ssize_t length)
195  : _ptr(0), _length(length), _stride(1), _writable(true),
196  _handle(), _unmaskedLength(0)
197  {
198  if (_length < 0) {
199  throw std::domain_error("Fixed array length must be non-negative");
200  }
201  hboost::shared_array<T> a(new T[length]);
202  for (Py_ssize_t i=0; i<length; ++i) a[i] = initialValue;
203  _handle = a;
204  _ptr = a.get();
205  }
206 
207  template <typename MaskArrayType>
208  FixedArray(FixedArray& f, const MaskArrayType& mask)
209  : _ptr(f._ptr), _stride(f._stride), _writable(f._writable), _handle(f._handle), _unmaskedLength(0)
210  {
211  if (f.isMaskedReference())
212  {
213  throw std::invalid_argument("Masking an already-masked FixedArray not supported yet (SQ27000)");
214  }
215 
216  size_t len = f.match_dimension(mask);
217  _unmaskedLength = len;
218 
219  size_t reduced_len = 0;
220  for (size_t i = 0; i < len; ++i)
221  if (mask[i])
222  reduced_len++;
223 
224  _indices.reset(new size_t[reduced_len]);
225 
226  for (size_t i = 0, j = 0; i < len; ++i)
227  {
228  if (mask[i])
229  {
230  _indices[j] = i;
231  j++;
232  }
233  }
234 
235  _length = reduced_len;
236  }
237 
238  template <typename MaskArrayType>
239  FixedArray(const FixedArray& f, const MaskArrayType& mask)
240  : _ptr(f._ptr), _stride(f._stride), _writable(false), _handle(f._handle), _unmaskedLength(0)
241  {
242  if (f.isMaskedReference())
243  {
244  throw std::invalid_argument("Masking an already-masked FixedArray not supported yet (SQ27000)");
245  }
246 
247  size_t len = f.match_dimension(mask);
248  _unmaskedLength = len;
249 
250  size_t reduced_len = 0;
251  for (size_t i = 0; i < len; ++i)
252  if (mask[i])
253  reduced_len++;
254 
255  _indices.reset(new size_t[reduced_len]);
256 
257  for (size_t i = 0, j = 0; i < len; ++i)
258  {
259  if (mask[i])
260  {
261  _indices[j] = i;
262  j++;
263  }
264  }
265 
266  _length = reduced_len;
267  }
268 
269  template <class S>
270  explicit FixedArray(const FixedArray<S> &other)
271  : _ptr(0), _length(other.len()), _stride(1), _writable(true),
272  _handle(), _unmaskedLength(other.unmaskedLength())
273  {
274  hboost::shared_array<T> a(new T[_length]);
275  for (size_t i=0; i<_length; ++i) a[i] = T(other[i]);
276  _handle = a;
277  _ptr = a.get();
278 
279  if (_unmaskedLength)
280  {
281  _indices.reset(new size_t[_length]);
282 
283  for (size_t i = 0; i < _length; ++i)
284  _indices[i] = other.raw_ptr_index(i);
285  }
286  }
287 
288  FixedArray(const FixedArray &other)
289  : _ptr(other._ptr), _length(other._length), _stride(other._stride),
290  _writable(other._writable),
291  _handle(other._handle),
292  _indices(other._indices),
293  _unmaskedLength(other._unmaskedLength)
294  {
295  }
296 
297  const FixedArray &
298  operator = (const FixedArray &other)
299  {
300  if (&other == this) return *this;
301 
302  _ptr = other._ptr;
303  _length = other._length;
304  _stride = other._stride;
305  _writable = other._writable;
306  _handle = other._handle;
307  _unmaskedLength = other._unmaskedLength;
308  _indices = other._indices;
309 
310  return *this;
311  }
312 
314  {
315  // nothing
316  }
317 
318  explicit operator bool() const {return _ptr != nullptr;}
319 
320  const hboost::any & handle() { return _handle; }
321 
322  //
323  // Make an index suitable for indexing into an array in c++ from
324  // a python index, which can be negative for indexing relative to
325  // the end of an array
326  //
327  size_t canonical_index(Py_ssize_t index) const
328  {
329  if (index < 0) index += len();
330  if (index >= len() || index < 0) {
331  PyErr_SetString(PyExc_IndexError, "Index out of range");
332  hboost::python::throw_error_already_set();
333  }
334  return index; // still a virtual index if this is a masked reference array
335  }
336 
337  void extract_slice_indices(PyObject *index, size_t &start, size_t &end, Py_ssize_t &step, size_t &slicelength) const
338  {
339  if (PySlice_Check(index)) {
340 #if PY_MAJOR_VERSION > 2
341  PyObject *slice = index;
342 #else
343  PySliceObject *slice = reinterpret_cast<PySliceObject *>(index);
344 #endif
345  Py_ssize_t s,e,sl;
346  if (PySlice_GetIndicesEx(slice,_length,&s,&e,&step,&sl) == -1) {
347  hboost::python::throw_error_already_set();
348  }
349  // e can be -1 if the iteration is backwards with a negative slice operator [::-n] (n > 0).
350  if (s < 0 || e < -1 || sl < 0) {
351  throw std::domain_error("Slice extraction produced invalid start, end, or length indices");
352  }
353  start = s;
354  end = e;
355  slicelength = sl;
356  } else if (PyInt_Check(index)) {
357  size_t i = canonical_index(PyInt_AsSsize_t(index));
358  start = i; end = i+1; step = 1; slicelength = 1;
359  } else {
360  PyErr_SetString(PyExc_TypeError, "Object is not a slice");
361  hboost::python::throw_error_already_set();
362  }
363  }
364 
365  // Although this method isn't used directly by this class,
366  // there are some sub-classes that are using it.
367  typedef typename hboost::mpl::if_<hboost::is_class<T>, T&,T>::type get_type;
368  get_type getitem(Py_ssize_t index) { return (*this)[canonical_index(index)]; }
369  typedef typename hboost::mpl::if_<hboost::is_class<T>,const T&,T>::type get_type_const;
370  get_type_const getitem(Py_ssize_t index) const { return (*this)[canonical_index(index)]; }
371 
372  // We return an internal reference for class-types and a copy of the data
373  // for non-class types. Returning an internal refeference doesn't seem
374  // to work with non-class types.
375 
377  {
378  typedef typename hboost::mpl::if_<hboost::is_class<T>,
379  ReturnReference<T>,
380  ReturnByValue<T> >::type convertType;
381 
382  hboost::python::object retval;
383  int referenceMode = 0;
384 
385  const size_t i = canonical_index(index);
386  T& val = _ptr[(isMaskedReference() ? raw_ptr_index(i) : i) * _stride];
387 
388  if (_writable)
389  {
390  retval = convertType::applyWritable (val);
391 
392  if (convertType::isReferenceWrap())
393  referenceMode = 0; // Managed reference.
394  else
395  referenceMode = 2; // Default policy (return-by-value)
396  }
397  else
398  {
399  retval = convertType::applyReadOnly (val);
400 
401  if (convertType::isReferenceWrap())
402  referenceMode = 1; // Copy const reference
403  else
404  referenceMode = 2; // Default policy (return-by-value)
405  }
406 
407  return hboost::python::make_tuple (referenceMode, retval);
408  }
409 
411  {
412  typedef typename hboost::mpl::if_<hboost::is_class<T>,
413  ReturnReference<T>,
414  ReturnByValue<T> >::type convertType;
415 
416  hboost::python::object retval;
417  int referenceMode = 1;
418 
419  const size_t i = canonical_index(index);
420  const T& val = _ptr[(isMaskedReference() ? raw_ptr_index(i) : i) * _stride];
421 
422  retval = convertType::applyReadOnly (val);
423 
424  if (convertType::isReferenceWrap())
425  referenceMode = 1; // Copy const reference
426  else
427  referenceMode = 2; // Default policy (return-by-value)
428 
429  return hboost::python::make_tuple (referenceMode, retval);
430  }
431 
432  FixedArray getslice(::PyObject *index) const
433  {
434  size_t start=0, end=0, slicelength=0;
435  Py_ssize_t step;
436  extract_slice_indices(index,start,end,step,slicelength);
437  FixedArray f(slicelength);
438 
439  if (isMaskedReference())
440  {
441  for (size_t i=0; i<slicelength; ++i)
442  f._ptr[i] = _ptr[raw_ptr_index(start+i*step)*_stride];
443  }
444  else
445  {
446  for (size_t i=0; i<slicelength; ++i)
447  f._ptr[i] = _ptr[(start+i*step)*_stride];
448  }
449  return f;
450  }
451 
452  template <typename MaskArrayType>
453  FixedArray getslice_mask(const MaskArrayType& mask)
454  {
455  // 'writable' state is preserved in the returned fixed-array.
456  FixedArray f(*this, mask);
457  return f;
458  }
459 
460  void
461  setitem_scalar(PyObject *index, const T &data)
462  {
463  if (!_writable)
464  throw std::invalid_argument("Fixed array is read-only.");
465 
466  size_t start=0, end=0, slicelength=0;
467  Py_ssize_t step;
468  extract_slice_indices(index,start,end,step,slicelength);
469 
470  if (isMaskedReference())
471  {
472  for (size_t i=0; i<slicelength; ++i)
473  _ptr[raw_ptr_index(start+i*step)*_stride] = data;
474  }
475  else
476  {
477  for (size_t i=0; i<slicelength; ++i)
478  _ptr[(start+i*step)*_stride] = data;
479  }
480  }
481 
482  template <typename MaskArrayType>
483  void
484  setitem_scalar_mask(const MaskArrayType &mask, const T &data)
485  {
486  if (!_writable)
487  throw std::invalid_argument("Fixed array is read-only.");
488 
489  size_t len = match_dimension(mask, false);
490 
491  if (isMaskedReference())
492  {
493  for (size_t i = 0; i < len; ++i)
494  _ptr[raw_ptr_index(i)*_stride] = data;
495  }
496  else
497  {
498  for (size_t i=0; i<len; ++i)
499  if (mask[i]) _ptr[i*_stride] = data;
500  }
501  }
502 
503  template <typename ArrayType>
504  void
505  setitem_vector(::PyObject *index, const ArrayType &data)
506  {
507  if (!_writable)
508  throw std::invalid_argument("Fixed array is read-only.");
509 
510  size_t start=0, end=0, slicelength=0;
511  Py_ssize_t step;
512  extract_slice_indices(index,start,end,step,slicelength);
513 
514  // we have a valid range of indices
515  if ((size_t)data.len() != slicelength) {
516  PyErr_SetString(PyExc_IndexError, "Dimensions of source do not match destination");
517  hboost::python::throw_error_already_set();
518  }
519 
520  if (isMaskedReference())
521  {
522  for (size_t i=0; i<slicelength; ++i)
523  _ptr[raw_ptr_index(start+i*step)*_stride] = data[i];
524  }
525  else
526  {
527  for (size_t i=0; i<slicelength; ++i)
528  _ptr[(start+i*step)*_stride] = data[i];
529  }
530  }
531 
532  template <typename MaskArrayType, typename ArrayType>
533  void
534  setitem_vector_mask(const MaskArrayType &mask, const ArrayType &data)
535  {
536  if (!_writable)
537  throw std::invalid_argument("Fixed array is read-only.");
538 
539  // We could relax this but this restriction if there's a good
540  // enough reason too.
541 
542  if (isMaskedReference())
543  {
544  throw std::invalid_argument("We don't support setting item masks for masked reference arrays.");
545  }
546 
547  size_t len = match_dimension(mask);
548  if ((size_t)data.len() == len)
549  {
550  for (size_t i = 0; i < len; ++i)
551  if (mask[i]) _ptr[i*_stride] = data[i];
552  }
553  else
554  {
555  Py_ssize_t count = 0;
556  for (size_t i = 0; i < len; ++i)
557  if (mask[i]) count++;
558 
559  if (data.len() != count) {
560  throw std::invalid_argument("Dimensions of source data do not match destination either masked or unmasked");
561  }
562 
563  Py_ssize_t dataIndex = 0;
564  for (size_t i = 0; i < len; ++i)
565  {
566  if (mask[i])
567  {
568  _ptr[i*_stride] = data[dataIndex];
569  dataIndex++;
570  }
571  }
572  }
573  }
574 
575  // exposed as Py_ssize_t for compatilbity with standard python sequences
576  Py_ssize_t len() const { return _length; }
577  size_t stride() const { return _stride; }
578  bool writable() const { return _writable; }
579 
580  // This method is mainly here for use in confidence tests, but there may
581  // be other use-cases where a writable array needs to be made read-only.
582  // Note that we do not provide a 'makeWritable' method here, because that
583  // type of operation shouldn't be allowed.
584  void makeReadOnly() { _writable = false; }
585 
586  // no bounds checking on i!
587  T& operator [] (size_t i)
588  {
589  if (!_writable)
590  throw std::invalid_argument("Fixed array is read-only.");
591 
592  return _ptr[(isMaskedReference() ? raw_ptr_index(i) : i) * _stride];
593  }
594 
595  // no bounds checking on i!
596  const T& operator [] (size_t i) const
597  {
598  return _ptr[(isMaskedReference() ? raw_ptr_index(i) : i) * _stride];
599  }
600 
601  // no mask conversion or bounds checking on i!
602  T& direct_index(size_t i)
603  {
604  if (!_writable)
605  throw std::invalid_argument("Fixed array is read-only.");
606 
607  return _ptr[i*_stride];
608  }
609 
610  // no mask conversion or bounds checking on i!
611  const T& direct_index (size_t i) const
612  {
613  return _ptr[i*_stride];
614  }
615 
616  // In some cases, an access to the raw data without the 'writable' check
617  // is needed. Generally in specialized python-wrapping helpers.
618  T& unchecked_index (size_t i)
619  {
620  return _ptr[(isMaskedReference() ? raw_ptr_index(i) : i) * _stride];
621  }
622 
624  {
625  return _ptr[i*_stride];
626  }
627 
628  bool isMaskedReference() const {return _indices.get() != 0;}
629  size_t unmaskedLength() const {return _unmaskedLength;}
630 
631  // Conversion of indices to raw pointer indices.
632  // This should only be called when this is a masked reference.
633  // No safety checks done for performance.
634  size_t raw_ptr_index(size_t i) const
635  {
636  assert(isMaskedReference());
637  assert(i < _length);
638  assert(_indices[i] >= 0 && _indices[i] < _unmaskedLength);
639  return _indices[i];
640  }
641 
642  static hboost::python::class_<FixedArray<T> > register_(const char *doc)
643  {
644  // Depending on the data-type (class or fundamental) and the writable
645  // state of the array, different forms are returned by the '__getitem__'
646  // method. If writable and a class, an internal reference to the data
647  // is returned so that its value can be changed. If not-writable or a
648  // fundemental data type (float, int, etc.), then a 'copy' of the data
649  // is returned.
650 
651  typename hboost::python::object (FixedArray<T>::*nonconst_getobject)(Py_ssize_t) =
653  typename hboost::python::object (FixedArray<T>:: *const_getobject)(Py_ssize_t) const =
655 
656  hboost::python::class_<FixedArray<T> > c(name(),doc, hboost::python::init<size_t>("construct an array of the specified length initialized to the default value for the type"));
657  c
658  .def(hboost::python::init<const FixedArray<T> &>("construct an array with the same values as the given array"))
659  .def(hboost::python::init<const T &,size_t>("construct an array of the specified length initialized to the specified default value"))
660  .def("__getitem__", &FixedArray<T>::getslice)
661  .def("__getitem__", &FixedArray<T>::getslice_mask<FixedArray<int> > )
662  .def("__getitem__", const_getobject,
664  hboost::python::with_custodian_and_ward_postcall<0,1>,
665  hboost::python::return_value_policy<hboost::python::copy_const_reference>,
666  hboost::python::default_call_policies>())
667  .def("__getitem__", nonconst_getobject,
669  hboost::python::with_custodian_and_ward_postcall<0,1>,
670  hboost::python::return_value_policy<hboost::python::copy_const_reference>,
671  hboost::python::default_call_policies>())
672  .def("__setitem__", &FixedArray<T>::setitem_scalar)
674  .def("__setitem__", &FixedArray<T>::setitem_vector<FixedArray<T> >)
676  .def("__len__",&FixedArray<T>::len)
677  .def("writable",&FixedArray<T>::writable)
678  .def("makeReadOnly", &FixedArray<T>::makeReadOnly)
679  .def("ifelse",&FixedArray<T>::ifelse_scalar)
680  .def("ifelse",&FixedArray<T>::ifelse_vector)
681  ;
682  return c;
683  }
684 
685  template <typename ArrayType>
686  size_t match_dimension(const ArrayType &a1, bool strictComparison = true) const
687  {
688  if (len() == a1.len())
689  return len();
690 
691  bool throwExc = false;
692  if (strictComparison)
693  throwExc = true;
694  else if (isMaskedReference())
695  {
696  if (static_cast<Py_ssize_t>(_unmaskedLength) != a1.len())
697  throwExc = true;
698  }
699  else
700  throwExc = true;
701 
702  if (throwExc)
703  {
704  throw std::invalid_argument("Dimensions of source do not match destination");
705  }
706 
707  return len();
708  }
709 
711  size_t len = match_dimension(choice);
712  match_dimension(other);
713  FixedArray<T> tmp(len); // should use default construction but V3f doens't initialize
714  for (size_t i=0; i < len; ++i) tmp[i] = choice[i] ? (*this)[i] : other[i];
715  return tmp;
716  }
717 
718  FixedArray<T> ifelse_scalar(const FixedArray<int> &choice, const T &other) {
719  size_t len = match_dimension(choice);
720  FixedArray<T> tmp(len); // should use default construction but V3f doens't initialize
721  for (size_t i=0; i < len; ++i) tmp[i] = choice[i] ? (*this)[i] : other;
722  return tmp;
723  }
724 
725  // Instantiations of fixed ararys must implement this static member
726  static const char *name();
727 
728  // Various 'Accessor' classes used in performance-critical areas while also
729  // managing the writable/read-only state efficiently.
730 
732  {
733  public:
735  : _ptr (array._ptr), _stride (array._stride)
736  {
737  if (array.isMaskedReference())
738  throw std::invalid_argument ("Fixed array is masked. ReadOnlyDirectAccess not granted.");
739  }
740 
742  : _ptr (other._ptr), _stride (other._stride) {}
743 
744  const T& operator[] (size_t i) const { return _ptr[i*_stride]; }
745 
746  private:
747  const T* _ptr;
748 
749  protected:
750  const size_t _stride;
751  };
752 
754  {
755  public:
757  : ReadOnlyDirectAccess (array), _ptr (array._ptr)
758  {
759  if (!array.writable())
760  throw std::invalid_argument ("Fixed array is read-only. WritableDirectAccess not granted.");
761  }
762 
764  : ReadOnlyDirectAccess (other), _ptr (other._ptr) {}
765 
766  T& operator[] (size_t i) { return _ptr[i*_stride]; }
767 
768  private:
769  T* _ptr;
770 
772  };
773 
774  //
775 
777  {
778  public:
780  : _ptr (array._ptr), _stride (array._stride),
781  _indices (array._indices)
782  {
783  if (!array.isMaskedReference())
784  throw std::invalid_argument ("Fixed array is not masked. ReadOnlyMaskedAccess not granted.");
785  }
786 
788  : _ptr (other._ptr), _stride (other._stride),
789  _indices (other._indices) {}
790 
791  // No index-range check here.
792  const T& operator[] (size_t i) const { return _ptr[_indices[i]*_stride]; }
793 
794  private:
795  const T* _ptr;
796 
797  protected:
798  const size_t _stride;
799  hboost::shared_array<size_t> _indices;
800  };
801 
803  {
804  public:
806  : ReadOnlyMaskedAccess (array), _ptr (array._ptr)
807  {
808  if (!array.writable())
809  std::invalid_argument ("Fixed array is read-only. WritableMaskedAccess not granted.");
810  }
811 
813  : ReadOnlyMaskedAccess (other), _ptr (other._ptr) {}
814 
815  // No index-range check here.
816  T& operator[] (size_t i) { return _ptr[_indices[i]*_stride]; }
817 
818  private:
819  T* _ptr;
820 
823  };
824 
825 };
826 
827 //
828 // Helper struct for arary indexing with a known compile time length
829 //
830 template <class Container, class Data>
832  typedef Data & result_type;
833  static Data & apply(Container &c, size_t i) { return c[i]; }
834 };
835 
836 template <class Data>
838  using Container = IMATH_INTERNAL_NAMESPACE::Vec2<Data>;
839  typedef Data & result_type;
840  static Data & apply(Container &c, size_t i) { return *(c.getValue () + i); }
841 };
842 
843 template <class Data>
845  using Container = IMATH_INTERNAL_NAMESPACE::Vec3<Data>;
846  typedef Data & result_type;
847  static Data & apply(Container &c, size_t i) { return *(c.getValue () + i); }
848 };
849 
850 template <class Data>
852  using Container = IMATH_INTERNAL_NAMESPACE::Vec4<Data>;
853  typedef Data & result_type;
854  static Data & apply(Container &c, size_t i) { return *(c.getValue () + i); }
855 };
856 
857 template <class Container, class Data, int Length, class IndexAccess = IndexAccessDefault<Container,Data> >
859 {
860  static Py_ssize_t len(const Container &) { return Length; }
861  static typename IndexAccess::result_type getitem(Container &c, Py_ssize_t index) { return IndexAccess::apply(c,canonical_index(index)); }
862  static void setitem(Container &c, Py_ssize_t index, const Data &data) { IndexAccess::apply(c,canonical_index(index)) = data; }
863  static size_t canonical_index(Py_ssize_t index)
864  {
865  if (index < 0) index += Length;
866  if (index < 0 || index >= Length) {
867  PyErr_SetString(PyExc_IndexError, "Index out of range");
868  hboost::python::throw_error_already_set();
869  }
870  return index;
871  }
872 };
873 
874 }
875 
876 #endif // _PyImathFixedArray_h_
FixedArray(const T *ptr, Py_ssize_t length, Py_ssize_t stride, hboost::any handle)
type
Definition: core.h:556
void setitem_vector_mask(const MaskArrayType &mask, const ArrayType &data)
size_t match_dimension(const ArrayType &a1, bool strictComparison=true) const
bool isMaskedReference() const
ReadOnlyDirectAccess(const FixedArray< T > &array)
get_type getitem(Py_ssize_t index)
FixedArray(const FixedArray< S > &other)
Py_ssize_t len() const
#define IMATH_INTERNAL_NAMESPACE
Definition: ImathConfig.h:39
static hboost::python::class_< FixedArray< T > > register_(const char *doc)
FixedArray< T > ifelse_scalar(const FixedArray< int > &choice, const T &other)
Definition: ImathVec.h:40
FixedArray(const T &initialValue, Py_ssize_t length)
FixedArray(const FixedArray &other)
GLboolean * data
Definition: glcorearb.h:131
static Data & apply(Container &c, size_t i)
GLuint start
Definition: glcorearb.h:475
FixedArray(const FixedArray &f, const MaskArrayType &mask)
hboost::mpl::if_< hboost::is_class< T >, const T &, T >::type get_type_const
GLboolean GLboolean GLboolean GLboolean a
Definition: glcorearb.h:1222
GLdouble s
Definition: glad.h:3009
GLuint GLsizei GLsizei * length
Definition: glcorearb.h:795
WritableDirectAccess(const WritableDirectAccess &other)
WritableMaskedAccess(const WritableMaskedAccess &other)
static const char * name()
OutGridT const XformOp bool bool
size_t raw_ptr_index(size_t i) const
const T & direct_index(size_t i) const
ReadOnlyDirectAccess(const ReadOnlyDirectAccess &other)
T & direct_index(size_t i)
hboost::shared_array< size_t > _indices
hboost::mpl::if_< hboost::is_class< T >, T &, T >::type get_type
FixedArray(const T *ptr, Py_ssize_t length, Py_ssize_t stride=1)
GLfloat f
Definition: glcorearb.h:1926
GLint GLint GLsizei GLint GLenum GLenum type
Definition: glcorearb.h:108
void setitem_vector(::PyObject *index, const ArrayType &data)
bool any(const vbool4 &v)
Definition: simd.h:3600
size_t canonical_index(Py_ssize_t index) const
FixedArray(Py_ssize_t length, Uninitialized)
FixedArray(Py_ssize_t length)
const hboost::any & handle()
GLuint GLuint end
Definition: glcorearb.h:475
GLint GLenum GLboolean GLsizei stride
Definition: glcorearb.h:872
GLint GLuint mask
Definition: glcorearb.h:124
hboost::python::object getobjectTuple(Py_ssize_t index) const
T & operator[](size_t i)
void setitem_scalar(PyObject *index, const T &data)
size_t unmaskedLength() const
FixedArray< T > ifelse_vector(const FixedArray< int > &choice, const FixedArray< T > &other)
T & unchecked_index(size_t i)
void setitem_scalar_mask(const MaskArrayType &mask, const T &data)
const FixedArray & operator=(const FixedArray &other)
uint8_t ArrayType
Definition: NanoVDB.h:5566
GLint j
Definition: glad.h:2733
FixedArray getslice(::PyObject *index) const
FixedArray(T *ptr, Py_ssize_t length, Py_ssize_t stride=1, bool writable=true)
T & unchecked_direct_index(size_t i)
ReadOnlyMaskedAccess(const ReadOnlyMaskedAccess &other)
static IndexAccess::result_type getitem(Container &c, Py_ssize_t index)
Definition: ImathVec.h:39
GLuint index
Definition: glcorearb.h:786
FixedArray(T *ptr, Py_ssize_t length, Py_ssize_t stride, hboost::any handle, bool writable=true)
auto ptr(T p) -> const void *
Definition: format.h:4331
GLuint GLfloat * val
Definition: glcorearb.h:1608
FixedArray getslice_mask(const MaskArrayType &mask)
size_t stride() const
static void setitem(Container &c, Py_ssize_t index, const Data &data)
static Py_ssize_t len(const Container &)
ReadOnlyMaskedAccess(const FixedArray< T > &array)
void extract_slice_indices(PyObject *index, size_t &start, size_t &end, Py_ssize_t &step, size_t &slicelength) const
Definition: ImathVec.h:41
FixedArray(FixedArray &f, const MaskArrayType &mask)
hboost::python::object getobjectTuple(Py_ssize_t index)
get_type_const getitem(Py_ssize_t index) const
static size_t canonical_index(Py_ssize_t index)
GLint GLsizei count
Definition: glcorearb.h:405
Definition: format.h:1821