diff --git a/include/span.h b/include/span.h index cbc766b..be7e74f 100644 --- a/include/span.h +++ b/include/span.h @@ -1045,174 +1045,6 @@ template class general_span_iterator; enum class byte : std::uint8_t {}; -template -class basic_span -{ -public: - static const size_t rank = BoundsType::rank; - using bounds_type = BoundsType; - using size_type = typename bounds_type::size_type; - using index_type = typename bounds_type::index_type; - using value_type = ValueType; - using const_value_type = std::add_const_t; - using pointer = ValueType*; - using reference = ValueType&; - using iterator = std::conditional_t::value, contiguous_span_iterator, general_span_iterator>; - using const_iterator = std::conditional_t::value, contiguous_span_iterator>, general_span_iterator>>; - using reverse_iterator = std::reverse_iterator; - using const_reverse_iterator = std::reverse_iterator; - using sliced_type = std::conditional_t>; - -private: - pointer m_pdata; - bounds_type m_bounds; - -public: - constexpr bounds_type bounds() const noexcept - { - return m_bounds; - } - template - constexpr size_type extent() const noexcept - { - static_assert(Dim < rank, "dimension should be less than rank (dimension count starts from 0)"); - return m_bounds.template extent(); - } - constexpr size_type size() const noexcept - { - return m_bounds.size(); - } - constexpr reference operator[](const index_type& idx) const - { - return m_pdata[m_bounds.linearize(idx)]; - } - constexpr pointer data() const noexcept - { - return m_pdata; - } - template 1), typename Ret = std::enable_if_t> - constexpr Ret operator[](size_type idx) const - { - fail_fast_assert(idx < m_bounds.size(), "index is out of bounds of the array"); - const size_type ridx = idx * m_bounds.stride(); - - fail_fast_assert(ridx < m_bounds.total_size(), "index is out of bounds of the underlying data"); - return Ret {m_pdata + ridx, m_bounds.slice()}; - } - - constexpr operator bool () const noexcept - { - return m_pdata != nullptr; - } - - constexpr iterator begin() const - { - return iterator {this, true}; - } - constexpr iterator end() const - { - return iterator {this, false}; - } - constexpr const_iterator cbegin() const - { - return const_iterator {reinterpret_cast *>(this), true}; - } - constexpr const_iterator cend() const - { - return const_iterator {reinterpret_cast *>(this), false}; - } - - constexpr reverse_iterator rbegin() const - { - return reverse_iterator {end()}; - } - constexpr reverse_iterator rend() const - { - return reverse_iterator {begin()}; - } - constexpr const_reverse_iterator crbegin() const - { - return const_reverse_iterator {cend()}; - } - constexpr const_reverse_iterator crend() const - { - return const_reverse_iterator {cbegin()}; - } - - template , std::remove_cv_t>::value>> - constexpr bool operator== (const basic_span & other) const noexcept - { - return m_bounds.size() == other.m_bounds.size() && - (m_pdata == other.m_pdata || std::equal(this->begin(), this->end(), other.begin())); - } - - template , std::remove_cv_t>::value>> - constexpr bool operator!= (const basic_span & other) const noexcept - { - return !(*this == other); - } - - template , std::remove_cv_t>::value>> - constexpr bool operator< (const basic_span & other) const noexcept - { - return std::lexicographical_compare(this->begin(), this->end(), other.begin(), other.end()); - } - - template , std::remove_cv_t>::value>> - constexpr bool operator<= (const basic_span & other) const noexcept - { - return !(other < *this); - } - - template , std::remove_cv_t>::value>> - constexpr bool operator> (const basic_span & other) const noexcept - { - return (other < *this); - } - - template , std::remove_cv_t>::value>> - constexpr bool operator>= (const basic_span & other) const noexcept - { - return !(*this < other); - } - -public: - template ::value - && std::is_convertible::value>> - constexpr basic_span(const basic_span & other ) noexcept - : m_pdata(other.m_pdata), m_bounds(other.m_bounds) - { - } -protected: - - constexpr basic_span(pointer data, bounds_type bound) noexcept - : m_pdata(data) - , m_bounds(std::move(bound)) - { - fail_fast_assert((m_bounds.size() > 0 && data != nullptr) || m_bounds.size() == 0); - } - template - constexpr basic_span(T *data, std::enable_if_t>::value, bounds_type> bound) noexcept - : m_pdata(reinterpret_cast(data)) - , m_bounds(std::move(bound)) - { - fail_fast_assert((m_bounds.size() > 0 && data != nullptr) || m_bounds.size() == 0); - } - template - constexpr basic_span as_span(const DestBounds &bounds) - { - details::verifyBoundsReshape(m_bounds, bounds); - return {m_pdata, bounds}; - } -private: - - friend iterator; - friend const_iterator; - template - friend class basic_span; -}; - template struct dim { @@ -1328,15 +1160,14 @@ class span friend class span; public: - using BoundsType = static_bounds; - static const size_t rank = BoundsType::rank; - using bounds_type = BoundsType; + using bounds_type = static_bounds; + static const size_t rank = bounds_type::rank; using size_type = typename bounds_type::size_type; using index_type = typename bounds_type::index_type; using value_type = ValueType; using const_value_type = std::add_const_t; - using pointer = ValueType*; - using reference = ValueType&; + using pointer = std::add_pointer_t; + using reference = std::add_lvalue_reference_t; using iterator = contiguous_span_iterator; using const_span = span; using const_iterator = contiguous_span_iterator; @@ -1353,40 +1184,45 @@ private: public: - constexpr span(pointer data, bounds_type bound) noexcept - : m_pdata(data), m_bounds(std::move(bound)) + constexpr span(pointer data, bounds_type bounds) noexcept + : m_pdata(data), m_bounds(std::move(bounds)) { fail_fast_assert((m_bounds.size() > 0 && data != nullptr) || m_bounds.size() == 0); } - constexpr span(pointer ptr, size_type size) : span(ptr, bounds_type{ size }) + constexpr span(pointer ptr, size_type size) noexcept + : span(ptr, bounds_type{ size }) {} - constexpr span(std::nullptr_t) : span(nullptr, bounds_type{}) + constexpr span(std::nullptr_t) noexcept + : span(nullptr, bounds_type{}) {} - constexpr span(std::nullptr_t, size_type size) : span(nullptr, bounds_type{}) + constexpr span(std::nullptr_t, size_type size) noexcept + : span(nullptr, bounds_type{}) { fail_fast_assert(size == 0); } // default template > - constexpr span() : span(nullptr, bounds_type()) + constexpr span() noexcept + : span(nullptr, bounds_type()) {} // from n-dimensions dynamic array (e.g. new int[m][4]) (precedence will be lower than the 1-dimension pointer) - template + template , + typename Dummy = std::enable_if_t>::value> /*typename Dummy = std::enable_if_t::value>*/ > - constexpr span(T* const& data, size_type size) : span(data, typename Helper::bounds_type{size}) + constexpr span(T* const& data, size_type size) : span(reinterpret_cast(data), typename Helper::bounds_type{size}) {} // from n-dimensions static array template , typename = std::enable_if_t::value> > - constexpr span (T (&arr)[N]) : span(arr, typename Helper::bounds_type()) + constexpr span (T (&arr)[N]) : span(reinterpret_cast(arr), typename Helper::bounds_type()) {} // from n-dimensions static array with size @@ -1436,13 +1272,13 @@ public: typename OtherBounds = static_bounds, typename Dummy = std::enable_if_t::value && std::is_convertible::value> > - constexpr span(const span& other) + constexpr span(const span& other) noexcept : m_pdata(other.m_pdata), m_bounds(other.m_bounds) {} // reshape // DimCount here is a workaround for a bug in MSVC 2015 - template 0)>> + template 0), typename Dummy = std::enable_if_t> constexpr span as_span(Dimensions2... dims) { using BoundsType = typename span::bounds_type; @@ -1550,19 +1386,19 @@ public: } // section - constexpr strided_span section(index_type origin, index_type extents) const + constexpr strided_span section(index_type origin, index_type extents) const noexcept { size_type size = this->bounds().total_size() - this->bounds().linearize(origin); return{ &this->operator[](origin), size, strided_bounds {extents, details::make_stride(bounds())} }; } - constexpr reference operator[](const index_type& idx) const + constexpr reference operator[](const index_type& idx) const noexcept { return m_pdata[m_bounds.linearize(idx)]; } template 1), typename Ret = std::enable_if_t> - constexpr Ret operator[](size_type idx) const + constexpr Ret operator[](size_type idx) const noexcept { fail_fast_assert(idx < m_bounds.size(), "index is out of bounds of the array"); const size_type ridx = idx * m_bounds.stride(); @@ -1598,42 +1434,42 @@ public: return m_pdata != nullptr; } - constexpr iterator begin() const + constexpr iterator begin() const noexcept { return iterator{ this, true }; } - constexpr iterator end() const + constexpr iterator end() const noexcept { return iterator{ this, false }; } - constexpr const_iterator cbegin() const + constexpr const_iterator cbegin() const noexcept { return const_iterator{ reinterpret_cast(this), true }; } - constexpr const_iterator cend() const + constexpr const_iterator cend() const noexcept { return const_iterator{ reinterpret_cast(this), false }; } - constexpr reverse_iterator rbegin() const + constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{ end() }; } - constexpr reverse_iterator rend() const + constexpr reverse_iterator rend() const noexcept { return reverse_iterator{ begin() }; } - constexpr const_reverse_iterator crbegin() const + constexpr const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator{ cend() }; } - constexpr const_reverse_iterator crend() const + constexpr const_reverse_iterator crend() const noexcept { return const_reverse_iterator{ cbegin() }; } @@ -1674,22 +1510,6 @@ public: { return !(*this < other); } - -private: - - template - constexpr span(T *data, std::enable_if_t>::value, bounds_type> bound) noexcept - : m_pdata(reinterpret_cast(data)), m_bounds(std::move(bound)) - { - fail_fast_assert((m_bounds.size() > 0 && data != nullptr) || m_bounds.size() == 0); - } - - template - constexpr span as_span(const static_bounds &bounds) - { - details::verifyBoundsReshape(m_bounds, bounds); - return{ m_pdata, bounds }; - } }; template @@ -1744,56 +1564,62 @@ constexpr auto as_span(Cont &&arr) -> std::enable_if_t, dynamic_range>> = delete; template -class strided_span : public basic_span> +class strided_span { - using Base = basic_span>; +public: + using bounds_type = strided_bounds; + using size_type = typename bounds_type::size_type; + using index_type = typename bounds_type::index_type; + using value_type = ValueType; + using const_value_type = std::add_const_t; + using pointer = std::add_pointer_t; + using reference = std::add_lvalue_reference_t; + using iterator = general_span_iterator; + using const_strided_span = strided_span; + using const_iterator = general_span_iterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using sliced_type = std::conditional_t>; - template +private: + pointer m_pdata; + bounds_type m_bounds; + + friend iterator; + friend const_iterator; + template friend class strided_span; public: - using Base::rank; - using typename Base::bounds_type; - using typename Base::size_type; - using typename Base::pointer; - using typename Base::value_type; - using typename Base::index_type; - using typename Base::iterator; - using typename Base::const_iterator; - using typename Base::reference; - - // from static array of size N - template - strided_span(value_type(&values)[N], bounds_type bounds) : Base(values, std::move(bounds)) - { - fail_fast_assert(this->bounds().total_size() <= N, "Bounds cross data boundaries"); - } - // from raw data - strided_span(pointer ptr, size_type size, bounds_type bounds): Base(ptr, std::move(bounds)) + constexpr strided_span(pointer ptr, size_type size, bounds_type bounds) + : m_pdata(ptr), m_bounds(std::move(bounds)) { + fail_fast_assert((m_bounds.size() > 0 && ptr != nullptr) || m_bounds.size() == 0); fail_fast_assert(this->bounds().total_size() <= size, "Bounds cross data boundaries"); } + // from static array of size N + template + constexpr strided_span(value_type(&values)[N], bounds_type bounds) : strided_span(values, N, std::move(bounds)) + {} + // from array view template > - strided_span(span av, bounds_type bounds) : Base(av.data(), std::move(bounds)) - { - fail_fast_assert(this->bounds().total_size() <= av.bounds().total_size(), "Bounds cross data boundaries"); - } + constexpr strided_span(span av, bounds_type bounds) : strided_span(av.data(), av.bounds().total_size(), std::move(bounds)) + {} // convertible template >, - typename OtherBaseType = basic_span>, - typename Dummy = std::enable_if_t::value> + typename Dummy = std::enable_if_t::value> > - constexpr strided_span(const strided_span &av) : Base(static_cast::Base &>(av)) // static_cast is required + constexpr strided_span(const strided_span& other) + : m_pdata(other.m_pdata), m_bounds(other.m_bounds) {} // convert from bytes - template - strided_span::value, OtherValueType>::type, rank> as_strided_span() const + template + constexpr strided_span::value, OtherValueType>::type, Rank> as_strided_span() const { static_assert((sizeof(OtherValueType) >= sizeof(value_type)) && (sizeof(OtherValueType) % sizeof(value_type) == 0), "OtherValueType should have a size to contain a multiple of ValueTypes"); auto d = static_cast(sizeof(OtherValueType) / sizeof(value_type)); @@ -1802,54 +1628,163 @@ public: return{ (OtherValueType*)this->data(), size, bounds_type{ resize_extent(this->bounds().index_bounds(), d), resize_stride(this->bounds().strides(), d)} }; } - strided_span section(index_type origin, index_type extents) const + constexpr strided_span section(index_type origin, index_type extents) const { size_type size = this->bounds().total_size() - this->bounds().linearize(origin); - return { &this->operator[](origin), size, bounds_type {extents, details::make_stride(Base::bounds())}}; + return { &this->operator[](origin), size, bounds_type {extents, details::make_stride(bounds())}}; } constexpr reference operator[](const index_type& idx) const { - return Base::operator[](idx); + return m_pdata[m_bounds.linearize(idx)]; } - template 1), typename Dummy = std::enable_if_t> - constexpr strided_span operator[](size_type idx) const + template 1), typename Ret = std::enable_if_t> + constexpr Ret operator[](size_type idx) const { - auto ret = Base::operator[](idx); - return{ ret.data(), ret.bounds().total_size(), ret.bounds() }; + fail_fast_assert(idx < m_bounds.size(), "index is out of bounds of the array"); + const size_type ridx = idx * m_bounds.stride(); + + fail_fast_assert(ridx < m_bounds.total_size(), "index is out of bounds of the underlying data"); + return{ m_pdata + ridx, m_bounds.slice().total_size(), m_bounds.slice() }; + } + + constexpr bounds_type bounds() const noexcept + { + return m_bounds; + } + + template + constexpr size_type extent() const noexcept + { + static_assert(Dim < Rank, "dimension should be less than Rank (dimension count starts from 0)"); + return m_bounds.template extent(); + } + + constexpr size_type size() const noexcept + { + return m_bounds.size(); + } + + constexpr pointer data() const noexcept + { + return m_pdata; + } + + constexpr operator bool() const noexcept + { + return m_pdata != nullptr; + } + + constexpr iterator begin() const + { + return iterator{ this, true }; + } + + constexpr iterator end() const + { + return iterator{ this, false }; + } + + constexpr const_iterator cbegin() const + { + return const_iterator{ reinterpret_cast(this), true }; + } + + constexpr const_iterator cend() const + { + return const_iterator{ reinterpret_cast(this), false }; + } + + constexpr reverse_iterator rbegin() const + { + return reverse_iterator{ end() }; + } + + constexpr reverse_iterator rend() const + { + return reverse_iterator{ begin() }; + } + + constexpr const_reverse_iterator crbegin() const + { + return const_reverse_iterator{ cend() }; + } + + constexpr const_reverse_iterator crend() const + { + return const_reverse_iterator{ cbegin() }; + } + + template , std::remove_cv_t>::value>> + constexpr bool operator== (const strided_span& other) const noexcept + { + return m_bounds.size() == other.m_bounds.size() && + (m_pdata == other.m_pdata || std::equal(this->begin(), this->end(), other.begin())); + } + + template , std::remove_cv_t>::value>> + constexpr bool operator!= (const strided_span& other) const noexcept + { + return !(*this == other); + } + + template , std::remove_cv_t>::value>> + constexpr bool operator< (const strided_span& other) const noexcept + { + return std::lexicographical_compare(this->begin(), this->end(), other.begin(), other.end()); + } + + template , std::remove_cv_t>::value>> + constexpr bool operator<= (const strided_span& other) const noexcept + { + return !(other < *this); + } + + template , std::remove_cv_t>::value>> + constexpr bool operator> (const strided_span& other) const noexcept + { + return (other < *this); + } + + template , std::remove_cv_t>::value>> + constexpr bool operator>= (const strided_span& other) const noexcept + { + return !(*this < other); } private: static index_type resize_extent(const index_type& extent, std::ptrdiff_t d) { - fail_fast_assert(extent[rank - 1] >= d && (extent[rank-1] % d == 0), "The last dimension of the array needs to contain a multiple of new type elements"); + fail_fast_assert(extent[Rank - 1] >= d && (extent[Rank-1] % d == 0), "The last dimension of the array needs to contain a multiple of new type elements"); index_type ret = extent; - ret[rank - 1] /= d; + ret[Rank - 1] /= d; return ret; } - template > + template > static index_type resize_stride(const index_type& strides, std::ptrdiff_t , void * = 0) { - fail_fast_assert(strides[rank - 1] == 1, "Only strided arrays with regular strides can be resized"); + fail_fast_assert(strides[Rank - 1] == 1, "Only strided arrays with regular strides can be resized"); return strides; } - template 1), typename Dummy = std::enable_if_t> + template 1), typename Dummy = std::enable_if_t> static index_type resize_stride(const index_type& strides, std::ptrdiff_t d) { - fail_fast_assert(strides[rank - 1] == 1, "Only strided arrays with regular strides can be resized"); - fail_fast_assert(strides[rank - 2] >= d && (strides[rank - 2] % d == 0), "The strides must have contiguous chunks of memory that can contain a multiple of new type elements"); + fail_fast_assert(strides[Rank - 1] == 1, "Only strided arrays with regular strides can be resized"); + fail_fast_assert(strides[Rank - 2] >= d && (strides[Rank - 2] % d == 0), "The strides must have contiguous chunks of memory that can contain a multiple of new type elements"); - for (size_t i = rank - 1; i > 0; --i) - fail_fast_assert((strides[i-1] >= strides[i]) && (strides[i-1] % strides[i] == 0), "Only strided arrays with regular strides can be resized"); + for (size_t i = Rank - 1; i > 0; --i) + { + fail_fast_assert((strides[i - 1] >= strides[i]) && (strides[i - 1] % strides[i] == 0), "Only strided arrays with regular strides can be resized"); + } index_type ret = strides / d; - ret[rank - 1] = 1; + ret[Rank - 1] = 1; return ret; } @@ -1986,12 +1921,12 @@ public: using typename Base::difference_type; using typename Base::value_type; private: - template - friend class basic_span; + template + friend class strided_span; - const Span * m_container; + const Span* m_container; typename Span::bounds_type::iterator m_itr; - general_span_iterator(const Span *container, bool isbegin) : + general_span_iterator(const Span* container, bool isbegin) : m_container(container), m_itr(isbegin ? m_container->bounds().begin() : m_container->bounds().end()) {} public: @@ -2115,7 +2050,7 @@ general_span_iterator operator+(typename general_span_iterator::diff #endif // _MSC_VER #if defined(GSL_THROWS_FOR_TESTING) -#undef noexcept +#undef noexcept #endif // GSL_THROWS_FOR_TESTING diff --git a/tests/span_tests.cpp b/tests/span_tests.cpp index ecb2c4e..8a7c552 100644 --- a/tests/span_tests.cpp +++ b/tests/span_tests.cpp @@ -284,7 +284,7 @@ SUITE(span_tests) CHECK((av_section_2[{0, 1}] == 25)); CHECK((av_section_2[{1, 0}] == 34)); } - + TEST(strided_span_constructors) { // Check stride constructor @@ -1406,7 +1406,7 @@ SUITE(span_tests) } } - TEST(custmized_span_size) + TEST(customized_span_size) { double (*arr)[3][4] = new double[100][3][4]; span av1(arr, 10);