Conflicts:
	include/array_view.h
This commit is contained in:
Neil MacIntosh 2015-10-15 16:38:53 -07:00
commit d0f09e768e
3 changed files with 384 additions and 256 deletions

View File

@ -12,6 +12,7 @@ matrix:
packages: packages:
- clang-3.6 - clang-3.6
- cmake - cmake
- g++-5
sources: &sources sources: &sources
- ubuntu-toolchain-r-test - ubuntu-toolchain-r-test
- llvm-toolchain-precise-3.6 - llvm-toolchain-precise-3.6

View File

@ -24,6 +24,7 @@
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <limits> #include <limits>
#include <numeric>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include <array> #include <array>
@ -67,179 +68,6 @@ namespace gsl {
*/ */
namespace details namespace details
{ {
template <typename ConcreteType, size_t Rank>
class coordinate_facade
{
static_assert(Rank > 0, "Rank must be greater than 0!");
template <typename OtherConcreteType, size_t OtherRank>
friend class coordinate_facade;
public:
using reference = std::add_lvalue_reference_t<std::ptrdiff_t>;
using const_reference = std::add_const_t<reference>;
using value_type = std::ptrdiff_t;
static const size_t rank = Rank;
constexpr coordinate_facade() noexcept
{
static_assert(std::is_base_of<coordinate_facade, ConcreteType>::value, "ConcreteType must be derived from coordinate_facade.");
}
constexpr coordinate_facade(const value_type(&values)[rank]) noexcept
{
static_assert(std::is_base_of<coordinate_facade, ConcreteType>::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<coordinate_facade, ConcreteType>::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<value_type> il)
{
static_assert(std::is_base_of<coordinate_facade, ConcreteType>::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 <typename OtherConcreteType>
constexpr coordinate_facade(const coordinate_facade<OtherConcreteType, Rank>& other)
{
for (size_t i = 0; i < rank; ++i)
elems[i] = 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<ValueType>{});
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<const ConcreteType&>(*this);
}
constexpr ConcreteType& to_concrete() noexcept
{
return static_cast<ConcreteType&>(*this);
}
};
template <typename T> template <typename T>
class arrow_proxy class arrow_proxy
{ {
@ -261,43 +89,156 @@ namespace details
} }
template <size_t Rank> template <size_t Rank>
class index : private details::coordinate_facade<index<Rank>, Rank> class index final
{ {
using Base = details::coordinate_facade<index<Rank>, Rank>; static_assert(Rank > 0, "Rank must be greater than 0!");
friend Base;
template <size_t OtherRank> template <size_t OtherRank>
friend class index; friend class index;
public: public:
using Base::rank; static const size_t rank = Rank;
using reference = typename Base::reference; using value_type = std::remove_reference_t<ValueType>;
using const_reference = typename Base::const_reference; using reference = std::add_lvalue_reference_t<value_type>;
using size_type = typename Base::value_type; using const_reference = std::add_lvalue_reference_t<std::add_const_t<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<value_type> il) : Base(il) {}
constexpr index(const index &) = default; constexpr index() noexcept
{}
constexpr static index shift_left(const index<rank+1>& other) noexcept constexpr index(const value_type(&values)[Rank]) noexcept
{ {
value_type (&arr)[rank] = (value_type(&)[rank])(*(other.elems + 1)); std::copy(values, values + Rank, elems);
return index(arr);
} }
using Base::operator[]; // Preconditions: il.size() == rank
using Base::operator==; constexpr index(std::initializer_list<value_type> il) noexcept
using Base::operator!=; {
using Base::operator+; fail_fast_assert(il.size() == Rank, "The size of the initializer list must match the rank of the array");
using Base::operator-; std::copy(begin(il), end(il), elems);
using Base::operator+=; }
using Base::operator-=;
using Base::operator++; constexpr index(const index& other) noexcept = default;
using Base::operator--;
using Base::operator*; // copy from index over smaller domain
using Base::operator/; template <typename OtherValueType,
using Base::operator*=; bool Enabled = (details::SizeTypeTraits<OtherValueType>::max_value <= details::SizeTypeTraits<value_type>::max_value),
using Base::operator/=; typename Other = std::enable_if_t<Enabled, index<Rank, OtherValueType>>>
constexpr index(const index<Rank, OtherValueType>& other) noexcept
{
std::copy(other.elems, other.elems + Rank, elems);
}
// copy from index over larger domain
template <typename OtherValueType,
bool Enabled = (details::SizeTypeTraits<OtherValueType>::max_value > details::SizeTypeTraits<value_type>::max_value),
typename Other = std::enable_if_t<Enabled, index<Rank, OtherValueType>>>
constexpr index(const index<Rank, OtherValueType>& other, void* ptr = 0) noexcept
{
bool ok = std::accumulate(other.elems, other.elems + Rank, true,
[&](bool b, OtherValueType val) { return b && (val <= static_cast<OtherValueType>(details::SizeTypeTraits<value_type>::max_value)); }
);
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<value_type>(val); });
}
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<ValueType>{});
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<ValueType>{});
return *this;
}
constexpr index& operator-=(const index& rhs) noexcept
{
std::transform(elems, elems + rank, rhs.elems, elems, std::minus<ValueType>{});
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 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<ValueType>{}(x, v); });
return *this;
}
constexpr index& operator/=(value_type v) noexcept
{
std::transform(elems, elems + rank, elems, [v](value_type x) { return std::divides<ValueType>{}(x, v); });
return *this;
}
private:
value_type elems[Rank] = {};
}; };
template<> template<>
@ -326,12 +267,19 @@ public:
value = begin(il)[0]; value = begin(il)[0];
} }
constexpr index(const index &) = default; template <size_t, typename OtherValueType>
friend class index;
constexpr static index shift_left(const index<rank + 1>& other) noexcept constexpr index() noexcept : value(0)
{ {}
return other.elems[1];
} 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;
// Preconditions: component_idx < rank // Preconditions: component_idx < rank
constexpr reference operator[](size_type component_idx) noexcept constexpr reference operator[](size_type component_idx) noexcept
@ -439,7 +387,7 @@ public:
friend constexpr index operator*(value_type v, const index& rhs) noexcept friend constexpr index operator*(value_type v, const index& rhs) noexcept
{ {
return index(rhs * v); return{ rhs * v };
} }
private: private:
@ -696,6 +644,17 @@ namespace details
{ {
return TypeListIndexer<TypeChain>(obj); return TypeListIndexer<TypeChain>(obj);
} }
template <size_t Rank, typename ValueType, bool Enabled = (Rank > 1), typename Ret = std::enable_if_t<Enabled, index<Rank - 1, ValueType>>>
constexpr Ret shift_left(const index<Rank, ValueType>& other) noexcept
{
Ret ret;
for (size_t i = 0; i < Rank - 1; ++i)
{
ret[i] = other[i + 1];
}
return ret;
}
} }
template <typename IndexType> template <typename IndexType>
@ -799,9 +758,9 @@ public:
constexpr index_type index_bounds() const noexcept constexpr index_type index_bounds() const noexcept
{ {
index_type extents; size_type extents[rank] = {};
m_ranges.serialize(extents); m_ranges.serialize(extents);
return extents; return{ extents };
} }
template <std::ptrdiff_t... Ranges> template <std::ptrdiff_t... Ranges>
@ -823,8 +782,6 @@ public:
constexpr const_iterator end() const noexcept constexpr const_iterator end() const noexcept
{ {
index_type boundary;
m_ranges.serialize(boundary);
return const_iterator(*this, this->index_bounds()); return const_iterator(*this, this->index_bounds());
} }
}; };
@ -839,20 +796,21 @@ class strided_bounds : private details::coordinate_facade<strided_bounds<Rank>,
friend class strided_bounds; friend class strided_bounds;
public: public:
using Base::rank; static const size_t rank = Rank;
using reference = typename Base::reference; using reference = SizeType&;
using const_reference = typename Base::const_reference; using const_reference = const SizeType&;
using size_type = typename Base::value_type; using size_type = SizeType;
using difference_type = typename Base::value_type; using difference_type = SizeType;
using value_type = typename Base::value_type; using value_type = SizeType;
using index_type = index<rank>; using index_type = index<rank, size_type>;
using iterator = bounds_iterator<index_type>; using iterator = bounds_iterator<index_type>;
using const_iterator = bounds_iterator<index_type>; using const_iterator = bounds_iterator<index_type>;
static const int dynamic_rank = rank; static const size_t dynamic_rank = rank;
static const std::ptrdiff_t static_size = dynamic_range; static const std::ptrdiff_t static_size = dynamic_range;
using sliced_type = std::conditional_t<rank != 0, strided_bounds<rank - 1>, void>; using sliced_type = std::conditional_t<rank != 0, strided_bounds<rank - 1>, void>;
using mapping_type = generalized_mapping_tag; using mapping_type = generalized_mapping_tag;
constexpr strided_bounds(const strided_bounds &) = default;
constexpr strided_bounds(const strided_bounds &) noexcept = default;
constexpr strided_bounds(const index_type& extents, const index_type& strides) constexpr strided_bounds(const index_type& extents, const index_type& strides)
: m_strides(strides) : m_strides(strides)
@ -865,6 +823,10 @@ public:
: Base(values), m_strides(std::move(strides)) : Base(values), m_strides(std::move(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 constexpr index_type strides() const noexcept
{ {
return m_strides; return m_strides;
@ -874,7 +836,9 @@ public:
{ {
size_type ret = 0; size_type ret = 0;
for (size_t i = 0; i < rank; ++i) 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; return ret + 1;
} }
@ -882,7 +846,9 @@ public:
{ {
size_type ret = 1; size_type ret = 1;
for (size_t i = 0; i < rank; ++i) for (size_t i = 0; i < rank; ++i)
ret *= Base::elems[i]; {
ret *= m_extents[i];
}
return ret; return ret;
} }
@ -890,18 +856,18 @@ public:
{ {
for (size_t i = 0; i < rank; ++i) 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 false;
} }
return true; 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; size_type ret = 0;
for (size_t i = 0; i < rank; i++) 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]; ret += idx[i] * m_strides[i];
} }
return ret; return ret;
@ -915,19 +881,19 @@ public:
template <bool Enabled = (rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>> template <bool Enabled = (rank > 1), typename Ret = std::enable_if_t<Enabled, sliced_type>>
constexpr sliced_type slice() const constexpr sliced_type slice() const
{ {
return{ (value_type(&)[rank - 1])Base::elems[1], sliced_type::index_type::shift_left(m_strides) }; return{ details::shift_left(m_extents), details::shift_left(m_strides) };
} }
template <size_t Dim = 0> template <size_t Dim = 0>
constexpr size_type extent() const noexcept constexpr size_type extent() const noexcept
{ {
static_assert(Dim < Rank, "dimension should be less than rank (dimension count starts from 0)"); 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 constexpr index_type index_bounds() const noexcept
{ {
return index_type(Base::elems); return m_extents;
} }
const_iterator begin() const noexcept const_iterator begin() const noexcept
@ -941,6 +907,7 @@ public:
} }
private: private:
index_type m_extents;
index_type m_strides; index_type m_strides;
}; };
@ -968,7 +935,7 @@ public:
using typename Base::difference_type; using typename Base::difference_type;
using typename Base::value_type; using typename Base::value_type;
using index_type = value_type; using index_type = value_type;
using index_size_type = typename IndexType::size_type; using index_size_type = typename IndexType::value_type;
template <typename Bounds> template <typename Bounds>
explicit bounds_iterator(const Bounds& bnd, value_type curr = value_type{}) noexcept explicit bounds_iterator(const Bounds& bnd, value_type curr = value_type{}) noexcept
: boundary(bnd.index_bounds()) : boundary(bnd.index_bounds())
@ -1278,11 +1245,14 @@ namespace details
constexpr std::enable_if_t<std::is_same<typename Bounds::mapping_type, contiguous_mapping_tag>::value, typename Bounds::index_type> make_stride(const Bounds& bnd) noexcept constexpr std::enable_if_t<std::is_same<typename Bounds::mapping_type, contiguous_mapping_tag>::value, typename Bounds::index_type> make_stride(const Bounds& bnd) noexcept
{ {
auto extents = bnd.index_bounds(); auto extents = bnd.index_bounds();
typename Bounds::index_type stride; typename Bounds::size_type stride[Bounds::rank] = {};
stride[Bounds::rank - 1] = 1; 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]; {
return stride; stride[Bounds::rank - i - 1] = stride[Bounds::rank - i] * extents[Bounds::rank - i];
}
return{ stride };
} }
template <typename BoundsSrc, typename BoundsDest> template <typename BoundsSrc, typename BoundsDest>

