/* Copyright 2019 The Mathworks, Inc. */ /* Copied from * fullfile(matlabroot,'extern','include','coder','coder_array','coder_array_rtw_cpp11.h') */ #ifndef _mw_coder_array_cpp11_h #define _mw_coder_array_cpp11_h // Usage: // // coder::array: T base type of data, N number of dimensions // // coder::array() // : default constructor // coder::array(coder::array const &) // : copy constructor (always make a deep copy of other array) // coder::array(T const *data, SizeType const *sz) // : Set data with sizes of this array. // : (Data is not copied, data is not deleted) // coder::array::operator = (coder coder::array &) // : Assign into this array; // : delete its previous contents (if owning the data.) // set(T const *data, SizeType sz1, SizeType sz2, ...) // : Set data with dimensions. // : (Data is not copied, data is not deleted) // set_size(SizeType sz1, SizeType sz2, ...) // : Set sizes of array. Reallocate memory of data if needed. // bool is_owner() : Return true if the data is owned by the class. // void set_owner(b) : Set if the data is owned by the class. // SizeType capacity() : How many entries are reserved by memory allocation. // reshape( SizeType sz1, SizeType sz2, ...) // : Reshape array to a different ND shape. Do not copy the data. // : The number of elements must not be changed (numel()==sz1*sz2*...) // : Return the array with possibly new number of dimensions. // clear() : Reset array to be empty. // SizeType numel() : Return the number of elements. // operator [] (SizeType index) : Extract element at linear index (0 based.) // size(SizeType dimension) : Size of array of the provided dimension. // SizeType * size() : Return the pointer to all the sizes of this array. // SizeType index(SizeType i1, SizeType i2, ...) // : Compute the linear index from ND index (i1,i2,...) // at(SizeType i1, SizeType i2, ...) : The element at index (i1,i2,...) #include #include #include #include #include #ifndef INT32_T #include "../rtwtypes.h" #endif namespace coder { #ifndef CODER_ARRAY_NEW_DELETE #define CODER_ARRAY_NEW_DELETE #define CODER_NEW(T, N) new T[N] #define CODER_DELETE(P) delete[](P) #endif #ifndef CODER_ARRAY_SIZE_TYPE_DEFINED using SizeType = int; #endif namespace std = ::std; namespace detail { #ifndef CODER_ARRAY_DATA_PTR_DEFINED template class data_ptr { public: using value_type = T; using size_type = SZ; data_ptr() : data_(nullptr) , size_(0) , capacity_(0) , owner_(false) { } data_ptr(T* _data, SZ _sz) : data_(_data) , size_(_sz) , capacity_(_sz) , owner_(false) { } data_ptr(data_ptr const& _other) : data_(_other.owner_ ? nullptr : _other.data_) , size_(_other.owner_ ? 0 : _other.size_) , capacity_(_other.owner_ ? 0 : _other.capacity_) , owner_(_other.owner_) { if (owner_) { resize(_other.size_); (void)std::copy(_other.data_, _other.data_ + size_, data_); } } ~data_ptr() { if (owner_) { CODER_DELETE(data_); } } SZ capacity() const { return capacity_; } void reserve(SZ _n) { if (_n > capacity_) { T* const new_data{CODER_NEW(T, _n)}; (void)std::copy(data_, data_ + size_, new_data); if (owner_) { CODER_DELETE(data_); } data_ = new_data; capacity_ = _n; owner_ = true; } } void resize(SZ _n) { reserve(_n); size_ = _n; } private: // Prohibit use of assignment operator to prevent subtle bugs void operator=(data_ptr const& _other); public: void set(T* _data, SZ _sz) { if (owner_) { CODER_DELETE(data_); } data_ = _data; size_ = _sz; owner_ = false; capacity_ = size_; } void copy(T const* const _data, SZ _size) { if (data_ == _data) { size_ = _size; return; } if (owner_) { CODER_DELETE(data_); } data_ = CODER_NEW(T, _size); owner_ = true; size_ = _size; capacity_ = size_; (void)std::copy(_data, _data + _size, data_); } void copy(data_ptr const& _other) { copy(_other.data_, _other.size_); } operator T*() { return &data_[0]; } operator T const *() const { return &data_[0]; } T& operator[](SZ _index) { return data_[_index]; } T const& operator[](SZ _index) const { return data_[_index]; } T* operator->() { return data_; } T const* operator->() const { return data_; } bool is_null() const { return data_ == nullptr; } void clear() { if (owner_) { CODER_DELETE(data_); } data_ = nullptr; size_ = 0; capacity_ = 0; owner_ = false; } bool is_owner() const { return owner_; } void set_owner(bool _b) { owner_ = _b; } private: T* data_; SZ size_; SZ capacity_; bool owner_; }; #endif } // namespace detail // Implementing the random access iterator class so coder::array can be // used in STL iterators. template class array_iterator : public std::iterator { public: array_iterator() : arr_(nullptr) , i_(0) { } array_iterator(array_iterator const& other) : arr_(other.arr_) , i_(other.i_) { } ~array_iterator() { } typename T::value_type& operator*() const { return (*arr_)[i_]; } typename T::value_type* operator->() const { return &(*arr_)[i_]; } typename T::value_type& operator[](typename T::size_type _di) const { return (*arr_)[i_ + _di]; } array_iterator& operator++() { ++i_; return *this; } array_iterator& operator--() { --i_; return *this; } array_iterator operator++(int) { array_iterator cp{*this}; ++i_; return cp; } array_iterator operator--(int) { array_iterator cp{*this}; --i_; return cp; } array_iterator& operator=(array_iterator const& _other) { this->i_ = _other.i_; return *this; } bool operator==(array_iterator const& _other) const { return i_ == _other.i_; } bool operator!=(array_iterator const& _other) const { return i_ != _other.i_; } bool operator<(array_iterator const& _other) const { return i_ < _other.i_; } bool operator>(array_iterator const& _other) const { return i_ > _other.i_; } bool operator<=(array_iterator const& _other) const { return i_ <= _other.i_; } bool operator>=(array_iterator const& _other) const { return i_ >= _other.i_; } array_iterator operator+(typename T::size_type _add) const { array_iterator cp{*this}; cp.i_ += _add; return cp; } array_iterator& operator+=(typename T::size_type _add) { this->i_ += _add; return *this; } array_iterator operator-(typename T::size_type _subtract) const { array_iterator cp{*this}; cp.i_ -= _subtract; return cp; } array_iterator& operator-=(typename T::size_type _subtract) { this->i_ -= _subtract; return *this; } typename T::size_type operator-(array_iterator const& _other) const { return static_cast(this->i_ - _other.i_); } array_iterator(T* _arr, typename T::size_type _i) : arr_(_arr) , i_(_i) { } private: T* arr_; typename T::size_type i_; }; // Const version of the array iterator. template class const_array_iterator : public std::iterator { public: const_array_iterator() : arr_(nullptr) , i_(0) { } const_array_iterator(const_array_iterator const& other) : arr_(other.arr_) , i_(other.i_) { } ~const_array_iterator() { } typename T::value_type const& operator*() const { return (*arr_)[i_]; } typename T::value_type const* operator->() const { return &(*arr_)[i_]; } typename T::value_type const& operator[](typename T::size_type _di) const { return (*arr_)[i_ + _di]; } const_array_iterator& operator++() { ++i_; return *this; } const_array_iterator& operator--() { --i_; return *this; } const_array_iterator operator++(int) { const_array_iterator copy{*this}; ++i_; return copy; } const_array_iterator operator--(int) { const_array_iterator copy{*this}; --i_; return copy; } const_array_iterator& operator=(const_array_iterator const& _other) { this->i_ = _other.i_; return *this; } bool operator==(const_array_iterator const& _other) const { return i_ == _other.i_; } bool operator!=(const_array_iterator const& _other) const { return i_ != _other.i_; } bool operator<(const_array_iterator const& _other) const { return i_ < _other.i_; } bool operator>(const_array_iterator const& _other) const { return i_ > _other.i_; } bool operator<=(const_array_iterator const& _other) const { return i_ <= _other.i_; } bool operator>=(const_array_iterator const& _other) const { return i_ >= _other.i_; } const_array_iterator operator+(typename T::size_type _add) const { const_array_iterator cp{*this}; cp.i_ += _add; return cp; } const_array_iterator& operator+=(typename T::size_type _add) { this->i_ += _add; return *this; } const_array_iterator operator-(typename T::size_type _subtract) const { const_array_iterator cp{*this}; cp.i_ -= _subtract; return cp; } const_array_iterator& operator-=(typename T::size_type _subtract) { this->i_ -= _subtract; return *this; } typename T::size_type operator-(const_array_iterator const& _other) const { return static_cast(this->i_ - _other.i_); } const_array_iterator(T const* _arr, typename T::size_type _i) : arr_(_arr) , i_(_i) { } private: T const* arr_; typename T::size_type i_; typename T::size_type n_; }; namespace detail { // detail::numel: Compile-time product of the given size vector of length N. template class numel { public: template static SZ compute(SZ _size[]) { return _size[N - 1] * numel::compute(_size); } }; template <> class numel<0> { public: template static SZ compute(SZ[]) { return 1; } }; // Compute the product for a set of numeric arguments: product(10, 20, 30, ...) => // 10*20*30*... template struct product_i { static SZ compute(First _f, Rest... _rest) { return _f * product_i::compute(_rest...); } }; template struct product_i { static SZ compute(Last _l) { return _l; } }; template SZ product(Args... args) { return product_i::compute(args...); } // Compute flat index from (column-major) ND size vector and a list of indices. template class index_nd { public: template static SZ compute(SZ const _size[], SZ const _indices[]) { SZ const weight{numel::compute(_size)}; return weight * _indices[I - 1] + index_nd::compute(_size, _indices); } }; template <> class index_nd<0> { public: template static SZ compute(SZ[], SZ[]) { return 0; } }; template struct match_dimensions {}; template <> struct match_dimensions { static void check() { } }; } // namespace detail // Base class for code::array. SZ is the type used for sizes (currently int32_t.) // Overloading up to 10 dimensions (not using variadic templates to // stay compatible with C++98.) template class array_base { public: using value_type = T; using size_type = SZ; array_base() { (void)::memset(size_, 0, sizeof(SZ) * N); } array_base(T* _data, SZ const* _sz) : data_(_data, coder::detail::numel::compute(_sz)) { (void)std::copy(_sz, _sz + N, size_); } array_base& operator=(array_base const& _other) { data_.copy(_other.data_); (void)std::copy(_other.size_, _other.size_ + N, size_); return *this; } template void set(T* _data, Dims... dims) { coder::detail::match_dimensions::check(); data_.set(_data, coder::detail::product(dims...)); set_size_i<0>(dims...); } bool is_owner() const { return data_.is_owner(); } void set_owner(bool b) { data_.set_owner(b); } SZ capacity() const { return data_.capacity(); } private: template void set_size_i(First f, Rest... rest) { size_[_i] = f; set_size_i<_i + 1, Rest...>(rest...); } template void set_size_i(Last l) { size_[_i] = l; } public: template void set_size(Dims... dims) { coder::detail::match_dimensions::check(); set_size_i<0>(dims...); ensureCapacity(numel()); } template array_base reshape_n(SZ const (&_ns)[N1]) const { array_base reshaped{const_cast(&data_[0]), _ns}; return reshaped; } template array_base(sizeof...(Dims))> reshape(Dims... dims) const { SZ const ns[]{static_cast(dims)...}; return reshape_n(ns); } T& operator[](SZ _index) { return data_[_index]; } T const& operator[](SZ _index) const { return data_[_index]; } void clear() { data_.clear(); } T* data() { return data_; } T const* data() const { return data_; } SZ const* size() const { return &size_[0]; } SZ size(SZ _index) const { return size_[_index]; } SZ numel() const { return coder::detail::numel::compute(size_); } template SZ index(Dims... _dims) const { coder::detail::match_dimensions::check(); SZ const indices[]{static_cast(_dims)...}; return coder::detail::index_nd(sizeof...(_dims))>::compute(size_, indices); } template T& at(Dims... _i) { coder::detail::match_dimensions::check(); return data_[index(_i...)]; } template T const& at(Dims... _i) const { coder::detail::match_dimensions::check(); return data_[index(_i...)]; } array_iterator > begin() { return array_iterator >(this, 0); } array_iterator > end() { return array_iterator >(this, this->numel()); } const_array_iterator > begin() const { return const_array_iterator >(this, 0); } const_array_iterator > end() const { return const_array_iterator >(this, this->numel()); } protected: coder::detail::data_ptr data_; SZ size_[N]; private: void ensureCapacity(SZ _newNumel) { if (_newNumel > data_.capacity()) { SZ i{data_.capacity()}; if (i < 16) { i = 16; } while (i < _newNumel) { if (i > 1073741823) { i = MAX_int32_T; } else { i *= 2; } } data_.reserve(i); } data_.resize(_newNumel); } }; // The standard coder::array class with base type and number of dimensions. template class array : public array_base { private: using Base = array_base; public: array() : Base() { } array(array const& _other) : Base(_other) { } array(Base const& _other) : Base(_other) { } array(T* _data, SizeType const* _sz) : Base(_data, _sz) { } }; // Specialize on char_T (row vector) for better support on strings. template <> class array : public array_base { private: using Base = array_base; public: array() : array_base() { } array(array const& _other) : Base(_other) { } array(Base const& _other) : Base(_other) { } array(std::string const& _str) { operator=(_str); } array(char_T const* const _str) { operator=(_str); } array(std::vector const& _vec) { SizeType const n{static_cast(_vec.size())}; set_size(1, n); data_.copy(&_vec[0], n); } array& operator=(std::string const& _str) { SizeType const n{static_cast(_str.size())}; set_size(1, n); data_.copy(_str.c_str(), n); return *this; } array& operator=(char_T const* const _str) { SizeType const n{static_cast(strlen(_str))}; set_size(1, n); data_.copy(_str, n); return *this; } operator std::string() const { return std::string(static_cast(&(*this)[0]), static_cast(size(1))); } }; // Specialize on 2 dimensions for better support interactions with // std::vector and row vectors. template class array : public array_base { private: using Base = array_base; public: array() : Base() { } array(array const& _other) : Base(_other) { } array(Base const& _other) : Base(_other) { } array(std::vector const& _vec) { operator=(_vec); } array& operator=(std::vector const& _vec) { SizeType n{static_cast(_vec.size())}; Base::set_size(1, n); Base::data_.copy(&_vec[0], n); return *this; } operator std::vector() const { T const* p{&Base::data_[0]}; return std::vector(p, p + Base::numel()); } }; // Specialize on 1 dimension for better support with std::vector and // column vectors. template class array : public array_base { private: using Base = array_base; public: array() : Base() { } array(array const& _other) : Base(_other) { } array(Base const& _other) : Base(_other) { } array(std::vector const& _vec) { operator=(_vec); } array& operator=(std::vector const& _vec) { SizeType n{static_cast(_vec.size())}; Base::set_size(n); Base::data_.copy(&_vec[0], n); return *this; } operator std::vector() const { T const* p{&Base::data_[0]}; return std::vector(p, p + Base::numel()); } }; } // namespace coder #endif