mirror of
https://github.com/microsoft/GSL.git
synced 2024-11-03 17:56:43 -05:00
Merge pull request #146 from annagrin/dev/annagrin/remove_coordinate_facade
Remove unnecessary coordinate_facade class.
This commit is contained in:
commit
7d55c08330
@ -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
|
||||||
|
@ -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>
|
||||||
@ -70,183 +71,9 @@ namespace details
|
|||||||
template <typename SizeType>
|
template <typename SizeType>
|
||||||
struct SizeTypeTraits
|
struct SizeTypeTraits
|
||||||
{
|
{
|
||||||
static const size_t max_value = std::is_signed<SizeType>::value ? static_cast<typename std::make_unsigned<SizeType>::type>(-1) / 2 : static_cast<SizeType>(-1);
|
static const SizeType max_value = std::is_signed<SizeType>::value ? static_cast<typename std::make_unsigned<SizeType>::type>(-1) / 2 : static_cast<SizeType>(-1);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <typename ConcreteType, typename ValueType, size_t Rank>
|
|
||||||
class coordinate_facade
|
|
||||||
{
|
|
||||||
static_assert(std::is_integral<ValueType>::value
|
|
||||||
&& sizeof(ValueType) <= sizeof(size_t), "ValueType must be an integral type!");
|
|
||||||
static_assert(Rank > 0, "Rank must be greater than 0!");
|
|
||||||
|
|
||||||
template <typename OtherConcreteType, typename OtherValueType, size_t OtherRank>
|
|
||||||
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<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, typename OtherValueType>
|
|
||||||
constexpr coordinate_facade(const coordinate_facade<OtherConcreteType, OtherValueType, Rank> & other)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < rank; ++i)
|
|
||||||
{
|
|
||||||
fail_fast_assert(static_cast<size_t>(other.elems[i]) <= SizeTypeTraits<value_type>::max_value);
|
|
||||||
elems[i] = static_cast<value_type>(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
|
||||||
{
|
{
|
||||||
@ -268,47 +95,157 @@ namespace details
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <size_t Rank, typename ValueType = size_t>
|
template <size_t Rank, typename ValueType = size_t>
|
||||||
class index : private details::coordinate_facade<index<Rank, ValueType>, ValueType, Rank>
|
class index final
|
||||||
{
|
{
|
||||||
using Base = details::coordinate_facade<index<Rank, ValueType>, ValueType, Rank>;
|
static_assert(std::is_integral<ValueType>::value, "ValueType must be an integral type!");
|
||||||
friend Base;
|
static_assert(Rank > 0, "Rank must be greater than 0!");
|
||||||
|
|
||||||
template <size_t OtherRank, typename OtherValueType>
|
template <size_t OtherRank, typename OtherValueType>
|
||||||
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
|
||||||
|
{}
|
||||||
|
|
||||||
template <typename OtherValueType>
|
constexpr index(const value_type(&values)[Rank]) noexcept
|
||||||
constexpr index(const index<Rank, OtherValueType> &other) : Base(other)
|
|
||||||
{
|
{
|
||||||
}
|
std::copy(values, values + Rank, elems);
|
||||||
constexpr static index shift_left(const index<rank+1, value_type>& other) noexcept
|
|
||||||
{
|
|
||||||
value_type (&arr)[rank] = (value_type(&)[rank])(*(other.elems + 1));
|
|
||||||
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 <typename ValueType>
|
template <typename ValueType>
|
||||||
@ -316,51 +253,50 @@ class index<1, ValueType>
|
|||||||
{
|
{
|
||||||
template <size_t, typename OtherValueType>
|
template <size_t, typename OtherValueType>
|
||||||
friend class index;
|
friend class index;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static const size_t rank = 1;
|
static const size_t rank = 1;
|
||||||
using reference = ValueType&;
|
using value_type = std::remove_reference_t<ValueType>;
|
||||||
using const_reference = const ValueType&;
|
using reference = std::add_lvalue_reference_t<value_type>;
|
||||||
using size_type = ValueType;
|
using const_reference = std::add_lvalue_reference_t<std::add_const_t<value_type>>;
|
||||||
using value_type = ValueType;
|
|
||||||
|
|
||||||
constexpr index() noexcept : value(0)
|
constexpr index() noexcept : value(0)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
constexpr index(value_type e0) noexcept : value(e0)
|
constexpr index(value_type e) noexcept : value(e)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
constexpr index(const value_type(&values)[1]) noexcept : index(values[0])
|
constexpr index(const value_type(&values)[1]) noexcept : index(values[0])
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
// Preconditions: il.size() == rank
|
|
||||||
constexpr index(std::initializer_list<value_type> il)
|
|
||||||
{
|
|
||||||
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 <typename OtherValueType>
|
template <typename OtherValueType,
|
||||||
constexpr index(const index<1, OtherValueType> & other)
|
bool Enabled = (details::SizeTypeTraits<OtherValueType>::max_value <= details::SizeTypeTraits<value_type>::max_value),
|
||||||
|
typename Other = std::enable_if_t<Enabled, index<1, OtherValueType>>>
|
||||||
|
constexpr index(const index<1, OtherValueType>& other) noexcept
|
||||||
{
|
{
|
||||||
fail_fast_assert(other.value <= details::SizeTypeTraits<ValueType>::max_value);
|
|
||||||
value = static_cast<ValueType>(other.value);
|
value = static_cast<ValueType>(other.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr static index shift_left(const index<rank + 1, value_type>& other) noexcept
|
template <typename OtherValueType,
|
||||||
|
bool Enabled = (details::SizeTypeTraits<OtherValueType>::max_value > details::SizeTypeTraits<value_type>::max_value),
|
||||||
|
typename Other = std::enable_if_t<Enabled, index<1, OtherValueType>>>
|
||||||
|
constexpr index(const index<1, OtherValueType>& other, void* ptr=0) noexcept
|
||||||
{
|
{
|
||||||
return other.elems[1];
|
fail_fast_assert(other.value <= static_cast<OtherValueType>(details::SizeTypeTraits<value_type>::max_value));
|
||||||
|
value = static_cast<value_type>(other.value);
|
||||||
}
|
}
|
||||||
// Preconditions: component_idx < rank
|
|
||||||
constexpr reference operator[](size_type component_idx) noexcept
|
// 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");
|
fail_fast_assert(component_idx == 0, "Component index must be less than rank");
|
||||||
(void)(component_idx);
|
(void)(component_idx);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
// Preconditions: component_idx < rank
|
// Preconditions: component_idx < 1
|
||||||
constexpr const_reference operator[](size_type component_idx) const noexcept
|
constexpr const_reference operator[](value_type component_idx) const noexcept
|
||||||
{
|
{
|
||||||
fail_fast_assert(component_idx == 0, "Component index must be less than rank");
|
fail_fast_assert(component_idx == 0, "Component index must be less than rank");
|
||||||
(void)(component_idx);
|
(void)(component_idx);
|
||||||
@ -442,7 +378,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:
|
||||||
value_type value;
|
value_type value;
|
||||||
@ -751,6 +687,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>
|
||||||
@ -855,9 +802,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 <typename OtherSizeTypes, size_t... Ranges>
|
template <typename OtherSizeTypes, size_t... Ranges>
|
||||||
@ -879,27 +826,23 @@ 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());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <size_t Rank, typename SizeType = size_t>
|
template <size_t Rank, typename SizeType = size_t>
|
||||||
class strided_bounds : private details::coordinate_facade<strided_bounds<Rank>, SizeType, Rank>
|
class strided_bounds
|
||||||
{
|
{
|
||||||
using Base = details::coordinate_facade<strided_bounds<Rank>, SizeType, Rank>;
|
|
||||||
friend Base;
|
|
||||||
template <size_t OtherRank, typename OtherSizeType>
|
template <size_t OtherRank, typename OtherSizeType>
|
||||||
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, size_type>;
|
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>;
|
||||||
@ -907,24 +850,15 @@ public:
|
|||||||
static const size_t static_size = dynamic_range;
|
static const size_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;
|
||||||
|
|
||||||
template <typename OtherSizeType>
|
template <typename OtherSizeType>
|
||||||
constexpr strided_bounds(const strided_bounds<rank, OtherSizeType> &other)
|
constexpr strided_bounds(const strided_bounds<rank, OtherSizeType> &other) noexcept
|
||||||
: Base(other), m_strides(other.strides)
|
: 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 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 index_type strides() const noexcept
|
constexpr index_type strides() const noexcept
|
||||||
{
|
{
|
||||||
return m_strides;
|
return m_strides;
|
||||||
@ -933,31 +867,35 @@ 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;
|
||||||
}
|
}
|
||||||
constexpr size_type size() const noexcept
|
constexpr size_type size() const noexcept
|
||||||
{
|
{
|
||||||
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;
|
||||||
}
|
}
|
||||||
constexpr bool contains(const index_type& idx) const noexcept
|
constexpr bool contains(const index_type& idx) const noexcept
|
||||||
{
|
{
|
||||||
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;
|
||||||
@ -969,17 +907,17 @@ 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
|
||||||
{
|
{
|
||||||
@ -990,6 +928,7 @@ public:
|
|||||||
return const_iterator{ *this, index_bounds() };
|
return const_iterator{ *this, index_bounds() };
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
|
index_type m_extents;
|
||||||
index_type m_strides;
|
index_type m_strides;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1017,7 +956,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())
|
||||||
@ -1210,7 +1149,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 index_type::size_type;
|
using index_size_type = typename index_type::value_type;
|
||||||
|
|
||||||
template <typename Bounds>
|
template <typename Bounds>
|
||||||
explicit bounds_iterator(const Bounds &, value_type curr = value_type{}) noexcept
|
explicit bounds_iterator(const Bounds &, value_type curr = value_type{}) noexcept
|
||||||
@ -1327,11 +1266,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>
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user