Eigen  5.0.1
 
Loading...
Searching...
No Matches
CoreEvaluators.h
1// This file is part of Eigen, a lightweight C++ template library
2// for linear algebra.
3//
4// Copyright (C) 2011 Benoit Jacob <jacob.benoit.1@gmail.com>
5// Copyright (C) 2011-2014 Gael Guennebaud <gael.guennebaud@inria.fr>
6// Copyright (C) 2011-2012 Jitse Niesen <jitse@maths.leeds.ac.uk>
7//
8// This Source Code Form is subject to the terms of the Mozilla
9// Public License v. 2.0. If a copy of the MPL was not distributed
10// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
11// SPDX-License-Identifier: MPL-2.0
12
13#ifndef EIGEN_COREEVALUATORS_H
14#define EIGEN_COREEVALUATORS_H
15
16// IWYU pragma: private
17#include "./InternalHeaderCheck.h"
18
19namespace Eigen {
20
21namespace internal {
22
23// This class returns the evaluator kind from the expression storage kind.
24// Default assumes index based accessors
25template <typename StorageKind>
26struct storage_kind_to_evaluator_kind {
27 using Kind = IndexBased;
28};
29
30// This class returns the evaluator shape from the expression storage kind.
31// It can be Dense, Sparse, Triangular, Diagonal, SelfAdjoint, Band, etc.
32template <typename StorageKind>
33struct storage_kind_to_shape;
34
35template <>
36struct storage_kind_to_shape<Dense> {
37 using Shape = DenseShape;
38};
39template <>
40struct storage_kind_to_shape<SolverStorage> {
41 using Shape = SolverShape;
42};
43template <>
44struct storage_kind_to_shape<PermutationStorage> {
45 using Shape = PermutationShape;
46};
47template <>
48struct storage_kind_to_shape<TranspositionsStorage> {
49 using Shape = TranspositionsShape;
50};
51
52// Evaluators have to be specialized with respect to various criteria such as:
53// - storage/structure/shape
54// - scalar type
55// - etc.
56// Therefore, we need specialization of evaluator providing additional template arguments for each kind of evaluators.
57// We currently distinguish the following kind of evaluators:
58// - unary_evaluator for expressions taking only one argument (CwiseUnaryOp, CwiseUnaryView, Transpose,
59// MatrixWrapper, ArrayWrapper, Reverse, Replicate)
60// - binary_evaluator for expression taking two arguments (CwiseBinaryOp)
61// - ternary_evaluator for expression taking three arguments (CwiseTernaryOp)
62// - product_evaluator for linear algebra products (Product); special case of binary_evaluator because it requires
63// additional tags for dispatching.
64// - mapbase_evaluator for Map, Block, Ref
65// - block_evaluator for Block (special dispatching to a mapbase_evaluator or unary_evaluator)
66
67template <typename T, typename Arg1Kind = typename evaluator_traits<typename T::Arg1>::Kind,
68 typename Arg2Kind = typename evaluator_traits<typename T::Arg2>::Kind,
69 typename Arg3Kind = typename evaluator_traits<typename T::Arg3>::Kind,
70 typename Arg1Scalar = typename traits<typename T::Arg1>::Scalar,
71 typename Arg2Scalar = typename traits<typename T::Arg2>::Scalar,
72 typename Arg3Scalar = typename traits<typename T::Arg3>::Scalar>
73struct ternary_evaluator;
74
75template <typename T, typename LhsKind = typename evaluator_traits<typename T::Lhs>::Kind,
76 typename RhsKind = typename evaluator_traits<typename T::Rhs>::Kind,
77 typename LhsScalar = typename traits<typename T::Lhs>::Scalar,
78 typename RhsScalar = typename traits<typename T::Rhs>::Scalar>
79struct binary_evaluator;
80
81template <typename T, typename Kind = typename evaluator_traits<typename T::NestedExpression>::Kind,
82 typename Scalar = typename T::Scalar>
83struct unary_evaluator;
84
85// evaluator_traits<T> contains traits for evaluator<T>
86
87template <typename T>
88struct evaluator_traits_base {
89 // by default, get evaluator kind and shape from storage
90 using Kind = typename storage_kind_to_evaluator_kind<typename traits<T>::StorageKind>::Kind;
91 using Shape = typename storage_kind_to_shape<typename traits<T>::StorageKind>::Shape;
92};
93
94// Default evaluator traits
95template <typename T>
96struct evaluator_traits : public evaluator_traits_base<T> {};
97
98template <typename T, typename Shape = typename evaluator_traits<T>::Shape>
99struct evaluator_assume_aliasing : std::false_type {};
100
101// By default, we assume a unary expression:
102template <typename T>
103struct evaluator : public unary_evaluator<T> {
104 using Base = unary_evaluator<T>;
105 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE explicit evaluator(const T& xpr) : Base(xpr) {}
106};
107
108// TODO: Think about const-correctness
109template <typename T>
110struct evaluator<const T> : evaluator<T> {
111 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE explicit evaluator(const T& xpr) : evaluator<T>(xpr) {}
112};
113
114// ---------- base class for all evaluators ----------
115
116template <typename ExpressionType>
117struct evaluator_base {
118 // TODO: find a way to avoid propagating all these traits. They are currently only needed to handle
119 // outer,inner indices.
120 using ExpressionTraits = traits<ExpressionType>;
121
122 enum { Alignment = 0 };
123 // Spell out deleted copy operations instead of inheriting from an empty helper:
124 // an extra base can kill EBO and make complex evaluators larger than they should be.
125 EIGEN_DEVICE_FUNC constexpr evaluator_base() = default;
126
127 evaluator_base(const evaluator_base&) = delete;
128 evaluator_base& operator=(const evaluator_base&) = delete;
129};
130
131// -------------------- Matrix and Array --------------------
132//
133// evaluator<PlainObjectBase> is a common base class for the
134// Matrix and Array evaluators.
135// Here we directly specialize evaluator. This is not really a unary expression, and it is, by definition, dense,
136// so no need for more sophisticated dispatching.
137
138// this helper permits to completely eliminate m_outerStride if it is known at compiletime.
139template <typename Scalar, int OuterStride>
140class plainobjectbase_evaluator_data {
141 public:
142 EIGEN_DEVICE_FUNC constexpr plainobjectbase_evaluator_data(const Scalar* ptr, Index outerStride) : data(ptr) {
143 EIGEN_UNUSED_VARIABLE(outerStride);
144 eigen_internal_assert(outerStride == OuterStride);
145 }
146 EIGEN_DEVICE_FUNC constexpr Index outerStride() const noexcept { return OuterStride; }
147 const Scalar* data;
148};
149
150template <typename Scalar>
151class plainobjectbase_evaluator_data<Scalar, Dynamic> {
152 public:
153 EIGEN_DEVICE_FUNC constexpr plainobjectbase_evaluator_data(const Scalar* ptr, Index outerStride)
154 : data(ptr), m_outerStride(outerStride) {}
155 EIGEN_DEVICE_FUNC constexpr Index outerStride() const { return m_outerStride; }
156 const Scalar* data;
157
158 protected:
159 Index m_outerStride;
160};
161
162template <typename Derived>
163struct evaluator<PlainObjectBase<Derived>> : evaluator_base<Derived> {
164 using PlainObjectType = PlainObjectBase<Derived>;
165 using Scalar = typename PlainObjectType::Scalar;
166 using CoeffReturnType = typename PlainObjectType::CoeffReturnType;
167
168 enum {
169 IsRowMajor = PlainObjectType::IsRowMajor,
170 IsVectorAtCompileTime = PlainObjectType::IsVectorAtCompileTime,
171 RowsAtCompileTime = PlainObjectType::RowsAtCompileTime,
172 ColsAtCompileTime = PlainObjectType::ColsAtCompileTime,
173
174 CoeffReadCost = NumTraits<Scalar>::ReadCost,
175 Flags = traits<Derived>::EvaluatorFlags,
176 Alignment = traits<Derived>::Alignment
177 };
178 enum {
179 // We do not need to know the outer stride for vectors
180 OuterStrideAtCompileTime = IsVectorAtCompileTime ? 0
181 : int(IsRowMajor) ? ColsAtCompileTime
182 : RowsAtCompileTime
183 };
184
185 EIGEN_DEVICE_FUNC constexpr evaluator() : m_d(0, OuterStrideAtCompileTime) {
186 EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
187 }
188
189 EIGEN_DEVICE_FUNC constexpr explicit evaluator(const PlainObjectType& m)
190 : m_d(m.data(), IsVectorAtCompileTime ? 0 : m.outerStride()) {
191 EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
192 }
193
194 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE constexpr CoeffReturnType coeff(Index row, Index col) const {
195 return coeff(getIndex(row, col));
196 }
197
198 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE constexpr CoeffReturnType coeff(Index index) const { return m_d.data[index]; }
199
200 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE constexpr Scalar& coeffRef(Index row, Index col) {
201 return coeffRef(getIndex(row, col));
202 }
203
204 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE constexpr Scalar& coeffRef(Index index) {
205 return const_cast<Scalar*>(m_d.data)[index];
206 }
207
208 template <int LoadMode, typename PacketType>
209 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const {
210 return packet<LoadMode, PacketType>(getIndex(row, col));
211 }
212
213 template <int LoadMode, typename PacketType>
214 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(Index index) const {
215 return ploadt<PacketType, LoadMode>(m_d.data + index);
216 }
217
218 template <int StoreMode, typename PacketType>
219 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writePacket(Index row, Index col, const PacketType& x) {
220 writePacket<StoreMode, PacketType>(getIndex(row, col), x);
221 }
222
223 template <int StoreMode, typename PacketType>
224 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writePacket(Index index, const PacketType& x) {
225 pstoret<Scalar, PacketType, StoreMode>(const_cast<Scalar*>(m_d.data) + index, x);
226 }
227
228 template <int LoadMode, typename PacketType>
229 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetSegment(Index row, Index col, Index begin, Index count) const {
230 return packetSegment<LoadMode, PacketType>(getIndex(row, col), begin, count);
231 }
232
233 template <int LoadMode, typename PacketType>
234 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetSegment(Index index, Index begin, Index count) const {
235 return ploadtSegment<PacketType, LoadMode>(m_d.data + index, begin, count);
236 }
237
238 template <int StoreMode, typename PacketType>
239 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writePacketSegment(Index row, Index col, const PacketType& x, Index begin,
240 Index count) {
241 writePacketSegment<StoreMode, PacketType>(getIndex(row, col), x, begin, count);
242 }
243
244 template <int StoreMode, typename PacketType>
245 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writePacketSegment(Index index, const PacketType& x, Index begin,
246 Index count) {
247 pstoretSegment<Scalar, PacketType, StoreMode>(const_cast<Scalar*>(m_d.data) + index, x, begin, count);
248 }
249
250 protected:
251 plainobjectbase_evaluator_data<Scalar, OuterStrideAtCompileTime> m_d;
252
253 private:
254 EIGEN_DEVICE_FUNC constexpr Index getIndex(Index row, Index col) const {
255 return IsRowMajor ? row * m_d.outerStride() + col : row + col * m_d.outerStride();
256 }
257};
258
259template <typename Scalar, int Rows, int Cols, int Options, int MaxRows, int MaxCols>
260struct evaluator<Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols>>
261 : evaluator<PlainObjectBase<Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols>>> {
262 using XprType = Matrix<Scalar, Rows, Cols, Options, MaxRows, MaxCols>;
263
264 EIGEN_DEVICE_FUNC constexpr evaluator() = default;
265
266 EIGEN_DEVICE_FUNC constexpr explicit evaluator(const XprType& m) : evaluator<PlainObjectBase<XprType>>(m) {}
267};
268
269template <typename Scalar, int Rows, int Cols, int Options, int MaxRows, int MaxCols>
270struct evaluator<Array<Scalar, Rows, Cols, Options, MaxRows, MaxCols>>
271 : evaluator<PlainObjectBase<Array<Scalar, Rows, Cols, Options, MaxRows, MaxCols>>> {
272 using XprType = Array<Scalar, Rows, Cols, Options, MaxRows, MaxCols>;
273
274 EIGEN_DEVICE_FUNC constexpr evaluator() = default;
275
276 EIGEN_DEVICE_FUNC constexpr explicit evaluator(const XprType& m) : evaluator<PlainObjectBase<XprType>>(m) {}
277};
278
279// -------------------- Transpose --------------------
280
281template <typename ArgType>
282struct unary_evaluator<Transpose<ArgType>, IndexBased> : evaluator_base<Transpose<ArgType>> {
283 using XprType = Transpose<ArgType>;
284
285 enum {
286 CoeffReadCost = evaluator<ArgType>::CoeffReadCost,
287 Flags = evaluator<ArgType>::Flags ^ RowMajorBit,
288 Alignment = evaluator<ArgType>::Alignment
289 };
290
291 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE explicit unary_evaluator(const XprType& t)
292 : m_argImpl(t.nestedExpression()) {}
293
294 using Scalar = typename XprType::Scalar;
295 using CoeffReturnType = typename XprType::CoeffReturnType;
296
297 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const {
298 return m_argImpl.coeff(col, row);
299 }
300
301 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const {
302 return m_argImpl.coeff(index);
303 }
304
305 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col) {
306 return m_argImpl.coeffRef(col, row);
307 }
308
309 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE typename XprType::Scalar& coeffRef(Index index) {
310 return m_argImpl.coeffRef(index);
311 }
312
313 template <int LoadMode, typename PacketType>
314 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const {
315 return m_argImpl.template packet<LoadMode, PacketType>(col, row);
316 }
317
318 template <int LoadMode, typename PacketType>
319 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(Index index) const {
320 return m_argImpl.template packet<LoadMode, PacketType>(index);
321 }
322
323 template <int StoreMode, typename PacketType>
324 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writePacket(Index row, Index col, const PacketType& x) {
325 m_argImpl.template writePacket<StoreMode, PacketType>(col, row, x);
326 }
327
328 template <int StoreMode, typename PacketType>
329 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writePacket(Index index, const PacketType& x) {
330 m_argImpl.template writePacket<StoreMode, PacketType>(index, x);
331 }
332
333 template <int LoadMode, typename PacketType>
334 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetSegment(Index row, Index col, Index begin, Index count) const {
335 return m_argImpl.template packetSegment<LoadMode, PacketType>(col, row, begin, count);
336 }
337
338 template <int LoadMode, typename PacketType>
339 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetSegment(Index index, Index begin, Index count) const {
340 return m_argImpl.template packetSegment<LoadMode, PacketType>(index, begin, count);
341 }
342
343 template <int StoreMode, typename PacketType>
344 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writePacketSegment(Index row, Index col, const PacketType& x, Index begin,
345 Index count) {
346 m_argImpl.template writePacketSegment<StoreMode, PacketType>(col, row, x, begin, count);
347 }
348
349 template <int StoreMode, typename PacketType>
350 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writePacketSegment(Index index, const PacketType& x, Index begin,
351 Index count) {
352 m_argImpl.template writePacketSegment<StoreMode, PacketType>(index, x, begin, count);
353 }
354
355 protected:
356 evaluator<ArgType> m_argImpl;
357};
358
359// -------------------- CwiseNullaryOp --------------------
360// Like Matrix and Array, this is not really a unary expression, so we directly specialize evaluator.
361// Likewise, there is no need for more sophisticated dispatching here.
362
363template <typename Scalar, typename NullaryOp, bool has_nullary = has_nullary_operator<NullaryOp>::value,
364 bool has_unary = has_unary_operator<NullaryOp>::value,
365 bool has_binary = has_binary_operator<NullaryOp>::value>
366struct nullary_wrapper {
367 template <typename IndexType>
368 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i,
369 IndexType j) const {
370 return op(i, j);
371 }
372 template <typename IndexType>
373 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i) const {
374 return op(i);
375 }
376
377 template <typename T, typename IndexType>
378 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i, IndexType j) const {
379 return op.template packetOp<T>(i, j);
380 }
381 template <typename T, typename IndexType>
382 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i) const {
383 return op.template packetOp<T>(i);
384 }
385};
386
387template <typename Scalar, typename NullaryOp>
388struct nullary_wrapper<Scalar, NullaryOp, true, false, false> {
389 template <typename IndexType>
390 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType = 0,
391 IndexType = 0) const {
392 return op();
393 }
394 template <typename T, typename IndexType>
395 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType = 0, IndexType = 0) const {
396 return op.template packetOp<T>();
397 }
398};
399
400template <typename Scalar, typename NullaryOp>
401struct nullary_wrapper<Scalar, NullaryOp, false, false, true> {
402 template <typename IndexType>
403 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i,
404 IndexType j = 0) const {
405 return op(i, j);
406 }
407 template <typename T, typename IndexType>
408 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i, IndexType j = 0) const {
409 return op.template packetOp<T>(i, j);
410 }
411};
412
413// We need the following specialization for vector-only functors assigned to a runtime vector,
414// for instance, using linspace and assigning a RowVectorXd to a MatrixXd or even a row of a MatrixXd.
415// In this case, i==0 and j is used for the actual iteration.
416template <typename Scalar, typename NullaryOp>
417struct nullary_wrapper<Scalar, NullaryOp, false, true, false> {
418 template <typename IndexType>
419 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i,
420 IndexType j) const {
421 eigen_assert(i == 0 || j == 0);
422 return op(i + j);
423 }
424 template <typename T, typename IndexType>
425 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i, IndexType j) const {
426 eigen_assert(i == 0 || j == 0);
427 return op.template packetOp<T>(i + j);
428 }
429
430 template <typename IndexType>
431 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar operator()(const NullaryOp& op, IndexType i) const {
432 return op(i);
433 }
434 template <typename T, typename IndexType>
435 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE T packetOp(const NullaryOp& op, IndexType i) const {
436 return op.template packetOp<T>(i);
437 }
438};
439
440template <typename Scalar, typename NullaryOp>
441struct nullary_wrapper<Scalar, NullaryOp, false, false, false> {};
442
443template <typename NullaryOp, typename PlainObjectType>
444struct evaluator<CwiseNullaryOp<NullaryOp, PlainObjectType>>
445 : evaluator_base<CwiseNullaryOp<NullaryOp, PlainObjectType>> {
446 using XprType = CwiseNullaryOp<NullaryOp, PlainObjectType>;
447 using PlainObjectTypeCleaned = remove_all_t<PlainObjectType>;
448
449 enum {
450 CoeffReadCost = functor_traits<NullaryOp>::Cost,
451
452 Flags = (evaluator<PlainObjectTypeCleaned>::Flags &
453 (HereditaryBits | (functor_has_linear_access<NullaryOp>::value ? LinearAccessBit : 0) |
454 (functor_traits<NullaryOp>::PacketAccess ? PacketAccessBit : 0))) |
455 (functor_traits<NullaryOp>::IsRepeatable ? 0 : EvalBeforeNestingBit),
456 Alignment = AlignedMax
457 };
458
459 EIGEN_DEVICE_FUNC constexpr explicit evaluator(const XprType& n) : m_functor(n.functor()), m_wrapper() {
460 EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
461 }
462
463 using CoeffReturnType = typename XprType::CoeffReturnType;
464
465 template <typename IndexType>
466 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE CoeffReturnType coeff(IndexType row, IndexType col) const {
467 return m_wrapper(m_functor, row, col);
468 }
469
470 template <typename IndexType>
471 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE CoeffReturnType coeff(IndexType index) const {
472 return m_wrapper(m_functor, index);
473 }
474
475 template <int LoadMode, typename PacketType, typename IndexType>
476 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(IndexType row, IndexType col) const {
477 return m_wrapper.template packetOp<PacketType>(m_functor, row, col);
478 }
479
480 template <int LoadMode, typename PacketType, typename IndexType>
481 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(IndexType index) const {
482 return m_wrapper.template packetOp<PacketType>(m_functor, index);
483 }
484
485 template <int LoadMode, typename PacketType, typename IndexType>
486 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetSegment(IndexType row, IndexType col, Index /*begin*/,
487 Index /*count*/) const {
488 return packet<LoadMode, PacketType, IndexType>(row, col);
489 }
490
491 template <int LoadMode, typename PacketType, typename IndexType>
492 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetSegment(IndexType index, Index /*begin*/,
493 Index /*count*/) const {
494 return packet<LoadMode, PacketType, IndexType>(index);
495 }
496
497 protected:
498 const NullaryOp m_functor;
499 const nullary_wrapper<CoeffReturnType, NullaryOp> m_wrapper;
500};
501
502// -------------------- CwiseUnaryOp --------------------
503
504template <typename UnaryOp, typename ArgType>
505struct unary_evaluator<CwiseUnaryOp<UnaryOp, ArgType>, IndexBased> : evaluator_base<CwiseUnaryOp<UnaryOp, ArgType>> {
506 using XprType = CwiseUnaryOp<UnaryOp, ArgType>;
507
508 enum {
509 CoeffReadCost = int(evaluator<ArgType>::CoeffReadCost) + int(functor_traits<UnaryOp>::Cost),
510
511 Flags = evaluator<ArgType>::Flags &
512 (HereditaryBits | LinearAccessBit | (functor_traits<UnaryOp>::PacketAccess ? PacketAccessBit : 0)),
513 Alignment = evaluator<ArgType>::Alignment
514 };
515
516 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE explicit unary_evaluator(const XprType& op) : m_d(op) {
517 EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits<UnaryOp>::Cost);
518 EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
519 }
520
521 using CoeffReturnType = typename XprType::CoeffReturnType;
522
523 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const {
524 return m_d.func()(m_d.argImpl.coeff(row, col));
525 }
526
527 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const {
528 return m_d.func()(m_d.argImpl.coeff(index));
529 }
530
531 template <int LoadMode, typename PacketType>
532 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const {
533 return m_d.func().packetOp(m_d.argImpl.template packet<LoadMode, PacketType>(row, col));
534 }
535
536 template <int LoadMode, typename PacketType>
537 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(Index index) const {
538 return m_d.func().packetOp(m_d.argImpl.template packet<LoadMode, PacketType>(index));
539 }
540
541 template <int LoadMode, typename PacketType>
542 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetSegment(Index row, Index col, Index begin, Index count) const {
543 return m_d.func().packetOp(m_d.argImpl.template packetSegment<LoadMode, PacketType>(row, col, begin, count));
544 }
545
546 template <int LoadMode, typename PacketType>
547 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetSegment(Index index, Index begin, Index count) const {
548 return m_d.func().packetOp(m_d.argImpl.template packetSegment<LoadMode, PacketType>(index, begin, count));
549 }
550
551 protected:
552 // this helper permits to completely eliminate the functor if it is empty
553 struct Data {
554 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Data(const XprType& xpr)
555 : op(xpr.functor()), argImpl(xpr.nestedExpression()) {}
556 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE const UnaryOp& func() const { return op; }
557 UnaryOp op;
558 evaluator<ArgType> argImpl;
559 };
560
561 Data m_d;
562};
563
564// ----------------------- Casting ---------------------
565
566template <typename SrcType, typename DstType, typename ArgType>
567struct unary_evaluator<CwiseUnaryOp<core_cast_op<SrcType, DstType>, ArgType>, IndexBased> {
568 using CastOp = core_cast_op<SrcType, DstType>;
569 using XprType = CwiseUnaryOp<CastOp, ArgType>;
570
571 // Use the largest packet type by default
572 using SrcPacketType = typename packet_traits<SrcType>::type;
573 static constexpr int SrcPacketSize = unpacket_traits<SrcPacketType>::size;
574 static constexpr int SrcPacketBytes = SrcPacketSize * sizeof(SrcType);
575
576 enum {
577 CoeffReadCost = int(evaluator<ArgType>::CoeffReadCost) + int(functor_traits<CastOp>::Cost),
578 PacketAccess = functor_traits<CastOp>::PacketAccess,
579 ActualPacketAccessBit = PacketAccess ? PacketAccessBit : 0,
580 Flags = evaluator<ArgType>::Flags & (HereditaryBits | LinearAccessBit | ActualPacketAccessBit),
581 IsRowMajor = (evaluator<ArgType>::Flags & RowMajorBit),
582 Alignment = evaluator<ArgType>::Alignment
583 };
584
585 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE explicit unary_evaluator(const XprType& xpr)
586 : m_argImpl(xpr.nestedExpression()), m_rows(xpr.rows()), m_cols(xpr.cols()) {
587 EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits<CastOp>::Cost);
588 EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
589 }
590
591 template <typename DstPacketType>
592 using AltSrcScalarOp = std::enable_if_t<(unpacket_traits<DstPacketType>::size < SrcPacketSize &&
593 !find_packet_by_size<SrcType, unpacket_traits<DstPacketType>::size>::value),
594 bool>;
595 template <typename DstPacketType>
596 using SrcPacketArgs1 =
597 std::enable_if_t<(find_packet_by_size<SrcType, unpacket_traits<DstPacketType>::size>::value), bool>;
598 template <typename DstPacketType>
599 using SrcPacketArgs2 = std::enable_if_t<(unpacket_traits<DstPacketType>::size) == (2 * SrcPacketSize), bool>;
600 template <typename DstPacketType>
601 using SrcPacketArgs4 = std::enable_if_t<(unpacket_traits<DstPacketType>::size) == (4 * SrcPacketSize), bool>;
602 template <typename DstPacketType>
603 using SrcPacketArgs8 = std::enable_if_t<(unpacket_traits<DstPacketType>::size) == (8 * SrcPacketSize), bool>;
604
605 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool check_array_bounds(Index row, Index col, Index begin, Index count) const {
606 return IsRowMajor ? (col + count + begin <= cols()) : (row + count + begin <= rows());
607 }
608 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE bool check_array_bounds(Index index, Index begin, Index count) const {
609 return index + count + begin <= size();
610 }
611
612 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE SrcType srcCoeff(Index row, Index col, Index offset) const {
613 Index actualRow = IsRowMajor ? row : row + offset;
614 Index actualCol = IsRowMajor ? col + offset : col;
615 return m_argImpl.coeff(actualRow, actualCol);
616 }
617 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE SrcType srcCoeff(Index index, Index offset) const {
618 Index actualIndex = index + offset;
619 return m_argImpl.coeff(actualIndex);
620 }
621
622 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE DstType coeff(Index row, Index col) const {
623 return cast<SrcType, DstType>(srcCoeff(row, col, 0));
624 }
625 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE DstType coeff(Index index) const {
626 return cast<SrcType, DstType>(srcCoeff(index, 0));
627 }
628
629 template <int LoadMode, typename PacketType = SrcPacketType>
630 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType srcPacket(Index row, Index col, Index offset) const {
631 constexpr int PacketSize = unpacket_traits<PacketType>::size;
632 Index packetOffset = offset * PacketSize;
633 Index actualRow = IsRowMajor ? row : row + packetOffset;
634 Index actualCol = IsRowMajor ? col + packetOffset : col;
635 eigen_assert(check_array_bounds(actualRow, actualCol, 0, PacketSize) && "Array index out of bounds");
636 return m_argImpl.template packet<LoadMode, PacketType>(actualRow, actualCol);
637 }
638 template <int LoadMode, typename PacketType = SrcPacketType>
639 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType srcPacket(Index index, Index offset) const {
640 constexpr int PacketSize = unpacket_traits<PacketType>::size;
641 Index packetOffset = offset * PacketSize;
642 Index actualIndex = index + packetOffset;
643 eigen_assert(check_array_bounds(actualIndex, 0, PacketSize) && "Array index out of bounds");
644 return m_argImpl.template packet<LoadMode, PacketType>(actualIndex);
645 }
646 template <int LoadMode, typename PacketType = SrcPacketType>
647 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType srcPacketSegment(Index row, Index col, Index begin, Index count,
648 Index offset) const {
649 constexpr int PacketSize = unpacket_traits<PacketType>::size;
650 Index packetOffset = offset * PacketSize;
651 Index actualRow = IsRowMajor ? row : row + packetOffset;
652 Index actualCol = IsRowMajor ? col + packetOffset : col;
653 eigen_assert(check_array_bounds(actualRow, actualCol, begin, count) && "Array index out of bounds");
654 return m_argImpl.template packetSegment<LoadMode, PacketType>(actualRow, actualCol, begin, count);
655 }
656 template <int LoadMode, typename PacketType = SrcPacketType>
657 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType srcPacketSegment(Index index, Index begin, Index count,
658 Index offset) const {
659 constexpr int PacketSize = unpacket_traits<PacketType>::size;
660 Index packetOffset = offset * PacketSize;
661 Index actualIndex = index + packetOffset;
662 eigen_assert(check_array_bounds(actualIndex, begin, count) && "Array index out of bounds");
663 return m_argImpl.template packetSegment<LoadMode, PacketType>(actualIndex, begin, count);
664 }
665
666 template <int NumPackets, int LoadMode, typename PacketType = SrcPacketType>
667 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketBlock<PacketType, NumPackets> srcPacketSegmentHelper(Index row, Index col,
668 Index begin,
669 Index count) const {
670 constexpr int SrcLoadMode = plain_enum_min(SrcPacketBytes, LoadMode);
671 PacketBlock<PacketType, NumPackets> packets;
672 for (Index i = 0; i < NumPackets; i++) packets.packet[i] = pzero(PacketType());
673 Index offset = begin / SrcPacketSize;
674 Index actualBegin = begin % SrcPacketSize;
675 for (; offset < NumPackets; offset++) {
676 Index actualCount = numext::mini(SrcPacketSize - actualBegin, count);
677 packets.packet[offset] = srcPacketSegment<SrcLoadMode>(row, col, actualBegin, actualCount, offset);
678 if (count == actualCount) break;
679 actualBegin = 0;
680 count -= actualCount;
681 }
682 return packets;
683 }
684 template <int NumPackets, int LoadMode, typename PacketType = SrcPacketType>
685 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketBlock<PacketType, NumPackets> srcPacketSegmentHelper(Index index,
686 Index begin,
687 Index count) const {
688 constexpr int SrcLoadMode = plain_enum_min(SrcPacketBytes, LoadMode);
689 PacketBlock<PacketType, NumPackets> packets;
690 for (Index i = 0; i < NumPackets; i++) packets.packet[i] = pzero(PacketType());
691 Index offset = begin / SrcPacketSize;
692 Index actualBegin = begin % SrcPacketSize;
693 for (; offset < NumPackets; offset++) {
694 Index actualCount = numext::mini(SrcPacketSize - actualBegin, count);
695 packets.packet[offset] = srcPacketSegment<SrcLoadMode>(index, actualBegin, actualCount, offset);
696 if (count == actualCount) break;
697 actualBegin = 0;
698 count -= actualCount;
699 }
700 return packets;
701 }
702
703 // There is no source packet type with equal or fewer elements than DstPacketType.
704 // This is problematic as the evaluation loop may attempt to access data outside the bounds of the array.
705 // For example, consider the cast utilizing pcast<Packet4f,Packet2d> with an array of size 4: {0.0f,1.0f,2.0f,3.0f}.
706 // The first iteration of the evaluation loop will load 16 bytes: {0.0f,1.0f,2.0f,3.0f} and cast to {0.0,1.0}, which
707 // is acceptable. The second iteration will load 16 bytes: {2.0f,3.0f,?,?}, which is outside the bounds of the array.
708 template <int LoadMode, typename DstPacketType, AltSrcScalarOp<DstPacketType> = true>
709 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE DstPacketType packet(Index row, Index col) const {
710 constexpr int DstPacketSize = unpacket_traits<DstPacketType>::size;
711 constexpr int SrcBytesIncrement = DstPacketSize * sizeof(SrcType);
712 constexpr int SrcLoadMode = plain_enum_min(SrcBytesIncrement, LoadMode);
713 return pcast<SrcPacketType, DstPacketType>(srcPacketSegment<SrcLoadMode>(row, col, 0, DstPacketSize, 0));
714 }
715 // Use the source packet type with the same size as DstPacketType, if it exists
716 template <int LoadMode, typename DstPacketType, SrcPacketArgs1<DstPacketType> = true>
717 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE DstPacketType packet(Index row, Index col) const {
718 constexpr int DstPacketSize = unpacket_traits<DstPacketType>::size;
719 using SizedSrcPacketType = typename find_packet_by_size<SrcType, DstPacketSize>::type;
720 constexpr int SrcBytesIncrement = DstPacketSize * sizeof(SrcType);
721 constexpr int SrcLoadMode = plain_enum_min(SrcBytesIncrement, LoadMode);
722 return pcast<SizedSrcPacketType, DstPacketType>(srcPacket<SrcLoadMode, SizedSrcPacketType>(row, col, 0));
723 }
724 // unpacket_traits<DstPacketType>::size == 2 * SrcPacketSize
725 template <int LoadMode, typename DstPacketType, SrcPacketArgs2<DstPacketType> = true>
726 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE DstPacketType packet(Index row, Index col) const {
727 constexpr int SrcLoadMode = plain_enum_min(SrcPacketBytes, LoadMode);
728 return pcast<SrcPacketType, DstPacketType>(srcPacket<SrcLoadMode>(row, col, 0),
729 srcPacket<SrcLoadMode>(row, col, 1));
730 }
731 // unpacket_traits<DstPacketType>::size == 4 * SrcPacketSize
732 template <int LoadMode, typename DstPacketType, SrcPacketArgs4<DstPacketType> = true>
733 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE DstPacketType packet(Index row, Index col) const {
734 constexpr int SrcLoadMode = plain_enum_min(SrcPacketBytes, LoadMode);
735 return pcast<SrcPacketType, DstPacketType>(srcPacket<SrcLoadMode>(row, col, 0), srcPacket<SrcLoadMode>(row, col, 1),
736 srcPacket<SrcLoadMode>(row, col, 2),
737 srcPacket<SrcLoadMode>(row, col, 3));
738 }
739 // unpacket_traits<DstPacketType>::size == 8 * SrcPacketSize
740 template <int LoadMode, typename DstPacketType, SrcPacketArgs8<DstPacketType> = true>
741 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE DstPacketType packet(Index row, Index col) const {
742 constexpr int SrcLoadMode = plain_enum_min(SrcPacketBytes, LoadMode);
743 return pcast<SrcPacketType, DstPacketType>(
744 srcPacket<SrcLoadMode>(row, col, 0), srcPacket<SrcLoadMode>(row, col, 1), srcPacket<SrcLoadMode>(row, col, 2),
745 srcPacket<SrcLoadMode>(row, col, 3), srcPacket<SrcLoadMode>(row, col, 4), srcPacket<SrcLoadMode>(row, col, 5),
746 srcPacket<SrcLoadMode>(row, col, 6), srcPacket<SrcLoadMode>(row, col, 7));
747 }
748
749 // packetSegment variants
750 template <int LoadMode, typename DstPacketType, AltSrcScalarOp<DstPacketType> = true>
751 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE DstPacketType packetSegment(Index row, Index col, Index begin,
752 Index count) const {
753 constexpr int DstPacketSize = unpacket_traits<DstPacketType>::size;
754 constexpr int SrcBytesIncrement = DstPacketSize * sizeof(SrcType);
755 constexpr int SrcLoadMode = plain_enum_min(SrcBytesIncrement, LoadMode);
756 return pcast<SrcPacketType, DstPacketType>(srcPacketSegment<SrcLoadMode>(row, col, begin, count, 0));
757 }
758 // Use the source packet type with the same size as DstPacketType, if it exists
759 template <int LoadMode, typename DstPacketType, SrcPacketArgs1<DstPacketType> = true>
760 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE DstPacketType packetSegment(Index row, Index col, Index begin,
761 Index count) const {
762 constexpr int DstPacketSize = unpacket_traits<DstPacketType>::size;
763 using SizedSrcPacketType = typename find_packet_by_size<SrcType, DstPacketSize>::type;
764 constexpr int SrcBytesIncrement = DstPacketSize * sizeof(SrcType);
765 constexpr int SrcLoadMode = plain_enum_min(SrcBytesIncrement, LoadMode);
766 return pcast<SizedSrcPacketType, DstPacketType>(
767 srcPacketSegment<SrcLoadMode, SizedSrcPacketType>(row, col, begin, count, 0));
768 }
769 // unpacket_traits<DstPacketType>::size == 2 * SrcPacketSize
770 template <int LoadMode, typename DstPacketType, SrcPacketArgs2<DstPacketType> = true>
771 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE DstPacketType packetSegment(Index row, Index col, Index begin,
772 Index count) const {
773 constexpr int NumPackets = 2;
774 constexpr int SrcLoadMode = plain_enum_min(SrcPacketBytes, LoadMode);
775 PacketBlock<SrcPacketType, NumPackets> packets =
776 srcPacketSegmentHelper<NumPackets, SrcLoadMode>(row, col, begin, count);
777 return pcast<SrcPacketType, DstPacketType>(packets.packet[0], packets.packet[1]);
778 }
779 // unpacket_traits<DstPacketType>::size == 4 * SrcPacketSize
780 template <int LoadMode, typename DstPacketType, SrcPacketArgs4<DstPacketType> = true>
781 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE DstPacketType packetSegment(Index row, Index col, Index begin,
782 Index count) const {
783 constexpr int NumPackets = 4;
784 constexpr int SrcLoadMode = plain_enum_min(SrcPacketBytes, LoadMode);
785 PacketBlock<SrcPacketType, NumPackets> packets =
786 srcPacketSegmentHelper<NumPackets, SrcLoadMode>(row, col, begin, count);
787 return pcast<SrcPacketType, DstPacketType>(packets.packet[0], packets.packet[1], packets.packet[2],
788 packets.packet[3]);
789 }
790 // unpacket_traits<DstPacketType>::size == 8 * SrcPacketSize
791 template <int LoadMode, typename DstPacketType, SrcPacketArgs8<DstPacketType> = true>
792 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE DstPacketType packetSegment(Index row, Index col, Index begin,
793 Index count) const {
794 constexpr int NumPackets = 8;
795 constexpr int SrcLoadMode = plain_enum_min(SrcPacketBytes, LoadMode);
796 PacketBlock<SrcPacketType, NumPackets> packets =
797 srcPacketSegmentHelper<NumPackets, SrcLoadMode>(row, col, begin, count);
798 return pcast<SrcPacketType, DstPacketType>(packets.packet[0], packets.packet[1], packets.packet[2],
799 packets.packet[3], packets.packet[4], packets.packet[5],
800 packets.packet[6], packets.packet[7]);
801 }
802
803 // Analogous routines for linear access.
804 template <int LoadMode, typename DstPacketType, AltSrcScalarOp<DstPacketType> = true>
805 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE DstPacketType packet(Index index) const {
806 constexpr int DstPacketSize = unpacket_traits<DstPacketType>::size;
807 constexpr int SrcBytesIncrement = DstPacketSize * sizeof(SrcType);
808 constexpr int SrcLoadMode = plain_enum_min(SrcBytesIncrement, LoadMode);
809 return pcast<SrcPacketType, DstPacketType>(srcPacketSegment<SrcLoadMode>(index, 0, DstPacketSize, 0));
810 }
811 template <int LoadMode, typename DstPacketType, SrcPacketArgs1<DstPacketType> = true>
812 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE DstPacketType packet(Index index) const {
813 constexpr int DstPacketSize = unpacket_traits<DstPacketType>::size;
814 using SizedSrcPacketType = typename find_packet_by_size<SrcType, DstPacketSize>::type;
815 constexpr int SrcBytesIncrement = DstPacketSize * sizeof(SrcType);
816 constexpr int SrcLoadMode = plain_enum_min(SrcBytesIncrement, LoadMode);
817 return pcast<SizedSrcPacketType, DstPacketType>(srcPacket<SrcLoadMode, SizedSrcPacketType>(index, 0));
818 }
819 template <int LoadMode, typename DstPacketType, SrcPacketArgs2<DstPacketType> = true>
820 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE DstPacketType packet(Index index) const {
821 constexpr int SrcLoadMode = plain_enum_min(SrcPacketBytes, LoadMode);
822 return pcast<SrcPacketType, DstPacketType>(srcPacket<SrcLoadMode>(index, 0), srcPacket<SrcLoadMode>(index, 1));
823 }
824 template <int LoadMode, typename DstPacketType, SrcPacketArgs4<DstPacketType> = true>
825 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE DstPacketType packet(Index index) const {
826 constexpr int SrcLoadMode = plain_enum_min(SrcPacketBytes, LoadMode);
827 return pcast<SrcPacketType, DstPacketType>(srcPacket<SrcLoadMode>(index, 0), srcPacket<SrcLoadMode>(index, 1),
828 srcPacket<SrcLoadMode>(index, 2), srcPacket<SrcLoadMode>(index, 3));
829 }
830 template <int LoadMode, typename DstPacketType, SrcPacketArgs8<DstPacketType> = true>
831 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE DstPacketType packet(Index index) const {
832 constexpr int SrcLoadMode = plain_enum_min(SrcPacketBytes, LoadMode);
833 return pcast<SrcPacketType, DstPacketType>(srcPacket<SrcLoadMode>(index, 0), srcPacket<SrcLoadMode>(index, 1),
834 srcPacket<SrcLoadMode>(index, 2), srcPacket<SrcLoadMode>(index, 3),
835 srcPacket<SrcLoadMode>(index, 4), srcPacket<SrcLoadMode>(index, 5),
836 srcPacket<SrcLoadMode>(index, 6), srcPacket<SrcLoadMode>(index, 7));
837 }
838
839 // packetSegment variants
840 template <int LoadMode, typename DstPacketType, AltSrcScalarOp<DstPacketType> = true>
841 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE DstPacketType packetSegment(Index index, Index begin, Index count) const {
842 constexpr int DstPacketSize = unpacket_traits<DstPacketType>::size;
843 constexpr int SrcBytesIncrement = DstPacketSize * sizeof(SrcType);
844 constexpr int SrcLoadMode = plain_enum_min(SrcBytesIncrement, LoadMode);
845 return pcast<SrcPacketType, DstPacketType>(srcPacketSegment<SrcLoadMode>(index, begin, count, 0));
846 }
847 // Use the source packet type with the same size as DstPacketType, if it exists
848 template <int LoadMode, typename DstPacketType, SrcPacketArgs1<DstPacketType> = true>
849 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE DstPacketType packetSegment(Index index, Index begin, Index count) const {
850 constexpr int DstPacketSize = unpacket_traits<DstPacketType>::size;
851 using SizedSrcPacketType = typename find_packet_by_size<SrcType, DstPacketSize>::type;
852 constexpr int SrcBytesIncrement = DstPacketSize * sizeof(SrcType);
853 constexpr int SrcLoadMode = plain_enum_min(SrcBytesIncrement, LoadMode);
854 return pcast<SizedSrcPacketType, DstPacketType>(
855 srcPacketSegment<SrcLoadMode, SizedSrcPacketType>(index, begin, count, 0));
856 }
857 // unpacket_traits<DstPacketType>::size == 2 * SrcPacketSize
858 template <int LoadMode, typename DstPacketType, SrcPacketArgs2<DstPacketType> = true>
859 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE DstPacketType packetSegment(Index index, Index begin, Index count) const {
860 constexpr int NumPackets = 2;
861 constexpr int SrcLoadMode = plain_enum_min(SrcPacketBytes, LoadMode);
862 PacketBlock<SrcPacketType, NumPackets> packets =
863 srcPacketSegmentHelper<NumPackets, SrcLoadMode>(index, begin, count);
864 return pcast<SrcPacketType, DstPacketType>(packets.packet[0], packets.packet[1]);
865 }
866 // unpacket_traits<DstPacketType>::size == 4 * SrcPacketSize
867 template <int LoadMode, typename DstPacketType, SrcPacketArgs4<DstPacketType> = true>
868 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE DstPacketType packetSegment(Index index, Index begin, Index count) const {
869 constexpr int NumPackets = 4;
870 constexpr int SrcLoadMode = plain_enum_min(SrcPacketBytes, LoadMode);
871 PacketBlock<SrcPacketType, NumPackets> packets =
872 srcPacketSegmentHelper<NumPackets, SrcLoadMode>(index, begin, count);
873 return pcast<SrcPacketType, DstPacketType>(packets.packet[0], packets.packet[1], packets.packet[2],
874 packets.packet[3]);
875 }
876 // unpacket_traits<DstPacketType>::size == 8 * SrcPacketSize
877 template <int LoadMode, typename DstPacketType, SrcPacketArgs8<DstPacketType> = true>
878 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE DstPacketType packetSegment(Index index, Index begin, Index count) const {
879 constexpr int NumPackets = 8;
880 constexpr int SrcLoadMode = plain_enum_min(SrcPacketBytes, LoadMode);
881 PacketBlock<SrcPacketType, NumPackets> packets =
882 srcPacketSegmentHelper<NumPackets, SrcLoadMode>(index, begin, count);
883 return pcast<SrcPacketType, DstPacketType>(packets.packet[0], packets.packet[1], packets.packet[2],
884 packets.packet[3], packets.packet[4], packets.packet[5],
885 packets.packet[6], packets.packet[7]);
886 }
887
888 constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index rows() const { return m_rows; }
889 constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index cols() const { return m_cols; }
890 constexpr EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index size() const { return m_rows * m_cols; }
891
892 protected:
893 const evaluator<ArgType> m_argImpl;
894 const variable_if_dynamic<Index, XprType::RowsAtCompileTime> m_rows;
895 const variable_if_dynamic<Index, XprType::ColsAtCompileTime> m_cols;
896};
897
898// -------------------- CwiseTernaryOp --------------------
899
900// this is a ternary expression
901template <typename TernaryOp, typename Arg1, typename Arg2, typename Arg3>
902struct evaluator<CwiseTernaryOp<TernaryOp, Arg1, Arg2, Arg3>>
903 : public ternary_evaluator<CwiseTernaryOp<TernaryOp, Arg1, Arg2, Arg3>> {
904 using XprType = CwiseTernaryOp<TernaryOp, Arg1, Arg2, Arg3>;
905 using Base = ternary_evaluator<CwiseTernaryOp<TernaryOp, Arg1, Arg2, Arg3>>;
906
907 EIGEN_DEVICE_FUNC constexpr explicit evaluator(const XprType& xpr) : Base(xpr) {}
908};
909
910template <typename TernaryOp, typename Arg1, typename Arg2, typename Arg3>
911struct ternary_evaluator<CwiseTernaryOp<TernaryOp, Arg1, Arg2, Arg3>, IndexBased, IndexBased>
912 : evaluator_base<CwiseTernaryOp<TernaryOp, Arg1, Arg2, Arg3>> {
913 using XprType = CwiseTernaryOp<TernaryOp, Arg1, Arg2, Arg3>;
914
915 enum {
916 CoeffReadCost = int(evaluator<Arg1>::CoeffReadCost) + int(evaluator<Arg2>::CoeffReadCost) +
917 int(evaluator<Arg3>::CoeffReadCost) + int(functor_traits<TernaryOp>::Cost),
918
919 Arg1Flags = evaluator<Arg1>::Flags,
920 Arg2Flags = evaluator<Arg2>::Flags,
921 Arg3Flags = evaluator<Arg3>::Flags,
922 SameType = std::is_same<typename Arg1::Scalar, typename Arg2::Scalar>::value &&
923 std::is_same<typename Arg1::Scalar, typename Arg3::Scalar>::value,
924 StorageOrdersAgree = (int(Arg1Flags) & RowMajorBit) == (int(Arg2Flags) & RowMajorBit) &&
925 (int(Arg1Flags) & RowMajorBit) == (int(Arg3Flags) & RowMajorBit),
926 Flags0 = (int(Arg1Flags) | int(Arg2Flags) | int(Arg3Flags)) &
927 (HereditaryBits |
928 (int(Arg1Flags) & int(Arg2Flags) & int(Arg3Flags) &
929 ((StorageOrdersAgree ? LinearAccessBit : 0) |
930 (functor_traits<TernaryOp>::PacketAccess && StorageOrdersAgree && SameType ? PacketAccessBit : 0)))),
931 Flags = (Flags0 & ~RowMajorBit) | (Arg1Flags & RowMajorBit),
932 Alignment = plain_enum_min(plain_enum_min(evaluator<Arg1>::Alignment, evaluator<Arg2>::Alignment),
933 evaluator<Arg3>::Alignment)
934 };
935
936 EIGEN_DEVICE_FUNC constexpr explicit ternary_evaluator(const XprType& xpr) : m_d(xpr) {
937 EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits<TernaryOp>::Cost);
938 EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
939 }
940
941 using CoeffReturnType = typename XprType::CoeffReturnType;
942
943 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const {
944 return m_d.func()(m_d.arg1Impl.coeff(row, col), m_d.arg2Impl.coeff(row, col), m_d.arg3Impl.coeff(row, col));
945 }
946
947 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const {
948 return m_d.func()(m_d.arg1Impl.coeff(index), m_d.arg2Impl.coeff(index), m_d.arg3Impl.coeff(index));
949 }
950
951 template <int LoadMode, typename PacketType>
952 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const {
953 return m_d.func().packetOp(m_d.arg1Impl.template packet<LoadMode, PacketType>(row, col),
954 m_d.arg2Impl.template packet<LoadMode, PacketType>(row, col),
955 m_d.arg3Impl.template packet<LoadMode, PacketType>(row, col));
956 }
957
958 template <int LoadMode, typename PacketType>
959 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(Index index) const {
960 return m_d.func().packetOp(m_d.arg1Impl.template packet<LoadMode, PacketType>(index),
961 m_d.arg2Impl.template packet<LoadMode, PacketType>(index),
962 m_d.arg3Impl.template packet<LoadMode, PacketType>(index));
963 }
964
965 template <int LoadMode, typename PacketType>
966 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetSegment(Index row, Index col, Index begin, Index count) const {
967 return m_d.func().packetOp(m_d.arg1Impl.template packetSegment<LoadMode, PacketType>(row, col, begin, count),
968 m_d.arg2Impl.template packetSegment<LoadMode, PacketType>(row, col, begin, count),
969 m_d.arg3Impl.template packetSegment<LoadMode, PacketType>(row, col, begin, count));
970 }
971
972 template <int LoadMode, typename PacketType>
973 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetSegment(Index index, Index begin, Index count) const {
974 return m_d.func().packetOp(m_d.arg1Impl.template packetSegment<LoadMode, PacketType>(index, begin, count),
975 m_d.arg2Impl.template packetSegment<LoadMode, PacketType>(index, begin, count),
976 m_d.arg3Impl.template packetSegment<LoadMode, PacketType>(index, begin, count));
977 }
978
979 protected:
980 // this helper permits to completely eliminate the functor if it is empty
981 struct Data {
982 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Data(const XprType& xpr)
983 : op(xpr.functor()), arg1Impl(xpr.arg1()), arg2Impl(xpr.arg2()), arg3Impl(xpr.arg3()) {}
984 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE const TernaryOp& func() const { return op; }
985 TernaryOp op;
986 evaluator<Arg1> arg1Impl;
987 evaluator<Arg2> arg2Impl;
988 evaluator<Arg3> arg3Impl;
989 };
990
991 Data m_d;
992};
993
994template <typename Arg1, typename Arg2, typename Scalar, typename CmpLhsType, typename CmpRhsType, ComparisonName cmp>
995struct scalar_boolean_select_spec {
996 using DummyTernaryOp = scalar_boolean_select_op<Scalar, Scalar, bool>;
997 using DummyArg3 = CwiseBinaryOp<scalar_cmp_op<Scalar, Scalar, cmp, false>, CmpLhsType, CmpRhsType>;
998 using DummyXprType = CwiseTernaryOp<DummyTernaryOp, Arg1, Arg2, DummyArg3>;
999
1000 using PacketTernaryOp = scalar_boolean_select_op<Scalar, Scalar, Scalar>;
1001 using PacketArg3 = CwiseBinaryOp<scalar_cmp_op<Scalar, Scalar, cmp, true>, CmpLhsType, CmpRhsType>;
1002 using PacketXprType = CwiseTernaryOp<PacketTernaryOp, Arg1, Arg2, PacketArg3>;
1003
1004 // Rebuild the comparison with a typed result only when the entire select expression can use packets. Otherwise,
1005 // evaluate the original expression so indirect evaluators do not retain references into a temporary rewrite.
1006 static constexpr bool UseTyped = (ternary_evaluator<PacketXprType>::Flags & PacketAccessBit) != 0;
1007 using Arg3 = std::conditional_t<UseTyped, PacketArg3, DummyArg3>;
1008 using XprType = std::conditional_t<UseTyped, PacketXprType, DummyXprType>;
1009
1010 using Base = ternary_evaluator<XprType>;
1011
1012 EIGEN_DEVICE_FUNC constexpr static const DummyXprType& expression(const DummyXprType& xpr, std::false_type) {
1013 return xpr;
1014 }
1015
1016 EIGEN_DEVICE_FUNC constexpr static XprType expression(const DummyXprType& xpr, std::true_type) {
1017 return XprType(xpr.arg1(), xpr.arg2(), Arg3(xpr.arg3().lhs(), xpr.arg3().rhs()));
1018 }
1019};
1020
1021// specialization for expressions like (a < b).select(c, d) to enable full vectorization
1022template <typename Arg1, typename Arg2, typename Scalar, typename CmpLhsType, typename CmpRhsType, ComparisonName cmp>
1023struct evaluator<CwiseTernaryOp<scalar_boolean_select_op<Scalar, Scalar, bool>, Arg1, Arg2,
1024 CwiseBinaryOp<scalar_cmp_op<Scalar, Scalar, cmp, false>, CmpLhsType, CmpRhsType>>>
1025 : public scalar_boolean_select_spec<Arg1, Arg2, Scalar, CmpLhsType, CmpRhsType, cmp>::Base {
1026 using Helper = scalar_boolean_select_spec<Arg1, Arg2, Scalar, CmpLhsType, CmpRhsType, cmp>;
1027 using Base = typename Helper::Base;
1028 using DummyXprType = typename Helper::DummyXprType;
1029
1030 EIGEN_DEVICE_FUNC constexpr explicit evaluator(const DummyXprType& xpr)
1031 : Base(Helper::expression(xpr, bool_constant<Helper::UseTyped>())) {}
1032};
1033
1034// -------------------- CwiseBinaryOp --------------------
1035
1036// this is a binary expression
1037template <typename BinaryOp, typename Lhs, typename Rhs>
1038struct evaluator<CwiseBinaryOp<BinaryOp, Lhs, Rhs>> : public binary_evaluator<CwiseBinaryOp<BinaryOp, Lhs, Rhs>> {
1039 using XprType = CwiseBinaryOp<BinaryOp, Lhs, Rhs>;
1040 using Base = binary_evaluator<CwiseBinaryOp<BinaryOp, Lhs, Rhs>>;
1041
1042 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE explicit evaluator(const XprType& xpr) : Base(xpr) {}
1043};
1044
1045template <typename BinaryOp, typename Lhs, typename Rhs>
1046struct binary_evaluator<CwiseBinaryOp<BinaryOp, Lhs, Rhs>, IndexBased, IndexBased>
1047 : evaluator_base<CwiseBinaryOp<BinaryOp, Lhs, Rhs>> {
1048 using XprType = CwiseBinaryOp<BinaryOp, Lhs, Rhs>;
1049
1050 enum {
1051 CoeffReadCost =
1052 int(evaluator<Lhs>::CoeffReadCost) + int(evaluator<Rhs>::CoeffReadCost) + int(functor_traits<BinaryOp>::Cost),
1053
1054 LhsFlags = evaluator<Lhs>::Flags,
1055 RhsFlags = evaluator<Rhs>::Flags,
1056 SameType = std::is_same<typename Lhs::Scalar, typename Rhs::Scalar>::value,
1057 StorageOrdersAgree = (int(LhsFlags) & RowMajorBit) == (int(RhsFlags) & RowMajorBit),
1058 Flags0 = (int(LhsFlags) | int(RhsFlags)) &
1059 (HereditaryBits |
1060 (int(LhsFlags) & int(RhsFlags) &
1061 ((StorageOrdersAgree ? LinearAccessBit : 0) |
1062 (functor_traits<BinaryOp>::PacketAccess && StorageOrdersAgree && SameType ? PacketAccessBit : 0)))),
1063 Flags = (Flags0 & ~RowMajorBit) | (LhsFlags & RowMajorBit),
1064 Alignment = plain_enum_min(evaluator<Lhs>::Alignment, evaluator<Rhs>::Alignment)
1065 };
1066
1067 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE explicit binary_evaluator(const XprType& xpr) : m_d(xpr) {
1068 EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits<BinaryOp>::Cost);
1069 EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
1070 }
1071
1072 using CoeffReturnType = typename XprType::CoeffReturnType;
1073
1074 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const {
1075 return m_d.func()(m_d.lhsImpl.coeff(row, col), m_d.rhsImpl.coeff(row, col));
1076 }
1077
1078 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const {
1079 return m_d.func()(m_d.lhsImpl.coeff(index), m_d.rhsImpl.coeff(index));
1080 }
1081
1082 template <int LoadMode, typename PacketType>
1083 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const {
1084 return m_d.func().packetOp(m_d.lhsImpl.template packet<LoadMode, PacketType>(row, col),
1085 m_d.rhsImpl.template packet<LoadMode, PacketType>(row, col));
1086 }
1087
1088 template <int LoadMode, typename PacketType>
1089 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(Index index) const {
1090 return m_d.func().packetOp(m_d.lhsImpl.template packet<LoadMode, PacketType>(index),
1091 m_d.rhsImpl.template packet<LoadMode, PacketType>(index));
1092 }
1093
1094 template <int LoadMode, typename PacketType>
1095 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetSegment(Index row, Index col, Index begin, Index count) const {
1096 return m_d.func().packetOp(m_d.lhsImpl.template packetSegment<LoadMode, PacketType>(row, col, begin, count),
1097 m_d.rhsImpl.template packetSegment<LoadMode, PacketType>(row, col, begin, count));
1098 }
1099
1100 template <int LoadMode, typename PacketType>
1101 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetSegment(Index index, Index begin, Index count) const {
1102 return m_d.func().packetOp(m_d.lhsImpl.template packetSegment<LoadMode, PacketType>(index, begin, count),
1103 m_d.rhsImpl.template packetSegment<LoadMode, PacketType>(index, begin, count));
1104 }
1105
1106 protected:
1107 // this helper permits to completely eliminate the functor if it is empty
1108 struct Data {
1109 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Data(const XprType& xpr)
1110 : op(xpr.functor()), lhsImpl(xpr.lhs()), rhsImpl(xpr.rhs()) {}
1111 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE const BinaryOp& func() const { return op; }
1112 BinaryOp op;
1113 evaluator<Lhs> lhsImpl;
1114 evaluator<Rhs> rhsImpl;
1115 };
1116
1117 Data m_d;
1118};
1119
1120// -------------------- CwiseUnaryView --------------------
1121
1122template <typename UnaryOp, typename ArgType, typename StrideType>
1123struct unary_evaluator<CwiseUnaryView<UnaryOp, ArgType, StrideType>, IndexBased>
1124 : evaluator_base<CwiseUnaryView<UnaryOp, ArgType, StrideType>> {
1125 using XprType = CwiseUnaryView<UnaryOp, ArgType, StrideType>;
1126
1127 enum {
1128 CoeffReadCost = int(evaluator<ArgType>::CoeffReadCost) + int(functor_traits<UnaryOp>::Cost),
1129
1130 Flags = (evaluator<ArgType>::Flags & (HereditaryBits | LinearAccessBit | DirectAccessBit)),
1131
1132 Alignment = 0 // FIXME: clarify why alignment is lost for CwiseUnaryView.
1133 };
1134
1135 EIGEN_DEVICE_FUNC constexpr explicit unary_evaluator(const XprType& op) : m_d(op) {
1136 EIGEN_INTERNAL_CHECK_COST_VALUE(functor_traits<UnaryOp>::Cost);
1137 EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
1138 }
1139
1140 using Scalar = typename XprType::Scalar;
1141 using CoeffReturnType = typename XprType::CoeffReturnType;
1142
1143 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const {
1144 return m_d.func()(m_d.argImpl.coeff(row, col));
1145 }
1146
1147 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const {
1148 return m_d.func()(m_d.argImpl.coeff(index));
1149 }
1150
1151 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col) {
1152 return m_d.func()(m_d.argImpl.coeffRef(row, col));
1153 }
1154
1155 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) {
1156 return m_d.func()(m_d.argImpl.coeffRef(index));
1157 }
1158
1159 protected:
1160 // this helper permits to completely eliminate the functor if it is empty
1161 struct Data {
1162 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Data(const XprType& xpr)
1163 : op(xpr.functor()), argImpl(xpr.nestedExpression()) {}
1164 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE const UnaryOp& func() const { return op; }
1165 UnaryOp op;
1166 evaluator<ArgType> argImpl;
1167 };
1168
1169 Data m_d;
1170};
1171
1172// Read-only component evaluators can gather from contiguous std::complex storage. In particular,
1173// PacketAccessBit on a custom expression does not imply array-oriented component access.
1174template <typename XprType, int Component,
1175 bool Vectorizable = bool(traits<typename XprType::NestedExpression>::Flags & DirectAccessBit) &&
1176 inner_stride_at_compile_time<typename XprType::NestedExpression>::value == 1 &&
1177 (std::is_same<typename XprType::Scalar, float>::value ||
1178 std::is_same<typename XprType::Scalar, double>::value) &&
1179 packet_traits<typename XprType::Scalar>::Vectorizable &&
1180 std::is_same<typename XprType::Scalar, typename unpacket_traits<typename packet_traits<
1181 typename XprType::Scalar>::type>::type>::value>
1182struct complex_component_evaluator : unary_evaluator<XprType> {
1183 using Base = unary_evaluator<XprType>;
1184 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE explicit complex_component_evaluator(const XprType& xpr)
1185 : Base(xpr) {}
1186};
1187
1188template <typename XprType, int Component>
1189struct complex_component_evaluator<XprType, Component, true> : unary_evaluator<XprType> {
1190 using Base = unary_evaluator<XprType>;
1191 using Scalar = typename XprType::Scalar;
1192 // Not named ArgType: MSVC 19.29 resolves the derived evaluator specializations' ArgType template
1193 // parameter to this member through the dependent base, and it drops the nested expression's const.
1194 using NestedXpr = typename XprType::NestedExpression;
1195 // Blocks must delegate packet reads here rather than reinterpret this stride-2 view as a contiguous Map.
1196 static constexpr unsigned int Flags = (Base::Flags & ~DirectAccessBit) | PacketAccessBit;
1197 static constexpr int Alignment = 0;
1198
1199 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE explicit complex_component_evaluator(const XprType& xpr)
1200 : Base(xpr),
1201 m_data(reinterpret_cast<const Scalar*>(xpr.nestedExpression().data())),
1202 m_outerStride(xpr.nestedExpression().outerStride()) {}
1203
1204 template <int LoadMode, typename PacketType>
1205 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(Index index) const {
1206 return pgather<Scalar, PacketType>(m_data + 2 * index + Component, 2);
1207 }
1208
1209 template <int LoadMode, typename PacketType>
1210 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const {
1211 const Index index = XprType::IsRowMajor ? row * m_outerStride.value() + col : col * m_outerStride.value() + row;
1212 return packet<LoadMode, PacketType>(index);
1213 }
1214
1215 template <int LoadMode, typename PacketType>
1216 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetSegment(Index index, Index begin, Index count) const {
1217 Scalar values[unpacket_traits<PacketType>::size] = {};
1218 for (Index i = begin; i < begin + count; ++i) values[i] = Base::coeff(index + i);
1219 return ploadu<PacketType>(values);
1220 }
1221
1222 template <int LoadMode, typename PacketType>
1223 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetSegment(Index row, Index col, Index begin, Index count) const {
1224 Scalar values[unpacket_traits<PacketType>::size] = {};
1225 for (Index i = begin; i < begin + count; ++i)
1226 values[i] = Base::coeff(row + (XprType::IsRowMajor ? 0 : i), col + (XprType::IsRowMajor ? i : 0));
1227 return ploadu<PacketType>(values);
1228 }
1229
1230 private:
1231 const Scalar* m_data;
1232 const variable_if_dynamic<Index, outer_stride_at_compile_time<NestedXpr>::value> m_outerStride;
1233};
1234
1235template <typename Real, typename ArgType>
1236struct evaluator<CwiseUnaryOp<scalar_real_op<std::complex<Real>>, ArgType>>
1237 : complex_component_evaluator<CwiseUnaryOp<scalar_real_op<std::complex<Real>>, ArgType>, 0> {
1238 using XprType = CwiseUnaryOp<scalar_real_op<std::complex<Real>>, ArgType>;
1239 using Base = complex_component_evaluator<XprType, 0>;
1240 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE explicit evaluator(const XprType& xpr) : Base(xpr) {}
1241};
1242
1243// Writable views keep scalar stores: assignment functors require contiguous destination packets.
1244template <typename Real, typename ArgType>
1245struct evaluator<const CwiseUnaryView<scalar_real_ref_op<std::complex<Real>>, ArgType, Stride<0, 0>>>
1246 : complex_component_evaluator<CwiseUnaryView<scalar_real_ref_op<std::complex<Real>>, ArgType, Stride<0, 0>>, 0> {
1247 using XprType = CwiseUnaryView<scalar_real_ref_op<std::complex<Real>>, ArgType, Stride<0, 0>>;
1248 using Base = complex_component_evaluator<XprType, 0>;
1249 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE explicit evaluator(const XprType& xpr) : Base(xpr) {}
1250};
1251
1252template <typename Real, typename ArgType>
1253struct evaluator<CwiseUnaryOp<scalar_imag_op<std::complex<Real>>, ArgType>>
1254 : complex_component_evaluator<CwiseUnaryOp<scalar_imag_op<std::complex<Real>>, ArgType>, 1> {
1255 using XprType = CwiseUnaryOp<scalar_imag_op<std::complex<Real>>, ArgType>;
1256 using Base = complex_component_evaluator<XprType, 1>;
1257 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE explicit evaluator(const XprType& xpr) : Base(xpr) {}
1258};
1259
1260template <typename Real, typename ArgType>
1261struct evaluator<const CwiseUnaryView<scalar_imag_ref_op<std::complex<Real>>, ArgType, Stride<0, 0>>>
1262 : complex_component_evaluator<CwiseUnaryView<scalar_imag_ref_op<std::complex<Real>>, ArgType, Stride<0, 0>>, 1> {
1263 using XprType = CwiseUnaryView<scalar_imag_ref_op<std::complex<Real>>, ArgType, Stride<0, 0>>;
1264 using Base = complex_component_evaluator<XprType, 1>;
1265 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE explicit evaluator(const XprType& xpr) : Base(xpr) {}
1266};
1267
1268// -------------------- Map --------------------
1269
1270// FIXME: consider using Derived::PlainObject for PlainObjectType.
1271// but that might complicate template specialization
1272template <typename Derived, typename PlainObjectType>
1273struct mapbase_evaluator;
1274
1275template <typename Derived, typename PlainObjectType>
1276struct mapbase_evaluator : evaluator_base<Derived> {
1277 using XprType = Derived;
1278 using PointerType = typename XprType::PointerType;
1279 using Scalar = typename XprType::Scalar;
1280 using CoeffReturnType = typename XprType::CoeffReturnType;
1281
1282 enum {
1283 IsRowMajor = XprType::IsRowMajor,
1284 ColsAtCompileTime = XprType::ColsAtCompileTime,
1285 CoeffReadCost = NumTraits<Scalar>::ReadCost
1286 };
1287
1288 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE explicit mapbase_evaluator(const XprType& map)
1289 : m_data(const_cast<PointerType>(map.data())),
1290 m_innerStride(map.innerStride()),
1291 m_outerStride(map.outerStride()) {
1292 EIGEN_STATIC_ASSERT(check_implication((evaluator<Derived>::Flags & PacketAccessBit) != 0,
1293 inner_stride_at_compile_time<Derived>::value == 1),
1294 PACKET_ACCESS_REQUIRES_TO_HAVE_INNER_STRIDE_FIXED_TO_1);
1295 EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
1296 }
1297
1298 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const {
1299 return m_data[col * colStride() + row * rowStride()];
1300 }
1301
1302 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const {
1303 return m_data[index * m_innerStride.value()];
1304 }
1305
1306 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col) {
1307 return m_data[col * colStride() + row * rowStride()];
1308 }
1309
1310 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) {
1311 return m_data[index * m_innerStride.value()];
1312 }
1313
1314 template <int LoadMode, typename PacketType>
1315 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const {
1316 PointerType ptr = m_data + row * rowStride() + col * colStride();
1317 return ploadt<PacketType, LoadMode>(ptr);
1318 }
1319
1320 template <int LoadMode, typename PacketType>
1321 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(Index index) const {
1322 return ploadt<PacketType, LoadMode>(m_data + index * m_innerStride.value());
1323 }
1324
1325 template <int StoreMode, typename PacketType>
1326 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writePacket(Index row, Index col, const PacketType& x) {
1327 PointerType ptr = m_data + row * rowStride() + col * colStride();
1328 pstoret<Scalar, PacketType, StoreMode>(ptr, x);
1329 }
1330
1331 template <int StoreMode, typename PacketType>
1332 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writePacket(Index index, const PacketType& x) {
1333 pstoret<Scalar, PacketType, StoreMode>(m_data + index * m_innerStride.value(), x);
1334 }
1335
1336 template <int LoadMode, typename PacketType>
1337 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetSegment(Index row, Index col, Index begin, Index count) const {
1338 PointerType ptr = m_data + row * rowStride() + col * colStride();
1339 return ploadtSegment<PacketType, LoadMode>(ptr, begin, count);
1340 }
1341
1342 template <int LoadMode, typename PacketType>
1343 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetSegment(Index index, Index begin, Index count) const {
1344 return ploadtSegment<PacketType, LoadMode>(m_data + index * m_innerStride.value(), begin, count);
1345 }
1346
1347 template <int StoreMode, typename PacketType>
1348 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writePacketSegment(Index row, Index col, const PacketType& x, Index begin,
1349 Index count) {
1350 PointerType ptr = m_data + row * rowStride() + col * colStride();
1351 pstoretSegment<Scalar, PacketType, StoreMode>(ptr, x, begin, count);
1352 }
1353
1354 template <int StoreMode, typename PacketType>
1355 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writePacketSegment(Index index, const PacketType& x, Index begin,
1356 Index count) {
1357 pstoretSegment<Scalar, PacketType, StoreMode>(m_data + index * m_innerStride.value(), x, begin, count);
1358 }
1359
1360 protected:
1361 EIGEN_DEVICE_FUNC constexpr Index rowStride() const noexcept {
1362 return XprType::IsRowMajor ? m_outerStride.value() : m_innerStride.value();
1363 }
1364 EIGEN_DEVICE_FUNC constexpr Index colStride() const noexcept {
1365 return XprType::IsRowMajor ? m_innerStride.value() : m_outerStride.value();
1366 }
1367
1368 PointerType m_data;
1369 const variable_if_dynamic<Index, XprType::InnerStrideAtCompileTime> m_innerStride;
1370 const variable_if_dynamic<Index, XprType::OuterStrideAtCompileTime> m_outerStride;
1371};
1372
1373template <typename PlainObjectType, int MapOptions, typename StrideType>
1374struct evaluator<Map<PlainObjectType, MapOptions, StrideType>>
1375 : public mapbase_evaluator<Map<PlainObjectType, MapOptions, StrideType>, PlainObjectType> {
1376 using XprType = Map<PlainObjectType, MapOptions, StrideType>;
1377 using Scalar = typename XprType::Scalar;
1378 // TODO: should check for smaller packet types once we can handle multi-sized packet types
1379 using PacketScalar = typename packet_traits<Scalar>::type;
1380
1381 enum {
1382 InnerStrideAtCompileTime = StrideType::InnerStrideAtCompileTime == 0
1383 ? int(PlainObjectType::InnerStrideAtCompileTime)
1384 : int(StrideType::InnerStrideAtCompileTime),
1385 OuterStrideAtCompileTime = StrideType::OuterStrideAtCompileTime == 0
1386 ? int(PlainObjectType::OuterStrideAtCompileTime)
1387 : int(StrideType::OuterStrideAtCompileTime),
1388 HasNoInnerStride = InnerStrideAtCompileTime == 1,
1389 HasNoOuterStride = StrideType::OuterStrideAtCompileTime == 0,
1390 HasNoStride = HasNoInnerStride && HasNoOuterStride,
1391 IsDynamicSize = PlainObjectType::SizeAtCompileTime == Dynamic,
1392
1393 PacketAccessMask = bool(HasNoInnerStride) ? ~int(0) : ~int(PacketAccessBit),
1394 LinearAccessMask =
1395 bool(HasNoStride) || bool(PlainObjectType::IsVectorAtCompileTime) ? ~int(0) : ~int(LinearAccessBit),
1396 Flags = int(evaluator<PlainObjectType>::Flags) & (LinearAccessMask & PacketAccessMask),
1397
1398 Alignment = int(MapOptions) & int(AlignedMask)
1399 };
1400
1401 EIGEN_DEVICE_FUNC constexpr explicit evaluator(const XprType& map)
1402 : mapbase_evaluator<XprType, PlainObjectType>(map) {}
1403};
1404
1405// -------------------- Ref --------------------
1406
1407template <typename PlainObjectType, int RefOptions, typename StrideType>
1408struct evaluator<Ref<PlainObjectType, RefOptions, StrideType>>
1409 : public mapbase_evaluator<Ref<PlainObjectType, RefOptions, StrideType>, PlainObjectType> {
1410 using XprType = Ref<PlainObjectType, RefOptions, StrideType>;
1411
1412 enum {
1413 Flags = evaluator<Map<PlainObjectType, RefOptions, StrideType>>::Flags,
1414 Alignment = evaluator<Map<PlainObjectType, RefOptions, StrideType>>::Alignment
1415 };
1416
1417 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE explicit evaluator(const XprType& ref)
1418 : mapbase_evaluator<XprType, PlainObjectType>(ref) {}
1419};
1420
1421// -------------------- Block --------------------
1422
1423template <typename ArgType, int BlockRows, int BlockCols, bool InnerPanel,
1424 bool HasDirectAccess = has_direct_access<ArgType>::value && bool(evaluator<ArgType>::Flags & DirectAccessBit)>
1425struct block_evaluator;
1426
1427template <typename ArgType, int BlockRows, int BlockCols, bool InnerPanel>
1428struct evaluator<Block<ArgType, BlockRows, BlockCols, InnerPanel>>
1429 : block_evaluator<ArgType, BlockRows, BlockCols, InnerPanel> {
1430 using XprType = Block<ArgType, BlockRows, BlockCols, InnerPanel>;
1431 using Scalar = typename XprType::Scalar;
1432 // TODO: should check for smaller packet types once we can handle multi-sized packet types
1433 using PacketScalar = typename packet_traits<Scalar>::type;
1434
1435 enum {
1436 CoeffReadCost = evaluator<ArgType>::CoeffReadCost,
1437
1438 RowsAtCompileTime = traits<XprType>::RowsAtCompileTime,
1439 ColsAtCompileTime = traits<XprType>::ColsAtCompileTime,
1440 MaxRowsAtCompileTime = traits<XprType>::MaxRowsAtCompileTime,
1441 MaxColsAtCompileTime = traits<XprType>::MaxColsAtCompileTime,
1442
1443 ArgTypeIsRowMajor = (int(evaluator<ArgType>::Flags) & RowMajorBit) != 0,
1444 IsRowMajor = (MaxRowsAtCompileTime == 1 && MaxColsAtCompileTime != 1) ? 1
1445 : (MaxColsAtCompileTime == 1 && MaxRowsAtCompileTime != 1) ? 0
1446 : ArgTypeIsRowMajor,
1447 HasSameStorageOrderAsArgType = (IsRowMajor == ArgTypeIsRowMajor),
1448 InnerSize = IsRowMajor ? int(ColsAtCompileTime) : int(RowsAtCompileTime),
1449 InnerStrideAtCompileTime = HasSameStorageOrderAsArgType ? int(inner_stride_at_compile_time<ArgType>::value)
1450 : int(outer_stride_at_compile_time<ArgType>::value),
1451 OuterStrideAtCompileTime = HasSameStorageOrderAsArgType ? int(outer_stride_at_compile_time<ArgType>::value)
1452 : int(inner_stride_at_compile_time<ArgType>::value),
1453 // Direct-access blocks use mapbase_evaluator's contiguous loads, not the parent's packet method.
1454 MaskPacketAccessBit = (InnerStrideAtCompileTime == 1 ||
1455 (!(evaluator<ArgType>::Flags & DirectAccessBit) && HasSameStorageOrderAsArgType))
1457 : 0,
1458
1459 FlagsLinearAccessBit = (RowsAtCompileTime == 1 || ColsAtCompileTime == 1 ||
1460 (InnerPanel && (evaluator<ArgType>::Flags & LinearAccessBit)))
1462 : 0,
1463 FlagsRowMajorBit = XprType::Flags & RowMajorBit,
1464 Flags0 = evaluator<ArgType>::Flags & ((HereditaryBits & ~RowMajorBit) | DirectAccessBit | MaskPacketAccessBit),
1465 Flags = Flags0 | FlagsLinearAccessBit | FlagsRowMajorBit,
1466
1467 PacketAlignment = unpacket_traits<PacketScalar>::alignment,
1468 Alignment0 = (InnerPanel && (OuterStrideAtCompileTime != Dynamic) && (OuterStrideAtCompileTime != 0) &&
1469 (((OuterStrideAtCompileTime * int(sizeof(Scalar))) % int(PacketAlignment)) == 0))
1470 ? int(PacketAlignment)
1471 : 0,
1472 Alignment = plain_enum_min(evaluator<ArgType>::Alignment, Alignment0)
1473 };
1474 using block_evaluator_type = block_evaluator<ArgType, BlockRows, BlockCols, InnerPanel>;
1475 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE explicit evaluator(const XprType& block)
1476 : block_evaluator_type(block) {
1477 EIGEN_INTERNAL_CHECK_COST_VALUE(CoeffReadCost);
1478 }
1479};
1480
1481// no direct-access => dispatch to a unary evaluator
1482template <typename ArgType, int BlockRows, int BlockCols, bool InnerPanel>
1483struct block_evaluator<ArgType, BlockRows, BlockCols, InnerPanel, /*HasDirectAccess*/ false>
1484 : unary_evaluator<Block<ArgType, BlockRows, BlockCols, InnerPanel>> {
1485 using XprType = Block<ArgType, BlockRows, BlockCols, InnerPanel>;
1486
1487 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE explicit block_evaluator(const XprType& block)
1488 : unary_evaluator<XprType>(block) {}
1489};
1490
1491template <typename ArgType, int BlockRows, int BlockCols, bool InnerPanel>
1492struct unary_evaluator<Block<ArgType, BlockRows, BlockCols, InnerPanel>, IndexBased>
1493 : evaluator_base<Block<ArgType, BlockRows, BlockCols, InnerPanel>> {
1494 using XprType = Block<ArgType, BlockRows, BlockCols, InnerPanel>;
1495
1496 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE explicit unary_evaluator(const XprType& block)
1497 : m_argImpl(block.nestedExpression()),
1498 m_startRow(block.startRow()),
1499 m_startCol(block.startCol()),
1500 m_linear_offset(ForwardLinearAccess
1501 ? (ArgType::IsRowMajor
1502 ? block.startRow() * block.nestedExpression().cols() + block.startCol()
1503 : block.startCol() * block.nestedExpression().rows() + block.startRow())
1504 : 0) {}
1505
1506 using Scalar = typename XprType::Scalar;
1507 using CoeffReturnType = typename XprType::CoeffReturnType;
1508
1509 enum {
1510 RowsAtCompileTime = XprType::RowsAtCompileTime,
1511 ForwardLinearAccess = (InnerPanel || int(XprType::IsRowMajor) == int(ArgType::IsRowMajor)) &&
1512 bool(evaluator<ArgType>::Flags & LinearAccessBit)
1513 };
1514
1515 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const {
1516 return m_argImpl.coeff(m_startRow.value() + row, m_startCol.value() + col);
1517 }
1518
1519 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const {
1520 return linear_coeff_impl(index, bool_constant<ForwardLinearAccess>());
1521 }
1522
1523 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col) {
1524 return m_argImpl.coeffRef(m_startRow.value() + row, m_startCol.value() + col);
1525 }
1526
1527 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) {
1528 return linear_coeffRef_impl(index, bool_constant<ForwardLinearAccess>());
1529 }
1530
1531 template <int LoadMode, typename PacketType>
1532 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const {
1533 return m_argImpl.template packet<LoadMode, PacketType>(m_startRow.value() + row, m_startCol.value() + col);
1534 }
1535
1536 template <int LoadMode, typename PacketType>
1537 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(Index index) const {
1538 EIGEN_IF_CONSTEXPR (ForwardLinearAccess)
1539 return m_argImpl.template packet<LoadMode, PacketType>(m_linear_offset.value() + index);
1540 else
1541 return packet<LoadMode, PacketType>(RowsAtCompileTime == 1 ? 0 : index, RowsAtCompileTime == 1 ? index : 0);
1542 }
1543
1544 template <int StoreMode, typename PacketType>
1545 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writePacket(Index row, Index col, const PacketType& x) {
1546 return m_argImpl.template writePacket<StoreMode, PacketType>(m_startRow.value() + row, m_startCol.value() + col, x);
1547 }
1548
1549 template <int StoreMode, typename PacketType>
1550 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writePacket(Index index, const PacketType& x) {
1551 EIGEN_IF_CONSTEXPR (ForwardLinearAccess)
1552 return m_argImpl.template writePacket<StoreMode, PacketType>(m_linear_offset.value() + index, x);
1553 else
1554 return writePacket<StoreMode, PacketType>(RowsAtCompileTime == 1 ? 0 : index, RowsAtCompileTime == 1 ? index : 0,
1555 x);
1556 }
1557
1558 template <int LoadMode, typename PacketType>
1559 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetSegment(Index row, Index col, Index begin, Index count) const {
1560 return m_argImpl.template packetSegment<LoadMode, PacketType>(m_startRow.value() + row, m_startCol.value() + col,
1561 begin, count);
1562 }
1563
1564 template <int LoadMode, typename PacketType>
1565 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetSegment(Index index, Index begin, Index count) const {
1566 EIGEN_IF_CONSTEXPR (ForwardLinearAccess)
1567 return m_argImpl.template packetSegment<LoadMode, PacketType>(m_linear_offset.value() + index, begin, count);
1568 else
1569 return packetSegment<LoadMode, PacketType>(RowsAtCompileTime == 1 ? 0 : index, RowsAtCompileTime == 1 ? index : 0,
1570 begin, count);
1571 }
1572
1573 template <int StoreMode, typename PacketType>
1574 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writePacketSegment(Index row, Index col, const PacketType& x, Index begin,
1575 Index count) {
1576 return m_argImpl.template writePacketSegment<StoreMode, PacketType>(m_startRow.value() + row,
1577 m_startCol.value() + col, x, begin, count);
1578 }
1579
1580 template <int StoreMode, typename PacketType>
1581 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writePacketSegment(Index index, const PacketType& x, Index begin,
1582 Index count) {
1583 EIGEN_IF_CONSTEXPR (ForwardLinearAccess)
1584 return m_argImpl.template writePacketSegment<StoreMode, PacketType>(m_linear_offset.value() + index, x, begin,
1585 count);
1586 else
1587 return writePacketSegment<StoreMode, PacketType>(RowsAtCompileTime == 1 ? 0 : index,
1588 RowsAtCompileTime == 1 ? index : 0, x, begin, count);
1589 }
1590
1591 protected:
1592 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE CoeffReturnType
1593 linear_coeff_impl(Index index, std::true_type /* ForwardLinearAccess */) const {
1594 return m_argImpl.coeff(m_linear_offset.value() + index);
1595 }
1596 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE CoeffReturnType
1597 linear_coeff_impl(Index index, std::false_type /* not ForwardLinearAccess */) const {
1598 return coeff(RowsAtCompileTime == 1 ? 0 : index, RowsAtCompileTime == 1 ? index : 0);
1599 }
1600
1601 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar& linear_coeffRef_impl(
1602 Index index, std::true_type /* ForwardLinearAccess */) {
1603 return m_argImpl.coeffRef(m_linear_offset.value() + index);
1604 }
1605 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar& linear_coeffRef_impl(
1606 Index index, std::false_type /* not ForwardLinearAccess */) {
1607 return coeffRef(RowsAtCompileTime == 1 ? 0 : index, RowsAtCompileTime == 1 ? index : 0);
1608 }
1609
1610 evaluator<ArgType> m_argImpl;
1611 const variable_if_dynamic<Index, (ArgType::RowsAtCompileTime == 1 && BlockRows == 1) ? 0 : Dynamic> m_startRow;
1612 const variable_if_dynamic<Index, (ArgType::ColsAtCompileTime == 1 && BlockCols == 1) ? 0 : Dynamic> m_startCol;
1613 const variable_if_dynamic<Index, ForwardLinearAccess ? Dynamic : 0> m_linear_offset;
1614};
1615
1616// TODO: This evaluator does not actually use the child evaluator;
1617// all action is via the data() as returned by the Block expression.
1618
1619template <typename ArgType, int BlockRows, int BlockCols, bool InnerPanel>
1620struct block_evaluator<ArgType, BlockRows, BlockCols, InnerPanel, /* HasDirectAccess */ true>
1621 : mapbase_evaluator<Block<ArgType, BlockRows, BlockCols, InnerPanel>,
1622 typename Block<ArgType, BlockRows, BlockCols, InnerPanel>::PlainObject> {
1623 using XprType = Block<ArgType, BlockRows, BlockCols, InnerPanel>;
1624 using Scalar = typename XprType::Scalar;
1625
1626 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE explicit block_evaluator(const XprType& block)
1627 : mapbase_evaluator<XprType, typename XprType::PlainObject>(block) {
1628 eigen_internal_assert((internal::is_constant_evaluated() ||
1629 (std::uintptr_t(block.data()) % plain_enum_max(1, evaluator<XprType>::Alignment)) == 0) &&
1630 "data is not aligned");
1631 }
1632};
1633
1634// -------------------- Replicate --------------------
1635
1636template <typename ArgType, int RowFactor, int ColFactor>
1637struct unary_evaluator<Replicate<ArgType, RowFactor, ColFactor>>
1638 : evaluator_base<Replicate<ArgType, RowFactor, ColFactor>> {
1639 using XprType = Replicate<ArgType, RowFactor, ColFactor>;
1640 using CoeffReturnType = typename XprType::CoeffReturnType;
1641 enum { Factor = (RowFactor == Dynamic || ColFactor == Dynamic) ? Dynamic : RowFactor * ColFactor };
1642 using ArgTypeNested = typename nested_eval<ArgType, Factor>::type;
1643 using ArgTypeNestedCleaned = remove_all_t<ArgTypeNested>;
1644
1645 enum {
1646 CoeffReadCost = evaluator<ArgTypeNestedCleaned>::CoeffReadCost,
1647 LinearAccessMask = XprType::IsVectorAtCompileTime ? LinearAccessBit : 0,
1648 // The packet paths below load from a single copy of the nested expression, so they are valid
1649 // exactly when a packet cannot cross a replication boundary: the inner (storage-order)
1650 // direction must not be replicated. The outer coordinate's modulo then maps any packet into
1651 // the nested expression unchanged. When the inner direction is replicated, serving a packet
1652 // would need a broadcast (or a wrap-around load) the methods below do not perform.
1653 InnerFactor = traits<XprType>::IsRowMajor ? ColFactor : RowFactor,
1654 MaskPacketAccessBit = InnerFactor == 1 ? PacketAccessBit : 0,
1655 Flags = (evaluator<ArgTypeNestedCleaned>::Flags & (HereditaryBits | LinearAccessMask | MaskPacketAccessBit) &
1656 ~RowMajorBit) |
1657 (traits<XprType>::Flags & RowMajorBit),
1658
1659 Alignment = evaluator<ArgTypeNestedCleaned>::Alignment
1660 };
1661
1662 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE explicit unary_evaluator(const XprType& replicate)
1663 : m_arg(replicate.nestedExpression()),
1664 m_argImpl(m_arg),
1665 m_rows(replicate.nestedExpression().rows()),
1666 m_cols(replicate.nestedExpression().cols()) {}
1667
1668 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const {
1669 // try to avoid using modulo; this is a pure optimization strategy
1670 const Index actual_row = traits<XprType>::RowsAtCompileTime == 1 ? 0 : RowFactor == 1 ? row : row % m_rows.value();
1671 const Index actual_col = traits<XprType>::ColsAtCompileTime == 1 ? 0 : ColFactor == 1 ? col : col % m_cols.value();
1672
1673 return m_argImpl.coeff(actual_row, actual_col);
1674 }
1675
1676 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const {
1677 // try to avoid using modulo; this is a pure optimization strategy
1678 const Index actual_index = traits<XprType>::RowsAtCompileTime == 1
1679 ? (ColFactor == 1 ? index : index % m_cols.value())
1680 : (RowFactor == 1 ? index : index % m_rows.value());
1681
1682 return m_argImpl.coeff(actual_index);
1683 }
1684
1685 template <int LoadMode, typename PacketType>
1686 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const {
1687 const Index actual_row = traits<XprType>::RowsAtCompileTime == 1 ? 0 : RowFactor == 1 ? row : row % m_rows.value();
1688 const Index actual_col = traits<XprType>::ColsAtCompileTime == 1 ? 0 : ColFactor == 1 ? col : col % m_cols.value();
1689
1690 return m_argImpl.template packet<LoadMode, PacketType>(actual_row, actual_col);
1691 }
1692
1693 template <int LoadMode, typename PacketType>
1694 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(Index index) const {
1695 const Index actual_index = traits<XprType>::RowsAtCompileTime == 1
1696 ? (ColFactor == 1 ? index : index % m_cols.value())
1697 : (RowFactor == 1 ? index : index % m_rows.value());
1698
1699 return m_argImpl.template packet<LoadMode, PacketType>(actual_index);
1700 }
1701
1702 template <int LoadMode, typename PacketType>
1703 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetSegment(Index row, Index col, Index begin, Index count) const {
1704 const Index actual_row = traits<XprType>::RowsAtCompileTime == 1 ? 0 : RowFactor == 1 ? row : row % m_rows.value();
1705 const Index actual_col = traits<XprType>::ColsAtCompileTime == 1 ? 0 : ColFactor == 1 ? col : col % m_cols.value();
1706
1707 return m_argImpl.template packetSegment<LoadMode, PacketType>(actual_row, actual_col, begin, count);
1708 }
1709
1710 template <int LoadMode, typename PacketType>
1711 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetSegment(Index index, Index begin, Index count) const {
1712 const Index actual_index = traits<XprType>::RowsAtCompileTime == 1
1713 ? (ColFactor == 1 ? index : index % m_cols.value())
1714 : (RowFactor == 1 ? index : index % m_rows.value());
1715
1716 return m_argImpl.template packetSegment<LoadMode, PacketType>(actual_index, begin, count);
1717 }
1718
1719 protected:
1720 ArgTypeNested m_arg;
1721 evaluator<ArgTypeNestedCleaned> m_argImpl;
1722 const variable_if_dynamic<Index, ArgType::RowsAtCompileTime> m_rows;
1723 const variable_if_dynamic<Index, ArgType::ColsAtCompileTime> m_cols;
1724};
1725
1726// -------------------- MatrixWrapper and ArrayWrapper --------------------
1727//
1728// evaluator_wrapper_base<T> is a common base class for the
1729// MatrixWrapper and ArrayWrapper evaluators.
1730
1731template <typename XprType>
1732struct evaluator_wrapper_base : evaluator_base<XprType> {
1733 using ArgType = remove_all_t<typename XprType::NestedExpressionType>;
1734 enum {
1735 CoeffReadCost = evaluator<ArgType>::CoeffReadCost,
1736 Flags = evaluator<ArgType>::Flags,
1737 Alignment = evaluator<ArgType>::Alignment
1738 };
1739
1740 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE explicit evaluator_wrapper_base(const ArgType& arg) : m_argImpl(arg) {}
1741
1742 using Scalar = typename ArgType::Scalar;
1743 using CoeffReturnType = typename ArgType::CoeffReturnType;
1744
1745 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const {
1746 return m_argImpl.coeff(row, col);
1747 }
1748
1749 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const {
1750 return m_argImpl.coeff(index);
1751 }
1752
1753 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col) {
1754 return m_argImpl.coeffRef(row, col);
1755 }
1756
1757 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) { return m_argImpl.coeffRef(index); }
1758
1759 template <int LoadMode, typename PacketType>
1760 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const {
1761 return m_argImpl.template packet<LoadMode, PacketType>(row, col);
1762 }
1763
1764 template <int LoadMode, typename PacketType>
1765 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(Index index) const {
1766 return m_argImpl.template packet<LoadMode, PacketType>(index);
1767 }
1768
1769 template <int StoreMode, typename PacketType>
1770 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writePacket(Index row, Index col, const PacketType& x) {
1771 m_argImpl.template writePacket<StoreMode>(row, col, x);
1772 }
1773
1774 template <int StoreMode, typename PacketType>
1775 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writePacket(Index index, const PacketType& x) {
1776 m_argImpl.template writePacket<StoreMode>(index, x);
1777 }
1778
1779 template <int LoadMode, typename PacketType>
1780 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetSegment(Index row, Index col, Index begin, Index count) const {
1781 return m_argImpl.template packetSegment<LoadMode, PacketType>(row, col, begin, count);
1782 }
1783
1784 template <int LoadMode, typename PacketType>
1785 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetSegment(Index index, Index begin, Index count) const {
1786 return m_argImpl.template packetSegment<LoadMode, PacketType>(index, begin, count);
1787 }
1788
1789 template <int StoreMode, typename PacketType>
1790 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writePacketSegment(Index row, Index col, const PacketType& x, Index begin,
1791 Index count) {
1792 m_argImpl.template writePacketSegment<StoreMode>(row, col, x, begin, count);
1793 }
1794
1795 template <int StoreMode, typename PacketType>
1796 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writePacketSegment(Index index, const PacketType& x, Index begin,
1797 Index count) {
1798 m_argImpl.template writePacketSegment<StoreMode>(index, x, begin, count);
1799 }
1800
1801 protected:
1802 evaluator<ArgType> m_argImpl;
1803};
1804
1805template <typename TArgType>
1806struct unary_evaluator<MatrixWrapper<TArgType>> : evaluator_wrapper_base<MatrixWrapper<TArgType>> {
1807 using XprType = MatrixWrapper<TArgType>;
1808
1809 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE explicit unary_evaluator(const XprType& wrapper)
1810 : evaluator_wrapper_base<MatrixWrapper<TArgType>>(wrapper.nestedExpression()) {}
1811};
1812
1813template <typename TArgType>
1814struct unary_evaluator<ArrayWrapper<TArgType>> : evaluator_wrapper_base<ArrayWrapper<TArgType>> {
1815 using XprType = ArrayWrapper<TArgType>;
1816
1817 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE explicit unary_evaluator(const XprType& wrapper)
1818 : evaluator_wrapper_base<ArrayWrapper<TArgType>>(wrapper.nestedExpression()) {}
1819};
1820
1821// -------------------- Reverse --------------------
1822
1823// defined in Reverse.h:
1824template <typename PacketType, bool ReversePacket>
1825struct reverse_packet_cond;
1826
1827template <typename ArgType, int Direction>
1828struct unary_evaluator<Reverse<ArgType, Direction>> : evaluator_base<Reverse<ArgType, Direction>> {
1829 using XprType = Reverse<ArgType, Direction>;
1830 using Scalar = typename XprType::Scalar;
1831 using CoeffReturnType = typename XprType::CoeffReturnType;
1832
1833 enum {
1834 IsRowMajor = XprType::IsRowMajor,
1835 IsColMajor = !IsRowMajor,
1836 ReverseRow = (Direction == Vertical) || (Direction == BothDirections),
1837 ReverseCol = (Direction == Horizontal) || (Direction == BothDirections),
1838 ReversePacket = (Direction == BothDirections) || ((Direction == Vertical) && IsColMajor) ||
1839 ((Direction == Horizontal) && IsRowMajor),
1840
1841 CoeffReadCost = evaluator<ArgType>::CoeffReadCost,
1842
1843 // let's enable LinearAccess only with vectorization because of the product overhead
1844 // FIXME: consider enabling DirectAccess with negative strides.
1845 Flags0 = evaluator<ArgType>::Flags,
1846 LinearAccess =
1847 ((Direction == BothDirections) && (int(Flags0) & PacketAccessBit)) ||
1848 ((ReverseRow && XprType::ColsAtCompileTime == 1) || (ReverseCol && XprType::RowsAtCompileTime == 1))
1849 ? LinearAccessBit
1850 : 0,
1851
1852 Flags = int(Flags0) & (HereditaryBits | PacketAccessBit | LinearAccess),
1853
1854 Alignment = 0 // FIXME: in some rare cases, Alignment could be preserved.
1855 };
1856
1857 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE explicit unary_evaluator(const XprType& reverse)
1858 : m_argImpl(reverse.nestedExpression()),
1859 m_rows(ReverseRow ? reverse.nestedExpression().rows() : 1),
1860 m_cols(ReverseCol ? reverse.nestedExpression().cols() : 1) {}
1861
1862 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index col) const {
1863 return m_argImpl.coeff(ReverseRow ? m_rows.value() - row - 1 : row, ReverseCol ? m_cols.value() - col - 1 : col);
1864 }
1865
1866 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const {
1867 return m_argImpl.coeff(m_rows.value() * m_cols.value() - index - 1);
1868 }
1869
1870 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col) {
1871 return m_argImpl.coeffRef(ReverseRow ? m_rows.value() - row - 1 : row, ReverseCol ? m_cols.value() - col - 1 : col);
1872 }
1873
1874 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) {
1875 return m_argImpl.coeffRef(m_rows.value() * m_cols.value() - index - 1);
1876 }
1877
1878 template <int LoadMode, typename PacketType>
1879 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(Index row, Index col) const {
1880 static constexpr int PacketSize = unpacket_traits<PacketType>::size;
1881 static constexpr int OffsetRow = ReverseRow && IsColMajor ? PacketSize : 1;
1882 static constexpr int OffsetCol = ReverseCol && IsRowMajor ? PacketSize : 1;
1883 using reverse_packet = reverse_packet_cond<PacketType, ReversePacket>;
1884
1885 Index actualRow = ReverseRow ? m_rows.value() - row - OffsetRow : row;
1886 Index actualCol = ReverseCol ? m_cols.value() - col - OffsetCol : col;
1887
1888 return reverse_packet::run(m_argImpl.template packet<LoadMode, PacketType>(actualRow, actualCol));
1889 }
1890
1891 template <int LoadMode, typename PacketType>
1892 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packet(Index index) const {
1893 static constexpr int PacketSize = unpacket_traits<PacketType>::size;
1894
1895 Index actualIndex = m_rows.value() * m_cols.value() - index - PacketSize;
1896
1897 return preverse(m_argImpl.template packet<LoadMode, PacketType>(actualIndex));
1898 }
1899
1900 template <int LoadMode, typename PacketType>
1901 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writePacket(Index row, Index col, const PacketType& x) {
1902 static constexpr int PacketSize = unpacket_traits<PacketType>::size;
1903 static constexpr int OffsetRow = ReverseRow && IsColMajor ? PacketSize : 1;
1904 static constexpr int OffsetCol = ReverseCol && IsRowMajor ? PacketSize : 1;
1905 using reverse_packet = reverse_packet_cond<PacketType, ReversePacket>;
1906
1907 Index actualRow = ReverseRow ? m_rows.value() - row - OffsetRow : row;
1908 Index actualCol = ReverseCol ? m_cols.value() - col - OffsetCol : col;
1909
1910 m_argImpl.template writePacket<LoadMode>(actualRow, actualCol, reverse_packet::run(x));
1911 }
1912
1913 template <int LoadMode, typename PacketType>
1914 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writePacket(Index index, const PacketType& x) {
1915 static constexpr int PacketSize = unpacket_traits<PacketType>::size;
1916
1917 Index actualIndex = m_rows.value() * m_cols.value() - index - PacketSize;
1918
1919 m_argImpl.template writePacket<LoadMode>(actualIndex, preverse(x));
1920 }
1921
1922 template <int LoadMode, typename PacketType>
1923 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetSegment(Index row, Index col, Index begin, Index count) const {
1924 static constexpr int PacketSize = unpacket_traits<PacketType>::size;
1925 static constexpr int OffsetRow = ReverseRow && IsColMajor ? PacketSize : 1;
1926 static constexpr int OffsetCol = ReverseCol && IsRowMajor ? PacketSize : 1;
1927 using reverse_packet = reverse_packet_cond<PacketType, ReversePacket>;
1928
1929 Index actualRow = ReverseRow ? m_rows.value() - row - OffsetRow : row;
1930 Index actualCol = ReverseCol ? m_cols.value() - col - OffsetCol : col;
1931 Index actualBegin = ReversePacket ? (PacketSize - count - begin) : begin;
1932
1933 return reverse_packet::run(
1934 m_argImpl.template packetSegment<LoadMode, PacketType>(actualRow, actualCol, actualBegin, count));
1935 }
1936
1937 template <int LoadMode, typename PacketType>
1938 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE PacketType packetSegment(Index index, Index begin, Index count) const {
1939 static constexpr int PacketSize = unpacket_traits<PacketType>::size;
1940
1941 Index actualIndex = m_rows.value() * m_cols.value() - index - PacketSize;
1942 Index actualBegin = PacketSize - count - begin;
1943
1944 return preverse(m_argImpl.template packetSegment<LoadMode, PacketType>(actualIndex, actualBegin, count));
1945 }
1946
1947 template <int LoadMode, typename PacketType>
1948 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writePacketSegment(Index row, Index col, const PacketType& x, Index begin,
1949 Index count) {
1950 static constexpr int PacketSize = unpacket_traits<PacketType>::size;
1951 static constexpr int OffsetRow = ReverseRow && IsColMajor ? PacketSize : 1;
1952 static constexpr int OffsetCol = ReverseCol && IsRowMajor ? PacketSize : 1;
1953 using reverse_packet = reverse_packet_cond<PacketType, ReversePacket>;
1954
1955 Index actualRow = ReverseRow ? m_rows.value() - row - OffsetRow : row;
1956 Index actualCol = ReverseCol ? m_cols.value() - col - OffsetCol : col;
1957 Index actualBegin = ReversePacket ? (PacketSize - count - begin) : begin;
1958
1959 m_argImpl.template writePacketSegment<LoadMode>(actualRow, actualCol, reverse_packet::run(x), actualBegin, count);
1960 }
1961
1962 template <int LoadMode, typename PacketType>
1963 EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void writePacketSegment(Index index, const PacketType& x, Index begin,
1964 Index count) {
1965 static constexpr int PacketSize = unpacket_traits<PacketType>::size;
1966
1967 Index actualIndex = m_rows.value() * m_cols.value() - index - PacketSize;
1968 Index actualBegin = PacketSize - count - begin;
1969
1970 m_argImpl.template writePacketSegment<LoadMode>(actualIndex, preverse(x), actualBegin, count);
1971 }
1972
1973 protected:
1974 evaluator<ArgType> m_argImpl;
1975
1976 // If we do not reverse rows, then we do not need to know the number of rows; same for columns
1977 // Nonetheless, in this case it is important to set to 1 such that the coeff(index) method works fine for vectors.
1978 const variable_if_dynamic<Index, ReverseRow ? ArgType::RowsAtCompileTime : 1> m_rows;
1979 const variable_if_dynamic<Index, ReverseCol ? ArgType::ColsAtCompileTime : 1> m_cols;
1980};
1981
1982// -------------------- Diagonal --------------------
1983
1984template <typename ArgType, int DiagIndex>
1985struct evaluator<Diagonal<ArgType, DiagIndex>> : evaluator_base<Diagonal<ArgType, DiagIndex>> {
1986 using XprType = Diagonal<ArgType, DiagIndex>;
1987
1988 enum {
1989 CoeffReadCost = evaluator<ArgType>::CoeffReadCost,
1990
1991 Flags = static_cast<unsigned int>(evaluator<ArgType>::Flags & (HereditaryBits | DirectAccessBit) & ~RowMajorBit) |
1992 LinearAccessBit,
1993
1994 Alignment = 0
1995 };
1996
1997 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE explicit evaluator(const XprType& diagonal)
1998 : m_argImpl(diagonal.nestedExpression()), m_index(diagonal.index()) {}
1999
2000 using Scalar = typename XprType::Scalar;
2001 using CoeffReturnType = typename XprType::CoeffReturnType;
2002
2003 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE CoeffReturnType coeff(Index row, Index) const {
2004 return m_argImpl.coeff(row + rowOffset(), row + colOffset());
2005 }
2006
2007 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE CoeffReturnType coeff(Index index) const {
2008 return m_argImpl.coeff(index + rowOffset(), index + colOffset());
2009 }
2010
2011 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index) {
2012 return m_argImpl.coeffRef(row + rowOffset(), row + colOffset());
2013 }
2014
2015 EIGEN_DEVICE_FUNC constexpr EIGEN_STRONG_INLINE Scalar& coeffRef(Index index) {
2016 return m_argImpl.coeffRef(index + rowOffset(), index + colOffset());
2017 }
2018
2019 protected:
2020 evaluator<ArgType> m_argImpl;
2021 const variable_if_dynamicindex<Index, XprType::DiagIndex> m_index;
2022
2023 private:
2024 EIGEN_DEVICE_FUNC constexpr Index rowOffset() const { return m_index.value() > 0 ? 0 : -m_index.value(); }
2025 EIGEN_DEVICE_FUNC constexpr Index colOffset() const { return m_index.value() > 0 ? m_index.value() : 0; }
2026};
2027
2028//----------------------------------------------------------------------
2029// deprecated code
2030//----------------------------------------------------------------------
2031
2032// -------------------- EvalToTemp --------------------
2033
2034// expression class for evaluating nested expression to a temporary
2035
2036template <typename ArgType>
2037class EvalToTemp;
2038
2039template <typename ArgType>
2040struct traits<EvalToTemp<ArgType>> : public traits<ArgType> {};
2041
2042template <typename ArgType>
2043class EvalToTemp : public dense_xpr_base<EvalToTemp<ArgType>>::type {
2044 public:
2045 using Base = typename dense_xpr_base<EvalToTemp>::type;
2046 EIGEN_GENERIC_PUBLIC_INTERFACE(EvalToTemp)
2047
2048 explicit EvalToTemp(const ArgType& arg) : m_arg(arg) {}
2049
2050 const ArgType& arg() const { return m_arg; }
2051
2052 constexpr Index rows() const noexcept { return m_arg.rows(); }
2053
2054 constexpr Index cols() const noexcept { return m_arg.cols(); }
2055
2056 private:
2057 const ArgType& m_arg;
2058};
2059
2060template <typename ArgType>
2061struct evaluator<EvalToTemp<ArgType>> : public evaluator<typename ArgType::PlainObject> {
2062 using XprType = EvalToTemp<ArgType>;
2063 using PlainObject = typename ArgType::PlainObject;
2064 using Base = evaluator<PlainObject>;
2065
2066 EIGEN_DEVICE_FUNC constexpr explicit evaluator(const XprType& xpr) : m_result(xpr.arg()) {
2067 internal::construct_at<Base>(this, m_result);
2068 }
2069
2070 // This constructor is used when nesting an EvalTo evaluator in another evaluator
2071 EIGEN_DEVICE_FUNC constexpr evaluator(const ArgType& arg) : m_result(arg) {
2072 internal::construct_at<Base>(this, m_result);
2073 }
2074
2075 protected:
2076 PlainObject m_result;
2077};
2078
2079} // namespace internal
2080
2081} // end namespace Eigen
2082
2083#endif // EIGEN_COREEVALUATORS_H
@ BothDirections
Definition Constants.h:273
@ Horizontal
Definition Constants.h:270
@ Vertical
Definition Constants.h:267
constexpr unsigned int ActualPacketAccessBit
Definition Constants.h:109
constexpr unsigned int PacketAccessBit
Definition Constants.h:98
constexpr unsigned int DirectAccessBit
Definition Constants.h:160
constexpr unsigned int EvalBeforeNestingBit
Definition Constants.h:75
constexpr unsigned int LinearAccessBit
Definition Constants.h:134
constexpr unsigned int RowMajorBit
Definition Constants.h:71