///////////////////////////////////////////////////////////////////////// // // Copyright (c) 2013, Industrial Light & Magic, a division of Lucas // Digital Ltd. LLC // // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Industrial Light & Magic nor the names of // its contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // /////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include namespace PyImath { template FixedVArray::FixedVArray (std::vector* ptr, Py_ssize_t length, Py_ssize_t stride) : _ptr(ptr), _length(length), _stride(stride), _handle(), _unmaskedLength(0) { if (length < 0) { throw IEX_NAMESPACE::ArgExc("Fixed array length must be non-negative"); } if (stride <= 0) { throw IEX_NAMESPACE::ArgExc("Fixed array stride must be positive"); } // Nothing else to do (pointer given, so we have the data) } template FixedVArray::FixedVArray (std::vector* ptr, Py_ssize_t length, Py_ssize_t stride, boost::any handle) : _ptr(ptr), _length(length), _stride(stride), _handle(handle), _unmaskedLength(0) { if (length < 0) { throw IEX_NAMESPACE::ArgExc("Fixed array length must be non-negative"); } if (stride <= 0) { throw IEX_NAMESPACE::ArgExc("Fixed array stride must be positive"); } // Nothing else to do (pointer given, so we have the data) } template FixedVArray::FixedVArray(Py_ssize_t length) : _ptr(0), _length(length), _stride(1), _handle(), _unmaskedLength(0) { if (length < 0) { throw IEX_NAMESPACE::ArgExc("Fixed array length must be non-negative"); } boost::shared_array > a(new std::vector[length]); // Initial vectors in the array will be zero-length. _handle = a; _ptr = a.get(); } // template // FixedVArray::FixedVArray(Py_ssize_t length, Uninitialized) // : _ptr(0), _length(length), _stride(1), _handle(), _unmaskedLength(0) // { // if (length < 0) // { // throw IEX_NAMESPACE::ArgExc("Fixed array length must be non-negative"); // } // // boost::shared_array > a(new std::vector[length]); // _handle = a; // _ptr = a.get(); // } template FixedVArray::FixedVArray(const T& initialValue, Py_ssize_t length) : _ptr(0), _length(length), _stride(1), _handle(), _unmaskedLength(0) { if (length < 0) { throw IEX_NAMESPACE::ArgExc("Fixed array length must be non-negative"); } boost::shared_array > a(new std::vector[length]); for (size_t i = 0; i < length; ++i) { a[i].push_back (initialValue); } _handle = a; _ptr = a.get(); } template FixedVArray::FixedVArray(FixedVArray& other, const FixedArray& mask) : _ptr(other._ptr), _stride(other._stride), _handle(other._handle) { if (other.isMaskedReference()) { throw IEX_NAMESPACE::NoImplExc ("Masking an already-masked FixedVArray is not supported yet (SQ27000)"); } size_t len = other.match_dimension (mask); _unmaskedLength = len; size_t reduced_len = 0; for (size_t i = 0; i < len; ++i) { if (mask[i]) { reduced_len++; } } _indices.reset (new size_t[reduced_len]); for (size_t i = 0, j = 0; i < len; ++i) { if (mask[i]) { _indices[j] = i; j++; } } _length = reduced_len; } // template // explicit FixedVArray(const FixedVArray &other) // AAJ (WHAT DOES THE TEMPLATE LOOK LIKE?) // { // } template FixedVArray::FixedVArray(const FixedVArray& other) : _ptr(other._ptr), _length(other._length), _stride(other._stride), _handle(other._handle), _indices(other._indices), _unmaskedLength(other._unmaskedLength) { // Nothing. } template const FixedVArray & FixedVArray::operator = (const FixedVArray& other) // AAJ (WHY SHALLOW COPY) { if (&other == this) return *this; _ptr = other._ptr; _length = other._length; _stride = other._stride; _handle = other._handle; _unmaskedLength = other._unmaskedLength; _indices = other._indices; return *this; } template FixedVArray::~FixedVArray() // AAJ (NOT DELETED BECAUSE SHARED ARRAY THAT HANDLE HAS?) { // Nothing. } template std::vector& FixedVArray::operator [] (size_t i) { return _ptr[(_indices ? raw_ptr_index(i) : i) * _stride]; } template const std::vector& FixedVArray::operator [] (size_t i) const { return _ptr[(_indices ? raw_ptr_index(i) : i) * _stride]; } namespace { // // Make an index suitable for indexing into an array in c++ // from a python index, which can be negative for indexing // relative to the end of an array. // size_t canonical_index (Py_ssize_t index, const size_t& totalLength) { if (index < 0) { index += totalLength; } if (index >= totalLength || index < 0) { PyErr_SetString (PyExc_IndexError, "Index out of range"); boost::python::throw_error_already_set(); } return index; // still a 'virtual' index if this is a masked reference array } void extract_slice_indices (PyObject* index, size_t& start, size_t& end, Py_ssize_t& step, size_t& sliceLength, const size_t& totalLength) { if (PySlice_Check (index)) { PySliceObject* slice = reinterpret_cast(index); Py_ssize_t s, e, sl; if (PySlice_GetIndicesEx(slice, totalLength, &s, &e, &step, &sl) == -1) { boost::python::throw_error_already_set(); } if (s < 0 || e < -1 || sl < 0) { throw IEX_NAMESPACE::LogicExc ("Slice extraction produced invalid start, end, or length indices"); } start = s; end = e; sliceLength = sl; } else if (PyInt_Check (index)) { size_t i = canonical_index (PyInt_AsSsize_t(index), totalLength); start = i; end = i + 1; step = 1; sliceLength = 1; } else { PyErr_SetString (PyExc_TypeError, "Object is not a slice"); boost::python::throw_error_already_set(); } } } // namespace // template // typename boost::mpl::if_,T&,T>::type // FixedVArray::getitem (Py_ssize_t index) // { // return (*this)[canonical_index (index, _length)]; // } // // template // typename boost::mpl::if_,const T&,T>::type // FixedVArray::getitem (Py_ssize_t index) const // { // return (*this)[canonical_index (index, _length)]; // } template FixedVArray FixedVArray::getslice (PyObject* index) const { size_t start = 0; size_t end = 0; size_t sliceLength = 0; Py_ssize_t step; extract_slice_indices (index, start, end, step, sliceLength, _length); FixedVArray f(sliceLength); if (_indices) { for (size_t i = 0; i < sliceLength; ++i) { f._ptr[i] = _ptr[raw_ptr_index(start + i*step)*_stride]; } } else { for (size_t i = 0; i < sliceLength; ++i) { f._ptr[i] = _ptr[(start + i*step)*_stride]; } } return f; } template FixedVArray FixedVArray::getslice_mask (const FixedArray& mask) { return FixedVArray (*this, mask); } // template // void // FixedVArray::setitem_scalar (PyObject* index, const T& data) // { // size_t start = 0; // size_t end = 0; // size_t sliceLength = 0; // Py_ssize_t step; // extract_slice_indices (index, start, end, step, sliceLength, _length); // // if (_indices) // { // for (size_t i = 0; i < sliceLength; ++i) // { // _ptr[raw_ptr_index(start + i*step)*_stride] = data; // } // } // else // { // for (size_t i = 0; i < sliceLength; ++i) // { // _ptr[(start + i*step)*_stride] = data; // } // } // } // // template // void // FixedVArray::setitem_scalar_mask (const FixedArray& mask, const T& data) // { // size_t len = match_dimension(mask, false); // // if (_indices) // { // for (size_t i = 0; i < len; ++i) // { // // We don't need to actually look at 'mask' because // // match_dimensions has already forced some expected condition. // _ptr[raw_ptr_index(i)*_stride] = data; // } // } // else // { // for (size_t i = 0; i < len; ++i) // { // if (mask[i]) // { // _ptr[i*_stride] = data; // } // } // } // } template void FixedVArray::setitem_vector (PyObject* index, const FixedVArray& data) { size_t start = 0; size_t end = 0; size_t sliceLength = 0; Py_ssize_t step; extract_slice_indices (index, start, end, step, sliceLength, _length); if (data.len() != sliceLength) { PyErr_SetString (PyExc_IndexError, "Dimensions of source do not match destination"); boost::python::throw_error_already_set(); } if (_indices) { for (size_t i = 0; i < sliceLength; ++i) { _ptr[raw_ptr_index(start + i*step)*_stride] = data[i]; } } else { for (size_t i = 0; i < sliceLength; ++i) { _ptr[(start + i*step)*_stride] = data[i]; } } } template void FixedVArray::setitem_vector_mask (const FixedArray& mask, const FixedVArray& data) { // This restriction could be removed if there is a compelling use-case. if (_indices) { throw IEX_NAMESPACE::ArgExc ("We don't support setting item masks for masked reference arrays"); } size_t len = match_dimension(mask); if (data.len() == len) { for (size_t i = 0; i < len; ++i) { if (mask[i]) { _ptr[i*_stride] = data[i]; } } } else { size_t count = 0; for (size_t i = 0; i < len; ++i) { if (mask[i]) { count++; } } if (data.len() != count) { throw IEX_NAMESPACE::ArgExc ("Dimensions of source data do not match destination " "either masked or unmasked"); } Py_ssize_t dataIndex = 0; for (size_t i = 0; i < len; ++i) { if (mask[i]) { _ptr[i*_stride] = data[dataIndex]; dataIndex++; } } } } // template // FixedVArray // FixedVArray::ifelse_scalar(const FixedArray& choice, const T& other) // { // size_t len = match_dimension (choice); // // FixedVArray tmp(len); // for (size_t i = 0; i < len; ++i) // { // tmp[i] = choice[i] ? (*this)[i] : other; // } // // return tmp; // } template FixedVArray FixedVArray::ifelse_vector(const FixedArray& choice, const FixedVArray& other) { size_t len = match_dimension (choice); match_dimension (other); FixedVArray tmp(len); for (size_t i = 0; i < len; ++i) { tmp[i] = choice[i] ? (*this)[i] : other[i]; } return tmp; } template size_t FixedVArray::raw_ptr_index (size_t i) const { assert (isMaskedReference()); assert (i < _length); assert (_indices[i] >= 0 && _indices[i] < _unmaskedLength); return _indices[i]; } // static template boost::python::class_ > FixedVArray::register_(const char* doc) { // // See 'PyImathFixedArray.h' for some explanation. // typedef typename boost::mpl::if_< // boost::is_class, // boost::python::return_internal_reference<>, // boost::python::default_call_policies>::type call_policy; // typedef typename boost::mpl::if_< // boost::is_class, // boost::python::return_value_policy, // boost::python::default_call_policies>::type const_call_policy; // // typename FixedVArray::get_type (FixedVArray::*nonconst_getitem)(Py_ssize_t) = // &FixedVArray::getitem; // // typename FixedVArray::get_type_const (FixedVArray::*const_getitem)(Py_ssize_t) const = // &FixedVArray::getitem; boost::python::class_ > c (name(), doc, boost::python::init("Construct a variable array of the " "specified length initialized to the default value for the given type")); c.def(boost::python::init &>("Construct a variable array with the same values as the given array")) .def(boost::python::init("Construct a variable array of the specified length initialized to the specified default value")) .def("__getitem__", &FixedVArray::getslice) .def("__getitem__", &FixedVArray::getslice_mask) .def("__setitem__", &FixedVArray::setitem_vector) .def("__setitem__", &FixedVArray::setitem_vector_mask) .def("__len__", &FixedVArray::len) .def("ifelse", &FixedVArray::ifelse_vector) ; // .def("__setitem__", &FixedVArray::setitem_scalar) // .def("__setitem__", &FixedVArray::setitem_scalar_mask) // .def("__getitem__", const_getitem, const_call_policy()) // .def("__getitem__", nonconst_getitem, call_policy()) // .def("ifelse", &FixedVArray::ifelse_scalar) return c; } // ---- Explicit Class Instantiation --------------------------------- template class PYIMATH_EXPORT FixedVArray; } // namespace PyImath