diff --git a/include/array_view.h b/include/array_view.h index cc7ab23..0145799 100644 --- a/include/array_view.h +++ b/include/array_view.h @@ -72,27 +72,15 @@ namespace details template struct SizeTypeTraits { - static const SizeType max_value = std::is_signed::value ? static_cast::type>(-1) / 2 : static_cast(-1); + static const SizeType max_value = std::numeric_limits::max(); }; - template - class arrow_proxy - { - public: - explicit arrow_proxy(T t) - : val(t) - {} - const T operator*() const noexcept - { - return val; - } - const T* operator->() const noexcept - { - return &val; - } - private: - T val; - }; + + template + class are_integral : public std::integral_constant {}; + + template + class are_integral : public std::integral_constant::value && are_integral::value> {}; } template @@ -118,12 +106,9 @@ public: std::copy(values, values + Rank, elems); } - // 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); - } + template::value, typename Dummy = std::enable_if_t> + constexpr index(Ts... ds) noexcept : elems{ static_cast(ds)... } + {} constexpr index(const index& other) noexcept = default; @@ -249,142 +234,6 @@ private: value_type elems[Rank] = {}; }; -template -class index<1, ValueType> -{ - template - friend class index; - -public: - static const size_t rank = 1; - 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 e) noexcept : value(e) - {} - - constexpr index(const value_type(&values)[1]) noexcept : index(values[0]) - {} - - constexpr index(const index &) noexcept = default; - - 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 ::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(details::SizeTypeTraits::max_value)); - value = static_cast(other.value); - } - - // 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 < 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); - return value; - } - constexpr bool operator==(const index& rhs) const noexcept - { - return value == rhs.value; - } - constexpr bool operator!=(const index& rhs) const noexcept - { - return !(*this == rhs); - } - constexpr index operator+() const noexcept - { - return *this; - } - constexpr index operator-() const noexcept - { - return index(-value); - } - constexpr index operator+(const index& rhs) const noexcept - { - return index(value + rhs.value); - } - constexpr index operator-(const index& rhs) const noexcept - { - return index(value - rhs.value); - } - constexpr index& operator+=(const index& rhs) noexcept - { - value += rhs.value; - return *this; - } - constexpr index& operator-=(const index& rhs) noexcept - { - value -= rhs.value; - return *this; - } - constexpr index& operator++() noexcept - { - ++value; - return *this; - } - constexpr index operator++(int) noexcept - { - index ret = *this; - ++(*this); - return ret; - } - constexpr index& operator--() noexcept - { - --value; - return *this; - } - constexpr index operator--(int) noexcept - { - index ret = *this; - --(*this); - return ret; - } - constexpr index operator*(value_type v) const noexcept - { - return index(value * v); - } - constexpr index operator/(value_type v) const noexcept - { - return index(value / v); - } - constexpr index& operator*=(value_type v) noexcept - { - value *= v; - return *this; - } - constexpr index& operator/=(value_type v) noexcept - { - value /= v; - return *this; - } - friend constexpr index operator*(value_type v, const index& rhs) noexcept - { - return{ rhs * v }; - } -private: - value_type value; -}; - #ifndef _MSC_VER struct static_bounds_dynamic_range_t @@ -730,8 +579,9 @@ public: using size_type = SizeType; using index_type = index; - using iterator = bounds_iterator; - using const_iterator = bounds_iterator; + using const_index_type = std::add_const_t; + using iterator = bounds_iterator; + using const_iterator = bounds_iterator; using difference_type = ptrdiff_t; using sliced_type = static_bounds; using mapping_type = contiguous_mapping_tag; @@ -822,7 +672,7 @@ public: constexpr const_iterator begin() const noexcept { - return const_iterator(*this); + return const_iterator(*this, index_type{}); } constexpr const_iterator end() const noexcept @@ -845,8 +695,9 @@ public: using difference_type = SizeType; using value_type = SizeType; using index_type = index; - using iterator = bounds_iterator; - using const_iterator = bounds_iterator; + using const_index_type = std::add_const_t; + using iterator = bounds_iterator; + using const_iterator = bounds_iterator; static const int dynamic_rank = rank; static const size_t static_size = dynamic_range; using sliced_type = std::conditional_t, void>; @@ -920,11 +771,11 @@ public: { return m_extents; } - const_iterator begin() const noexcept + constexpr const_iterator begin() const noexcept { - return const_iterator{ *this }; + return const_iterator{ *this, index_type{} }; } - const_iterator end() const noexcept + constexpr const_iterator end() const noexcept { return const_iterator{ *this, index_bounds() }; } @@ -941,15 +792,11 @@ template struct is_bounds> : std::integral_constant {}; template -class bounds_iterator - : public std::iterator, - const IndexType> +class bounds_iterator: public std::iterator { private: - using Base = std::iterator , const IndexType>; + using Base = std::iterator ; + public: static const size_t rank = IndexType::rank; using typename Base::reference; @@ -959,79 +806,88 @@ public: using index_type = value_type; using index_size_type = typename IndexType::value_type; template - explicit bounds_iterator(const Bounds& bnd, value_type curr = value_type{}) noexcept - : boundary(bnd.index_bounds()) - , curr(std::move(curr)) + explicit bounds_iterator(const Bounds& bnd, value_type curr) noexcept + : boundary(bnd.index_bounds()), curr(std::move(curr)) { static_assert(is_bounds::value, "Bounds type must be provided"); } - reference operator*() const noexcept + + constexpr reference operator*() const noexcept { return curr; } - pointer operator->() const noexcept + + constexpr pointer operator->() const noexcept { - return details::arrow_proxy{ curr }; + return &curr; } - bounds_iterator& operator++() noexcept + + constexpr bounds_iterator& operator++() noexcept { for (size_t i = rank; i-- > 0;) { - if (++curr[i] < boundary[i]) + if (curr[i] < boundary[i] - 1) { + curr[i]++; return *this; } - else - { - curr[i] = 0; - } + curr[i] = 0; } // If we're here we've wrapped over - set to past-the-end. - for (size_t i = 0; i < rank; ++i) - { - curr[i] = boundary[i]; - } + curr = boundary; return *this; } - bounds_iterator operator++(int) noexcept + + constexpr bounds_iterator operator++(int) noexcept { auto ret = *this; ++(*this); return ret; } - bounds_iterator& operator--() noexcept + + constexpr bounds_iterator& operator--() noexcept { - for (size_t i = rank; i-- > 0;) + if (!less(curr, boundary)) { - if (curr[i]-- > 0) - { - return *this; - } - else + // if at the past-the-end, set to last element + for (size_t i = 0; i < rank; ++i) { curr[i] = boundary[i] - 1; } + return *this; + } + for (size_t i = rank; i-- > 0;) + { + if (curr[i] >= 1) + { + curr[i]--; + return *this; + } + curr[i] = boundary[i] - 1; } // If we're here the preconditions were violated // "pre: there exists s such that r == ++s" fail_fast_assert(false); return *this; } - bounds_iterator operator--(int) noexcept + + constexpr bounds_iterator operator--(int) noexcept { auto ret = *this; --(*this); return ret; } - bounds_iterator operator+(difference_type n) const noexcept + + constexpr bounds_iterator operator+(difference_type n) const noexcept { bounds_iterator ret{ *this }; return ret += n; } - bounds_iterator& operator+=(difference_type n) noexcept + + constexpr bounds_iterator& operator+=(difference_type n) noexcept { auto linear_idx = linearize(curr) + n; - value_type stride; + std::remove_const_t stride; stride[rank - 1] = 1; for (size_t i = rank - 1; i-- > 0;) { @@ -1042,76 +898,84 @@ public: curr[i] = linear_idx / stride[i]; linear_idx = linear_idx % stride[i]; } + fail_fast_assert(!less(curr, index_type{}) && !less(boundary, curr), "index is out of bounds of the array"); return *this; } - bounds_iterator operator-(difference_type n) const noexcept + + constexpr bounds_iterator operator-(difference_type n) const noexcept { bounds_iterator ret{ *this }; return ret -= n; } - bounds_iterator& operator-=(difference_type n) noexcept + + constexpr bounds_iterator& operator-=(difference_type n) noexcept { return *this += -n; } - difference_type operator-(const bounds_iterator& rhs) const noexcept + + constexpr difference_type operator-(const bounds_iterator& rhs) const noexcept { return linearize(curr) - linearize(rhs.curr); } - reference operator[](difference_type n) const noexcept + + constexpr reference operator[](difference_type n) const noexcept { return *(*this + n); } - bool operator==(const bounds_iterator& rhs) const noexcept + + constexpr bool operator==(const bounds_iterator& rhs) const noexcept { return curr == rhs.curr; } - bool operator!=(const bounds_iterator& rhs) const noexcept + + constexpr bool operator!=(const bounds_iterator& rhs) const noexcept { return !(*this == rhs); } - bool operator<(const bounds_iterator& rhs) const noexcept + + constexpr bool operator<(const bounds_iterator& rhs) const noexcept { - for (size_t i = 0; i < rank; ++i) - { - if (curr[i] < rhs.curr[i]) - return true; - } - return false; + return less(curr, rhs.curr); } - bool operator<=(const bounds_iterator& rhs) const noexcept + + constexpr bool operator<=(const bounds_iterator& rhs) const noexcept { return !(rhs < *this); } - bool operator>(const bounds_iterator& rhs) const noexcept + + constexpr bool operator>(const bounds_iterator& rhs) const noexcept { return rhs < *this; } - bool operator>=(const bounds_iterator& rhs) const noexcept + + constexpr bool operator>=(const bounds_iterator& rhs) const noexcept { return !(rhs > *this); } + void swap(bounds_iterator& rhs) noexcept { std::swap(boundary, rhs.boundary); std::swap(curr, rhs.curr); } private: - index_size_type linearize(const value_type& idx) const noexcept + constexpr bool less(index_type& one, index_type& other) const noexcept + { + for (size_t i = 0; i < rank; ++i) + { + if (one[i] < other[i]) + return true; + } + return false; + } + + constexpr index_size_type linearize(const value_type& idx) const noexcept { // TODO: Smarter impl. // Check if past-the-end - bool pte = true; - for (size_t i = 0; i < rank; ++i) - { - if (idx[i] != boundary[i]) - { - pte = false; - break; - } - } index_size_type multiplier = 1; index_size_type res = 0; - if (pte) + if (!less(idx, boundary)) { res = 1; for (size_t i = rank; i-- > 0;) @@ -1130,119 +994,9 @@ private: } return res; } + value_type boundary; - value_type curr; -}; - -template -class bounds_iterator> - : public std::iterator, - ptrdiff_t, - const details::arrow_proxy>, - const index<1, SizeType>> -{ - using Base = std::iterator, ptrdiff_t, const details::arrow_proxy>, const index<1, SizeType>>; - -public: - using typename Base::reference; - using typename Base::pointer; - using typename Base::difference_type; - using typename Base::value_type; - using index_type = value_type; - using index_size_type = typename index_type::value_type; - - template - explicit bounds_iterator(const Bounds &, value_type curr = value_type{}) noexcept - : curr( std::move(curr) ) - {} - reference operator*() const noexcept - { - return curr; - } - pointer operator->() const noexcept - { - return details::arrow_proxy{ curr }; - } - bounds_iterator& operator++() noexcept - { - ++curr; - return *this; - } - bounds_iterator operator++(int) noexcept - { - auto ret = *this; - ++(*this); - return ret; - } - bounds_iterator& operator--() noexcept - { - curr--; - return *this; - } - bounds_iterator operator--(int) noexcept - { - auto ret = *this; - --(*this); - return ret; - } - bounds_iterator operator+(difference_type n) const noexcept - { - bounds_iterator ret{ *this }; - return ret += n; - } - bounds_iterator& operator+=(difference_type n) noexcept - { - curr += n; - return *this; - } - bounds_iterator operator-(difference_type n) const noexcept - { - bounds_iterator ret{ *this }; - return ret -= n; - } - bounds_iterator& operator-=(difference_type n) noexcept - { - return *this += -n; - } - difference_type operator-(const bounds_iterator& rhs) const noexcept - { - return curr[0] - rhs.curr[0]; - } - reference operator[](difference_type n) const noexcept - { - return curr + n; - } - bool operator==(const bounds_iterator& rhs) const noexcept - { - return curr == rhs.curr; - } - bool operator!=(const bounds_iterator& rhs) const noexcept - { - return !(*this == rhs); - } - bool operator<(const bounds_iterator& rhs) const noexcept - { - return curr[0] < rhs.curr[0]; - } - bool operator<=(const bounds_iterator& rhs) const noexcept - { - return !(rhs < *this); - } - bool operator>(const bounds_iterator& rhs) const noexcept - { - return rhs < *this; - } - bool operator>=(const bounds_iterator& rhs) const noexcept - { - return !(rhs > *this); - } - void swap(bounds_iterator& rhs) noexcept - { - std::swap(curr, rhs.curr); - } -private: - value_type curr; + std::remove_const_t curr; }; template @@ -1304,10 +1058,11 @@ public: 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_array_view_iterator, general_array_view_iterator>; - using const_iterator = std::conditional_t::value, contiguous_array_view_iterator>, general_array_view_iterator>>; + using const_iterator = std::conditional_t::value, contiguous_array_view_iterator>, general_array_view_iterator>>; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; using sliced_type = std::conditional_t>; @@ -1360,7 +1115,7 @@ public: } constexpr iterator end() const { - return iterator {this}; + return iterator {this, false}; } constexpr const_iterator cbegin() const { @@ -1368,7 +1123,7 @@ public: } constexpr const_iterator cend() const { - return const_iterator {reinterpret_cast *>(this)}; + return const_iterator {reinterpret_cast *>(this), false}; } constexpr reverse_iterator rbegin() const @@ -1999,8 +1754,8 @@ private: { 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_array_view_iterator (const ArrayView *container, bool isbegin = false) : - m_pdata(isbegin ? container->m_pdata : container->m_pdata + container->size()), m_validator(container) { } + contiguous_array_view_iterator (const ArrayView *container, bool isbegin) : + m_pdata(isbegin ? container->m_pdata : container->m_pdata + container->size()), m_validator(container) {} public: reference operator*() const noexcept { @@ -2115,16 +1870,16 @@ private: friend class basic_array_view; const ArrayView * m_container; typename ArrayView::bounds_type::iterator m_itr; - general_array_view_iterator(const ArrayView *container, bool isbegin = false) : + general_array_view_iterator(const ArrayView *container, bool isbegin) : m_container(container), m_itr(isbegin ? m_container->bounds().begin() : m_container->bounds().end()) { } public: - reference operator*() const noexcept + reference operator*() noexcept { return (*m_container)[*m_itr]; } - pointer operator->() const noexcept + pointer operator->() noexcept { return &(*m_container)[*m_itr]; } diff --git a/tests/array_view_tests.cpp b/tests/array_view_tests.cpp index f84e908..3a8acc2 100644 --- a/tests/array_view_tests.cpp +++ b/tests/array_view_tests.cpp @@ -16,16 +16,11 @@ #include #include -#include -#include -#include + #include #include #include #include -#include -#include - using namespace std; using namespace gsl; @@ -639,23 +634,14 @@ SUITE(array_view_tests) 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 + strided_array_view sav12{ av.as_array_view(dim<2>(), dim<2>()),{ { 1 },{ 1 } } }; + strided_array_view sav13{ av.as_array_view(dim<2>(), dim<2>()),{ { 1 },{ 1,1,1 } } }; + strided_array_view sav14{ av.as_array_view(dim<2>(), dim<2>()),{ { 1,1,1 },{ 1 } } }; } #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) @@ -839,6 +825,94 @@ SUITE(array_view_tests) delete[] arr; } + TEST(index_constructors) + { + { + // components of the same type + index<3> i1(0, 1, 2); + CHECK(i1[0] == 0); + + // components of different types + size_t c0 = 0; + size_t c1 = 1; + index<3> i2(c0, c1, 2); + CHECK(i2[0] == 0); + + // from array + index<3> i3 = { 0,1,2 }; + CHECK(i3[0] == 0); + + // from other index of the same size type + index<3> i4 = i3; + CHECK(i4[0] == 0); + + // from other index of bigger size type + index<3, short> i5 = i4; + CHECK(i5[0] == 0); + + // from other index of smaller size type + index<3, long long> i6 = i4; + CHECK(i6[0] == 0); + + // default + index<3, long long> i7; + CHECK(i7[0] == 0); + + // default + index<3, long long> i9 = {}; + CHECK(i9[0] == 0); + } + + { + // components of the same type + index<1> i1(0); + CHECK(i1[0] == 0); + + // components of different types + size_t c0 = 0; + index<1> i2(c0); + CHECK(i2[0] == 0); + + // from array + index<1> i3 = { 0 }; + CHECK(i3[0] == 0); + + // from int + index<1> i4 = 0; + CHECK(i4[0] == 0); + + // from other index of the same size type + index<1> i5 = i3; + CHECK(i5[0] == 0); + + // from other index of bigger size type + index<1, short> i6 = i5; + CHECK(i6[0] == 0); + + // from other index of smaller size type + index<1, long long> i7 = i6; + CHECK(i7[0] == 0); + + // default + index<1, long long> i8; + CHECK(i8[0] == 0); + + // default + index<1, long long> i9 = {}; + CHECK(i9[0] == 0); + } + +#ifdef CONFIRM_COMPILATION_ERRORS + { + index<3> i1(0, 1); + index<3> i2(0, 1, 2, 3); + index<3> i3 = { 0 }; + index<3> i4 = { 0, 1, 2, 3 }; + index<1> i5 = { 0,1 }; + } +#endif + } + TEST(index_operations) { size_t a[3] = { 0, 1, 2 }; @@ -925,11 +999,35 @@ SUITE(array_view_tests) } } - size_t idx = 0; - for (auto num : section) + size_t check_sum = 0; + for (size_t i = 0; i < length; ++i) { - CHECK(num == av[idx][1]); - idx++; + check_sum += av[i][1]; + } + + { + size_t idx = 0; + size_t sum = 0; + for (auto num : section) + { + CHECK(num == av[idx][1]); + sum += num; + idx++; + } + + CHECK(sum == check_sum); + } + { + size_t idx = length - 1; + size_t sum = 0; + for (auto iter = section.rbegin(); iter != section.rend(); ++iter) + { + CHECK(*iter == av[idx][1]); + sum += *iter; + idx--; + } + + CHECK(sum == check_sum); } } @@ -1688,7 +1786,7 @@ SUITE(array_view_tests) CHECK_THROW(f(), fail_fast); } - TEST(AsWriteableBytes) + TEST(AsWriteableBytes) { int a[] = { 1, 2, 3, 4 }; @@ -1714,7 +1812,36 @@ SUITE(array_view_tests) CHECK(wav.data() == (byte*)&a[0]); CHECK(wav.length() == sizeof(a)); } + } + TEST(NonConstIterator) + { + int a[] = { 1, 2, 3, 4 }; + + { + array_view av = a; + auto wav = av.as_writeable_bytes(); + for (auto& b : wav) + { + b = byte(0); + } + for (size_t i = 0; i < 4; ++i) + { + CHECK(a[i] == 0); + } + } + + { + array_view av = a; + for (auto& n : av) + { + n = 1; + } + for (size_t i = 0; i < 4; ++i) + { + CHECK(a[i] == 1); + } + } } TEST(ArrayViewComparison)