From db38497d05887e8c901504fa09d71042ed8bb3c0 Mon Sep 17 00:00:00 2001 From: Anna Gringauze Date: Mon, 5 Oct 2015 12:34:23 -0700 Subject: [PATCH 1/5] Removed coordinate_facade class --- include/array_view.h | 499 ++++++++++++++++--------------------- tests/array_view_tests.cpp | 23 +- 2 files changed, 224 insertions(+), 298 deletions(-) diff --git a/include/array_view.h b/include/array_view.h index 046cbf8..aa1b4e5 100644 --- a/include/array_view.h +++ b/include/array_view.h @@ -73,180 +73,6 @@ namespace details static const size_t max_value = std::is_signed::value ? static_cast::type>(-1) / 2 : static_cast(-1); }; - - template - class coordinate_facade - { - static_assert(std::is_integral::value - && sizeof(ValueType) <= sizeof(size_t), "ValueType must be an integral type!"); - static_assert(Rank > 0, "Rank must be greater than 0!"); - - template - friend class coordinate_facade; - public: - using reference = ValueType&; - using const_reference = const ValueType&; - using value_type = ValueType; - static const size_t rank = Rank; - constexpr coordinate_facade() noexcept - { - static_assert(std::is_base_of::value, "ConcreteType must be derived from coordinate_facade."); - } - constexpr coordinate_facade(const value_type(&values)[rank]) noexcept - { - static_assert(std::is_base_of::value, "ConcreteType must be derived from coordinate_facade."); - for (size_t i = 0; i < rank; ++i) - elems[i] = values[i]; - } - constexpr coordinate_facade(value_type e0) noexcept - { - static_assert(std::is_base_of::value, "ConcreteType must be derived from coordinate_facade."); - static_assert(rank == 1, "This constructor can only be used with rank == 1."); - elems[0] = e0; - } - // Preconditions: il.size() == rank - constexpr coordinate_facade(std::initializer_list il) - { - static_assert(std::is_base_of::value, "ConcreteType must be derived from coordinate_facade."); - fail_fast_assert(il.size() == rank, "The size of the initializer list must match the rank of the array"); - for (size_t i = 0; i < rank; ++i) - { - elems[i] = begin(il)[i]; - } - } - - constexpr coordinate_facade(const coordinate_facade & other) = default; - - template - constexpr coordinate_facade(const coordinate_facade & other) - { - for (size_t i = 0; i < rank; ++i) - { - fail_fast_assert(static_cast(other.elems[i]) <= SizeTypeTraits::max_value); - elems[i] = static_cast(other.elems[i]); - } - } - protected: - coordinate_facade& operator=(const coordinate_facade& rhs) = default; - // Preconditions: component_idx < rank - constexpr reference operator[](size_t component_idx) - { - fail_fast_assert(component_idx < rank, "Component index must be less than rank"); - return elems[component_idx]; - } - // Preconditions: component_idx < rank - constexpr const_reference operator[](size_t component_idx) const - { - fail_fast_assert(component_idx < rank, "Component index must be less than rank"); - return elems[component_idx]; - } - constexpr bool operator==(const ConcreteType& rhs) const noexcept - { - return std::equal(elems, elems + rank, rhs.elems); - } - constexpr bool operator!=(const ConcreteType& rhs) const noexcept - { - return !(to_concrete() == rhs); - } - constexpr ConcreteType operator+() const noexcept - { - return to_concrete(); - } - constexpr ConcreteType operator-() const - { - ConcreteType ret = to_concrete(); - std::transform(ret, ret + rank, ret, std::negate{}); - return ret; - } - constexpr ConcreteType operator+(const ConcreteType& rhs) const - { - ConcreteType ret = to_concrete(); - ret += rhs; - return ret; - } - constexpr ConcreteType operator-(const ConcreteType& rhs) const - { - ConcreteType ret = to_concrete(); - ret -= rhs; - return ret; - } - constexpr ConcreteType& operator+=(const ConcreteType& rhs) - { - for (size_t i = 0; i < rank; ++i) - elems[i] += rhs.elems[i]; - return to_concrete(); - } - constexpr ConcreteType& operator-=(const ConcreteType& rhs) - { - for (size_t i = 0; i < rank; ++i) - elems[i] -= rhs.elems[i]; - return to_concrete(); - } - constexpr ConcreteType& operator++() - { - static_assert(rank == 1, "This operator can only be used with rank == 1."); - ++elems[0]; - return to_concrete(); - } - constexpr ConcreteType operator++(int) - { - static_assert(rank == 1, "This operator can only be used with rank == 1."); - ConcreteType ret = to_concrete(); - ++(*this); - return ret; - } - constexpr ConcreteType& operator--() - { - static_assert(rank == 1, "This operator can only be used with rank == 1."); - --elems[0]; - return to_concrete(); - } - constexpr ConcreteType operator--(int) - { - static_assert(rank == 1, "This operator can only be used with rank == 1."); - ConcreteType ret = to_concrete(); - --(*this); - return ret; - } - constexpr ConcreteType operator*(value_type v) const - { - ConcreteType ret = to_concrete(); - ret *= v; - return ret; - } - constexpr ConcreteType operator/(value_type v) const - { - ConcreteType ret = to_concrete(); - ret /= v; - return ret; - } - friend constexpr ConcreteType operator*(value_type v, const ConcreteType& rhs) - { - return rhs * v; - } - constexpr ConcreteType& operator*=(value_type v) - { - for (size_t i = 0; i < rank; ++i) - elems[i] *= v; - return to_concrete(); - } - constexpr ConcreteType& operator/=(value_type v) - { - for (size_t i = 0; i < rank; ++i) - elems[i] /= v; - return to_concrete(); - } - value_type elems[rank] = {}; - private: - constexpr const ConcreteType& to_concrete() const noexcept - { - return static_cast(*this); - } - constexpr ConcreteType& to_concrete() noexcept - { - return static_cast(*this); - } - }; template class arrow_proxy { @@ -268,47 +94,160 @@ namespace details } template -class index : private details::coordinate_facade, ValueType, Rank> +class index final { - using Base = details::coordinate_facade, ValueType, Rank>; - friend Base; + static_assert(std::is_integral::value, "ValueType must be an integral type!"); + static_assert(Rank > 0, "Rank must be greater than 0!"); + template friend class index; + public: - using Base::rank; - using reference = typename Base::reference; - using const_reference = typename Base::const_reference; - using size_type = typename Base::value_type; - using value_type = typename Base::value_type; - constexpr index() noexcept : Base(){} - constexpr index(const value_type (&values)[rank]) noexcept : Base(values) {} - constexpr index(std::initializer_list il) : Base(il) {} + static const size_t rank = Rank; + using value_type = std::remove_reference_t; + using reference = std::add_lvalue_reference_t; + using const_reference = std::add_lvalue_reference_t>; - constexpr index(const index &) = default; - - template - constexpr index(const index &other) : Base(other) + constexpr index(const value_type(&values)[Rank]) noexcept { - } - constexpr static index shift_left(const index& other) noexcept - { - value_type (&arr)[rank] = (value_type(&)[rank])(*(other.elems + 1)); - return index(arr); + std::copy(values, values + Rank, elems); } - using Base::operator[]; - using Base::operator==; - using Base::operator!=; - using Base::operator+; - using Base::operator-; - using Base::operator+=; - using Base::operator-=; - using Base::operator++; - using Base::operator--; - using Base::operator*; - using Base::operator/; - using Base::operator*=; - using Base::operator/=; + // Preconditions: il.size() == rank + constexpr index(std::initializer_list il) noexcept + { + fail_fast_assert(il.size() == Rank, "The size of the initializer list must match the rank of the array"); + std::copy(begin(il), end(il), elems); + } + + constexpr index(const index& other) noexcept = default; + + // copy from index over smaller domain + template + constexpr index(typename std::enable_if_t<(details::SizeTypeTraits::max_value <= details::SizeTypeTraits::max_value), const index>::type& other) noexcept + { + std::copy(other.elems, other.elems + Rank, elems); + } + + // copy from index over larger domain + template + constexpr index(typename std::enable_if_t<(details::SizeTypeTraits::max_value > details::SizeTypeTraits::max_value), const index>::type& other) noexcept + { + for (size_t i = 0; i < Rank; ++i) + { + fail_fast_assert(other.elems[i] <= static_cast(SizeTypeTraits::max_value)); + elems[i] = static_cast(other.elems[i]); + } + } + + constexpr static index shift_left(const index& other) noexcept + { + value_type(&arr)[Rank] = (value_type(&)[Rank])(*(other.elems + 1)); + return index(arr); + } + + constexpr static index zero() noexcept + { + value_type zero[Rank] = {}; + return index(zero); + } + + constexpr index& operator=(const index& rhs) noexcept = default; + + // Preconditions: component_idx < rank + constexpr reference operator[](size_t component_idx) + { + fail_fast_assert(component_idx < Rank, "Component index must be less than rank"); + return elems[component_idx]; + } + + // Preconditions: component_idx < rank + constexpr const_reference operator[](size_t component_idx) const noexcept + { + fail_fast_assert(component_idx < Rank, "Component index must be less than rank"); + return elems[component_idx]; + } + + constexpr bool operator==(const index& rhs) const noexcept + { + return std::equal(elems, elems + rank, rhs.elems); + } + + constexpr bool operator!=(const index& rhs) const noexcept + { + return !(this == rhs); + } + + constexpr index operator+() const noexcept + { + return *this; + } + + constexpr index operator-() const noexcept + { + index ret = *this; + std::transform(ret, ret + rank, ret, std::negate{}); + return ret; + } + + constexpr index operator+(const index& rhs) const noexcept + { + index ret = *this; + ret += rhs; + return ret; + } + + constexpr index operator-(const index& rhs) const noexcept + { + index ret = *this; + ret -= rhs; + return ret; + } + + constexpr index& operator+=(const index& rhs) noexcept + { + std::transform(elems, elems + rank, rhs.elems, elems, std::plus{}); + return *this; + } + + constexpr index& operator-=(const index& rhs) noexcept + { + std::transform(elems, elems + rank, rhs.elems, elems, std::minus{}); + return *this; + } + + constexpr index operator*(value_type v) const noexcept + { + index ret = *this; + ret *= v; + return ret; + } + + constexpr index operator/(value_type v) const noexcept + { + index ret = *this; + ret /= v; + return ret; + } + + friend static constexpr index operator*(value_type v, const index& rhs) noexcept + { + return rhs * v; + } + + constexpr index& operator*=(value_type v) noexcept + { + std::transform(elems, elems + rank, elems, [v](value_type x) { return std::multiplies{}(x, v); }); + return *this; + } + + constexpr index& operator/=(value_type v) noexcept + { + std::transform(elems, elems + rank, elems, [v](value_type x) { return std::divides{}(x, v); }); + return *this; + } +private: + value_type elems[Rank] = {}; }; template @@ -316,51 +255,60 @@ class index<1, ValueType> { template friend class index; + public: static const size_t rank = 1; - using reference = ValueType&; - using const_reference = const ValueType&; - using size_type = ValueType; - using value_type = ValueType; + using value_type = std::remove_reference_t; + using reference = std::add_lvalue_reference_t; + using const_reference = std::add_lvalue_reference_t>; - constexpr index() noexcept : value(0) - { - } constexpr index(value_type e0) noexcept : value(e0) - { - } + {} + constexpr index(const value_type(&values)[1]) noexcept : index(values[0]) - { - } + {} + // Preconditions: il.size() == rank - constexpr index(std::initializer_list il) + constexpr index(std::initializer_list il) noexcept { fail_fast_assert(il.size() == rank, "Size of the initializer list must match the rank of the array"); value = begin(il)[0]; } - constexpr index(const index &) = default; + constexpr index(const index &) noexcept = default; template - constexpr index(const index<1, OtherValueType> & other) + constexpr index(typename std::enable_if_t<(details::SizeTypeTraits::max_value <= details::SizeTypeTraits::max_value), const index<1, OtherValueType>>::type& other) noexcept { - fail_fast_assert(other.value <= details::SizeTypeTraits::max_value); value = static_cast(other.value); } - constexpr static index shift_left(const index& other) noexcept + template + constexpr index(typename std::enable_if_t<(details::SizeTypeTraits::max_value > details::SizeTypeTraits::max_value), const index<1, OtherValueType>>::type& other) noexcept + { + fail_fast_assert(other.value <= static_cast(SizeTypeTraits::max_value)); + value = static_cast(other.value); + } + + constexpr static index shift_left(const index<2, value_type>& other) noexcept { return other.elems[1]; } - // Preconditions: component_idx < rank - constexpr reference operator[](size_type component_idx) noexcept + + constexpr static index zero() noexcept + { + return 0; + } + + // Preconditions: component_idx < 1 + constexpr reference operator[](value_type component_idx) noexcept { fail_fast_assert(component_idx == 0, "Component index must be less than rank"); (void)(component_idx); return value; } - // Preconditions: component_idx < rank - constexpr const_reference operator[](size_type component_idx) const noexcept + // Preconditions: component_idx < 1 + constexpr const_reference operator[](value_type component_idx) const noexcept { fail_fast_assert(component_idx == 0, "Component index must be less than rank"); (void)(component_idx); @@ -440,9 +388,9 @@ public: value /= v; return *this; } - friend constexpr index operator*(value_type v, const index& rhs) noexcept + friend static constexpr index operator*(value_type v, const index& rhs) noexcept { - return index(rhs * v); + return{ rhs * v }; } private: value_type value; @@ -855,9 +803,9 @@ public: constexpr index_type index_bounds() const noexcept { - index_type extents; + size_type extents[rank]; m_ranges.serialize(extents); - return extents; + return{ extents }; } template @@ -874,32 +822,28 @@ public: constexpr const_iterator begin() const noexcept { - return const_iterator(*this); + return const_iterator(*this, index_type::zero()); } constexpr const_iterator end() const noexcept { - index_type boundary; - m_ranges.serialize(boundary); return const_iterator(*this, this->index_bounds()); } }; template -class strided_bounds : private details::coordinate_facade, SizeType, Rank> +class strided_bounds { - using Base = details::coordinate_facade, SizeType, Rank>; - friend Base; template friend class strided_bounds; public: - using Base::rank; - using reference = typename Base::reference; - using const_reference = typename Base::const_reference; - using size_type = typename Base::value_type; - using difference_type = typename Base::value_type; - using value_type = typename Base::value_type; + static const size_t rank = Rank; + using reference = typename SizeType&; + using const_reference = typename const SizeType&; + using size_type = typename SizeType; + using difference_type = typename SizeType; + using value_type = typename SizeType; using index_type = index; using iterator = bounds_iterator; using const_iterator = bounds_iterator; @@ -907,57 +851,52 @@ public: static const size_t static_size = dynamic_range; using sliced_type = std::conditional_t, void>; using mapping_type = generalized_mapping_tag; - constexpr strided_bounds(const strided_bounds &) = default; + constexpr strided_bounds(const strided_bounds &) noexcept = default; template - constexpr strided_bounds(const strided_bounds &other) - : Base(other), m_strides(other.strides) - { - } - - constexpr strided_bounds(const index_type &extents, const index_type &strides) - : m_strides(strides) - { - for (size_t i = 0; i < rank; i++) - Base::elems[i] = extents[i]; - } - constexpr strided_bounds(const value_type(&values)[rank], index_type strides) - : Base(values), m_strides(std::move(strides)) - { - } + constexpr strided_bounds(const strided_bounds &other) noexcept + : m_extents(other.extents), m_strides(other.strides) + {} + constexpr strided_bounds(const index_type &extents, const index_type &strides) noexcept + : m_extents(extents), m_strides(strides) + {} constexpr index_type strides() const noexcept - { - return m_strides; + { + return m_strides; } constexpr size_type total_size() const noexcept { size_type ret = 0; for (size_t i = 0; i < rank; ++i) - ret += (Base::elems[i] - 1) * m_strides[i]; + { + ret += (m_extents[i] - 1) * m_strides[i]; + } return ret + 1; } constexpr size_type size() const noexcept { size_type ret = 1; for (size_t i = 0; i < rank; ++i) - ret *= Base::elems[i]; + { + ret *= m_extents[i]; + } return ret; } constexpr bool contains(const index_type& idx) const noexcept { for (size_t i = 0; i < rank; ++i) { - if (idx[i] < 0 || idx[i] >= Base::elems[i]) + if (idx[i] < 0 || idx[i] >= m_extents[i]) return false; } return true; } - constexpr size_type linearize(const index_type & idx) const + constexpr size_type linearize(const index_type & idx) const noexcept { size_type ret = 0; for (size_t i = 0; i < rank; i++) { - fail_fast_assert(idx[i] < Base::elems[i], "index is out of bounds of the array"); + fail_fast_assert(idx[i] < m_extents[i], "index is out of bounds of the array"); ret += idx[i] * m_strides[i]; } return ret; @@ -969,27 +908,28 @@ public: template 1), typename Ret = std::enable_if_t> constexpr sliced_type slice() const { - return{ (value_type(&)[rank - 1])Base::elems[1], sliced_type::index_type::shift_left(m_strides) }; + return{ sliced_type::index_type::shift_left(m_extents), sliced_type::index_type::shift_left(m_strides) }; } template constexpr size_type extent() const noexcept { static_assert(Dim < Rank, "dimension should be less than rank (dimension count starts from 0)"); - return Base::elems[Dim]; + return m_extents[Dim]; } constexpr index_type index_bounds() const noexcept { - return index_type(Base::elems); + return m_extents; } const_iterator begin() const noexcept { - return const_iterator{ *this }; + return const_iterator{ *this, index_type::zero() }; } const_iterator end() const noexcept { return const_iterator{ *this, index_bounds() }; } private: + index_type m_extents; index_type m_strides; }; @@ -1017,9 +957,9 @@ public: using typename Base::difference_type; using typename Base::value_type; using index_type = value_type; - using index_size_type = typename IndexType::size_type; + using index_size_type = typename IndexType::value_type; template - explicit bounds_iterator(const Bounds & bnd, value_type curr = value_type{}) noexcept + explicit bounds_iterator(const Bounds& bnd, value_type curr) noexcept : boundary(bnd.index_bounds()) , curr( std::move(curr) ) { @@ -1210,7 +1150,7 @@ public: using typename Base::difference_type; using typename Base::value_type; using index_type = value_type; - using index_size_type = typename index_type::size_type; + using index_size_type = typename index_type::value_type; template explicit bounds_iterator(const Bounds &, value_type curr = value_type{}) noexcept @@ -1327,11 +1267,14 @@ namespace details constexpr std::enable_if_t::value, typename Bounds::index_type> make_stride(const Bounds& bnd) noexcept { auto extents = bnd.index_bounds(); - typename Bounds::index_type stride; - stride[Bounds::rank - 1] = 1; - for (size_t i = Bounds::rank - 1; Bounds::rank > 1 && i > 0; --i) - stride[i-1] = stride[i] * extents[i]; - return stride; + Bounds::size_type stride[Bounds::rank]; + + stride[Bounds::rank - 1] = 1; + for (size_t i = Bounds::rank - 1; Bounds::rank > 1 && i > 0; --i) + { + stride[i - 1] = stride[i] * extents[i]; + } + return{ stride }; } template diff --git a/tests/array_view_tests.cpp b/tests/array_view_tests.cpp index 918df9e..ec10bbd 100644 --- a/tests/array_view_tests.cpp +++ b/tests/array_view_tests.cpp @@ -552,26 +552,6 @@ SUITE(array_view_tests) CHECK_THROW(av.section(5, 5), fail_fast); } - { - // zero stride - strided_array_view sav{ av, {{4}, {}} }; - CHECK(sav[0] == 0); - CHECK(sav[3] == 0); - CHECK_THROW(sav[4], fail_fast); - } - - { - // zero extent - strided_array_view sav{ av,{ {},{1} } }; - CHECK_THROW(sav[0], fail_fast); - } - - { - // zero extent and stride - strided_array_view sav{ av,{ {},{} } }; - CHECK_THROW(sav[0], fail_fast); - } - { // strided array ctor with matching strided bounds strided_array_view sav{ arr,{ 4, 1 } }; @@ -627,6 +607,9 @@ SUITE(array_view_tests) #ifdef CONFIRM_COMPILATION_ERRORS { + strided_array_view sav{ av,{ { 4 },{} } }; + strided_array_view sav{ av,{ {},{ 1 } } }; + strided_array_view sav{ av,{ {},{} } }; strided_array_view sav0{ av.data(), { 3, 2 } }; strided_array_view sav1{ arr, { 1 } }; strided_array_view sav2{ arr, { 1,1,1 } }; From 546f8cc1306ec69cc3a8f292785658da8caf157a Mon Sep 17 00:00:00 2001 From: Anna Gringauze Date: Mon, 5 Oct 2015 21:04:56 -0700 Subject: [PATCH 2/5] Added tests for index size_type conversions --- include/array_view.h | 106 +++++++++---------- tests/array_view_tests.cpp | 209 +++++++++++++++++++++++++++++++++---- 2 files changed, 243 insertions(+), 72 deletions(-) diff --git a/include/array_view.h b/include/array_view.h index aa1b4e5..98bbadf 100644 --- a/include/array_view.h +++ b/include/array_view.h @@ -70,7 +70,7 @@ namespace details template struct SizeTypeTraits { - static const size_t max_value = std::is_signed::value ? static_cast::type>(-1) / 2 : static_cast(-1); + static const SizeType max_value = std::is_signed::value ? static_cast::type>(-1) / 2 : static_cast(-1); }; template @@ -108,6 +108,9 @@ public: using reference = std::add_lvalue_reference_t; using const_reference = std::add_lvalue_reference_t>; + constexpr index() noexcept + {} + constexpr index(const value_type(&values)[Rank]) noexcept { std::copy(values, values + Rank, elems); @@ -120,36 +123,29 @@ public: std::copy(begin(il), end(il), elems); } - constexpr index(const index& other) noexcept = default; + constexpr index(const index& other) noexcept = default; // copy from index over smaller domain - template - constexpr index(typename std::enable_if_t<(details::SizeTypeTraits::max_value <= details::SizeTypeTraits::max_value), const index>::type& other) noexcept + template ::max_value <= details::SizeTypeTraits::max_value), + typename Other = std::enable_if_t>> + constexpr index(const index& other) noexcept { std::copy(other.elems, other.elems + Rank, elems); } // copy from index over larger domain - template - constexpr index(typename std::enable_if_t<(details::SizeTypeTraits::max_value > details::SizeTypeTraits::max_value), const index>::type& other) noexcept + template ::max_value > details::SizeTypeTraits::max_value), + typename Other = std::enable_if_t>> + constexpr index(const index& other, void* ptr = 0) noexcept { - for (size_t i = 0; i < Rank; ++i) - { - fail_fast_assert(other.elems[i] <= static_cast(SizeTypeTraits::max_value)); - elems[i] = static_cast(other.elems[i]); - } - } + bool ok = std::accumulate(other.elems, other.elems + Rank, true, + [&](bool b, OtherValueType val) { return b && (val <= static_cast(details::SizeTypeTraits::max_value)); } + ); - constexpr static index shift_left(const index& other) noexcept - { - value_type(&arr)[Rank] = (value_type(&)[Rank])(*(other.elems + 1)); - return index(arr); - } - - constexpr static index zero() noexcept - { - value_type zero[Rank] = {}; - return index(zero); + fail_fast_assert(ok, "other value must fit in the new domain"); + std::transform(other.elems, other.elems + rank, elems, [&](OtherValueType val) { return static_cast(val); }); } constexpr index& operator=(const index& rhs) noexcept = default; @@ -230,7 +226,7 @@ public: return ret; } - friend static constexpr index operator*(value_type v, const index& rhs) noexcept + friend constexpr index operator*(value_type v, const index& rhs) noexcept { return rhs * v; } @@ -246,6 +242,7 @@ public: std::transform(elems, elems + rank, elems, [v](value_type x) { return std::divides{}(x, v); }); return *this; } + private: value_type elems[Rank] = {}; }; @@ -262,44 +259,34 @@ public: using reference = std::add_lvalue_reference_t; using const_reference = std::add_lvalue_reference_t>; - constexpr index(value_type e0) noexcept : value(e0) + constexpr index() noexcept : value(0) {} - constexpr index(const value_type(&values)[1]) noexcept : index(values[0]) + constexpr index(value_type e) noexcept : value(e) {} - // Preconditions: il.size() == rank - constexpr index(std::initializer_list il) noexcept - { - fail_fast_assert(il.size() == rank, "Size of the initializer list must match the rank of the array"); - value = begin(il)[0]; - } + constexpr index(const value_type(&values)[1]) noexcept : index(values[0]) + {} constexpr index(const index &) noexcept = default; - template - constexpr index(typename std::enable_if_t<(details::SizeTypeTraits::max_value <= details::SizeTypeTraits::max_value), const index<1, OtherValueType>>::type& other) noexcept + template ::max_value <= details::SizeTypeTraits::max_value), + typename Other = std::enable_if_t>> + constexpr index(const index<1, OtherValueType>& other) noexcept { value = static_cast(other.value); } - template - constexpr index(typename std::enable_if_t<(details::SizeTypeTraits::max_value > details::SizeTypeTraits::max_value), const index<1, OtherValueType>>::type& other) noexcept + template ::max_value > details::SizeTypeTraits::max_value), + typename Other = std::enable_if_t>> + constexpr index(const index<1, OtherValueType>& other, void* ptr=0) noexcept { - fail_fast_assert(other.value <= static_cast(SizeTypeTraits::max_value)); + fail_fast_assert(other.value <= static_cast(details::SizeTypeTraits::max_value)); value = static_cast(other.value); } - constexpr static index shift_left(const index<2, value_type>& other) noexcept - { - return other.elems[1]; - } - - constexpr static index zero() noexcept - { - return 0; - } - // Preconditions: component_idx < 1 constexpr reference operator[](value_type component_idx) noexcept { @@ -388,7 +375,7 @@ public: value /= v; return *this; } - friend static constexpr index operator*(value_type v, const index& rhs) noexcept + friend constexpr index operator*(value_type v, const index& rhs) noexcept { return{ rhs * v }; } @@ -822,7 +809,7 @@ public: constexpr const_iterator begin() const noexcept { - return const_iterator(*this, index_type::zero()); + return const_iterator(*this); } constexpr const_iterator end() const noexcept @@ -908,7 +895,7 @@ public: template 1), typename Ret = std::enable_if_t> constexpr sliced_type slice() const { - return{ sliced_type::index_type::shift_left(m_extents), sliced_type::index_type::shift_left(m_strides) }; + return{ details::shift_left(m_extents), details::shift_left(m_strides) }; } template constexpr size_type extent() const noexcept @@ -922,7 +909,7 @@ public: } const_iterator begin() const noexcept { - return const_iterator{ *this, index_type::zero() }; + return const_iterator{ *this }; } const_iterator end() const noexcept { @@ -959,9 +946,9 @@ public: using index_type = value_type; using index_size_type = typename IndexType::value_type; template - explicit bounds_iterator(const Bounds& bnd, value_type curr) noexcept + explicit bounds_iterator(const Bounds& bnd, value_type curr = value_type{}) noexcept : boundary(bnd.index_bounds()) - , curr( std::move(curr) ) + , curr(std::move(curr)) { static_assert(is_bounds::value, "Bounds type must be provided"); } @@ -1270,13 +1257,24 @@ namespace details Bounds::size_type stride[Bounds::rank]; stride[Bounds::rank - 1] = 1; - for (size_t i = Bounds::rank - 1; Bounds::rank > 1 && i > 0; --i) + for (size_t i = 1; i < Bounds::rank; ++i) { - stride[i - 1] = stride[i] * extents[i]; + stride[Bounds::rank - i - 1] = stride[Bounds::rank - i] * extents[Bounds::rank - i]; } return{ stride }; } + template 1), typename Ret = std::enable_if_t>> + constexpr Ret shift_left(const index& other) noexcept + { + Ret ret; + for (size_t i = 0; i < Rank - 1; ++i) + { + ret[i] = other[i + 1]; + } + return ret; + } + template void verifyBoundsReshape(const BoundsSrc &src, const BoundsDest &dest) { diff --git a/tests/array_view_tests.cpp b/tests/array_view_tests.cpp index ec10bbd..a56d0f2 100644 --- a/tests/array_view_tests.cpp +++ b/tests/array_view_tests.cpp @@ -552,6 +552,26 @@ SUITE(array_view_tests) CHECK_THROW(av.section(5, 5), fail_fast); } + { + // zero stride + strided_array_view sav{ av,{ { 4 },{} } }; + CHECK(sav[0] == 0); + CHECK(sav[3] == 0); + CHECK_THROW(sav[4], fail_fast); + } + + { + // zero extent + strided_array_view sav{ av,{ {},{ 1 } } }; + CHECK_THROW(sav[0], fail_fast); + } + + { + // zero extent and stride + strided_array_view sav{ av,{ {},{} } }; + CHECK_THROW(sav[0], fail_fast); + } + { // strided array ctor with matching strided bounds strided_array_view sav{ arr,{ 4, 1 } }; @@ -607,9 +627,6 @@ SUITE(array_view_tests) #ifdef CONFIRM_COMPILATION_ERRORS { - strided_array_view sav{ av,{ { 4 },{} } }; - strided_array_view sav{ av,{ {},{ 1 } } }; - strided_array_view sav{ av,{ {},{} } }; strided_array_view sav0{ av.data(), { 3, 2 } }; strided_array_view sav1{ arr, { 1 } }; strided_array_view sav2{ arr, { 1,1,1 } }; @@ -618,27 +635,26 @@ SUITE(array_view_tests) strided_array_view sav5{ av.as_array_view(dim<2>(), dim<2>()), { 1 } }; strided_array_view sav6{ av.as_array_view(dim<2>(), dim<2>()), { 1,1,1 } }; strided_array_view sav7{ av.as_array_view(dim<2>(), dim<2>()), { { 1,1 },{ 1,1 },{ 1,1 } } }; + + index<1> index{ 0, 1 }; + strided_array_view sav8{ arr,{ 1,{ 1,1 } } }; +#ifdef _MSC_VER + strided_array_view sav9{ arr,{ { 1,1 },{ 1,1 } } }; +#endif + strided_array_view sav10{ av,{ 1,{ 1,1 } } }; +#ifdef _MSC_VER + strided_array_view sav11{ av,{ { 1,1 },{ 1,1 } } }; +#endif } #endif - + { - // stride initializer list size should match the rank of the array - CHECK_THROW((index<1>{ 0,1 }), fail_fast); - CHECK_THROW((strided_array_view{ arr, {1, {1,1}} }), fail_fast); -#ifdef _MSC_VER - CHECK_THROW((strided_array_view{ arr, {{1,1 }, {1,1}} }), fail_fast); -#endif - CHECK_THROW((strided_array_view{ av, {1, {1,1}} }), fail_fast); -#ifdef _MSC_VER - CHECK_THROW((strided_array_view{ av, {{1,1 }, {1,1}} }), fail_fast); -#endif CHECK_THROW((strided_array_view{ av.as_array_view(dim<2>(), dim<2>()), {{1}, {1}} }), fail_fast); CHECK_THROW((strided_array_view{ av.as_array_view(dim<2>(), dim<2>()), {{1}, {1,1,1}} }), fail_fast); #ifdef _MSC_VER CHECK_THROW((strided_array_view{ av.as_array_view(dim<2>(), dim<2>()), {{1,1,1}, {1}} }), fail_fast); #endif } - } TEST(strided_array_view_type_conversion) @@ -856,7 +872,18 @@ SUITE(array_view_tests) } { - index<2> k = index<2>::shift_left(i); + index<3> k = 3 * i; + + CHECK(i[0] == 0); + CHECK(i[1] == 1); + CHECK(i[2] == 2); + CHECK(k[0] == 0); + CHECK(k[1] == 3); + CHECK(k[2] == 6); + } + + { + index<2> k = details::shift_left(i); CHECK(i[0] == 0); CHECK(i[1] == 1); @@ -972,7 +999,7 @@ SUITE(array_view_tests) auto bounds = strided_bounds<1>({ length }, { 2 }); #else auto bounds = strided_bounds<1>(index<1>{ length }, index<1>{ 2 }); -#endif +#endif strided_array_view strided(&av.data()[1], av.size() - 1, bounds); CHECK(strided.size() == length); @@ -1033,7 +1060,7 @@ SUITE(array_view_tests) for (unsigned int k = 0; k < section.extent<2>(); ++k) { auto idx = index<3>{ i,j,k }; // avoid braces in the CHECK macro - CHECK(section[idx] == expected[2 * i + 2 * j + k]); + CHECK(section[idx] == expected[2 * i + 2 * j + k]); } } @@ -1151,6 +1178,152 @@ SUITE(array_view_tests) } + template + index Convert(index index) + { + return{ index }; + } + + TEST(DomainConverters) + { + // to smaller + { + index<2, int> int_index{ 0,1 }; + index<2, short> short_index{ int_index }; + + CHECK(short_index[0] == 0); + CHECK(short_index[1] == 1); + } + + // to smaller (failure) + { + index<2, int> big_int_index{ INT_MAX, 1 }; + CHECK_THROW((Convert<2,int, short int>(big_int_index)), fail_fast); + } + + // to same, sign mismatch + { + index<2, int> int_index{ 0,1 }; + index<2, unsigned int> uint_index{ int_index }; + + CHECK(uint_index[0] == 0); + CHECK(uint_index[1] == 1); + } + + // to same, sign mismatch, reversed + { + index<2, unsigned int> uint_index{ 0,1 }; + index<2, int> int_index{ uint_index }; + + CHECK(int_index[0] == 0); + CHECK(int_index[1] == 1); + } + + // to smaller, sign mismatch + { + index<2, int> int_index{ 0,1 }; + index<2, unsigned short> ushort_index{ int_index }; + + CHECK(ushort_index[0] == 0); + CHECK(ushort_index[1] == 1); + } + + // to bigger + { + index<2, int> int_index{ 0,1 }; + index<2, long long> longlong_index{ int_index }; + + CHECK(longlong_index[0] == 0); + CHECK(longlong_index[1] == 1); + } + + // to bigger with max index + { + index<2, int> big_int_index{ INT_MAX, 1 }; + index<2, long long> longlong_index{ big_int_index }; + + CHECK(longlong_index[0] == INT_MAX); + CHECK(longlong_index[1] == 1); + } + + // to bigger, sign mismatch + { + index<2, int> int_index{ 0,1 }; + index<2, unsigned long long> ulonglong_index{ int_index }; + + CHECK(ulonglong_index[0] == 0); + CHECK(ulonglong_index[1] == 1); + } + + } + + TEST(DomainConvertersRank1) + { + // to smaller + { + index<1, int> int_index{ 0 }; + index<1, short> short_index{ int_index }; + + CHECK(short_index[0] == 0); + } + + // to smaller (failure) + { + index<1, int> big_int_index{ INT_MAX }; + + CHECK_THROW((Convert<1, int, short int>(big_int_index)), fail_fast); + } + + // to same, sign mismatch + { + index<1, int> int_index{ 0 }; + index<1, unsigned int> uint_index{ int_index }; + + CHECK(uint_index[0] == 0); + } + + // to same, sign mismatch, reversed + { + index<1, unsigned int> uint_index{ 0 }; + index<1, int> int_index{ uint_index }; + + CHECK(int_index[0] == 0); + } + + // to smaller, sign mismatch + { + index<1, int> int_index{ 0 }; + index<1, unsigned short> ushort_index{ int_index }; + + CHECK(ushort_index[0] == 0); + } + + // to bigger + { + index<1, int> int_index{ 0 }; + index<1, long long> longlong_index{ int_index }; + + CHECK(longlong_index[0] == 0); + } + + // to bigger with max index + { + index<1, int> big_int_index{ INT_MAX }; + index<1, long long> longlong_index{ big_int_index }; + + CHECK(longlong_index[0] == INT_MAX); + } + + // to bigger, sign mismatch + { + index<1, int> int_index{ 0 }; + index<1, unsigned long long> ulonglong_index{ int_index }; + + CHECK(ulonglong_index[0] == 0); + } + + } + TEST(constructors) { array_view av(nullptr); From fdf864347150a108a33a467bc7ba3efd1ad78b2f Mon Sep 17 00:00:00 2001 From: Anna Gringauze Date: Wed, 14 Oct 2015 10:46:22 -0700 Subject: [PATCH 3/5] Fixes for gcc --- include/array_view.h | 36 ++++++++++++++++++------------------ tests/array_view_tests.cpp | 13 +++++++------ 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/include/array_view.h b/include/array_view.h index 98bbadf..3502076 100644 --- a/include/array_view.h +++ b/include/array_view.h @@ -686,6 +686,17 @@ namespace details { return TypeListIndexer(obj); } + + template 1), typename Ret = std::enable_if_t>> + constexpr Ret shift_left(const index& other) noexcept + { + Ret ret; + for (size_t i = 0; i < Rank - 1; ++i) + { + ret[i] = other[i + 1]; + } + return ret; + } } template @@ -790,7 +801,7 @@ public: constexpr index_type index_bounds() const noexcept { - size_type extents[rank]; + size_type extents[rank] = {}; m_ranges.serialize(extents); return{ extents }; } @@ -826,11 +837,11 @@ class strided_bounds public: static const size_t rank = Rank; - using reference = typename SizeType&; - using const_reference = typename const SizeType&; - using size_type = typename SizeType; - using difference_type = typename SizeType; - using value_type = typename SizeType; + using reference = SizeType&; + using const_reference = const SizeType&; + using size_type = SizeType; + using difference_type = SizeType; + using value_type = SizeType; using index_type = index; using iterator = bounds_iterator; using const_iterator = bounds_iterator; @@ -1254,7 +1265,7 @@ namespace details constexpr std::enable_if_t::value, typename Bounds::index_type> make_stride(const Bounds& bnd) noexcept { auto extents = bnd.index_bounds(); - Bounds::size_type stride[Bounds::rank]; + typename Bounds::size_type stride[Bounds::rank] = {}; stride[Bounds::rank - 1] = 1; for (size_t i = 1; i < Bounds::rank; ++i) @@ -1264,17 +1275,6 @@ namespace details return{ stride }; } - template 1), typename Ret = std::enable_if_t>> - constexpr Ret shift_left(const index& other) noexcept - { - Ret ret; - for (size_t i = 0; i < Rank - 1; ++i) - { - ret[i] = other[i + 1]; - } - return ret; - } - template void verifyBoundsReshape(const BoundsSrc &src, const BoundsDest &dest) { diff --git a/tests/array_view_tests.cpp b/tests/array_view_tests.cpp index a56d0f2..f84e908 100644 --- a/tests/array_view_tests.cpp +++ b/tests/array_view_tests.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -1197,7 +1198,7 @@ SUITE(array_view_tests) // to smaller (failure) { - index<2, int> big_int_index{ INT_MAX, 1 }; + index<2, int> big_int_index{ std::numeric_limits::max(), 1 }; CHECK_THROW((Convert<2,int, short int>(big_int_index)), fail_fast); } @@ -1239,10 +1240,10 @@ SUITE(array_view_tests) // to bigger with max index { - index<2, int> big_int_index{ INT_MAX, 1 }; + index<2, int> big_int_index{ std::numeric_limits::max(), 1 }; index<2, long long> longlong_index{ big_int_index }; - CHECK(longlong_index[0] == INT_MAX); + CHECK(longlong_index[0] == std::numeric_limits::max()); CHECK(longlong_index[1] == 1); } @@ -1269,7 +1270,7 @@ SUITE(array_view_tests) // to smaller (failure) { - index<1, int> big_int_index{ INT_MAX }; + index<1, int> big_int_index{ std::numeric_limits::max() }; CHECK_THROW((Convert<1, int, short int>(big_int_index)), fail_fast); } @@ -1308,10 +1309,10 @@ SUITE(array_view_tests) // to bigger with max index { - index<1, int> big_int_index{ INT_MAX }; + index<1, int> big_int_index{ std::numeric_limits::max() }; index<1, long long> longlong_index{ big_int_index }; - CHECK(longlong_index[0] == INT_MAX); + CHECK(longlong_index[0] == std::numeric_limits::max()); } // to bigger, sign mismatch From f972b2d68c9a9d7ce151d93b3a3b3b2da9ecb6eb Mon Sep 17 00:00:00 2001 From: Anna Gringauze Date: Thu, 15 Oct 2015 13:00:10 -0700 Subject: [PATCH 4/5] Adding g++-5 libraries to clang travis configuration to fix build break --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 524f1fb..3c64230 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,7 @@ matrix: packages: - clang-3.6 - cmake + - g++-5 sources: &sources - ubuntu-toolchain-r-test - llvm-toolchain-precise-3.6 From 2cdedda7e4d85f356b8ef66f2d6f7e778538ba00 Mon Sep 17 00:00:00 2001 From: Anna Gringauze Date: Thu, 15 Oct 2015 13:19:24 -0700 Subject: [PATCH 5/5] Adding missing include library to array_view.h --- include/array_view.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/array_view.h b/include/array_view.h index 3502076..c884c11 100644 --- a/include/array_view.h +++ b/include/array_view.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include