View File

@ -17,6 +17,7 @@
#include <UnitTest++/UnitTest++.h> #include <UnitTest++/UnitTest++.h>
#include <array_view.h> #include <array_view.h>
#include <numeric> #include <numeric>
#include <limits>
#include <array> #include <array>
#include <string> #include <string>
#include <vector> #include <vector>
@ -635,27 +636,26 @@ SUITE(array_view_tests)
strided_array_view<int, 2> sav5{ av.as_array_view(dim<2>(), dim<2>()), { 1 } }; strided_array_view<int, 2> sav5{ av.as_array_view(dim<2>(), dim<2>()), { 1 } };
strided_array_view<int, 2> sav6{ av.as_array_view(dim<2>(), dim<2>()), { 1,1,1 } }; strided_array_view<int, 2> sav6{ av.as_array_view(dim<2>(), dim<2>()), { 1,1,1 } };
strided_array_view<int, 2> sav7{ av.as_array_view(dim<2>(), dim<2>()), { { 1,1 },{ 1,1 },{ 1,1 } } }; strided_array_view<int, 2> sav7{ av.as_array_view(dim<2>(), dim<2>()), { { 1,1 },{ 1,1 },{ 1,1 } } };
index<1> index{ 0, 1 };
strided_array_view<int, 1> sav8{ arr,{ 1,{ 1,1 } } };
#ifdef _MSC_VER
strided_array_view<int, 1> sav9{ arr,{ { 1,1 },{ 1,1 } } };
#endif
strided_array_view<int, 1> sav10{ av,{ 1,{ 1,1 } } };
#ifdef _MSC_VER
strided_array_view<int, 1> sav11{ av,{ { 1,1 },{ 1,1 } } };
#endif
} }
#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<int, 1>{ arr, {1, {1,1}} }), fail_fast);
#ifdef _MSC_VER
CHECK_THROW((strided_array_view<int, 1>{ arr, {{1,1 }, {1,1}} }), fail_fast);
#endif
CHECK_THROW((strided_array_view<int, 1>{ av, {1, {1,1}} }), fail_fast);
#ifdef _MSC_VER
CHECK_THROW((strided_array_view<int, 1>{ av, {{1,1 }, {1,1}} }), fail_fast);
#endif
CHECK_THROW((strided_array_view<int, 2>{ av.as_array_view(dim<2>(), dim<2>()), {{1}, {1}} }), fail_fast); CHECK_THROW((strided_array_view<int, 2>{ av.as_array_view(dim<2>(), dim<2>()), {{1}, {1}} }), fail_fast);
CHECK_THROW((strided_array_view<int, 2>{ av.as_array_view(dim<2>(), dim<2>()), {{1}, {1,1,1}} }), fail_fast); CHECK_THROW((strided_array_view<int, 2>{ av.as_array_view(dim<2>(), dim<2>()), {{1}, {1,1,1}} }), fail_fast);
#ifdef _MSC_VER #ifdef _MSC_VER
CHECK_THROW((strided_array_view<int, 2>{ av.as_array_view(dim<2>(), dim<2>()), {{1,1,1}, {1}} }), fail_fast); CHECK_THROW((strided_array_view<int, 2>{ av.as_array_view(dim<2>(), dim<2>()), {{1,1,1}, {1}} }), fail_fast);
#endif #endif
} }
} }
TEST(strided_array_view_type_conversion) TEST(strided_array_view_type_conversion)
@ -873,7 +873,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[0] == 0);
CHECK(i[1] == 1); CHECK(i[1] == 1);
@ -1168,6 +1179,152 @@ SUITE(array_view_tests)
} }
template<size_t Rank, typename T1, typename T2>
index<Rank, T2> Convert(index<Rank, T1> 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{ std::numeric_limits<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{ std::numeric_limits<int>::max(), 1 };
index<2, long long> longlong_index{ big_int_index };
CHECK(longlong_index[0] == std::numeric_limits<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{ std::numeric_limits<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{ std::numeric_limits<int>::max() };
index<1, long long> longlong_index{ big_int_index };
CHECK(longlong_index[0] == std::numeric_limits<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) TEST(constructors)
{ {
array_view<int, dynamic_range> av(nullptr); array_view<int, dynamic_range> av(nullptr);