Allow symbols to be used in compile-time expressions.
diff --git a/Eigen/src/Core/ArithmeticSequence.h b/Eigen/src/Core/ArithmeticSequence.h index ae3fac3..ae6373d 100644 --- a/Eigen/src/Core/ArithmeticSequence.h +++ b/Eigen/src/Core/ArithmeticSequence.h
@@ -61,26 +61,28 @@ template <typename FirstType, typename SizeType, typename IncrType> class ArithmeticSequence { public: - ArithmeticSequence(FirstType first, SizeType size) : m_first(first), m_size(size) {} - ArithmeticSequence(FirstType first, SizeType size, IncrType incr) : m_first(first), m_size(size), m_incr(incr) {} + constexpr ArithmeticSequence() = default; + constexpr ArithmeticSequence(FirstType first, SizeType size) : m_first(first), m_size(size) {} + constexpr ArithmeticSequence(FirstType first, SizeType size, IncrType incr) + : m_first(first), m_size(size), m_incr(incr) {} enum { - SizeAtCompileTime = internal::get_fixed_value<SizeType>::value, + // SizeAtCompileTime = internal::get_fixed_value<SizeType>::value, IncrAtCompileTime = internal::get_fixed_value<IncrType, DynamicIndex>::value }; /** \returns the size, i.e., number of elements, of the sequence */ - Index size() const { return m_size; } + constexpr Index size() const { return m_size; } /** \returns the first element \f$ a_0 \f$ in the sequence */ - Index first() const { return m_first; } + constexpr Index first() const { return m_first; } /** \returns the value \f$ a_i \f$ at index \a i in the sequence. */ - Index operator[](Index i) const { return m_first + i * m_incr; } + constexpr Index operator[](Index i) const { return m_first + i * m_incr; } - const FirstType& firstObject() const { return m_first; } - const SizeType& sizeObject() const { return m_size; } - const IncrType& incrObject() const { return m_incr; } + constexpr const FirstType& firstObject() const { return m_first; } + constexpr const SizeType& sizeObject() const { return m_size; } + constexpr const IncrType& incrObject() const { return m_incr; } protected: FirstType m_first; @@ -88,7 +90,7 @@ IncrType m_incr; public: - auto reverse() const -> decltype(Eigen::seqN(m_first + (m_size + fix<-1>()) * m_incr, m_size, -m_incr)) { + constexpr auto reverse() const -> decltype(Eigen::seqN(m_first + (m_size + fix<-1>()) * m_incr, m_size, -m_incr)) { return seqN(m_first + (m_size + fix<-1>()) * m_incr, m_size, -m_incr); } }; @@ -201,38 +203,6 @@ } // namespace placeholders -namespace internal { - -// Convert a symbolic span into a usable one (i.e., remove last/end "keywords") -template <typename T> -struct make_size_type { - typedef std::conditional_t<symbolic::is_symbolic<T>::value, Index, T> type; -}; - -template <typename FirstType, typename SizeType, typename IncrType, int XprSize> -struct IndexedViewCompatibleType<ArithmeticSequence<FirstType, SizeType, IncrType>, XprSize> { - typedef ArithmeticSequence<Index, typename make_size_type<SizeType>::type, IncrType> type; -}; - -template <typename FirstType, typename SizeType, typename IncrType> -ArithmeticSequence<Index, typename make_size_type<SizeType>::type, IncrType> makeIndexedViewCompatible( - const ArithmeticSequence<FirstType, SizeType, IncrType>& ids, Index size, SpecializedType) { - return ArithmeticSequence<Index, typename make_size_type<SizeType>::type, IncrType>( - eval_expr_given_size(ids.firstObject(), size), eval_expr_given_size(ids.sizeObject(), size), ids.incrObject()); -} - -template <typename FirstType, typename SizeType, typename IncrType> -struct get_compile_time_incr<ArithmeticSequence<FirstType, SizeType, IncrType> > { - enum { value = get_fixed_value<IncrType, DynamicIndex>::value }; -}; - -template <typename FirstType, typename SizeType, typename IncrType> -constexpr Index get_runtime_incr(const ArithmeticSequence<FirstType, SizeType, IncrType>& x) EIGEN_NOEXCEPT { - return static_cast<Index>(x.incrObject()); -} - -} // end namespace internal - /** \namespace Eigen::indexing * \ingroup Core_Module *
diff --git a/Eigen/src/Core/IndexedView.h b/Eigen/src/Core/IndexedView.h index b90ecb1..454e560 100644 --- a/Eigen/src/Core/IndexedView.h +++ b/Eigen/src/Core/IndexedView.h
@@ -20,8 +20,8 @@ template <typename XprType, typename RowIndices, typename ColIndices> struct traits<IndexedView<XprType, RowIndices, ColIndices>> : traits<XprType> { enum { - RowsAtCompileTime = int(array_size<RowIndices>::value), - ColsAtCompileTime = int(array_size<ColIndices>::value), + RowsAtCompileTime = int(IndexedViewHelper<RowIndices>::SizeAtCompileTime), + ColsAtCompileTime = int(IndexedViewHelper<ColIndices>::SizeAtCompileTime), MaxRowsAtCompileTime = RowsAtCompileTime, MaxColsAtCompileTime = ColsAtCompileTime, @@ -30,8 +30,8 @@ : (MaxColsAtCompileTime == 1 && MaxRowsAtCompileTime != 1) ? 0 : XprTypeIsRowMajor, - RowIncr = int(get_compile_time_incr<RowIndices>::value), - ColIncr = int(get_compile_time_incr<ColIndices>::value), + RowIncr = int(IndexedViewHelper<RowIndices>::IncrAtCompileTime), + ColIncr = int(IndexedViewHelper<ColIndices>::IncrAtCompileTime), InnerIncr = IsRowMajor ? ColIncr : RowIncr, OuterIncr = IsRowMajor ? RowIncr : ColIncr, @@ -47,24 +47,23 @@ is_same<AllRange<InnerSize>, std::conditional_t<XprTypeIsRowMajor, ColIndices, RowIndices>>::value, InnerStrideAtCompileTime = - InnerIncr < 0 || InnerIncr == DynamicIndex || XprInnerStride == Dynamic || InnerIncr == UndefinedIncr + InnerIncr < 0 || InnerIncr == DynamicIndex || XprInnerStride == Dynamic || InnerIncr == Undefined ? Dynamic : XprInnerStride * InnerIncr, OuterStrideAtCompileTime = - OuterIncr < 0 || OuterIncr == DynamicIndex || XprOuterstride == Dynamic || OuterIncr == UndefinedIncr + OuterIncr < 0 || OuterIncr == DynamicIndex || XprOuterstride == Dynamic || OuterIncr == Undefined ? Dynamic : XprOuterstride * OuterIncr, - ReturnAsScalar = is_same<RowIndices, SingleRange>::value && is_same<ColIndices, SingleRange>::value, + ReturnAsScalar = is_single_range<RowIndices>::value && is_single_range<ColIndices>::value, ReturnAsBlock = (!ReturnAsScalar) && IsBlockAlike, ReturnAsIndexedView = (!ReturnAsScalar) && (!ReturnAsBlock), // FIXME we deal with compile-time strides if and only if we have DirectAccessBit flag, // but this is too strict regarding negative strides... - DirectAccessMask = - (int(InnerIncr) != UndefinedIncr && int(OuterIncr) != UndefinedIncr && InnerIncr >= 0 && OuterIncr >= 0) - ? DirectAccessBit - : 0, + DirectAccessMask = (int(InnerIncr) != Undefined && int(OuterIncr) != Undefined && InnerIncr >= 0 && OuterIncr >= 0) + ? DirectAccessBit + : 0, FlagsRowMajorBit = IsRowMajor ? RowMajorBit : 0, FlagsLvalueBit = is_lvalue<XprType>::value ? LvalueBit : 0, FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1) ? LinearAccessBit : 0, @@ -153,10 +152,10 @@ : m_xpr(xpr), m_rowIndices(rowIndices), m_colIndices(colIndices) {} /** \returns number of rows */ - Index rows() const { return internal::index_list_size(m_rowIndices); } + Index rows() const { return IndexedViewHelper<RowIndices>::size(m_rowIndices); } /** \returns number of columns */ - Index cols() const { return internal::index_list_size(m_colIndices); } + Index cols() const { return IndexedViewHelper<ColIndices>::size(m_colIndices); } /** \returns the nested expression */ const internal::remove_all_t<XprType>& nestedExpression() const { return m_xpr; } @@ -198,16 +197,16 @@ IndexedViewImpl(XprType& xpr, const T0& rowIndices, const T1& colIndices) : Base(xpr, rowIndices, colIndices) {} Index rowIncrement() const { - if (traits<Derived>::RowIncr != DynamicIndex && traits<Derived>::RowIncr != UndefinedIncr) { + if (traits<Derived>::RowIncr != DynamicIndex && traits<Derived>::RowIncr != Undefined) { return traits<Derived>::RowIncr; } - return get_runtime_incr(this->rowIndices()); + return IndexedViewHelper<RowIndices>::incr(this->rowIndices()); } Index colIncrement() const { - if (traits<Derived>::ColIncr != DynamicIndex && traits<Derived>::ColIncr != UndefinedIncr) { + if (traits<Derived>::ColIncr != DynamicIndex && traits<Derived>::ColIncr != Undefined) { return traits<Derived>::ColIncr; } - return get_runtime_incr(this->colIndices()); + return IndexedViewHelper<ColIndices>::incr(this->colIndices()); } Index innerIncrement() const { return traits<Derived>::IsRowMajor ? colIncrement() : rowIncrement(); }
diff --git a/Eigen/src/Core/util/Constants.h b/Eigen/src/Core/util/Constants.h index 8b06c67..9f4a2d8 100644 --- a/Eigen/src/Core/util/Constants.h +++ b/Eigen/src/Core/util/Constants.h
@@ -29,9 +29,9 @@ */ const int DynamicIndex = 0xffffff; -/** This value means that the increment to go from one value to another in a sequence is not constant for each step. +/** This value means that the requested value is not defined. */ -const int UndefinedIncr = 0xfffffe; +const int Undefined = 0xfffffe; /** This value means +Infinity; it is currently used only as the p parameter to MatrixBase::lpNorm<int>(). * The value Infinity there means the L-infinity norm.
diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index c312939..2f2ba9b 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h
@@ -91,6 +91,8 @@ class IndexedView; template <typename XprType, int Rows = Dynamic, int Cols = Dynamic, int Order = 0> class Reshaped; +template <typename FirstType, typename SizeType, typename IncrType> +class ArithmeticSequence; template <typename MatrixType, int Size = Dynamic> class VectorBlock;
diff --git a/Eigen/src/Core/util/IndexedViewHelper.h b/Eigen/src/Core/util/IndexedViewHelper.h index 9d1b348..c187002 100644 --- a/Eigen/src/Core/util/IndexedViewHelper.h +++ b/Eigen/src/Core/util/IndexedViewHelper.h
@@ -17,6 +17,9 @@ namespace internal { struct symbolic_last_tag {}; + +struct all_t {}; + } // namespace internal namespace placeholders { @@ -42,131 +45,7 @@ * * \sa end */ -static const last_t last; - -} // namespace placeholders - -namespace internal { - -// Replace symbolic last/end "keywords" by their true runtime value -inline Index eval_expr_given_size(Index x, Index /* size */) { return x; } - -template <int N> -FixedInt<N> eval_expr_given_size(FixedInt<N> x, Index /*size*/) { - return x; -} - -template <typename Derived> -Index eval_expr_given_size(const symbolic::BaseExpr<Derived>& x, Index size) { - return x.derived().eval(Eigen::placeholders::last = size - 1); -} - -// Extract increment/step at compile time -template <typename T, typename EnableIf = void> -struct get_compile_time_incr { - enum { value = UndefinedIncr }; -}; - -template <typename T> -constexpr Index get_runtime_incr(const T&) EIGEN_NOEXCEPT { - return Index(1); -} - -// Analogue of std::get<0>(x), but tailored for our needs. -template <typename T> -EIGEN_CONSTEXPR Index first(const T& x) EIGEN_NOEXCEPT { - return x.first(); -} - -// IndexedViewCompatibleType/makeIndexedViewCompatible turn an arbitrary object of type T into something usable by -// MatrixSlice The generic implementation is a no-op -template <typename T, int XprSize, typename EnableIf = void> -struct IndexedViewCompatibleType { - typedef T type; -}; - -template <typename T, typename Q> -const T& makeIndexedViewCompatible(const T& x, Index /*size*/, Q) { - return x; -} - -//-------------------------------------------------------------------------------- -// Handling of a single Index -//-------------------------------------------------------------------------------- - -struct SingleRange { - enum { SizeAtCompileTime = 1 }; - SingleRange(Index val) : m_value(val) {} - Index operator[](Index) const { return m_value; } - static EIGEN_CONSTEXPR Index size() EIGEN_NOEXCEPT { return 1; } - Index first() const EIGEN_NOEXCEPT { return m_value; } - Index m_value; -}; - -template <> -struct get_compile_time_incr<SingleRange> { - enum { value = 1 }; // 1 or 0 ?? -}; - -// Turn a single index into something that looks like an array (i.e., that exposes a .size(), and operator[](int) -// methods) -template <typename T, int XprSize> -struct IndexedViewCompatibleType<T, XprSize, std::enable_if_t<internal::is_integral<T>::value>> { - // Here we could simply use Array, but maybe it's less work for the compiler to use - // a simpler wrapper as SingleRange - // typedef Eigen::Array<Index,1,1> type; - typedef SingleRange type; -}; - -template <typename T, int XprSize> -struct IndexedViewCompatibleType<T, XprSize, std::enable_if_t<symbolic::is_symbolic<T>::value>> { - typedef SingleRange type; -}; - -template <typename T> -std::enable_if_t<symbolic::is_symbolic<T>::value, SingleRange> makeIndexedViewCompatible(const T& id, Index size, - SpecializedType) { - return eval_expr_given_size(id, size); -} - -//-------------------------------------------------------------------------------- -// Handling of all -//-------------------------------------------------------------------------------- - -struct all_t { - all_t() {} -}; - -// Convert a symbolic 'all' into a usable range type -template <int XprSize> -struct AllRange { - enum { SizeAtCompileTime = XprSize }; - AllRange(Index size = XprSize) : m_size(size) {} - EIGEN_CONSTEXPR Index operator[](Index i) const EIGEN_NOEXCEPT { return i; } - EIGEN_CONSTEXPR Index size() const EIGEN_NOEXCEPT { return m_size.value(); } - EIGEN_CONSTEXPR Index first() const EIGEN_NOEXCEPT { return 0; } - variable_if_dynamic<Index, XprSize> m_size; -}; - -template <int XprSize> -struct IndexedViewCompatibleType<all_t, XprSize> { - typedef AllRange<XprSize> type; -}; - -template <typename XprSizeType> -inline AllRange<get_fixed_value<XprSizeType>::value> makeIndexedViewCompatible(all_t, XprSizeType size, - SpecializedType) { - return AllRange<get_fixed_value<XprSizeType>::value>(size); -} - -template <int Size> -struct get_compile_time_incr<AllRange<Size>> { - enum { value = 1 }; -}; - -} // end namespace internal - -namespace placeholders { +static constexpr const last_t last; typedef symbolic::AddExpr<symbolic::SymbolExpr<internal::symbolic_last_tag>, symbolic::ValueExpr<Eigen::internal::FixedInt<1>>> @@ -186,28 +65,251 @@ * \sa last */ #ifdef EIGEN_PARSED_BY_DOXYGEN -static const auto lastp1 = last + fix<1>; +static constexpr auto lastp1 = last + fix<1>; #else // Using a FixedExpr<1> expression is important here to make sure the compiler // can fully optimize the computation starting indices with zero overhead. -static const lastp1_t lastp1(last + fix<1>()); +static constexpr lastp1_t lastp1(last + fix<1>()); #endif /** \var end * \ingroup Core_Module * \sa lastp1 */ -static const lastp1_t end = lastp1; +static constexpr lastp1_t end = lastp1; /** \var all * \ingroup Core_Module * Can be used as a parameter to DenseBase::operator()(const RowIndices&, const ColIndices&) to index all rows or * columns */ -static const Eigen::internal::all_t all; +static constexpr Eigen::internal::all_t all; } // namespace placeholders +namespace internal { + +// Evaluate a symbolic expression or constant given the "size" of an object, allowing +// any symbols like `last` to be evaluated. The default here assumes a dynamic constant. +template <typename Expr, int SizeAtCompileTime, typename EnableIf = void> +struct SymbolicExpressionEvaluator { + static constexpr Index ValueAtCompileTime = Undefined; + static Index eval(const Expr& expr, Index /*size*/) { return static_cast<Index>(expr); } +}; + +// Symbolic expression with size known at compile-time. +template <typename Expr, int SizeAtCompileTime> +struct SymbolicExpressionEvaluator<Expr, SizeAtCompileTime, std::enable_if_t<symbolic::is_symbolic<Expr>::value>> { + static constexpr Index ValueAtCompileTime = + Expr::Derived::eval_at_compile_time(Eigen::placeholders::last = fix<SizeAtCompileTime - 1>); + static Index eval(const Expr& expr, Index /*size*/) { + return expr.eval(Eigen::placeholders::last = fix<SizeAtCompileTime - 1>); + } +}; + +// Symbolic expression with dynamic size. +template <typename Expr> +struct SymbolicExpressionEvaluator<Expr, Dynamic, std::enable_if_t<symbolic::is_symbolic<Expr>::value>> { + static constexpr Index ValueAtCompileTime = Undefined; + static Index eval(const Expr& expr, Index size) { return expr.eval(Eigen::placeholders::last = size - 1); } +}; + +// Fixed int. +template <int N, int SizeAtCompileTime> +struct SymbolicExpressionEvaluator<FixedInt<N>, SizeAtCompileTime, void> { + static constexpr Index ValueAtCompileTime = static_cast<Index>(N); + static Index eval(const FixedInt<N>& /*expr*/, Index /*size*/) { return ValueAtCompileTime; } +}; + +//-------------------------------------------------------------------------------- +// Handling of generic indices (e.g. array) +//-------------------------------------------------------------------------------- + +// Potentially wrap indices in a type that is better-suited for IndexedView evaluation. +template <typename Indices, int NestedSizeAtCompileTime, typename EnableIf = void> +struct IndexedViewHelperIndicesWrapper { + using type = Indices; + static const type& CreateIndexSequence(const Indices& indices, Index /*nested_size*/) { return indices; } +}; + +// Extract compile-time and runtime first, size, increments. +template <typename Indices, typename EnableIf = void> +struct IndexedViewHelper { + static constexpr Index FirstAtCompileTime = Undefined; + static constexpr Index SizeAtCompileTime = array_size<Indices>::value; + static constexpr Index IncrAtCompileTime = Undefined; + + static constexpr Index first(const Indices& indices) { return static_cast<Index>(indices[0]); } + static constexpr Index size(const Indices& indices) { return index_list_size(indices); } + static constexpr Index incr(const Indices& /*indices*/) { return Undefined; } +}; + +//-------------------------------------------------------------------------------- +// Handling of ArithmeticSequence +//-------------------------------------------------------------------------------- + +template <Index FirstAtCompileTime_, Index SizeAtCompileTime_, Index IncrAtCompileTime_> +class ArithmeticSequenceRange { + public: + static constexpr Index FirstAtCompileTime = FirstAtCompileTime_; + static constexpr Index SizeAtCompileTime = SizeAtCompileTime_; + static constexpr Index IncrAtCompileTime = IncrAtCompileTime_; + + constexpr ArithmeticSequenceRange(Index first, Index size, Index incr) : first_{first}, size_{size}, incr_{incr} {} + constexpr Index operator[](Index i) const { return first() + i * incr(); } + constexpr Index first() const noexcept { return first_.value(); } + constexpr Index size() const noexcept { return size_.value(); } + constexpr Index incr() const noexcept { return incr_.value(); } + + private: + variable_if_dynamicindex<Index, int(FirstAtCompileTime)> first_; + variable_if_dynamic<Index, int(SizeAtCompileTime)> size_; + variable_if_dynamicindex<Index, int(IncrAtCompileTime)> incr_; +}; + +template <typename FirstType, typename SizeType, typename IncrType, int NestedSizeAtCompileTime> +struct IndexedViewHelperIndicesWrapper<ArithmeticSequence<FirstType, SizeType, IncrType>, NestedSizeAtCompileTime, + void> { + static constexpr Index EvalFirstAtCompileTime = + SymbolicExpressionEvaluator<FirstType, NestedSizeAtCompileTime>::ValueAtCompileTime; + static constexpr Index EvalSizeAtCompileTime = + SymbolicExpressionEvaluator<SizeType, NestedSizeAtCompileTime>::ValueAtCompileTime; + static constexpr Index EvalIncrAtCompileTime = + SymbolicExpressionEvaluator<IncrType, NestedSizeAtCompileTime>::ValueAtCompileTime; + + static constexpr Index FirstAtCompileTime = + (int(EvalFirstAtCompileTime) == Undefined) ? Index(DynamicIndex) : EvalFirstAtCompileTime; + static constexpr Index SizeAtCompileTime = + (int(EvalSizeAtCompileTime) == Undefined) ? Index(Dynamic) : EvalSizeAtCompileTime; + static constexpr Index IncrAtCompileTime = + (int(EvalIncrAtCompileTime) == Undefined) ? Index(DynamicIndex) : EvalIncrAtCompileTime; + + using Indices = ArithmeticSequence<FirstType, SizeType, IncrType>; + using type = ArithmeticSequenceRange<FirstAtCompileTime, SizeAtCompileTime, IncrAtCompileTime>; + + static type CreateIndexSequence(const Indices& indices, Index nested_size) { + Index first = + SymbolicExpressionEvaluator<FirstType, NestedSizeAtCompileTime>::eval(indices.firstObject(), nested_size); + Index size = + SymbolicExpressionEvaluator<SizeType, NestedSizeAtCompileTime>::eval(indices.sizeObject(), nested_size); + Index incr = + SymbolicExpressionEvaluator<IncrType, NestedSizeAtCompileTime>::eval(indices.incrObject(), nested_size); + return type(first, size, incr); + } +}; + +template <Index FirstAtCompileTime_, Index SizeAtCompileTime_, Index IncrAtCompileTime_> +struct IndexedViewHelper<ArithmeticSequenceRange<FirstAtCompileTime_, SizeAtCompileTime_, IncrAtCompileTime_>, void> { + public: + using Indices = ArithmeticSequenceRange<FirstAtCompileTime_, SizeAtCompileTime_, IncrAtCompileTime_>; + static constexpr Index FirstAtCompileTime = Indices::FirstAtCompileTime; + static constexpr Index SizeAtCompileTime = Indices::SizeAtCompileTime; + static constexpr Index IncrAtCompileTime = Indices::IncrAtCompileTime; + static Index first(const Indices& indices) { return indices.first(); } + static Index size(const Indices& indices) { return indices.size(); } + static Index incr(const Indices& indices) { return indices.incr(); } +}; + +//-------------------------------------------------------------------------------- +// Handling of a single index. +//-------------------------------------------------------------------------------- + +template <Index ValueAtCompileTime> +class SingleRange { + public: + static constexpr Index FirstAtCompileTime = ValueAtCompileTime; + static constexpr Index SizeAtCompileTime = Index(1); + static constexpr Index IncrAtCompileTime = Index(1); // Needs to be 1 to be treated as block-like. + + constexpr SingleRange(Index v) noexcept : value_(v) {} + constexpr Index operator[](Index) const noexcept { return first(); } + constexpr Index first() const noexcept { return value_.value(); } + constexpr Index size() const noexcept { return SizeAtCompileTime; } + constexpr Index incr() const noexcept { return IncrAtCompileTime; } + + private: + variable_if_dynamicindex<Index, int(ValueAtCompileTime)> value_; +}; + +template <typename T> +struct is_single_range : public std::false_type {}; + +template <Index ValueAtCompileTime> +struct is_single_range<SingleRange<ValueAtCompileTime>> : public std::true_type {}; + +template <typename SingleIndex, int NestedSizeAtCompileTime> +struct IndexedViewHelperIndicesWrapper< + SingleIndex, NestedSizeAtCompileTime, + std::enable_if_t<std::is_integral<SingleIndex>::value || symbolic::is_symbolic<SingleIndex>::value>> { + static constexpr Index EvalValueAtCompileTime = + SymbolicExpressionEvaluator<SingleIndex, NestedSizeAtCompileTime>::ValueAtCompileTime; + static constexpr Index ValueAtCompileTime = + (int(EvalValueAtCompileTime) == Undefined) ? Index(DynamicIndex) : EvalValueAtCompileTime; + using type = SingleRange<ValueAtCompileTime>; + static type CreateIndexSequence(const SingleIndex& index, Index nested_size) { + return type(SymbolicExpressionEvaluator<SingleIndex, NestedSizeAtCompileTime>::eval(index, nested_size)); + } +}; + +template <int N, int NestedSizeAtCompileTime> +struct IndexedViewHelperIndicesWrapper<FixedInt<N>, NestedSizeAtCompileTime, void> { + using type = SingleRange<Index(N)>; + static type CreateIndexSequence(const FixedInt<N>& /*index*/) { return type(Index(N)); } +}; + +template <Index ValueAtCompileTime> +struct IndexedViewHelper<SingleRange<ValueAtCompileTime>, void> { + using Indices = SingleRange<ValueAtCompileTime>; + static constexpr Index FirstAtCompileTime = Indices::FirstAtCompileTime; + static constexpr Index SizeAtCompileTime = Indices::SizeAtCompileTime; + static constexpr Index IncrAtCompileTime = Indices::IncrAtCompileTime; + + static constexpr Index first(const Indices& indices) { return indices.first(); } + static constexpr Index size(const Indices& /*indices*/) { return SizeAtCompileTime; } + static constexpr Index incr(const Indices& /*indices*/) { return IncrAtCompileTime; } +}; + +//-------------------------------------------------------------------------------- +// Handling of all +//-------------------------------------------------------------------------------- + +// Convert a symbolic 'all' into a usable range type +template <Index SizeAtCompileTime_> +class AllRange { + public: + static constexpr Index FirstAtCompileTime = Index(0); + static constexpr Index SizeAtCompileTime = SizeAtCompileTime_; + static constexpr Index IncrAtCompileTime = Index(1); + constexpr AllRange(Index size) : size_(size) {} + constexpr Index operator[](Index i) const noexcept { return i; } + constexpr Index first() const noexcept { return FirstAtCompileTime; } + constexpr Index size() const noexcept { return size_.value(); } + constexpr Index incr() const noexcept { return IncrAtCompileTime; } + + private: + variable_if_dynamic<Index, int(SizeAtCompileTime)> size_; +}; + +template <int NestedSizeAtCompileTime> +struct IndexedViewHelperIndicesWrapper<all_t, NestedSizeAtCompileTime, void> { + using type = AllRange<Index(NestedSizeAtCompileTime)>; + static type CreateIndexSequence(const all_t& /*indices*/, Index nested_size) { return type(nested_size); } +}; + +template <Index SizeAtCompileTime_> +struct IndexedViewHelper<AllRange<SizeAtCompileTime_>, void> { + using Indices = AllRange<SizeAtCompileTime_>; + static constexpr Index FirstAtCompileTime = Indices::FirstAtCompileTime; + static constexpr Index SizeAtCompileTime = Indices::SizeAtCompileTime; + static constexpr Index IncrAtCompileTime = Indices::IncrAtCompileTime; + + static Index first(const Indices& indices) { return indices.first(); } + static Index size(const Indices& indices) { return indices.size(); } + static Index incr(const Indices& indices) { return indices.incr(); } +}; + +} // end namespace internal + } // end namespace Eigen #endif // EIGEN_INDEXED_VIEW_HELPER_H
diff --git a/Eigen/src/Core/util/IntegralConstant.h b/Eigen/src/Core/util/IntegralConstant.h index 279d553..2eb5fd9 100644 --- a/Eigen/src/Core/util/IntegralConstant.h +++ b/Eigen/src/Core/util/IntegralConstant.h
@@ -54,65 +54,60 @@ template <int N> class FixedInt { public: - static const int value = N; - EIGEN_CONSTEXPR operator int() const { return value; } + static constexpr int value = N; + constexpr operator int() const { return N; } - EIGEN_CONSTEXPR - FixedInt() = default; + constexpr FixedInt() = default; + constexpr FixedInt(std::integral_constant<int, N>) {} - EIGEN_CONSTEXPR - FixedInt(std::integral_constant<int, N>) {} - - EIGEN_CONSTEXPR - FixedInt(VariableAndFixedInt<N> other) { + constexpr FixedInt(VariableAndFixedInt<N> other) { #ifndef EIGEN_INTERNAL_DEBUGGING EIGEN_UNUSED_VARIABLE(other); #endif eigen_internal_assert(int(other) == N); } - EIGEN_CONSTEXPR - FixedInt<-N> operator-() const { return FixedInt<-N>(); } + constexpr FixedInt<-N> operator-() const { return FixedInt<-N>(); } template <int M> - EIGEN_CONSTEXPR FixedInt<N + M> operator+(FixedInt<M>) const { + constexpr FixedInt<N + M> operator+(FixedInt<M>) const { return FixedInt<N + M>(); } template <int M> - EIGEN_CONSTEXPR FixedInt<N - M> operator-(FixedInt<M>) const { + constexpr FixedInt<N - M> operator-(FixedInt<M>) const { return FixedInt<N - M>(); } template <int M> - EIGEN_CONSTEXPR FixedInt<N * M> operator*(FixedInt<M>) const { + constexpr FixedInt<N * M> operator*(FixedInt<M>) const { return FixedInt<N * M>(); } template <int M> - EIGEN_CONSTEXPR FixedInt<N / M> operator/(FixedInt<M>) const { + constexpr FixedInt<N / M> operator/(FixedInt<M>) const { return FixedInt<N / M>(); } template <int M> - EIGEN_CONSTEXPR FixedInt<N % M> operator%(FixedInt<M>) const { + constexpr FixedInt<N % M> operator%(FixedInt<M>) const { return FixedInt<N % M>(); } template <int M> - EIGEN_CONSTEXPR FixedInt<N | M> operator|(FixedInt<M>) const { + constexpr FixedInt<N | M> operator|(FixedInt<M>) const { return FixedInt<N | M>(); } template <int M> - EIGEN_CONSTEXPR FixedInt<N & M> operator&(FixedInt<M>) const { + constexpr FixedInt<N & M> operator&(FixedInt<M>) const { return FixedInt<N & M>(); } // Needed in C++14 to allow fix<N>(): - EIGEN_CONSTEXPR FixedInt operator()() const { return *this; } + constexpr FixedInt operator()() const { return *this; } - VariableAndFixedInt<N> operator()(int val) const { return VariableAndFixedInt<N>(val); } + constexpr VariableAndFixedInt<N> operator()(int val) const { return VariableAndFixedInt<N>(val); } }; /** \internal
diff --git a/Eigen/src/Core/util/SymbolicIndex.h b/Eigen/src/Core/util/SymbolicIndex.h index 136942c..befb485 100644 --- a/Eigen/src/Core/util/SymbolicIndex.h +++ b/Eigen/src/Core/util/SymbolicIndex.h
@@ -44,6 +44,8 @@ template <typename Tag> class Symbol; +template <typename Tag, typename Type> +class SymbolValue; template <typename Arg0> class NegateExpr; template <typename Arg1, typename Arg2> @@ -52,136 +54,123 @@ class ProductExpr; template <typename Arg1, typename Arg2> class QuotientExpr; - -// A simple wrapper around an integral value to provide the eval method. -// We could also use a free-function symbolic_eval... template <typename IndexType = Index> -class ValueExpr { - public: - ValueExpr(IndexType val) : m_value(val) {} - template <typename T> - IndexType eval_impl(const T&) const { - return m_value; - } - - protected: - IndexType m_value; -}; - -// Specialization for compile-time value, -// It is similar to ValueExpr(N) but this version helps the compiler to generate better code. -template <int N> -class ValueExpr<internal::FixedInt<N> > { - public: - ValueExpr() {} - template <typename T> - EIGEN_CONSTEXPR Index eval_impl(const T&) const { - return N; - } -}; +class ValueExpr; /** \class BaseExpr * \ingroup Core_Module * Common base class of any symbolic expressions */ -template <typename Derived> +template <typename Derived_> class BaseExpr { public: - const Derived& derived() const { return *static_cast<const Derived*>(this); } + using Derived = Derived_; + constexpr const Derived& derived() const { return *static_cast<const Derived*>(this); } /** Evaluate the expression given the \a values of the symbols. * - * \param values defines the values of the symbols, it can either be a SymbolValue or a std::tuple of SymbolValue - * as constructed by SymbolExpr::operator= operator. + * \param values defines the values of the symbols, as constructed by SymbolExpr::operator= operator. * */ - template <typename T> - Index eval(const T& values) const { - return derived().eval_impl(values); + template <typename... Tags, typename... Types> + constexpr Index eval(const SymbolValue<Tags, Types>&... values) const { + return derived().eval_impl(values...); } - template <typename... Types> - Index eval(Types&&... values) const { - return derived().eval_impl(std::make_tuple(values...)); + /** Evaluate the expression at compile time given the \a values of the symbols. + * + * If a value is not known at compile-time, returns Eigen::Undefined. + * + */ + template <typename... Tags, typename... Types> + static constexpr Index eval_at_compile_time(const SymbolValue<Tags, Types>&...) { + return Derived::eval_at_compile_time_impl(SymbolValue<Tags, Types>{}...); } - NegateExpr<Derived> operator-() const { return NegateExpr<Derived>(derived()); } + constexpr NegateExpr<Derived> operator-() const { return NegateExpr<Derived>(derived()); } - AddExpr<Derived, ValueExpr<> > operator+(Index b) const { return AddExpr<Derived, ValueExpr<> >(derived(), b); } - AddExpr<Derived, ValueExpr<> > operator-(Index a) const { return AddExpr<Derived, ValueExpr<> >(derived(), -a); } - ProductExpr<Derived, ValueExpr<> > operator*(Index a) const { + constexpr AddExpr<Derived, ValueExpr<>> operator+(Index b) const { + return AddExpr<Derived, ValueExpr<>>(derived(), b); + } + constexpr AddExpr<Derived, ValueExpr<>> operator-(Index a) const { + return AddExpr<Derived, ValueExpr<>>(derived(), -a); + } + constexpr ProductExpr<Derived, ValueExpr<>> operator*(Index a) const { return ProductExpr<Derived, ValueExpr<> >(derived(), a); } - QuotientExpr<Derived, ValueExpr<> > operator/(Index a) const { + constexpr QuotientExpr<Derived, ValueExpr<>> operator/(Index a) const { return QuotientExpr<Derived, ValueExpr<> >(derived(), a); } - friend AddExpr<Derived, ValueExpr<> > operator+(Index a, const BaseExpr& b) { + friend constexpr AddExpr<Derived, ValueExpr<>> operator+(Index a, const BaseExpr& b) { return AddExpr<Derived, ValueExpr<> >(b.derived(), a); } - friend AddExpr<NegateExpr<Derived>, ValueExpr<> > operator-(Index a, const BaseExpr& b) { + friend constexpr AddExpr<NegateExpr<Derived>, ValueExpr<>> operator-(Index a, const BaseExpr& b) { return AddExpr<NegateExpr<Derived>, ValueExpr<> >(-b.derived(), a); } - friend ProductExpr<ValueExpr<>, Derived> operator*(Index a, const BaseExpr& b) { + friend constexpr ProductExpr<ValueExpr<>, Derived> operator*(Index a, const BaseExpr& b) { return ProductExpr<ValueExpr<>, Derived>(a, b.derived()); } - friend QuotientExpr<ValueExpr<>, Derived> operator/(Index a, const BaseExpr& b) { + friend constexpr QuotientExpr<ValueExpr<>, Derived> operator/(Index a, const BaseExpr& b) { return QuotientExpr<ValueExpr<>, Derived>(a, b.derived()); } template <int N> - AddExpr<Derived, ValueExpr<internal::FixedInt<N> > > operator+(internal::FixedInt<N>) const { + constexpr AddExpr<Derived, ValueExpr<internal::FixedInt<N>>> operator+(internal::FixedInt<N>) const { return AddExpr<Derived, ValueExpr<internal::FixedInt<N> > >(derived(), ValueExpr<internal::FixedInt<N> >()); } template <int N> - AddExpr<Derived, ValueExpr<internal::FixedInt<-N> > > operator-(internal::FixedInt<N>) const { + constexpr AddExpr<Derived, ValueExpr<internal::FixedInt<-N>>> operator-(internal::FixedInt<N>) const { return AddExpr<Derived, ValueExpr<internal::FixedInt<-N> > >(derived(), ValueExpr<internal::FixedInt<-N> >()); } template <int N> - ProductExpr<Derived, ValueExpr<internal::FixedInt<N> > > operator*(internal::FixedInt<N>) const { + constexpr ProductExpr<Derived, ValueExpr<internal::FixedInt<N>>> operator*(internal::FixedInt<N>) const { return ProductExpr<Derived, ValueExpr<internal::FixedInt<N> > >(derived(), ValueExpr<internal::FixedInt<N> >()); } template <int N> - QuotientExpr<Derived, ValueExpr<internal::FixedInt<N> > > operator/(internal::FixedInt<N>) const { + constexpr QuotientExpr<Derived, ValueExpr<internal::FixedInt<N>>> operator/(internal::FixedInt<N>) const { return QuotientExpr<Derived, ValueExpr<internal::FixedInt<N> > >(derived(), ValueExpr<internal::FixedInt<N> >()); } template <int N> - friend AddExpr<Derived, ValueExpr<internal::FixedInt<N> > > operator+(internal::FixedInt<N>, const BaseExpr& b) { + friend constexpr AddExpr<Derived, ValueExpr<internal::FixedInt<N>>> operator+(internal::FixedInt<N>, + const BaseExpr& b) { return AddExpr<Derived, ValueExpr<internal::FixedInt<N> > >(b.derived(), ValueExpr<internal::FixedInt<N> >()); } template <int N> - friend AddExpr<NegateExpr<Derived>, ValueExpr<internal::FixedInt<N> > > operator-(internal::FixedInt<N>, - const BaseExpr& b) { + friend constexpr AddExpr<NegateExpr<Derived>, ValueExpr<internal::FixedInt<N>>> operator-(internal::FixedInt<N>, + const BaseExpr& b) { return AddExpr<NegateExpr<Derived>, ValueExpr<internal::FixedInt<N> > >(-b.derived(), ValueExpr<internal::FixedInt<N> >()); } template <int N> - friend ProductExpr<ValueExpr<internal::FixedInt<N> >, Derived> operator*(internal::FixedInt<N>, const BaseExpr& b) { + friend constexpr ProductExpr<ValueExpr<internal::FixedInt<N>>, Derived> operator*(internal::FixedInt<N>, + const BaseExpr& b) { return ProductExpr<ValueExpr<internal::FixedInt<N> >, Derived>(ValueExpr<internal::FixedInt<N> >(), b.derived()); } template <int N> - friend QuotientExpr<ValueExpr<internal::FixedInt<N> >, Derived> operator/(internal::FixedInt<N>, const BaseExpr& b) { + friend constexpr QuotientExpr<ValueExpr<internal::FixedInt<N>>, Derived> operator/(internal::FixedInt<N>, + const BaseExpr& b) { return QuotientExpr<ValueExpr<internal::FixedInt<N> >, Derived>(ValueExpr<internal::FixedInt<N> >(), b.derived()); } template <typename OtherDerived> - AddExpr<Derived, OtherDerived> operator+(const BaseExpr<OtherDerived>& b) const { + constexpr AddExpr<Derived, OtherDerived> operator+(const BaseExpr<OtherDerived>& b) const { return AddExpr<Derived, OtherDerived>(derived(), b.derived()); } template <typename OtherDerived> - AddExpr<Derived, NegateExpr<OtherDerived> > operator-(const BaseExpr<OtherDerived>& b) const { + constexpr AddExpr<Derived, NegateExpr<OtherDerived>> operator-(const BaseExpr<OtherDerived>& b) const { return AddExpr<Derived, NegateExpr<OtherDerived> >(derived(), -b.derived()); } template <typename OtherDerived> - ProductExpr<Derived, OtherDerived> operator*(const BaseExpr<OtherDerived>& b) const { + constexpr ProductExpr<Derived, OtherDerived> operator*(const BaseExpr<OtherDerived>& b) const { return ProductExpr<Derived, OtherDerived>(derived(), b.derived()); } template <typename OtherDerived> - QuotientExpr<Derived, OtherDerived> operator/(const BaseExpr<OtherDerived>& b) const { + constexpr QuotientExpr<Derived, OtherDerived> operator/(const BaseExpr<OtherDerived>& b) const { return QuotientExpr<Derived, OtherDerived>(derived(), b.derived()); } }; @@ -193,21 +182,137 @@ enum { value = internal::is_convertible<T, BaseExpr<T> >::value }; }; +// A simple wrapper around an integral value to provide the eval method. +// We could also use a free-function symbolic_eval... +template <typename IndexType> +class ValueExpr : BaseExpr<ValueExpr<IndexType>> { + public: + constexpr ValueExpr() = default; + constexpr ValueExpr(IndexType val) : value_(val) {} + template <typename... Tags, typename... Types> + constexpr IndexType eval_impl(const SymbolValue<Tags, Types>&...) const { + return value_; + } + template <typename... Tags, typename... Types> + static constexpr IndexType eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) { + return IndexType(Undefined); + } + + protected: + IndexType value_; +}; + +// Specialization for compile-time value, +// It is similar to ValueExpr(N) but this version helps the compiler to generate better code. +template <int N> +class ValueExpr<internal::FixedInt<N>> : public BaseExpr<ValueExpr<internal::FixedInt<N>>> { + public: + constexpr ValueExpr() = default; + constexpr ValueExpr(internal::FixedInt<N>) {} + template <typename... Tags, typename... Types> + constexpr Index eval_impl(const SymbolValue<Tags, Types>&...) const { + return Index(N); + } + template <typename... Tags, typename... Types> + static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) { + return Index(N); + } +}; + /** Represents the actual value of a symbol identified by its tag * * It is the return type of SymbolValue::operator=, and most of the time this is only way it is used. */ +template <typename Tag, typename Type> +class SymbolValue : public BaseExpr<SymbolValue<Tag, Type>> {}; + template <typename Tag> -class SymbolValue { +class SymbolValue<Tag, Index> : public BaseExpr<SymbolValue<Tag, Index>> { public: + constexpr SymbolValue() = default; + /** Default constructor from the value \a val */ - SymbolValue(Index val) : m_value(val) {} + constexpr SymbolValue(Index val) : value_(val) {} /** \returns the stored value of the symbol */ - Index value() const { return m_value; } + constexpr Index value() const { return value_; } + + /** \returns the stored value of the symbol at compile time, or Undefined if not known. */ + static constexpr Index value_at_compile_time() { return Index(Undefined); } + + template <typename... Tags, typename... Types> + constexpr Index eval_impl(const SymbolValue<Tags, Types>&...) const { + return value(); + } + + template <typename... Tags, typename... Types> + static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) { + return value_at_compile_time(); + } protected: - Index m_value; + Index value_; +}; + +template <typename Tag, int N> +class SymbolValue<Tag, internal::FixedInt<N>> : public BaseExpr<SymbolValue<Tag, internal::FixedInt<N>>> { + public: + constexpr SymbolValue() = default; + + /** Default constructor from the value \a val */ + constexpr SymbolValue(internal::FixedInt<N>){}; + + /** \returns the stored value of the symbol */ + constexpr Index value() const { return static_cast<Index>(N); } + + /** \returns the stored value of the symbol at compile time, or Undefined if not known. */ + static constexpr Index value_at_compile_time() { return static_cast<Index>(N); } + + template <typename... Tags, typename... Types> + constexpr Index eval_impl(const SymbolValue<Tags, Types>&...) const { + return value(); + } + + template <typename... Tags, typename... Types> + static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) { + return value_at_compile_time(); + } +}; + +// Find and return a symbol value based on the tag. +template <typename Tag, typename... Types> +struct EvalSymbolValueHelper; + +// Empty base case, symbol not found. +template <typename Tag> +struct EvalSymbolValueHelper<Tag> { + static constexpr Index eval_impl() { + eigen_assert(false && "Symbol not found."); + return Index(Undefined); + } + static constexpr Index eval_at_compile_time_impl() { return Index(Undefined); } +}; + +// We found a symbol value matching the provided Tag! +template <typename Tag, typename Type, typename... OtherTypes> +struct EvalSymbolValueHelper<Tag, SymbolValue<Tag, Type>, OtherTypes...> { + static constexpr Index eval_impl(const SymbolValue<Tag, Type>& symbol, const OtherTypes&...) { + return symbol.value(); + } + static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tag, Type>& symbol, const OtherTypes&...) { + return symbol.value_at_compile_time(); + } +}; + +// No symbol value in first value, recursive search starting with next. +template <typename Tag, typename T1, typename... OtherTypes> +struct EvalSymbolValueHelper<Tag, T1, OtherTypes...> { + static constexpr Index eval_impl(const T1&, const OtherTypes&... values) { + return EvalSymbolValueHelper<Tag, OtherTypes...>::eval_impl(values...); + } + static constexpr Index eval_at_compile_time_impl(const T1&, const OtherTypes&...) { + return EvalSymbolValueHelper<Tag, OtherTypes...>::eval_at_compile_time_impl(OtherTypes{}...); + } }; /** Expression of a symbol uniquely identified by the template parameter type \c tag */ @@ -217,32 +322,47 @@ /** Alias to the template parameter \c tag */ typedef tag Tag; - SymbolExpr() {} + constexpr SymbolExpr() = default; /** Associate the value \a val to the given symbol \c *this, uniquely identified by its \c Tag. * * The returned object should be passed to ExprBase::eval() to evaluate a given expression with this specified * runtime-time value. */ - SymbolValue<Tag> operator=(Index val) const { return SymbolValue<Tag>(val); } + constexpr SymbolValue<Tag, Index> operator=(Index val) const { return SymbolValue<Tag, Index>(val); } - Index eval_impl(const SymbolValue<Tag>& values) const { return values.value(); } + template <int N> + constexpr SymbolValue<Tag, internal::FixedInt<N>> operator=(internal::FixedInt<N>) const { + return SymbolValue<Tag, internal::FixedInt<N>>{internal::FixedInt<N>{}}; + } - // C++14 versions suitable for multiple symbols - template <typename... Types> - Index eval_impl(const std::tuple<Types...>& values) const { - return std::get<SymbolValue<Tag> >(values).value(); + template <typename... Tags, typename... Types> + constexpr Index eval_impl(const SymbolValue<Tags, Types>&... values) const { + return EvalSymbolValueHelper<Tag, SymbolValue<Tags, Types>...>::eval_impl(values...); + } + + template <typename... Tags, typename... Types> + static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) { + return EvalSymbolValueHelper<Tag, SymbolValue<Tags, Types>...>::eval_at_compile_time_impl( + SymbolValue<Tags, Types>{}...); } }; template <typename Arg0> class NegateExpr : public BaseExpr<NegateExpr<Arg0> > { public: - NegateExpr(const Arg0& arg0) : m_arg0(arg0) {} + constexpr NegateExpr() = default; + constexpr NegateExpr(const Arg0& arg0) : m_arg0(arg0) {} - template <typename T> - Index eval_impl(const T& values) const { - return -m_arg0.eval_impl(values); + template <typename... Tags, typename... Types> + constexpr Index eval_impl(const SymbolValue<Tags, Types>&... values) const { + return -m_arg0.eval_impl(values...); + } + + template <typename... Tags, typename... Types> + static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) { + constexpr Index v = Arg0::eval_at_compile_time_impl(SymbolValue<Tags, Types>{}...); + return (v == Undefined) ? Undefined : -v; } protected: @@ -252,11 +372,19 @@ template <typename Arg0, typename Arg1> class AddExpr : public BaseExpr<AddExpr<Arg0, Arg1> > { public: - AddExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} + constexpr AddExpr() = default; + constexpr AddExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} - template <typename T> - Index eval_impl(const T& values) const { - return m_arg0.eval_impl(values) + m_arg1.eval_impl(values); + template <typename... Tags, typename... Types> + constexpr Index eval_impl(const SymbolValue<Tags, Types>&... values) const { + return m_arg0.eval_impl(values...) + m_arg1.eval_impl(values...); + } + + template <typename... Tags, typename... Types> + static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) { + constexpr Index v0 = Arg0::eval_at_compile_time_impl(SymbolValue<Tags, Types>{}...); + constexpr Index v1 = Arg1::eval_at_compile_time_impl(SymbolValue<Tags, Types>{}...); + return (v0 == Undefined || v1 == Undefined) ? Undefined : v0 + v1; } protected: @@ -267,11 +395,19 @@ template <typename Arg0, typename Arg1> class ProductExpr : public BaseExpr<ProductExpr<Arg0, Arg1> > { public: - ProductExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} + constexpr ProductExpr() = default; + constexpr ProductExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} - template <typename T> - Index eval_impl(const T& values) const { - return m_arg0.eval_impl(values) * m_arg1.eval_impl(values); + template <typename... Tags, typename... Types> + constexpr Index eval_impl(const SymbolValue<Tags, Types>&... values) const { + return m_arg0.eval_impl(values...) * m_arg1.eval_impl(values...); + } + + template <typename... Tags, typename... Types> + static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) { + constexpr Index v0 = Arg0::eval_at_compile_time_impl(SymbolValue<Tags, Types>{}...); + constexpr Index v1 = Arg1::eval_at_compile_time_impl(SymbolValue<Tags, Types>{}...); + return (v0 == Undefined || v1 == Undefined) ? Undefined : v0 * v1; } protected: @@ -282,11 +418,19 @@ template <typename Arg0, typename Arg1> class QuotientExpr : public BaseExpr<QuotientExpr<Arg0, Arg1> > { public: - QuotientExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} + constexpr QuotientExpr() = default; + constexpr QuotientExpr(const Arg0& arg0, const Arg1& arg1) : m_arg0(arg0), m_arg1(arg1) {} - template <typename T> - Index eval_impl(const T& values) const { - return m_arg0.eval_impl(values) / m_arg1.eval_impl(values); + template <typename... Tags, typename... Types> + constexpr Index eval_impl(const SymbolValue<Tags, Types>&... values) const { + return m_arg0.eval_impl(values...) / m_arg1.eval_impl(values...); + } + + template <typename... Tags, typename... Types> + static constexpr Index eval_at_compile_time_impl(const SymbolValue<Tags, Types>&...) { + constexpr Index v0 = Arg0::eval_at_compile_time_impl(SymbolValue<Tags, Types>{}...); + constexpr Index v1 = Arg1::eval_at_compile_time_impl(SymbolValue<Tags, Types>{}...); + return (v0 == Undefined || v1 == Undefined) ? Undefined : v0 / v1; } protected:
diff --git a/Eigen/src/plugins/IndexedViewMethods.inc b/Eigen/src/plugins/IndexedViewMethods.inc index 26e7b5f..c3df429 100644 --- a/Eigen/src/plugins/IndexedViewMethods.inc +++ b/Eigen/src/plugins/IndexedViewMethods.inc
@@ -9,51 +9,47 @@ #if !defined(EIGEN_PARSED_BY_DOXYGEN) -protected: +public: // define some aliases to ease readability template <typename Indices> -using IvcRowType = typename internal::IndexedViewCompatibleType<Indices, RowsAtCompileTime>::type; +using IvcRowType = typename internal::IndexedViewHelperIndicesWrapper<Indices, RowsAtCompileTime>::type; template <typename Indices> -using IvcColType = typename internal::IndexedViewCompatibleType<Indices, ColsAtCompileTime>::type; +using IvcColType = typename internal::IndexedViewHelperIndicesWrapper<Indices, ColsAtCompileTime>::type; template <typename Indices> -using IvcType = typename internal::IndexedViewCompatibleType<Indices, SizeAtCompileTime>::type; - -typedef typename internal::IndexedViewCompatibleType<Index, 1>::type IvcIndex; +using IvcSizeType = typename internal::IndexedViewHelperIndicesWrapper<Indices, SizeAtCompileTime>::type; template <typename Indices> inline IvcRowType<Indices> ivcRow(const Indices& indices) const { - return internal::makeIndexedViewCompatible( - indices, internal::variable_if_dynamic<Index, RowsAtCompileTime>(derived().rows()), Specialized); + return internal::IndexedViewHelperIndicesWrapper<Indices, RowsAtCompileTime>::CreateIndexSequence(indices, + derived().rows()); } template <typename Indices> inline IvcColType<Indices> ivcCol(const Indices& indices) const { - return internal::makeIndexedViewCompatible( - indices, internal::variable_if_dynamic<Index, ColsAtCompileTime>(derived().cols()), Specialized); + return internal::IndexedViewHelperIndicesWrapper<Indices, ColsAtCompileTime>::CreateIndexSequence(indices, + derived().cols()); } template <typename Indices> -inline IvcType<Indices> ivcSize(const Indices& indices) const { - return internal::makeIndexedViewCompatible( - indices, internal::variable_if_dynamic<Index, SizeAtCompileTime>(derived().size()), Specialized); +inline IvcSizeType<Indices> ivcSize(const Indices& indices) const { + return internal::IndexedViewHelperIndicesWrapper<Indices, SizeAtCompileTime>::CreateIndexSequence(indices, + derived().size()); + ; } // this helper class assumes internal::valid_indexed_view_overload<RowIndices, ColIndices>::value == true -template <typename RowIndices, typename ColIndices, - bool UseSymbolic = - internal::traits<IndexedView<Derived, IvcRowType<RowIndices>, IvcColType<ColIndices>>>::ReturnAsScalar, - bool UseBlock = - internal::traits<IndexedView<Derived, IvcRowType<RowIndices>, IvcColType<ColIndices>>>::ReturnAsBlock, - bool UseGeneric = internal::traits< - IndexedView<Derived, IvcRowType<RowIndices>, IvcColType<ColIndices>>>::ReturnAsIndexedView> +template <typename RowIndices, typename ColIndices, typename EnableIf = void> struct IndexedViewSelector; // Generic template <typename RowIndices, typename ColIndices> -struct IndexedViewSelector<RowIndices, ColIndices, false, false, true> { +struct IndexedViewSelector< + RowIndices, ColIndices, + std::enable_if_t< + internal::traits<IndexedView<Derived, IvcRowType<RowIndices>, IvcColType<ColIndices>>>::ReturnAsIndexedView>> { using ReturnType = IndexedView<Derived, IvcRowType<RowIndices>, IvcColType<ColIndices>>; using ConstReturnType = IndexedView<const Derived, IvcRowType<RowIndices>, IvcColType<ColIndices>>; @@ -68,60 +64,73 @@ // Block template <typename RowIndices, typename ColIndices> -struct IndexedViewSelector<RowIndices, ColIndices, false, true, false> { - using IndexedViewType = IndexedView<Derived, IvcRowType<RowIndices>, IvcColType<ColIndices>>; - using ConstIndexedViewType = IndexedView<const Derived, IvcRowType<RowIndices>, IvcColType<ColIndices>>; +struct IndexedViewSelector<RowIndices, ColIndices, + std::enable_if_t<internal::traits< + IndexedView<Derived, IvcRowType<RowIndices>, IvcColType<ColIndices>>>::ReturnAsBlock>> { + using ActualRowIndices = IvcRowType<RowIndices>; + using ActualColIndices = IvcColType<ColIndices>; + using IndexedViewType = IndexedView<Derived, ActualRowIndices, ActualColIndices>; + using ConstIndexedViewType = IndexedView<const Derived, ActualRowIndices, ActualColIndices>; using ReturnType = typename internal::traits<IndexedViewType>::BlockType; using ConstReturnType = typename internal::traits<ConstIndexedViewType>::BlockType; + using RowHelper = internal::IndexedViewHelper<ActualRowIndices>; + using ColHelper = internal::IndexedViewHelper<ActualColIndices>; static inline ReturnType run(Derived& derived, const RowIndices& rowIndices, const ColIndices& colIndices) { - IvcRowType<RowIndices> actualRowIndices = derived.ivcRow(rowIndices); - IvcColType<ColIndices> actualColIndices = derived.ivcCol(colIndices); - return ReturnType(derived, internal::first(actualRowIndices), internal::first(actualColIndices), - internal::index_list_size(actualRowIndices), internal::index_list_size(actualColIndices)); + auto actualRowIndices = derived.ivcRow(rowIndices); + auto actualColIndices = derived.ivcCol(colIndices); + return ReturnType(derived, RowHelper::first(actualRowIndices), ColHelper::first(actualColIndices), + RowHelper::size(actualRowIndices), ColHelper::size(actualColIndices)); } static inline ConstReturnType run(const Derived& derived, const RowIndices& rowIndices, const ColIndices& colIndices) { - IvcRowType<RowIndices> actualRowIndices = derived.ivcRow(rowIndices); - IvcColType<ColIndices> actualColIndices = derived.ivcCol(colIndices); - return ConstReturnType(derived, internal::first(actualRowIndices), internal::first(actualColIndices), - internal::index_list_size(actualRowIndices), internal::index_list_size(actualColIndices)); + auto actualRowIndices = derived.ivcRow(rowIndices); + auto actualColIndices = derived.ivcCol(colIndices); + return ConstReturnType(derived, RowHelper::first(actualRowIndices), ColHelper::first(actualColIndices), + RowHelper::size(actualRowIndices), ColHelper::size(actualColIndices)); } }; -// Symbolic +// Scalar template <typename RowIndices, typename ColIndices> -struct IndexedViewSelector<RowIndices, ColIndices, true, false, false> { +struct IndexedViewSelector<RowIndices, ColIndices, + std::enable_if_t<internal::traits< + IndexedView<Derived, IvcRowType<RowIndices>, IvcColType<ColIndices>>>::ReturnAsScalar>> { using ReturnType = typename DenseBase<Derived>::Scalar&; using ConstReturnType = typename DenseBase<Derived>::CoeffReturnType; - + using ActualRowIndices = IvcRowType<RowIndices>; + using ActualColIndices = IvcColType<ColIndices>; + using RowHelper = internal::IndexedViewHelper<ActualRowIndices>; + using ColHelper = internal::IndexedViewHelper<ActualColIndices>; static inline ReturnType run(Derived& derived, const RowIndices& rowIndices, const ColIndices& colIndices) { - return derived(internal::eval_expr_given_size(rowIndices, derived.rows()), - internal::eval_expr_given_size(colIndices, derived.cols())); + auto actualRowIndices = derived.ivcRow(rowIndices); + auto actualColIndices = derived.ivcCol(colIndices); + return derived(RowHelper::first(actualRowIndices), ColHelper::first(actualColIndices)); } static inline ConstReturnType run(const Derived& derived, const RowIndices& rowIndices, const ColIndices& colIndices) { - return derived(internal::eval_expr_given_size(rowIndices, derived.rows()), - internal::eval_expr_given_size(colIndices, derived.cols())); + auto actualRowIndices = derived.ivcRow(rowIndices); + auto actualColIndices = derived.ivcCol(colIndices); + return derived(RowHelper::first(actualRowIndices), ColHelper::first(actualColIndices)); } }; // this helper class assumes internal::is_valid_index_type<Indices>::value == false -template <typename Indices, bool UseSymbolic = symbolic::is_symbolic<Indices>::value, - bool UseBlock = !UseSymbolic && internal::get_compile_time_incr<IvcType<Indices>>::value == 1, - bool UseGeneric = !UseSymbolic && !UseBlock> +template <typename Indices, typename EnableIf = void> struct VectorIndexedViewSelector; // Generic template <typename Indices> -struct VectorIndexedViewSelector<Indices, false, false, true> { +struct VectorIndexedViewSelector< + Indices, std::enable_if_t<!internal::is_single_range<IvcSizeType<Indices>>::value && + internal::IndexedViewHelper<IvcSizeType<Indices>>::IncrAtCompileTime != 1>> { static constexpr bool IsRowMajor = DenseBase<Derived>::IsRowMajor; + using ZeroIndex = internal::SingleRange<Index(0)>; + using RowMajorReturnType = IndexedView<Derived, ZeroIndex, IvcSizeType<Indices>>; + using ConstRowMajorReturnType = IndexedView<const Derived, ZeroIndex, IvcSizeType<Indices>>; - using RowMajorReturnType = IndexedView<Derived, IvcIndex, IvcType<Indices>>; - using ConstRowMajorReturnType = IndexedView<const Derived, IvcIndex, IvcType<Indices>>; - - using ColMajorReturnType = IndexedView<Derived, IvcType<Indices>, IvcIndex>; - using ConstColMajorReturnType = IndexedView<const Derived, IvcType<Indices>, IvcIndex>; + using ColMajorReturnType = IndexedView<Derived, IvcSizeType<Indices>, ZeroIndex>; + using ConstColMajorReturnType = IndexedView<const Derived, IvcSizeType<Indices>, ZeroIndex>; using ReturnType = typename internal::conditional<IsRowMajor, RowMajorReturnType, ColMajorReturnType>::type; using ConstReturnType = @@ -129,49 +138,53 @@ template <bool UseRowMajor = IsRowMajor, std::enable_if_t<UseRowMajor, bool> = true> static inline RowMajorReturnType run(Derived& derived, const Indices& indices) { - return RowMajorReturnType(derived, IvcIndex(0), derived.ivcCol(indices)); + return RowMajorReturnType(derived, ZeroIndex(0), derived.ivcCol(indices)); } template <bool UseRowMajor = IsRowMajor, std::enable_if_t<UseRowMajor, bool> = true> static inline ConstRowMajorReturnType run(const Derived& derived, const Indices& indices) { - return ConstRowMajorReturnType(derived, IvcIndex(0), derived.ivcCol(indices)); + return ConstRowMajorReturnType(derived, ZeroIndex(0), derived.ivcCol(indices)); } template <bool UseRowMajor = IsRowMajor, std::enable_if_t<!UseRowMajor, bool> = true> static inline ColMajorReturnType run(Derived& derived, const Indices& indices) { - return ColMajorReturnType(derived, derived.ivcRow(indices), IvcIndex(0)); + return ColMajorReturnType(derived, derived.ivcRow(indices), ZeroIndex(0)); } template <bool UseRowMajor = IsRowMajor, std::enable_if_t<!UseRowMajor, bool> = true> static inline ConstColMajorReturnType run(const Derived& derived, const Indices& indices) { - return ConstColMajorReturnType(derived, derived.ivcRow(indices), IvcIndex(0)); + return ConstColMajorReturnType(derived, derived.ivcRow(indices), ZeroIndex(0)); } }; // Block template <typename Indices> -struct VectorIndexedViewSelector<Indices, false, true, false> { - using ReturnType = VectorBlock<Derived, internal::array_size<Indices>::value>; - using ConstReturnType = VectorBlock<const Derived, internal::array_size<Indices>::value>; - +struct VectorIndexedViewSelector< + Indices, std::enable_if_t<!internal::is_single_range<IvcSizeType<Indices>>::value && + internal::IndexedViewHelper<IvcSizeType<Indices>>::IncrAtCompileTime == 1>> { + using Helper = internal::IndexedViewHelper<IvcSizeType<Indices>>; + using ReturnType = VectorBlock<Derived, Helper::SizeAtCompileTime>; + using ConstReturnType = VectorBlock<const Derived, Helper::SizeAtCompileTime>; static inline ReturnType run(Derived& derived, const Indices& indices) { - IvcType<Indices> actualIndices = derived.ivcSize(indices); - return ReturnType(derived, internal::first(actualIndices), internal::index_list_size(actualIndices)); + auto actualIndices = derived.ivcSize(indices); + return ReturnType(derived, Helper::first(actualIndices), Helper::size(actualIndices)); } static inline ConstReturnType run(const Derived& derived, const Indices& indices) { - IvcType<Indices> actualIndices = derived.ivcSize(indices); - return ConstReturnType(derived, internal::first(actualIndices), internal::index_list_size(actualIndices)); + auto actualIndices = derived.ivcSize(indices); + return ConstReturnType(derived, Helper::first(actualIndices), Helper::size(actualIndices)); } }; // Symbolic template <typename Indices> -struct VectorIndexedViewSelector<Indices, true, false, false> { +struct VectorIndexedViewSelector<Indices, std::enable_if_t<internal::is_single_range<IvcSizeType<Indices>>::value>> { using ReturnType = typename DenseBase<Derived>::Scalar&; using ConstReturnType = typename DenseBase<Derived>::CoeffReturnType; - - static inline ReturnType run(Derived& derived, const Indices& id) { - return derived(internal::eval_expr_given_size(id, derived.size())); + using Helper = internal::IndexedViewHelper<IvcSizeType<Indices>>; + static inline ReturnType run(Derived& derived, const Indices& indices) { + auto actualIndices = derived.ivcSize(indices); + return derived(Helper::first(actualIndices)); } - static inline ConstReturnType run(const Derived& derived, const Indices& id) { - return derived(internal::eval_expr_given_size(id, derived.size())); + static inline ConstReturnType run(const Derived& derived, const Indices& indices) { + auto actualIndices = derived.ivcSize(indices); + return derived(Helper::first(actualIndices)); } };
diff --git a/doc/TutorialSlicingIndexing.dox b/doc/TutorialSlicingIndexing.dox index 7f89554..6ebaa2d 100644 --- a/doc/TutorialSlicingIndexing.dox +++ b/doc/TutorialSlicingIndexing.dox
@@ -86,12 +86,12 @@ <td></td> </tr> <tr> - <td>First \c n odd rows A</td> + <td>First \c n odd rows of A</td> <td>\code A(seqN(1,n,2), all) \endcode</td> <td></td> </tr> <tr> - <td>The last past one column</td> + <td>The second-last column</td> <td>\code A(all, last-1) \endcode</td> <td>\code A.col(A.cols()-2) \endcode</td> </tr> @@ -158,7 +158,7 @@ \endcode We can revisit the <i>even columns of A</i> example as follows: -\code A(all, seq(0,last,fix<2>)) +\code A(all, seq(fix<0>,last,fix<2>)) \endcode
diff --git a/test/indexed_view.cpp b/test/indexed_view.cpp index d3cf4a6..f165e8b 100644 --- a/test/indexed_view.cpp +++ b/test/indexed_view.cpp
@@ -527,10 +527,323 @@ } } +void check_tutorial_examples() { + constexpr int kRows = 11; + constexpr int kCols = 21; + Matrix<double, kRows, kCols> A = Matrix<double, kRows, kCols>::Random(); + Vector<double, kRows> v = Vector<double, kRows>::Random(); + + { + auto slice = A(seqN(fix<0>, fix<5>, fix<2>), seqN(fix<2>, fix<7>, fix<1>)); + EIGEN_UNUSED_VARIABLE(slice); + VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), 5); + VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), 7); + } + { + auto slice = A(seqN(fix<0>, fix<5>, fix<2>), indexing::all); + EIGEN_UNUSED_VARIABLE(slice); + VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), 5); + VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), kCols); + } + + // Examples from slicing tutorial. + // Bottom-left corner. + { + Index i = 3; + Index n = 5; + auto slice = A(seq(i, indexing::last), seqN(0, n)); + auto block = A.bottomLeftCorner(A.rows() - i, n); + VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime)); + VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime)); + VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), Dynamic); + VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), Dynamic); + VERIFY_IS_EQUAL(slice, block); + } + { + auto i = fix<3>; + auto n = fix<5>; + auto slice = A(seq(i, indexing::last), seqN(fix<0>, n)); + auto block = A.bottomLeftCorner(fix<kRows> - i, n); + VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime)); + VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime)); + VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), A.RowsAtCompileTime - i); + VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), n); + VERIFY_IS_EQUAL(slice, block); + } + + // Block starting at i,j of size m,n. + { + Index i = 4; + Index j = 2; + Index m = 3; + Index n = 5; + auto slice = A(seqN(i, m), seqN(j, n)); + auto block = A.block(i, j, m, n); + VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime)); + VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime)); + VERIFY_IS_EQUAL(slice, block); + } + { + auto i = fix<4>; + auto j = fix<2>; + auto m = fix<3>; + auto n = fix<5>; + auto slice = A(seqN(i, m), seqN(j, n)); + auto block = A.block(i, j, m, n); + VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime)); + VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime)); + VERIFY_IS_EQUAL(slice, block); + } + + // Block starting at i0,j0 and ending at i1,j1. + { + Index i0 = 4; + Index i1 = 7; + Index j0 = 3; + Index j1 = 5; + auto slice = A(seq(i0, i1), seq(j0, j1)); + auto block = A.block(i0, j0, i1 - i0 + 1, j1 - j0 + 1); + VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime)); + VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime)); + VERIFY_IS_EQUAL(slice, block); + } + { + auto i0 = fix<4>; + auto i1 = fix<7>; + auto j0 = fix<3>; + auto j1 = fix<5>; + auto slice = A(seq(i0, i1), seq(j0, j1)); + auto block = A.block(i0, j0, i1 - i0 + fix<1>, j1 - j0 + fix<1>); + VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime)); + VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime)); + VERIFY_IS_EQUAL(slice, block); + } + + // Even columns of A. + { + auto slice = A(all, seq(0, last, 2)); + auto block = + Eigen::Map<Eigen::Matrix<double, kRows, Dynamic>, 0, OuterStride<2 * kRows>>(A.data(), kRows, (kCols + 1) / 2); + VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime)); + VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime)); + VERIFY_IS_EQUAL(slice, block); + } + { + auto slice = A(all, seq(fix<0>, last, fix<2>)); + auto block = Eigen::Map<Eigen::Matrix<double, kRows, (kCols + 1) / 2>, 0, OuterStride<2 * kRows>>(A.data()); + VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime)); + VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime)); + VERIFY_IS_EQUAL(slice, block); + } + + // First n odd rows of A. + { + Index n = 3; + auto slice = A(seqN(1, n, 2), all); + auto block = Eigen::Map<Eigen::Matrix<double, Dynamic, kCols>, 0, Stride<kRows, 2>>(A.data() + 1, n, kCols); + VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime)); + VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime)); + VERIFY_IS_EQUAL(slice, block); + } + { + auto n = fix<3>; + auto slice = A(seqN(fix<1>, n, fix<2>), all); + auto block = Eigen::Map<Eigen::Matrix<double, 3, kCols>, 0, Stride<kRows, 2>>(A.data() + 1); + VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime)); + VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime)); + VERIFY_IS_EQUAL(slice, block); + } + + // The second-last column. + { + auto slice = A(all, last - 1); + auto block = A.col(A.cols() - 2); + VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime)); + VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime)); + VERIFY_IS_EQUAL(slice, block); + } + { + auto slice = A(all, last - fix<1>); + auto block = A.col(fix<kCols> - fix<2>); + VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime)); + VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime)); + VERIFY_IS_EQUAL(slice, block); + } + + // The middle row. + { + auto slice = A(last / 2, all); + auto block = A.row((A.rows() - 1) / 2); + VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime)); + VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime)); + VERIFY_IS_EQUAL(slice, block); + } + { + auto slice = A(last / fix<2>, all); + auto block = A.row(fix<(kRows - 1) / 2>); + VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime)); + VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime)); + VERIFY_IS_EQUAL(slice, block); + } + + // Last elements of v starting at i. + { + Index i = 7; + auto slice = v(seq(i, last)); + auto block = v.tail(v.size() - i); + VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime)); + VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime)); + VERIFY_IS_EQUAL(slice, block); + } + { + auto i = fix<7>; + auto slice = v(seq(i, last)); + auto block = v.tail(fix<kRows> - i); + VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime)); + VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime)); + VERIFY_IS_EQUAL(slice, block); + } + + // Last n elements of v. + { + Index n = 6; + auto slice = v(seq(last + 1 - n, last)); + auto block = v.tail(n); + VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime)); + VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime)); + VERIFY_IS_EQUAL(slice, block); + } + { + auto n = fix<6>; + auto slice = v(seq(last + fix<1> - n, last)); + auto block = v.tail(n); + VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime)); + VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime)); + VERIFY_IS_EQUAL(slice, block); + } + + // Last n elements of v. + { + Index n = 6; + auto slice = v(lastN(n)); + auto block = v.tail(n); + VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime)); + VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime)); + VERIFY_IS_EQUAL(slice, block); + } + { + auto n = fix<6>; + auto slice = v(lastN(n)); + auto block = v.tail(n); + VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime)); + VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime)); + VERIFY_IS_EQUAL(slice, block); + } + + // Bottom-right corner of A of size m times n. + { + Index m = 3; + Index n = 6; + auto slice = A(lastN(m), lastN(n)); + auto block = A.bottomRightCorner(m, n); + VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime)); + VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime)); + VERIFY_IS_EQUAL(slice, block); + } + { + auto m = fix<3>; + auto n = fix<6>; + auto slice = A(lastN(m), lastN(n)); + auto block = A.bottomRightCorner(m, n); + VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime)); + VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime)); + VERIFY_IS_EQUAL(slice, block); + } + + // Last n columns with a stride of 3. + { + Index n = 4; + constexpr Index stride = 3; + auto slice = A(all, lastN(n, stride)); + auto block = Eigen::Map<Eigen::Matrix<double, kRows, Dynamic>, 0, OuterStride<stride * kRows>>( + A.data() + (kCols - 1 - (n - 1) * stride) * kRows, A.rows(), n); + VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime)); + VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime)); + VERIFY_IS_EQUAL(slice, block); + } + { + constexpr auto n = fix<4>; + constexpr auto stride = fix<3>; + auto slice = A(all, lastN(n, stride)); + auto block = Eigen::Map<Eigen::Matrix<double, kRows, n>, 0, OuterStride<stride * kRows>>( + A.data() + (kCols - 1 - (n - 1) * stride) * kRows, A.rows(), n); + VERIFY_IS_EQUAL(int(slice.RowsAtCompileTime), int(block.RowsAtCompileTime)); + VERIFY_IS_EQUAL(int(slice.ColsAtCompileTime), int(block.ColsAtCompileTime)); + VERIFY_IS_EQUAL(slice, block); + } + + // Compile time size and increment. + { + auto slice1 = v(seq(last - fix<7>, last - fix<2>)); + auto slice2 = v(seqN(last - 7, fix<6>)); + VERIFY_IS_EQUAL(slice1, slice2); + VERIFY_IS_EQUAL(int(slice1.SizeAtCompileTime), 6); + VERIFY_IS_EQUAL(int(slice2.SizeAtCompileTime), 6); + auto slice3 = A(all, seq(fix<0>, last, fix<2>)); + VERIFY_IS_EQUAL(int(slice3.RowsAtCompileTime), kRows); + VERIFY_IS_EQUAL(int(slice3.ColsAtCompileTime), (kCols + 1) / 2); + } + + // Reverse order. + { + auto slice = A(all, seq(20, 10, fix<-2>)); + auto block = Eigen::Map<Eigen::Matrix<double, kRows, Dynamic>, 0, OuterStride<-2 * kRows>>( + A.data() + 20 * kRows, A.rows(), (20 - 10 + 2) / 2); + VERIFY_IS_EQUAL(slice, block); + } + { + Index n = 10; + auto slice1 = A(seqN(last, n, fix<-1>), all); + auto slice2 = A(lastN(n).reverse(), all); + VERIFY_IS_EQUAL(slice1, slice2); + } + + // Array of indices. + { + std::vector<int> ind{4, 2, 5, 5, 3}; + auto slice1 = A(all, ind); + for (int i = 0; i < ind.size(); ++i) { + VERIFY_IS_EQUAL(slice1.col(i), A.col(ind[i])); + } + + auto slice2 = A(all, {4, 2, 5, 5, 3}); + VERIFY_IS_EQUAL(slice1, slice2); + + Eigen::ArrayXi indarray(5); + indarray << 4, 2, 5, 5, 3; + auto slice3 = A(all, indarray); + VERIFY_IS_EQUAL(slice1, slice3); + } + + // Custom index list. + { + struct pad { + Index size() const { return out_size; } + Index operator[](Index i) const { return std::max<Index>(0, i - (out_size - in_size)); } + Index in_size, out_size; + }; + + auto slice = A(pad{3, 5}, pad{3, 5}); + Eigen::MatrixXd B = slice; + VERIFY_IS_EQUAL(B.block(2, 2, 3, 3), A.block(0, 0, 3, 3)); + } +} + EIGEN_DECLARE_TEST(indexed_view) { for (int i = 0; i < g_repeat; i++) { CALL_SUBTEST_1(check_indexed_view()); } + CALL_SUBTEST_1(check_tutorial_examples()); // static checks of some internals: STATIC_CHECK((internal::is_valid_index_type<int>::value));