// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // Copyright (C) 2017 Gael Guennebaud // // This Source Code Form is subject to the terms of the Mozilla // Public License v. 2.0. If a copy of the MPL was not distributed // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. #ifndef EIGEN_INDEXED_VIEW_HELPER_H #define EIGEN_INDEXED_VIEW_HELPER_H // IWYU pragma: private #include "../InternalHeaderCheck.h" namespace Eigen { namespace internal { struct symbolic_last_tag {}; struct all_t {}; } // namespace internal namespace placeholders { typedef symbolic::SymbolExpr last_t; /** \var last * \ingroup Core_Module * * Can be used as a parameter to Eigen::seq and Eigen::seqN functions to symbolically reference the last * element/row/columns of the underlying vector or matrix once passed to DenseBase::operator()(const RowIndices&, const * ColIndices&). * * This symbolic placeholder supports standard arithmetic operations. * * A typical usage example would be: * \code * using namespace Eigen; * using Eigen::placeholders::last; * VectorXd v(n); * v(seq(2,last-2)).setOnes(); * \endcode * * \sa end */ static constexpr const last_t last; typedef symbolic::AddExpr, symbolic::ValueExpr>> lastp1_t; typedef Eigen::internal::all_t all_t; /** \var lastp1 * \ingroup Core_Module * * Can be used as a parameter to Eigen::seq and Eigen::seqN functions to symbolically * reference the last+1 element/row/columns of the underlying vector or matrix once * passed to DenseBase::operator()(const RowIndices&, const ColIndices&). * * This symbolic placeholder supports standard arithmetic operations. * It is essentially an alias to last+fix<1>. * * \sa last */ #ifdef EIGEN_PARSED_BY_DOXYGEN 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 constexpr lastp1_t lastp1(last + fix<1>()); #endif /** \var end * \ingroup Core_Module * \sa 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 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 struct SymbolicExpressionEvaluator { static constexpr Index ValueAtCompileTime = Undefined; static Index eval(const Expr& expr, Index /*size*/) { return static_cast(expr); } }; // Symbolic expression with size known at compile-time. template struct SymbolicExpressionEvaluator::value>> { static constexpr Index ValueAtCompileTime = Expr::Derived::eval_at_compile_time(Eigen::placeholders::last = fix); static Index eval(const Expr& expr, Index /*size*/) { return expr.eval(Eigen::placeholders::last = fix); } }; // Symbolic expression with dynamic size. template struct SymbolicExpressionEvaluator::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 struct SymbolicExpressionEvaluator, SizeAtCompileTime, void> { static constexpr Index ValueAtCompileTime = static_cast(N); static Index eval(const FixedInt& /*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 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 struct IndexedViewHelper { static constexpr Index FirstAtCompileTime = Undefined; static constexpr Index SizeAtCompileTime = array_size::value; static constexpr Index IncrAtCompileTime = Undefined; static constexpr Index first(const Indices& indices) { return static_cast(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 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 first_; variable_if_dynamic size_; variable_if_dynamicindex incr_; }; template struct IndexedViewHelperIndicesWrapper, NestedSizeAtCompileTime, void> { static constexpr Index EvalFirstAtCompileTime = SymbolicExpressionEvaluator::ValueAtCompileTime; static constexpr Index EvalSizeAtCompileTime = SymbolicExpressionEvaluator::ValueAtCompileTime; static constexpr Index EvalIncrAtCompileTime = SymbolicExpressionEvaluator::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; using type = ArithmeticSequenceRange; static type CreateIndexSequence(const Indices& indices, Index nested_size) { Index first = SymbolicExpressionEvaluator::eval(indices.firstObject(), nested_size); Index size = SymbolicExpressionEvaluator::eval(indices.sizeObject(), nested_size); Index incr = SymbolicExpressionEvaluator::eval(indices.incrObject(), nested_size); return type(first, size, incr); } }; template struct IndexedViewHelper, void> { public: using Indices = ArithmeticSequenceRange; 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 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 value_; }; template struct is_single_range : public std::false_type {}; template struct is_single_range> : public std::true_type {}; template struct IndexedViewHelperIndicesWrapper< SingleIndex, NestedSizeAtCompileTime, std::enable_if_t::value || symbolic::is_symbolic::value>> { static constexpr Index EvalValueAtCompileTime = SymbolicExpressionEvaluator::ValueAtCompileTime; static constexpr Index ValueAtCompileTime = (int(EvalValueAtCompileTime) == Undefined) ? Index(DynamicIndex) : EvalValueAtCompileTime; using type = SingleRange; static type CreateIndexSequence(const SingleIndex& index, Index nested_size) { return type(SymbolicExpressionEvaluator::eval(index, nested_size)); } }; template struct IndexedViewHelperIndicesWrapper, NestedSizeAtCompileTime, void> { using type = SingleRange; static type CreateIndexSequence(const FixedInt& /*index*/) { return type(Index(N)); } }; template struct IndexedViewHelper, void> { using Indices = SingleRange; 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 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 size_; }; template struct IndexedViewHelperIndicesWrapper { using type = AllRange; static type CreateIndexSequence(const all_t& /*indices*/, Index nested_size) { return type(nested_size); } }; template struct IndexedViewHelper, void> { using Indices = AllRange; 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(); } }; // this helper class assumes internal::valid_indexed_view_overload::value == true template struct IndexedViewSelector; template using IvcType = typename internal::IndexedViewHelperIndicesWrapper::type; template inline IvcType CreateIndexSequence(size_t size, const Indices& indices) { return internal::IndexedViewHelperIndicesWrapper::CreateIndexSequence(indices, size); } // Generic template struct IndexedViewSelector, IvcType>>::ReturnAsIndexedView>> { using ReturnType = IndexedView, IvcType>; using ConstReturnType = IndexedView, IvcType>; static inline ReturnType run(Derived& derived, const RowIndices& rowIndices, const ColIndices& colIndices) { return ReturnType(derived, CreateIndexSequence(derived.rows(), rowIndices), CreateIndexSequence(derived.cols(), colIndices)); } static inline ConstReturnType run(const Derived& derived, const RowIndices& rowIndices, const ColIndices& colIndices) { return ConstReturnType(derived, CreateIndexSequence(derived.rows(), rowIndices), CreateIndexSequence(derived.cols(), colIndices)); } }; // Block template struct IndexedViewSelector< Derived, RowIndices, ColIndices, std::enable_if_t, IvcType>>::ReturnAsBlock>> { using ActualRowIndices = IvcType; using ActualColIndices = IvcType; using IndexedViewType = IndexedView; using ConstIndexedViewType = IndexedView; using ReturnType = typename internal::traits::BlockType; using ConstReturnType = typename internal::traits::BlockType; using RowHelper = internal::IndexedViewHelper; using ColHelper = internal::IndexedViewHelper; static inline ReturnType run(Derived& derived, const RowIndices& rowIndices, const ColIndices& colIndices) { auto actualRowIndices = CreateIndexSequence(derived.rows(), rowIndices); auto actualColIndices = CreateIndexSequence(derived.cols(), 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) { auto actualRowIndices = CreateIndexSequence(derived.rows(), rowIndices); auto actualColIndices = CreateIndexSequence(derived.cols(), colIndices); return ConstReturnType(derived, RowHelper::first(actualRowIndices), ColHelper::first(actualColIndices), RowHelper::size(actualRowIndices), ColHelper::size(actualColIndices)); } }; // Scalar template struct IndexedViewSelector< Derived, RowIndices, ColIndices, std::enable_if_t, IvcType>>::ReturnAsScalar>> { using ReturnType = typename DenseBase::Scalar&; using ConstReturnType = typename DenseBase::CoeffReturnType; using ActualRowIndices = IvcType; using ActualColIndices = IvcType; using RowHelper = internal::IndexedViewHelper; using ColHelper = internal::IndexedViewHelper; static inline ReturnType run(Derived& derived, const RowIndices& rowIndices, const ColIndices& colIndices) { auto actualRowIndices = CreateIndexSequence(derived.rows(), rowIndices); auto actualColIndices = CreateIndexSequence(derived.cols(), colIndices); return derived(RowHelper::first(actualRowIndices), ColHelper::first(actualColIndices)); } static inline ConstReturnType run(const Derived& derived, const RowIndices& rowIndices, const ColIndices& colIndices) { auto actualRowIndices = CreateIndexSequence(derived.rows(), rowIndices); auto actualColIndices = CreateIndexSequence(derived.cols(), colIndices); return derived(RowHelper::first(actualRowIndices), ColHelper::first(actualColIndices)); } }; // this helper class assumes internal::is_valid_index_type::value == false template struct VectorIndexedViewSelector; // Generic template struct VectorIndexedViewSelector< Derived, Indices, std::enable_if_t>::value && internal::IndexedViewHelper>::IncrAtCompileTime != 1>> { static constexpr bool IsRowMajor = DenseBase::IsRowMajor; using ZeroIndex = internal::SingleRange; using RowMajorReturnType = IndexedView>; using ConstRowMajorReturnType = IndexedView>; using ColMajorReturnType = IndexedView, ZeroIndex>; using ConstColMajorReturnType = IndexedView, ZeroIndex>; using ReturnType = typename internal::conditional::type; using ConstReturnType = typename internal::conditional::type; template = true> static inline RowMajorReturnType run(Derived& derived, const Indices& indices) { return RowMajorReturnType(derived, ZeroIndex(0), CreateIndexSequence(derived.cols(), indices)); } template = true> static inline ConstRowMajorReturnType run(const Derived& derived, const Indices& indices) { return ConstRowMajorReturnType(derived, ZeroIndex(0), CreateIndexSequence(derived.cols(), indices)); } template = true> static inline ColMajorReturnType run(Derived& derived, const Indices& indices) { return ColMajorReturnType(derived, CreateIndexSequence(derived.rows(), indices), ZeroIndex(0)); } template = true> static inline ConstColMajorReturnType run(const Derived& derived, const Indices& indices) { return ConstColMajorReturnType(derived, CreateIndexSequence(derived.rows(), indices), ZeroIndex(0)); } }; // Block template struct VectorIndexedViewSelector< Derived, Indices, std::enable_if_t>::value && internal::IndexedViewHelper>::IncrAtCompileTime == 1>> { using Helper = internal::IndexedViewHelper>; using ReturnType = VectorBlock; using ConstReturnType = VectorBlock; static inline ReturnType run(Derived& derived, const Indices& indices) { auto actualIndices = CreateIndexSequence(derived.size(), indices); return ReturnType(derived, Helper::first(actualIndices), Helper::size(actualIndices)); } static inline ConstReturnType run(const Derived& derived, const Indices& indices) { auto actualIndices = CreateIndexSequence(derived.size(), indices); return ConstReturnType(derived, Helper::first(actualIndices), Helper::size(actualIndices)); } }; // Symbolic template struct VectorIndexedViewSelector< Derived, Indices, std::enable_if_t>::value>> { using ReturnType = typename DenseBase::Scalar&; using ConstReturnType = typename DenseBase::CoeffReturnType; using Helper = internal::IndexedViewHelper>; static inline ReturnType run(Derived& derived, const Indices& indices) { auto actualIndices = CreateIndexSequence(derived.size(), indices); return derived(Helper::first(actualIndices)); } static inline ConstReturnType run(const Derived& derived, const Indices& indices) { auto actualIndices = CreateIndexSequence(derived.size(), indices); return derived(Helper::first(actualIndices)); } }; } // end namespace internal } // end namespace Eigen #endif // EIGEN_INDEXED_VIEW_HELPER_H