// // helper.hpp // // LGPL Version 2.1 HEADER START // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, // MA 02110-1301 USA // // LGPL Version 2.1 HEADER END // // // Copyright (c) 2019, Regents of the University of Minnesota. // All rights reserved. // // Contributors: // Yaser Afshar // #ifndef SNAP_HELPER_HPP #define SNAP_HELPER_HPP /*! * \file helper.hpp * * \author Yaser Afshar (yafshar@umn.edu) * * \brief This file contains helper classes for memory management * which are STL like extension for multi-dimensional arrays * * \date 09-10-2019 */ #include #include #include #include #include #include #include #include #ifdef HELPER_LOG_ERROR #undef HELPER_LOG_ERROR #endif #ifdef HELPER_LOG_WARNING #undef HELPER_LOG_WARNING #endif /*! * \brief Helper macro for printing error message * formats messages, filename, line number and function * name into an std::ostringstream object * */ #define HELPER_LOG_ERROR(msg) \ { \ std::ostringstream ss; \ ss << "\nError :" << __FILE__ \ << ":" << __LINE__ << ":@(" \ << __FUNCTION__ << ")\n" \ << msg << "\n\n"; \ std::cerr << ss.str(); \ } #define HELPER_LOG_WARNING(msg) \ { \ std::ostringstream ss; \ ss << "\nWarning :" << __FILE__ \ << ":" << __LINE__ << ":@(" \ << __FUNCTION__ << ")\n" \ << msg << "\n\n"; \ std::cerr << ss.str(); \ } /*! Type alias for vector of constant dimension 3 */ using VectorOfSizeDIM = double[3]; /*! Type alias for vector of constant dimension 6 */ using VectorOfSizeSix = double[6]; /*! \class _Array_Basic The basic STL like container similar to `std::vector` to * handle multi-dimensional arrays. * * \brief An STL like container similar to std::vector * that encapsulates dynamic size arrays in a sequence container * * \tparam DataType The type of the elements. Default (double) */ template class _Array_Basic { public: /*! * \brief Construct a new _Array_Basic object * */ _Array_Basic(); /*! * \brief Construct a new _Array_Basic object * * \param count The size of the container */ explicit _Array_Basic(std::size_t const count); /*! * \brief Construct a new _Array_Basic object * * \param count The size of the container * \param value The value to initialize elements of the container with */ _Array_Basic(std::size_t const count, DataType const value); /*! * \brief Construct a new _Array_Basic object * * \param count The size of the container * \param array The array of data to initialize elements of the container * with. */ _Array_Basic(std::size_t const count, DataType const *array); /*! * \brief Construct a new _Array_Basic object * Copy constructor. Constructs the container with the copy of the contents of * other. * * \param other Another container to be used as source to initialize the * elements of the container with */ _Array_Basic(_Array_Basic const &other); /*! * \brief Construct a new _Array_Basic object * Move constructor. Constructs the container with the contents of other using * move semantics. * * \param other Another container to be used as source to initialize the * elements of the container with */ _Array_Basic(_Array_Basic &&other); /*! * \brief Destroy the _Array_Basic object * */ ~_Array_Basic(); /*! * \brief Copy assignment operator. Replaces the contents with a copy of the * contents of other * * \param other Another container to use as data source * * \return _Array_Basic& */ _Array_Basic &operator=(_Array_Basic const &other); /*! * \brief Move assignment operator. Replaces the contents with those of other * using move semantics * * \param other Another container to use as data source * * \return _Array_Basic& */ _Array_Basic &operator=(_Array_Basic &&other); /*! * \brief Returns pointer to the underlying array serving as element storage. * * \return DataType* */ inline DataType const *data() const noexcept; inline DataType *data() noexcept; /*! * \brief Returns the number of elements in the container. * * \return std::size_t */ inline std::size_t size() const; /*! * \brief Erases all elements from the container. * */ inline void clear() noexcept; /*! * \brief Requests the removal of unused capacity. * */ inline void shrink_to_fit(); /*! * \brief Returns the number of elements that the container has currently * allocated space for. * * \return std::size_t */ inline std::size_t capacity() const noexcept; /*! * \brief Appends the given element value to the end of the container. * * \param value */ inline void push_back(DataType const &value); inline void push_back(DataType &&value); protected: /*! * \brief Check the index range based on container size * * \param _n Index */ inline void _range_check(int _n) const; /*! * \brief Check the index range based on input size * * \param _n Index * \param tsize Input size */ inline void _range_check(int _n, std::size_t tsize) const; protected: /*! Dynamic contiguous array */ std::vector m; }; /*! \class Array1DView A 1-dimensional STL like container. * * \brief A 1-dimensional STL like container that encapsulates dynamic size * arrays in a sequence container * * \tparam DataType The type of the elements. Default (double) */ template class Array1DView { public: /*! * \brief Construct a new Array1DView object * * \param count The size of the container * \param array The array of data to initialize elements of the container * with. */ Array1DView(std::size_t const count, DataType *array); Array1DView(std::size_t const count, DataType const *array); /*! * \brief Construct a new Array1DView object * Copy constructor. Constructs the container with the copy of the contents of * other. * * \param other Another container to be used as source to initialize the * elements of the container with */ Array1DView(Array1DView const &other); /*! * \brief Destroy the Array1DView object * */ ~Array1DView(); /*! * \brief Returns pointer to the underlying array serving as element storage. * * \return DataType* */ inline DataType const *data() const noexcept; inline DataType *data() noexcept; /*! * \brief Returns the element at specified location \b i. * No bounds checking is performed. * * \param i Position of the element to return * * \return const DataType The requested element. */ inline const DataType operator()(int i) const; inline DataType &operator()(int i); /*! * \brief Returns the element at specified location \b i , with bounds * checking. * * \param i Position of the element to return * * \return const DataType The requested element. */ inline DataType const at(int i) const; inline DataType &at(int i); /*! * \brief Returns the element at specified location \b i. * No bounds checking is performed. * * \param i Position of the element to return * * \return const DataType The requested element. */ const DataType operator[](int i) const; DataType &operator[](int i); private: Array1DView() = delete; Array1DView &operator=(Array1DView const &other) = delete; Array1DView &operator=(Array1DView &&other) = delete; protected: /*! * \brief Check the index range based on input size * * \param _n Index * \param tsize Input size */ inline void _range_check(int _n, std::size_t tsize) const; protected: /*! The extent of the container in the 1st mode */ std::size_t _extentZero; /*! Data pointer */ DataType *const m; }; template class Array2DView { public: /*! * \brief Construct a new Array2DView object * * \param extentZero The extent of the container in the 1st mode * \param extentOne The extent of the container in the 2nd mode * \param array The array of data to set the pointer of the container to it. */ Array2DView(std::size_t const extentZero, std::size_t const extentOne, DataType *array); Array2DView(std::size_t const extentZero, std::size_t const extentOne, DataType const *array); /*! * \brief Construct a new Array2DView object * Copy constructor. Constructs the container with the copy of the contents of * other. * * \param other Another container to be used as source to initialize the * elements of the container with */ Array2DView(Array2DView const &other); /*! * \brief Destroy the Array2D object * */ ~Array2DView(); /*! * \brief Returns pointer to the underlying array serving as element storage. * * \return DataType* */ inline DataType const *data() const noexcept; inline DataType *data() noexcept; inline Array1DView const data_1D(int i) const; inline Array1DView data_1D(int i); /*! * \brief Returns the element at specified location \b (i, j). * No bounds checking is performed. * * \param i Position of the element in the 1st mode * \param j Position of the element in the 2nd mode * * \return const DataType The requested element. */ inline const DataType operator()(int i, int j) const; inline DataType &operator()(int i, int j); /*! * \brief Returns the element at specified location \b (i, j) , with bounds * checking. * * \param i Position of the element in the 1st mode * \param j Position of the element in the 2nd mode * * \return const DataType The requested element. */ inline DataType const at(int i, int j) const; inline DataType &at(int i, int j); /*! \class j_operator A helper class to provide multidimensional array access * semantics. * * \brief To provide 2-dimensional array access semantics, operator[] has to * return a reference to a 1D vector, which has to have its own operator[] * which returns a reference to the element. */ class j_operator { public: /*! * \brief Construct a new j_operator object * * \param _array Refernce to Array2D class * \param i Position of the element in the 1st mode */ j_operator(Array2DView &_array, int i); /*! * \brief Provide array-like access and returns the element at specified * location \b [i][j]. No bounds checking is performed. * * \param j Position of the element in the 2nd mode * * \return const DataType The requested element. */ const DataType operator[](int j) const; DataType &operator[](int j); private: /*! Refernce to Array2D class */ Array2DView &j_array; std::size_t _i; }; /*! * \brief Provide array-like access and returns the element at specified * location \b [i][j]. No bounds checking is performed. * * \param i Position of the element in the 1st mode * \param j Position of the element in the 2nd mode * * \return const DataType The requested element. * * \note * To provide multidimensional array access semantics, we are using multiple * overloads for \code operator[] \endcode . For speed one should avoid this * complexity, uses \code operator() \endcode as \code (i, j) \endcode * directly. */ const j_operator operator[](int i) const; j_operator operator[](int i); private: Array2DView() = delete; Array2DView &operator=(Array2DView const &other) = delete; Array2DView &operator=(Array2DView &&other) = delete; protected: /*! * \brief Check the index range based on input size * * \param _n Index * \param tsize Input size */ inline void _range_check(int _n, std::size_t tsize) const; protected: /*! The extent of the container in the 1st mode */ std::size_t _extentZero; /*! The extent of the container in the 2nd mode */ std::size_t _extentOne; /*! Data pointer */ DataType *const m; }; /*! \class Array2D A 2-dimensional STL like container. * * \brief A 2-dimensional STL like container that encapsulates dynamic size * arrays with a 2-dimensional shape in a sequence container * * \tparam DataType The type of the elements. Default (double) */ template class Array2D : public _Array_Basic { public: /*! * \brief Construct a new Array2D object * */ Array2D(); /*! * \brief Construct a new Array2D object * * \param extentZero The extent of the container in the 1st mode * \param extentOne The extent of the container in the 2nd mode */ Array2D(std::size_t const extentZero, std::size_t const extentOne); /*! * \brief Construct a new Array2D object * * \param extentZero The extent of the container in the 1st mode * \param extentOne The extent of the container in the 2nd mode * \param value The value to initialize elements of the container with */ Array2D(std::size_t const extentZero, std::size_t const extentOne, DataType const value); /*! * \brief Construct a new Array2D object * * \param extentZero The extent of the container in the 1st mode * \param extentOne The extent of the container in the 2nd mode * \param array The array of data to initialize elements of the container in a * row-major format. */ Array2D(std::size_t const extentZero, std::size_t const extentOne, DataType const *array); /*! * \brief Construct a new Array2D object * Copy constructor. Constructs the container with the copy of the contents of * other. * * \param other Another container to be used as source to initialize the * elements of the container with */ Array2D(Array2D const &other); /*! * \brief Construct a new Array2D object * Move constructor. Constructs the container with the contents of other using * move semantics. * * \param other Another container to be used as source to initialize the * elements of the container with */ Array2D(Array2D &&other); /*! * \brief Destroy the Array2D object * */ ~Array2D(); /*! * \brief Copy assignment operator. Replaces the contents with a copy of the * contents of other * * \param other Another container to use as data source * * \return Array2D& */ Array2D &operator=(Array2D const &other); /*! * \brief Move assignment operator. Replaces the contents with those of other * using move semantics * * \param other Another container to use as data source * * \return Array2D& */ Array2D &operator=(Array2D &&other); /*! * \brief Returns Array1DView to the underlying starting element at row \c i. * \sa Array1DView * * \param i Row index * \return Array1DView */ inline Array1DView const data_1D(int i) const; inline Array1DView data_1D(int i); /*! * \brief Resizes the container to contain \c extentZero times \c extentOne * elements. * * \param extentZero * \param extentOne */ inline void resize(int const extentZero, int const extentOne); /*! * \brief Resizes the container to contain \c extentZero times \c extentOne * elements. * * \param extentZero * \param extentOne * \param new_value The new value to initialize the new elements with */ inline void resize(int const extentZero, int const extentOne, DataType const new_value); /*! * \brief Resizes the container to contain \c extentZero times \c extentOne * elements. * * \param extentZero * \param extentOne * \param new_array The new array of data to initialize elements of the * container with. */ inline void resize(int const extentZero, int const extentOne, DataType const *new_array); /*! * \brief Returns the element at specified location \b (i, j). * No bounds checking is performed. * * \param i Position of the element in the 1st mode * \param j Position of the element in the 2nd mode * * \return const DataType The requested element. */ inline const DataType operator()(int i, int j) const; inline DataType &operator()(int i, int j); /*! * \brief Returns the element at specified location \b (i, j) , with bounds * checking. * * \param i Position of the element in the 1st mode * \param j Position of the element in the 2nd mode * * \return const DataType The requested element. */ inline DataType const at(int i, int j) const; inline DataType &at(int i, int j); /*! \class j_operator A helper class to provide multidimensional array access * semantics. * * \brief To provide 2-dimensional array access semantics, operator[] has to * return a reference to a 1D vector, which has to have its own operator[] * which returns a reference to the element. */ class j_operator { public: /*! * \brief Construct a new j_operator object * * \param _array Refernce to Array2D class * \param i Position of the element in the 1st mode */ j_operator(Array2D &_array, int i); /*! * \brief Provide array-like access and returns the element at specified * location \b [i][j]. No bounds checking is performed. * * \param j Position of the element in the 2nd mode * * \return const DataType The requested element. */ const DataType operator[](int j) const; DataType &operator[](int j); private: /*! Refernce to Array2D class */ Array2D &j_array; std::size_t _i; }; /*! * \brief Provide array-like access and returns the element at specified * location \b [i][j]. No bounds checking is performed. * * \param i Position of the element in the 1st mode * \param j Position of the element in the 2nd mode * * \return const DataType The requested element. * * \note * To provide multidimensional array access semantics, we are using multiple * overloads for \code operator[] \endcode . For speed one should avoid this * complexity, uses \code operator() \endcode as \code (i, j) \endcode * directly. */ const j_operator operator[](int i) const; j_operator operator[](int i); protected: /*! The extent of the container in the 1st mode */ std::size_t _extentZero; /*! The extent of the container in the 2nd mode */ std::size_t _extentOne; }; template class Array3D : public _Array_Basic { public: Array3D(); Array3D(std::size_t const extentZero, std::size_t const extentOne, std::size_t const extentTwo); Array3D(std::size_t const extentZero, std::size_t const extentOne, std::size_t const extentTwo, DataType const value); Array3D(std::size_t const extentZero, std::size_t const extentOne, std::size_t const extentTwo, DataType const *array); Array3D(Array3D const &other); Array3D(Array3D &&other); ~Array3D(); Array3D &operator=(Array3D const &other); Array3D &operator=(Array3D &&other); inline Array2DView const data_2D(int i) const; inline Array2DView data_2D(int i); inline Array1DView const data_1D(int i, int j) const; inline Array1DView data_1D(int i, int j); inline void resize(int const extentZero, int const extentOne, int const extentTwo); inline void resize(int const extentZero, int const extentOne, int const extentTwo, DataType const new_value); inline void resize(int const extentZero, int const extentOne, int const extentTwo, DataType const *new_array); inline const DataType operator()(int i, int j, int k) const; inline DataType &operator()(int i, int j, int k); inline DataType const at(int i, int j, int k) const; inline DataType &at(int i, int j, int k); class j_operator { public: j_operator(Array3D &_array, int i); class k_operator { public: k_operator(Array3D &_array, int i, int j); const DataType operator[](int k) const; DataType &operator[](int k); private: Array3D &k_array; std::size_t _i; std::size_t _j; }; const k_operator operator[](int j) const; k_operator operator[](int j); private: Array3D &j_array; std::size_t _i; }; const j_operator operator[](int i) const; j_operator operator[](int i); protected: std::size_t _extentZero; std::size_t _extentOne; std::size_t _extentTwo; }; template _Array_Basic::_Array_Basic() {} template _Array_Basic::_Array_Basic(std::size_t const count) : m(count) {} template _Array_Basic::_Array_Basic(std::size_t const count, DataType const value) : m(count, value) {} template _Array_Basic::_Array_Basic(std::size_t const count, DataType const *array) : m(array, array + count) {} template _Array_Basic::_Array_Basic(_Array_Basic const &other) : m(other.m) {} template _Array_Basic::_Array_Basic(_Array_Basic &&other) : m(std::move(other.m)) {} template _Array_Basic::~_Array_Basic() {} template _Array_Basic &_Array_Basic::operator=(_Array_Basic const &other) { m.resize(other.size()); std::copy(other.m.begin(), other.m.end(), m.begin()); return *this; } template _Array_Basic &_Array_Basic::operator=(_Array_Basic &&other) { m = std::move(other.m); return *this; } template inline DataType const *_Array_Basic::data() const noexcept { return m.data(); } template inline DataType *_Array_Basic::data() noexcept { return m.data(); } template inline std::size_t _Array_Basic::size() const { return m.size(); } template inline void _Array_Basic::clear() noexcept { m.clear(); } template inline void _Array_Basic::shrink_to_fit() { m.shrink_to_fit(); } template inline std::size_t _Array_Basic::capacity() const noexcept { return m.capacity(); } template inline void _Array_Basic::push_back(DataType const &value) { m.push_back(value); } template inline void _Array_Basic::push_back(DataType &&value) { m.push_back(value); } template inline void _Array_Basic::_range_check(int _n) const { if (_n >= size()) { HELPER_LOG_ERROR("The input index is out of range! " + std::to_string(_n) + " >= " + std::to_string(size())); std::abort(); } } template inline void _Array_Basic::_range_check(int _n, std::size_t tsize) const { if (_n >= tsize) { HELPER_LOG_ERROR("The input index is out of range! " + std::to_string(_n) + " >= " + std::to_string(tsize)); std::abort(); } } template Array1DView::Array1DView(std::size_t const count, DataType *array) : _extentZero(count), m(array) {} template Array1DView::Array1DView(std::size_t const count, DataType const *array) : _extentZero(count), m(const_cast(array)) {} template Array1DView::Array1DView(Array1DView const &other) : _extentZero(other._extentZero), m(other.m) {} template Array1DView::~Array1DView() {} template inline DataType const *Array1DView::data() const noexcept { return m; } template inline DataType *Array1DView::data() noexcept { return m; } template inline const DataType Array1DView::operator()(int i) const { return m[i]; } template inline DataType &Array1DView::operator()(int i) { return m[i]; } template inline DataType &Array1DView::at(int i) { _range_check(i, _extentZero); return m[i]; } template inline DataType const Array1DView::at(int i) const { _range_check(i, _extentZero); return m[i]; } template const DataType Array1DView::operator[](int i) const { return m[i]; } template DataType &Array1DView::operator[](int i) { return m[i]; } template inline void Array1DView::_range_check(int _n, std::size_t tsize) const { if (_n >= tsize) { HELPER_LOG_ERROR("The input index is out of range! " + std::to_string(_n) + " >= " + std::to_string(tsize)); std::abort(); } } template Array2DView::Array2DView(std::size_t const extentZero, std::size_t const extentOne, DataType *array) : _extentZero(extentZero), _extentOne(extentOne), m(array) {} template Array2DView::Array2DView(std::size_t const extentZero, std::size_t const extentOne, DataType const *array) : _extentZero(extentZero), _extentOne(extentOne), m(const_cast(array)) {} template Array2DView::Array2DView(Array2DView const &other) : _extentZero(other._extentZero), _extentOne(other._extentOne), m(other.m) {} template Array2DView::~Array2DView() {} template inline DataType const *Array2DView::data() const noexcept { return m; } template inline DataType *Array2DView::data() noexcept { return m; } template inline Array1DView const Array2DView::data_1D(int i) const { return Array1DView(_extentOne, m + i * _extentOne); } template inline Array1DView Array2DView::data_1D(int i) { return Array1DView(_extentOne, m + i * _extentOne); } template inline const DataType Array2DView::operator()(int i, int j) const { std::size_t const _n = i * _extentOne + j; return m[_n]; } template inline DataType &Array2DView::operator()(int i, int j) { std::size_t const _n = i * _extentOne + j; return m[_n]; } template inline DataType &Array2DView::at(int i, int j) { _range_check(i, _extentZero); _range_check(j, _extentOne); std::size_t const _n = i * _extentOne + j; return m[_n]; } template inline DataType const Array2DView::at(int i, int j) const { _range_check(i, _extentZero); _range_check(j, _extentOne); std::size_t const _n = i * _extentOne + j; return m[_n]; } template Array2DView::j_operator::j_operator(Array2DView &_array, int i) : j_array(_array), _i(i) {} template const DataType Array2DView::j_operator::operator[](int j) const { std::size_t const _n = _i * j_array._extentOne + j; return j_array.m[_n]; } template DataType &Array2DView::j_operator::operator[](int j) { std::size_t const _n = _i * j_array._extentOne + j; return j_array.m[_n]; } template const typename Array2DView::j_operator Array2DView::operator[](int i) const { return j_operator(*this, i); } template typename Array2DView::j_operator Array2DView::operator[](int i) { return j_operator(*this, i); } template inline void Array2DView::_range_check(int _n, std::size_t tsize) const { if (_n >= tsize) { HELPER_LOG_ERROR("The input index is out of range! " + std::to_string(_n) + " >= " + std::to_string(tsize)); std::abort(); } } template Array2D::Array2D() : _Array_Basic(), _extentZero(0), _extentOne(0) {} template Array2D::Array2D(std::size_t const extentZero, std::size_t const extentOne) : _Array_Basic(extentZero * extentOne), _extentZero(extentZero), _extentOne(extentOne) {} template Array2D::Array2D(std::size_t const extentZero, std::size_t const extentOne, DataType const value) : _Array_Basic(extentZero * extentOne, value), _extentZero(extentZero), _extentOne(extentOne) {} template Array2D::Array2D(std::size_t const extentZero, std::size_t const extentOne, DataType const *array) : _Array_Basic(extentZero * extentOne, array), _extentZero(extentZero), _extentOne(extentOne) {} template Array2D::Array2D(Array2D const &other) : _Array_Basic(other), _extentZero(other._extentZero), _extentOne(other._extentOne) {} template Array2D::Array2D(Array2D &&other) : _Array_Basic(std::move(other)), _extentZero(other._extentZero), _extentOne(other._extentOne) {} template Array2D::~Array2D() {} template Array2D &Array2D::operator=(Array2D const &other) { _Array_Basic::operator=(other); _extentZero = other._extentZero; _extentOne = other._extentOne; return *this; } template Array2D &Array2D::operator=(Array2D &&other) { _Array_Basic::operator=(std::move(other)); _extentZero = other._extentZero; _extentOne = other._extentOne; return *this; } template inline Array1DView const Array2D::data_1D(int i) const { return Array1DView(_extentOne, this->m.data() + i * _extentOne); } template inline Array1DView Array2D::data_1D(int i) { return Array1DView(_extentOne, this->m.data() + i * _extentOne); } template inline void Array2D::resize(int const extentZero, int const extentOne) { _extentZero = extentZero; _extentOne = extentOne; std::size_t const _n = _extentZero * _extentOne; this->m.resize(_n); } template inline void Array2D::resize(int const extentZero, int const extentOne, DataType const new_value) { _extentZero = extentZero; _extentOne = extentOne; std::size_t const _n = _extentZero * _extentOne; this->m.resize(_n, new_value); } template inline void Array2D::resize(int const extentZero, int const extentOne, DataType const *new_array) { _extentZero = extentZero; _extentOne = extentOne; std::size_t const _n = _extentZero * _extentOne; this->m.resize(_n); std::copy(new_array, new_array + _n, this->m.data()); } template inline const DataType Array2D::operator()(int i, int j) const { std::size_t const _n = i * _extentOne + j; return this->m[_n]; } template inline DataType &Array2D::operator()(int i, int j) { std::size_t const _n = i * _extentOne + j; return this->m[_n]; } template inline DataType &Array2D::at(int i, int j) { this->_range_check(i, _extentZero); this->_range_check(j, _extentOne); std::size_t const _n = i * _extentOne + j; return this->m[_n]; } template inline DataType const Array2D::at(int i, int j) const { this->_range_check(i, _extentZero); this->_range_check(j, _extentOne); std::size_t const _n = i * _extentOne + j; return this->m[_n]; } template Array2D::j_operator::j_operator(Array2D &_array, int i) : j_array(_array), _i(i) {} template const DataType Array2D::j_operator::operator[](int j) const { std::size_t const _n = _i * j_array._extentOne + j; return j_array.m[_n]; } template DataType &Array2D::j_operator::operator[](int j) { std::size_t const _n = _i * j_array._extentOne + j; return j_array.m[_n]; } template const typename Array2D::j_operator Array2D::operator[](int i) const { return j_operator(*this, i); } template typename Array2D::j_operator Array2D::operator[](int i) { return j_operator(*this, i); } template Array3D::Array3D() : _Array_Basic(), _extentZero(0), _extentOne(0), _extentTwo(0) {} template Array3D::Array3D(std::size_t const extentZero, std::size_t const extentOne, std::size_t const extentTwo) : _Array_Basic(extentZero * extentOne * extentTwo), _extentZero(extentZero), _extentOne(extentOne), _extentTwo(extentTwo) {} template Array3D::Array3D(std::size_t const extentZero, std::size_t const extentOne, std::size_t const extentTwo, DataType const value) : _Array_Basic(extentZero * extentOne * extentTwo, value), _extentZero(extentZero), _extentOne(extentOne), _extentTwo(extentTwo) {} template Array3D::Array3D(std::size_t const extentZero, std::size_t const extentOne, std::size_t const extentTwo, DataType const *array) : _Array_Basic(extentZero * extentOne * extentTwo, array), _extentZero(extentZero), _extentOne(extentOne), _extentTwo(extentTwo) {} template Array3D::Array3D(Array3D const &other) : _Array_Basic(other), _extentZero(other._extentZero), _extentOne(other._extentOne), _extentTwo(other._extentTwo) {} template Array3D::Array3D(Array3D &&other) : _Array_Basic(std::move(other)), _extentZero(other._extentZero), _extentOne(other._extentOne), _extentTwo(other._extentTwo) {} template Array3D::~Array3D() {} template Array3D &Array3D::operator=(Array3D const &other) { _Array_Basic::operator=(other); _extentZero = other._extentZero; _extentOne = other._extentOne; _extentTwo = other._extentTwo; return *this; } template Array3D &Array3D::operator=(Array3D &&other) { _Array_Basic::operator=(std::move(other)); _extentZero = other._extentZero; _extentOne = other._extentOne; _extentTwo = other._extentTwo; return *this; } template inline Array2DView const Array3D::data_2D(int i) const { return Array2DView(_extentOne, _extentTwo, this->m.data() + i * _extentOne * _extentTwo); } template inline Array2DView Array3D::data_2D(int i) { return Array2DView(_extentOne, _extentTwo, this->m.data() + i * _extentOne * _extentTwo); } template inline Array1DView const Array3D::data_1D(int i, int j) const { return Array1DView(_extentTwo, this->m.data() + (i * _extentOne + j) * _extentTwo); } template inline Array1DView Array3D::data_1D(int i, int j) { return Array1DView(_extentTwo, this->m.data() + (i * _extentOne + j) * _extentTwo); } template inline void Array3D::resize(int const extentZero, int const extentOne, int const extentTwo) { _extentZero = extentZero; _extentOne = extentOne; _extentTwo = extentTwo; std::size_t const _n = _extentZero * _extentOne * _extentTwo; this->m.resize(_n); } template inline void Array3D::resize(int const extentZero, int const extentOne, int const extentTwo, DataType const new_value) { _extentZero = extentZero; _extentOne = extentOne; _extentTwo = extentTwo; std::size_t const _n = _extentZero * _extentOne * _extentTwo; this->m.resize(_n, new_value); } template inline void Array3D::resize(int const extentZero, int const extentOne, int const extentTwo, DataType const *new_array) { _extentZero = extentZero; _extentOne = extentOne; _extentTwo = extentTwo; std::size_t const _n = _extentZero * _extentOne * _extentTwo; this->m.resize(_n); std::copy(new_array, new_array + _n, this->m.data()); } template inline const DataType Array3D::operator()(int i, int j, int k) const { std::size_t const _n = (i * _extentOne + j) * _extentTwo + k; return this->m[_n]; } template inline DataType &Array3D::operator()(int i, int j, int k) { std::size_t const _n = (i * _extentOne + j) * _extentTwo + k; return this->m[_n]; } template inline DataType const Array3D::at(int i, int j, int k) const { this->_range_check(i, _extentZero); this->_range_check(j, _extentOne); this->_range_check(k, _extentTwo); std::size_t const _n = (i * _extentOne + j) * _extentTwo + k; return this->m[_n]; } template inline DataType &Array3D::at(int i, int j, int k) { this->_range_check(i, _extentZero); this->_range_check(j, _extentOne); this->_range_check(k, _extentTwo); std::size_t const _n = (i * _extentOne + j) * _extentTwo + k; return this->m[_n]; } template Array3D::j_operator::j_operator(Array3D &_array, int i) : j_array(_array), _i(i) {} template Array3D::j_operator::k_operator::k_operator(Array3D &_array, int i, int j) : k_array(_array), _i(i), _j(j) {} template DataType const Array3D::j_operator::k_operator::operator[](int k) const { std::size_t const _n = (_i * k_array._extentOne + _j) * k_array._extentTwo + k; return k_array.m[_n]; } template DataType &Array3D::j_operator::k_operator::operator[](int k) { std::size_t const _n = (_i * k_array._extentOne + _j) * k_array._extentTwo + k; return k_array.m[_n]; } template const typename Array3D::j_operator::k_operator Array3D::j_operator::operator[](int j) const { return k_operator(j_array, _i, j); } template typename Array3D::j_operator::k_operator Array3D::j_operator::operator[](int j) { return k_operator(j_array, _i, j); } template const typename Array3D::j_operator Array3D::operator[](int i) const { return j_operator(*this, i); } template typename Array3D::j_operator Array3D::operator[](int i) { return j_operator(*this, i); } #endif // SNAP_HELPER_HPP