From 8aa42487225a537ddedac668ec14e179bb481935 Mon Sep 17 00:00:00 2001 From: Anna Gringauze Date: Wed, 11 Nov 2015 12:41:11 -0800 Subject: [PATCH 1/2] Removing basic_span base class from span --- include/span.h | 328 ++++++++++++++++++++++++++++++------------- tests/span_tests.cpp | 19 +-- 2 files changed, 239 insertions(+), 108 deletions(-) diff --git a/include/span.h b/include/span.h index f4a57d9..cbc766b 100644 --- a/include/span.h +++ b/include/span.h @@ -111,19 +111,19 @@ public: std::copy(values, values + Rank, elems); } -#ifdef GSL_MSVC_HAS_VARIADIC_CTOR_BUG - template::value && - details::are_integral::value>> - constexpr index(T t, Ts... ds) : index({ static_cast(t), static_cast(ds)... }) - {} -#else - template::value>> - constexpr index(Ts... ds) noexcept : elems{ static_cast(ds)... } - {} -#endif +#ifdef GSL_MSVC_HAS_VARIADIC_CTOR_BUG + template::value && + details::are_integral::value>> + constexpr index(T t, Ts... ds) : index({ static_cast(t), static_cast(ds)... }) + {} +#else + template::value>> + constexpr index(Ts... ds) noexcept : elems{ static_cast(ds)... } + {} +#endif constexpr index(const index& other) noexcept = default; @@ -1039,9 +1039,9 @@ namespace details } // namespace details -template +template class contiguous_span_iterator; -template +template class general_span_iterator; enum class byte : std::uint8_t {}; @@ -1235,21 +1235,21 @@ class strided_span; namespace details { template - struct ArrayViewTypeTraits + struct SpanTypeTraits { using value_type = T; using size_type = size_t; }; template - struct ArrayViewTypeTraits::type> + struct SpanTypeTraits::type> { using value_type = typename Traits::span_traits::value_type; using size_type = typename Traits::span_traits::size_type; }; template - struct ArrayViewArrayTraits { + struct SpanArrayTraits { using type = span; using value_type = T; using bounds_type = static_bounds; @@ -1257,7 +1257,7 @@ namespace details using reference = T&; }; template - struct ArrayViewArrayTraits : ArrayViewArrayTraits {}; + struct SpanArrayTraits : SpanArrayTraits {}; template BoundsType newBoundsHelperImpl(std::ptrdiff_t totalSize, std::true_type) // dynamic size @@ -1322,108 +1322,122 @@ namespace details template -class span : public basic_span > +class span { - template + template friend class span; - using Base = basic_span>; +public: + using BoundsType = static_bounds; + 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 = contiguous_span_iterator; + using const_span = span; + using const_iterator = contiguous_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; + + friend iterator; + friend const_iterator; public: - 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; - using Base::rank; -public: - // basic - constexpr span(pointer ptr, size_type size) : Base(ptr, bounds_type{ size }) + constexpr 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); + } + + constexpr span(pointer ptr, size_type size) : span(ptr, bounds_type{ size }) {} - constexpr span(pointer ptr, bounds_type bounds) : Base(ptr, std::move(bounds)) + constexpr span(std::nullptr_t) : span(nullptr, bounds_type{}) {} - constexpr span(std::nullptr_t) : Base(nullptr, bounds_type{}) - {} - - constexpr span(std::nullptr_t, size_type size) : Base(nullptr, bounds_type{}) + constexpr span(std::nullptr_t, size_type size) : span(nullptr, bounds_type{}) { fail_fast_assert(size == 0); } // default template > - constexpr span() : Base(nullptr, bounds_type()) + constexpr span() : 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 - /*typename Dummy = std::enable_if_t::value>*/> - constexpr span(T* const& data, size_type size) : Base(data, typename Helper::bounds_type{size}) + template + /*typename Dummy = std::enable_if_t::value>*/ + > + constexpr span(T* const& data, size_type size) : span(data, typename Helper::bounds_type{size}) {} // from n-dimensions static array - template , - typename = std::enable_if_t::value>> - constexpr span (T (&arr)[N]) : Base(arr, typename Helper::bounds_type()) + template , + typename = std::enable_if_t::value> + > + constexpr span (T (&arr)[N]) : span(arr, typename Helper::bounds_type()) {} // from n-dimensions static array with size - template , - typename = std::enable_if_t::value> + template , + typename = std::enable_if_t::value> > - constexpr span(T(&arr)[N], size_type size) : Base(arr, typename Helper::bounds_type{size}) + constexpr span(T(&arr)[N], size_type size) : span(arr, typename Helper::bounds_type{size}) { fail_fast_assert(size <= N); } // from std array template , typename Base::bounds_type>::value> + typename Dummy = std::enable_if_t, bounds_type>::value> > - constexpr span (std::array, N> & arr) : Base(arr.data(), static_bounds()) + constexpr span (std::array, N> & arr) : span(arr.data(), static_bounds()) {} template , typename Base::bounds_type>::value + typename Dummy = std::enable_if_t, bounds_type>::value && std::is_const::value> > - constexpr span (const std::array, N> & arr) : Base(arr.data(), static_bounds()) + constexpr span (const std::array, N> & arr) : span(arr.data(), static_bounds()) {} // from begin, end pointers. We don't provide iterator pair since no way to guarantee the contiguity template ::value - && details::LessThan::value> + && details::LessThan::value> > // remove literal 0 case - constexpr span (pointer begin, Ptr end) : Base(begin, details::newBoundsHelper(static_cast(end) - begin)) + constexpr span (pointer begin, Ptr end) : span(begin, details::newBoundsHelper(static_cast(end) - begin)) {} // from containers. It must has .size() and .data() two function signatures template ::value - && std::is_convertible::value + && std::is_convertible::value && std::is_same().size(), *std::declval().data())>, DataType>::value> > - constexpr span (Cont& cont) : Base(static_cast(cont.data()), details::newBoundsHelper(cont.size())) + constexpr span (Cont& cont) : span(static_cast(cont.data()), details::newBoundsHelper(cont.size())) {} constexpr span(const span &) = default; // convertible template >, - typename OtherBaseType = basic_span>, - typename Dummy = std::enable_if_t::value> + typename OtherBounds = static_bounds, + typename Dummy = std::enable_if_t::value && std::is_convertible::value> > - constexpr span(const span &av) - : Base(static_cast::Base&>(av)) + constexpr span(const span& other) + : m_pdata(other.m_pdata), m_bounds(other.m_bounds) {} // reshape @@ -1454,18 +1468,18 @@ public: // from bytes array template::value, typename = std::enable_if_t> - constexpr auto as_span() const noexcept -> span(static_cast(Base::bounds_type::static_size) / sizeof(U)) : dynamic_range)> + constexpr auto as_span() const noexcept -> span(static_cast(bounds_type::static_size) / sizeof(U)) : dynamic_range)> { - static_assert(std::is_standard_layout::value && (Base::bounds_type::static_size == dynamic_range || Base::bounds_type::static_size % static_cast(sizeof(U)) == 0), + static_assert(std::is_standard_layout::value && (bounds_type::static_size == dynamic_range || bounds_type::static_size % static_cast(sizeof(U)) == 0), "Target type must be standard layout and its size must match the byte array size"); fail_fast_assert((this->bytes() % sizeof(U)) == 0 && (this->bytes() / sizeof(U)) < PTRDIFF_MAX); return { reinterpret_cast(this->data()), this->bytes() / static_cast(sizeof(U)) }; } template::value, typename = std::enable_if_t> - constexpr auto as_span() const noexcept -> span(static_cast(Base::bounds_type::static_size) / sizeof(U)) : dynamic_range)> + constexpr auto as_span() const noexcept -> span(static_cast(bounds_type::static_size) / sizeof(U)) : dynamic_range)> { - static_assert(std::is_standard_layout::value && (Base::bounds_type::static_size == dynamic_range || Base::bounds_type::static_size % static_cast(sizeof(U)) == 0), + static_assert(std::is_standard_layout::value && (bounds_type::static_size == dynamic_range || bounds_type::static_size % static_cast(sizeof(U)) == 0), "Target type must be standard layout and its size must match the byte array size"); fail_fast_assert((this->bytes() % sizeof(U)) == 0); return { reinterpret_cast(this->data()), this->bytes() / static_cast(sizeof(U)) }; @@ -1539,27 +1553,143 @@ public: 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, strided_bounds {extents, details::make_stride(Base::bounds())} }; + 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 { - return Base::operator[](idx); + return m_pdata[m_bounds.linearize(idx)]; } - template 1), typename Dummy = std::enable_if_t> - constexpr 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() }; + 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() }; } - using Base::operator==; - using Base::operator!=; - using Base::operator<; - using Base::operator<=; - using Base::operator>; - using Base::operator>=; + 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 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 span & other) const noexcept + { + return !(*this == other); + } + + template , std::remove_cv_t>::value>> + constexpr bool operator< (const 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 span & other) const noexcept + { + return !(other < *this); + } + + template , std::remove_cv_t>::value>> + constexpr bool operator> (const span & other) const noexcept + { + return (other < *this); + } + + template , std::remove_cv_t>::value>> + constexpr bool operator>= (const span & other) const noexcept + { + 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 @@ -1569,13 +1699,13 @@ constexpr auto as_span(T* const& ptr, dim... args) -> span -constexpr auto as_span (T* arr, std::ptrdiff_t len) -> typename details::ArrayViewArrayTraits::type +constexpr auto as_span (T* arr, std::ptrdiff_t len) -> typename details::SpanArrayTraits::type { return {reinterpret_cast*>(arr), len}; } template -constexpr auto as_span (T (&arr)[N]) -> typename details::ArrayViewArrayTraits::type +constexpr auto as_span (T (&arr)[N]) -> typename details::SpanArrayTraits::type { return {arr}; } @@ -1725,26 +1855,26 @@ private: } }; -template -class contiguous_span_iterator : public std::iterator +template +class contiguous_span_iterator : public std::iterator { - using Base = std::iterator; + using Base = std::iterator; public: using typename Base::reference; using typename Base::pointer; using typename Base::difference_type; private: - template - friend class basic_span; + template + friend class span; pointer m_pdata; - const ArrayView * m_validator; + const Span* m_validator; void validateThis() const { fail_fast_assert(m_pdata >= m_validator->m_pdata && m_pdata < m_validator->m_pdata + m_validator->size(), "iterator is out of range of the array"); } - contiguous_span_iterator (const ArrayView *container, bool isbegin) : + contiguous_span_iterator (const Span* container, bool isbegin) : m_pdata(isbegin ? container->m_pdata : container->m_pdata + container->size()), m_validator(container) {} public: reference operator*() const noexcept @@ -1840,16 +1970,16 @@ public: } }; -template -contiguous_span_iterator operator+(typename contiguous_span_iterator::difference_type n, const contiguous_span_iterator& rhs) noexcept +template +contiguous_span_iterator operator+(typename contiguous_span_iterator::difference_type n, const contiguous_span_iterator& rhs) noexcept { return rhs + n; } -template -class general_span_iterator : public std::iterator +template +class general_span_iterator : public std::iterator { - using Base = std::iterator; + using Base = std::iterator; public: using typename Base::reference; using typename Base::pointer; @@ -1859,9 +1989,9 @@ private: template friend class basic_span; - const ArrayView * m_container; - typename ArrayView::bounds_type::iterator m_itr; - general_span_iterator(const ArrayView *container, bool isbegin) : + const Span * m_container; + typename Span::bounds_type::iterator m_itr; + general_span_iterator(const Span *container, bool isbegin) : m_container(container), m_itr(isbegin ? m_container->bounds().begin() : m_container->bounds().end()) {} public: @@ -1956,8 +2086,8 @@ public: } }; -template -general_span_iterator operator+(typename general_span_iterator::difference_type n, const general_span_iterator& rhs) noexcept +template +general_span_iterator operator+(typename general_span_iterator::difference_type n, const general_span_iterator& rhs) noexcept { return rhs + n; } diff --git a/tests/span_tests.cpp b/tests/span_tests.cpp index 6a67b02..ecb2c4e 100644 --- a/tests/span_tests.cpp +++ b/tests/span_tests.cpp @@ -323,28 +323,29 @@ SUITE(span_tests) CHECK(sav[1] == 2); #if _MSC_VER > 1800 - strided_span sav_c{ {src}, {2, 1} }; -#else + //strided_span sav_c{ {src}, {2, 1} }; strided_span sav_c{ span{src}, strided_bounds<1>{2, 1} }; -#endif +#else + strided_span sav_c{ span{src}, strided_bounds<1>{2, 1} }; +#endif CHECK(sav_c.bounds().index_bounds() == index<1>{ 2 }); CHECK(sav_c.bounds().strides() == index<1>{ 1 }); CHECK(sav_c[1] == 2); #if _MSC_VER > 1800 strided_span sav_v{ {src}, {2, 1} }; -#else +#else strided_span sav_v{ span{src}, strided_bounds<1>{2, 1} }; -#endif +#endif CHECK(sav_v.bounds().index_bounds() == index<1>{ 2 }); CHECK(sav_v.bounds().strides() == index<1>{ 1 }); CHECK(sav_v[1] == 2); #if _MSC_VER > 1800 strided_span sav_cv{ {src}, {2, 1} }; -#else +#else strided_span sav_cv{ span{src}, strided_bounds<1>{2, 1} }; -#endif +#endif CHECK(sav_cv.bounds().index_bounds() == index<1>{ 2 }); CHECK(sav_cv.bounds().strides() == index<1>{ 1 }); CHECK(sav_cv[1] == 2); @@ -363,7 +364,7 @@ SUITE(span_tests) strided_span sav_cv{ {src}, {2, 1} }; #else strided_span sav_cv{ span{src}, strided_bounds<1>{2, 1} }; -#endif +#endif CHECK(sav_cv.bounds().index_bounds() == index<1>{ 2 }); CHECK(sav_cv.bounds().strides() == index<1>{ 1 }); @@ -383,7 +384,7 @@ SUITE(span_tests) strided_span sav_cv{ {src}, {2, 1} }; #else strided_span sav_cv{ span{src}, strided_bounds<1>{2, 1} }; -#endif +#endif CHECK(sav_cv.bounds().index_bounds() == index<1>{ 2 }); CHECK(sav_cv.bounds().strides() == index<1>{ 1 }); CHECK(sav_cv[1] == 2); From f510025109a75035ba9c99616ab5232f86c0b51d Mon Sep 17 00:00:00 2001 From: Anna Gringauze Date: Thu, 12 Nov 2015 12:48:49 -0800 Subject: [PATCH 2/2] Removed basic_span class --- include/span.h | 463 +++++++++++++++++++------------------------ tests/span_tests.cpp | 4 +- 2 files changed, 201 insertions(+), 266 deletions(-) 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);