1 | // This file is part of Eigen, a lightweight C++ template library |
2 | // for linear algebra. |
3 | // |
4 | // Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud@inria.fr> |
5 | // |
6 | // This Source Code Form is subject to the terms of the Mozilla |
7 | // Public License v. 2.0. If a copy of the MPL was not distributed |
8 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. |
9 | |
10 | #ifndef EIGEN_ASSIGNMENT_FUNCTORS_H |
11 | #define EIGEN_ASSIGNMENT_FUNCTORS_H |
12 | |
13 | namespace Eigen { |
14 | |
15 | namespace internal { |
16 | |
17 | /** \internal |
18 | * \brief Template functor for scalar/packet assignment |
19 | * |
20 | */ |
21 | template<typename DstScalar,typename SrcScalar> struct assign_op { |
22 | |
23 | EIGEN_EMPTY_STRUCT_CTOR(assign_op) |
24 | EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeff(DstScalar& a, const SrcScalar& b) const { a = b; } |
25 | |
26 | template<int Alignment, typename Packet> |
27 | EIGEN_STRONG_INLINE void assignPacket(DstScalar* a, const Packet& b) const |
28 | { internal::pstoret<DstScalar,Packet,Alignment>(a,b); } |
29 | }; |
30 | |
31 | // Empty overload for void type (used by PermutationMatrix) |
32 | template<typename DstScalar> struct assign_op<DstScalar,void> {}; |
33 | |
34 | template<typename DstScalar,typename SrcScalar> |
35 | struct functor_traits<assign_op<DstScalar,SrcScalar> > { |
36 | enum { |
37 | Cost = NumTraits<DstScalar>::ReadCost, |
38 | PacketAccess = is_same<DstScalar,SrcScalar>::value && packet_traits<DstScalar>::Vectorizable && packet_traits<SrcScalar>::Vectorizable |
39 | }; |
40 | }; |
41 | |
42 | /** \internal |
43 | * \brief Template functor for scalar/packet assignment with addition |
44 | * |
45 | */ |
46 | template<typename DstScalar,typename SrcScalar> struct add_assign_op { |
47 | |
48 | EIGEN_EMPTY_STRUCT_CTOR(add_assign_op) |
49 | EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeff(DstScalar& a, const SrcScalar& b) const { a += b; } |
50 | |
51 | template<int Alignment, typename Packet> |
52 | EIGEN_STRONG_INLINE void assignPacket(DstScalar* a, const Packet& b) const |
53 | { internal::pstoret<DstScalar,Packet,Alignment>(a,internal::padd(internal::ploadt<Packet,Alignment>(a),b)); } |
54 | }; |
55 | template<typename DstScalar,typename SrcScalar> |
56 | struct functor_traits<add_assign_op<DstScalar,SrcScalar> > { |
57 | enum { |
58 | Cost = NumTraits<DstScalar>::ReadCost + NumTraits<DstScalar>::AddCost, |
59 | PacketAccess = is_same<DstScalar,SrcScalar>::value && packet_traits<DstScalar>::HasAdd |
60 | }; |
61 | }; |
62 | |
63 | /** \internal |
64 | * \brief Template functor for scalar/packet assignment with subtraction |
65 | * |
66 | */ |
67 | template<typename DstScalar,typename SrcScalar> struct sub_assign_op { |
68 | |
69 | EIGEN_EMPTY_STRUCT_CTOR(sub_assign_op) |
70 | EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeff(DstScalar& a, const SrcScalar& b) const { a -= b; } |
71 | |
72 | template<int Alignment, typename Packet> |
73 | EIGEN_STRONG_INLINE void assignPacket(DstScalar* a, const Packet& b) const |
74 | { internal::pstoret<DstScalar,Packet,Alignment>(a,internal::psub(internal::ploadt<Packet,Alignment>(a),b)); } |
75 | }; |
76 | template<typename DstScalar,typename SrcScalar> |
77 | struct functor_traits<sub_assign_op<DstScalar,SrcScalar> > { |
78 | enum { |
79 | Cost = NumTraits<DstScalar>::ReadCost + NumTraits<DstScalar>::AddCost, |
80 | PacketAccess = is_same<DstScalar,SrcScalar>::value && packet_traits<DstScalar>::HasSub |
81 | }; |
82 | }; |
83 | |
84 | /** \internal |
85 | * \brief Template functor for scalar/packet assignment with multiplication |
86 | * |
87 | */ |
88 | template<typename DstScalar, typename SrcScalar=DstScalar> |
89 | struct mul_assign_op { |
90 | |
91 | EIGEN_EMPTY_STRUCT_CTOR(mul_assign_op) |
92 | EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeff(DstScalar& a, const SrcScalar& b) const { a *= b; } |
93 | |
94 | template<int Alignment, typename Packet> |
95 | EIGEN_STRONG_INLINE void assignPacket(DstScalar* a, const Packet& b) const |
96 | { internal::pstoret<DstScalar,Packet,Alignment>(a,internal::pmul(internal::ploadt<Packet,Alignment>(a),b)); } |
97 | }; |
98 | template<typename DstScalar, typename SrcScalar> |
99 | struct functor_traits<mul_assign_op<DstScalar,SrcScalar> > { |
100 | enum { |
101 | Cost = NumTraits<DstScalar>::ReadCost + NumTraits<DstScalar>::MulCost, |
102 | PacketAccess = is_same<DstScalar,SrcScalar>::value && packet_traits<DstScalar>::HasMul |
103 | }; |
104 | }; |
105 | |
106 | /** \internal |
107 | * \brief Template functor for scalar/packet assignment with diviving |
108 | * |
109 | */ |
110 | template<typename DstScalar, typename SrcScalar=DstScalar> struct div_assign_op { |
111 | |
112 | EIGEN_EMPTY_STRUCT_CTOR(div_assign_op) |
113 | EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeff(DstScalar& a, const SrcScalar& b) const { a /= b; } |
114 | |
115 | template<int Alignment, typename Packet> |
116 | EIGEN_STRONG_INLINE void assignPacket(DstScalar* a, const Packet& b) const |
117 | { internal::pstoret<DstScalar,Packet,Alignment>(a,internal::pdiv(internal::ploadt<Packet,Alignment>(a),b)); } |
118 | }; |
119 | template<typename DstScalar, typename SrcScalar> |
120 | struct functor_traits<div_assign_op<DstScalar,SrcScalar> > { |
121 | enum { |
122 | Cost = NumTraits<DstScalar>::ReadCost + NumTraits<DstScalar>::MulCost, |
123 | PacketAccess = is_same<DstScalar,SrcScalar>::value && packet_traits<DstScalar>::HasDiv |
124 | }; |
125 | }; |
126 | |
127 | /** \internal |
128 | * \brief Template functor for scalar/packet assignment with swapping |
129 | * |
130 | * It works as follow. For a non-vectorized evaluation loop, we have: |
131 | * for(i) func(A.coeffRef(i), B.coeff(i)); |
132 | * where B is a SwapWrapper expression. The trick is to make SwapWrapper::coeff behaves like a non-const coeffRef. |
133 | * Actually, SwapWrapper might not even be needed since even if B is a plain expression, since it has to be writable |
134 | * B.coeff already returns a const reference to the underlying scalar value. |
135 | * |
136 | * The case of a vectorized loop is more tricky: |
137 | * for(i,j) func.assignPacket<A_Align>(&A.coeffRef(i,j), B.packet<B_Align>(i,j)); |
138 | * Here, B must be a SwapWrapper whose packet function actually returns a proxy object holding a Scalar*, |
139 | * the actual alignment and Packet type. |
140 | * |
141 | */ |
142 | template<typename Scalar> struct swap_assign_op { |
143 | |
144 | EIGEN_EMPTY_STRUCT_CTOR(swap_assign_op) |
145 | EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE void assignCoeff(Scalar& a, const Scalar& b) const |
146 | { |
147 | #ifdef __CUDACC__ |
148 | // FIXME is there some kind of cuda::swap? |
149 | Scalar t=b; const_cast<Scalar&>(b)=a; a=t; |
150 | #else |
151 | using std::swap; |
152 | swap(a,const_cast<Scalar&>(b)); |
153 | #endif |
154 | } |
155 | }; |
156 | template<typename Scalar> |
157 | struct functor_traits<swap_assign_op<Scalar> > { |
158 | enum { |
159 | Cost = 3 * NumTraits<Scalar>::ReadCost, |
160 | PacketAccess = packet_traits<Scalar>::Vectorizable |
161 | }; |
162 | }; |
163 | |
164 | } // namespace internal |
165 | |
166 | } // namespace Eigen |
167 | |
168 | #endif // EIGEN_ASSIGNMENT_FUNCTORS_H |
169 | |