From 8aa42487225a537ddedac668ec14e179bb481935 Mon Sep 17 00:00:00 2001 From: Anna Gringauze Date: Wed, 11 Nov 2015 12:41:11 -0800 Subject: [PATCH] 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);