// // SPDX-License-Identifier: BSD-3-Clause // Copyright (c) Contributors to the OpenEXR Project. // #ifndef INCLUDED_IMF_ARRAY_H #define INCLUDED_IMF_ARRAY_H #include "ImfForward.h" #include "IexBaseExc.h" #include "IexMathExc.h" #include #include #include //------------------------------------------------------------------------- // // class Array // class Array2D // // "Arrays of T" whose sizes are not known at compile time. // When an array goes out of scope, its elements are automatically // deleted. // // Usage example: // // struct C // { // C () {std::cout << "C::C (" << this << ")\n";}; // virtual ~C () {std::cout << "C::~C (" << this << ")\n";}; // }; // // int // main () // { // Array a(3); // // C &b = a[1]; // const C &c = a[1]; // C *d = a + 2; // const C *e = a; // // return 0; // } // //------------------------------------------------------------------------- OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_ENTER template class IMF_EXPORT_TEMPLATE_TYPE Array { public: //----------------------------- // Constructors and destructors //----------------------------- Array () { _data = 0; _size = 0; } Array (long size) : _size (0), _data (0) { if (size < 0) throw IEX_NAMESPACE::ArgExc ("Array size must be non-negative"); _data = new T[size]; _size = size; } ~Array () { delete[] _data; } //----------------------------- // Access to the array elements //----------------------------- operator T* () { return _data; } operator const T* () const { return _data; } //------------------------------------------------------ // Resize and clear the array (the contents of the array // are not preserved across the resize operation). // // resizeEraseUnsafe() is more memory efficient than // resizeErase() because it deletes the old memory block // before allocating a new one, but if allocating the // new block throws an exception, resizeEraseUnsafe() // leaves the array in an unusable state. // //------------------------------------------------------ void resizeErase (long size); void resizeEraseUnsafe (long size); //------------------------------- // Return the size of this array. //------------------------------- long size () const { return _size; } private: Array (const Array&) = delete; Array& operator= (const Array&) = delete; Array (Array&&) = delete; Array& operator= (Array&&) = delete; long _size; T* _data; }; template class IMF_EXPORT_TEMPLATE_TYPE Array2D { public: //----------------------------- // Constructors and destructors //----------------------------- Array2D (); // empty array, 0 by 0 elements Array2D (long sizeX, long sizeY); // sizeX by sizeY elements ~Array2D (); //----------------------------- // Access to the array elements //----------------------------- T* operator[] (long x); const T* operator[] (long x) const; //------------------------------------------------------ // Resize and clear the array (the contents of the array // are not preserved across the resize operation). // // resizeEraseUnsafe() is more memory efficient than // resizeErase() because it deletes the old memory block // before allocating a new one, but if allocating the // new block throws an exception, resizeEraseUnsafe() // leaves the array in an unusable state. // //------------------------------------------------------ void resizeErase (long sizeX, long sizeY); void resizeEraseUnsafe (long sizeX, long sizeY); //------------------------------- // Return the size of this array. //------------------------------- long height () const { return _sizeX; } long width () const { return _sizeY; } private: Array2D (const Array2D&) = delete; Array2D& operator= (const Array2D&) = delete; Array2D (Array2D&&) = delete; Array2D& operator= (Array2D&&) = delete; long _sizeX; long _sizeY; T* _data; }; //--------------- // Implementation //--------------- namespace { inline size_t array2DElementCount (long sizeX, long sizeY) { const uint64_t x = static_cast (sizeX); const uint64_t y = static_cast (sizeY); const uint64_t maxSize = std::numeric_limits::max (); if (y > 0 && x > maxSize / y) throw IEX_NAMESPACE::OverflowExc ("Array2D dimensions too large"); return static_cast (x * y); } } // namespace template inline void Array::resizeErase (long size) { if (size < 0) throw IEX_NAMESPACE::ArgExc ("Array size must be non-negative"); T* tmp = new T[size]; delete[] _data; _size = size; _data = tmp; } template inline void Array::resizeEraseUnsafe (long size) { if (size < 0) throw IEX_NAMESPACE::ArgExc ("Array size must be non-negative"); delete[] _data; _data = 0; _size = 0; _data = new T[size]; _size = size; } template inline Array2D::Array2D () : _sizeX (0), _sizeY (0), _data (0) { // empty } template inline Array2D::Array2D (long sizeX, long sizeY) : _sizeX (0), _sizeY (0), _data (0) { if (sizeX < 0 || sizeY < 0) throw IEX_NAMESPACE::ArgExc ("Array2D dimensions must be non-negative"); _sizeX = sizeX; _sizeY = sizeY; _data = new T[array2DElementCount (sizeX, sizeY)]; } template inline Array2D::~Array2D () { delete[] _data; } template inline T* Array2D::operator[] (long x) { return _data + x * _sizeY; } template inline const T* Array2D::operator[] (long x) const { return _data + x * _sizeY; } template inline void Array2D::resizeErase (long sizeX, long sizeY) { if (sizeX < 0 || sizeY < 0) throw IEX_NAMESPACE::ArgExc ("Array2D dimensions must be non-negative"); T* tmp = new T[array2DElementCount (sizeX, sizeY)]; delete[] _data; _sizeX = sizeX; _sizeY = sizeY; _data = tmp; } template inline void Array2D::resizeEraseUnsafe (long sizeX, long sizeY) { if (sizeX < 0 || sizeY < 0) throw IEX_NAMESPACE::ArgExc ("Array2D dimensions must be non-negative"); delete[] _data; _data = 0; _sizeX = 0; _sizeY = 0; _data = new T[array2DElementCount (sizeX, sizeY)]; _sizeX = sizeX; _sizeY = sizeY; } OPENEXR_IMF_INTERNAL_NAMESPACE_HEADER_EXIT #endif