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
13namespace Eigen {
14
15namespace internal {
16
17/** \internal
18 * \brief Template functor for scalar/packet assignment
19 *
20 */
21template<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)
32template<typename DstScalar> struct assign_op<DstScalar,void> {};
33
34template<typename DstScalar,typename SrcScalar>
35struct 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 */
46template<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};
55template<typename DstScalar,typename SrcScalar>
56struct 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 */
67template<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};
76template<typename DstScalar,typename SrcScalar>
77struct 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 */
88template<typename DstScalar, typename SrcScalar=DstScalar>
89struct 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};
98template<typename DstScalar, typename SrcScalar>
99struct 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 */
110template<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};
119template<typename DstScalar, typename SrcScalar>
120struct 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 */
142template<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};
156template<typename Scalar>
157struct 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