Home | History | Annotate | Download | only in Core
      1 // This file is part of Eigen, a lightweight C++ template library
      2 // for linear algebra.
      3 //
      4 // Copyright (C) 2007 Michael Olbrich <michael.olbrich (at) gmx.net>
      5 // Copyright (C) 2006-2010 Benoit Jacob <jacob.benoit.1 (at) gmail.com>
      6 // Copyright (C) 2008 Gael Guennebaud <gael.guennebaud (at) inria.fr>
      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 
     12 #ifndef EIGEN_ASSIGN_H
     13 #define EIGEN_ASSIGN_H
     14 
     15 namespace Eigen {
     16 
     17 namespace internal {
     18 
     19 /***************************************************************************
     20 * Part 1 : the logic deciding a strategy for traversal and unrolling       *
     21 ***************************************************************************/
     22 
     23 template <typename Derived, typename OtherDerived>
     24 struct assign_traits
     25 {
     26 public:
     27   enum {
     28     DstIsAligned = Derived::Flags & AlignedBit,
     29     DstHasDirectAccess = Derived::Flags & DirectAccessBit,
     30     SrcIsAligned = OtherDerived::Flags & AlignedBit,
     31     JointAlignment = bool(DstIsAligned) && bool(SrcIsAligned) ? Aligned : Unaligned
     32   };
     33 
     34 private:
     35   enum {
     36     InnerSize = int(Derived::IsVectorAtCompileTime) ? int(Derived::SizeAtCompileTime)
     37               : int(Derived::Flags)&RowMajorBit ? int(Derived::ColsAtCompileTime)
     38               : int(Derived::RowsAtCompileTime),
     39     InnerMaxSize = int(Derived::IsVectorAtCompileTime) ? int(Derived::MaxSizeAtCompileTime)
     40               : int(Derived::Flags)&RowMajorBit ? int(Derived::MaxColsAtCompileTime)
     41               : int(Derived::MaxRowsAtCompileTime),
     42     MaxSizeAtCompileTime = Derived::SizeAtCompileTime,
     43     PacketSize = packet_traits<typename Derived::Scalar>::size
     44   };
     45 
     46   enum {
     47     StorageOrdersAgree = (int(Derived::IsRowMajor) == int(OtherDerived::IsRowMajor)),
     48     MightVectorize = StorageOrdersAgree
     49                   && (int(Derived::Flags) & int(OtherDerived::Flags) & ActualPacketAccessBit),
     50     MayInnerVectorize  = MightVectorize && int(InnerSize)!=Dynamic && int(InnerSize)%int(PacketSize)==0
     51                        && int(DstIsAligned) && int(SrcIsAligned),
     52     MayLinearize = StorageOrdersAgree && (int(Derived::Flags) & int(OtherDerived::Flags) & LinearAccessBit),
     53     MayLinearVectorize = MightVectorize && MayLinearize && DstHasDirectAccess
     54                        && (DstIsAligned || MaxSizeAtCompileTime == Dynamic),
     55       /* If the destination isn't aligned, we have to do runtime checks and we don't unroll,
     56          so it's only good for large enough sizes. */
     57     MaySliceVectorize  = MightVectorize && DstHasDirectAccess
     58                        && (int(InnerMaxSize)==Dynamic || int(InnerMaxSize)>=3*PacketSize)
     59       /* slice vectorization can be slow, so we only want it if the slices are big, which is
     60          indicated by InnerMaxSize rather than InnerSize, think of the case of a dynamic block
     61          in a fixed-size matrix */
     62   };
     63 
     64 public:
     65   enum {
     66     Traversal = int(MayInnerVectorize)  ? int(InnerVectorizedTraversal)
     67               : int(MayLinearVectorize) ? int(LinearVectorizedTraversal)
     68               : int(MaySliceVectorize)  ? int(SliceVectorizedTraversal)
     69               : int(MayLinearize)       ? int(LinearTraversal)
     70                                         : int(DefaultTraversal),
     71     Vectorized = int(Traversal) == InnerVectorizedTraversal
     72               || int(Traversal) == LinearVectorizedTraversal
     73               || int(Traversal) == SliceVectorizedTraversal
     74   };
     75 
     76 private:
     77   enum {
     78     UnrollingLimit      = EIGEN_UNROLLING_LIMIT * (Vectorized ? int(PacketSize) : 1),
     79     MayUnrollCompletely = int(Derived::SizeAtCompileTime) != Dynamic
     80                        && int(OtherDerived::CoeffReadCost) != Dynamic
     81                        && int(Derived::SizeAtCompileTime) * int(OtherDerived::CoeffReadCost) <= int(UnrollingLimit),
     82     MayUnrollInner      = int(InnerSize) != Dynamic
     83                        && int(OtherDerived::CoeffReadCost) != Dynamic
     84                        && int(InnerSize) * int(OtherDerived::CoeffReadCost) <= int(UnrollingLimit)
     85   };
     86 
     87 public:
     88   enum {
     89     Unrolling = (int(Traversal) == int(InnerVectorizedTraversal) || int(Traversal) == int(DefaultTraversal))
     90                 ? (
     91                     int(MayUnrollCompletely) ? int(CompleteUnrolling)
     92                   : int(MayUnrollInner)      ? int(InnerUnrolling)
     93                                              : int(NoUnrolling)
     94                   )
     95               : int(Traversal) == int(LinearVectorizedTraversal)
     96                 ? ( bool(MayUnrollCompletely) && bool(DstIsAligned) ? int(CompleteUnrolling) : int(NoUnrolling) )
     97               : int(Traversal) == int(LinearTraversal)
     98                 ? ( bool(MayUnrollCompletely) ? int(CompleteUnrolling) : int(NoUnrolling) )
     99               : int(NoUnrolling)
    100   };
    101 
    102 #ifdef EIGEN_DEBUG_ASSIGN
    103   static void debug()
    104   {
    105     EIGEN_DEBUG_VAR(DstIsAligned)
    106     EIGEN_DEBUG_VAR(SrcIsAligned)
    107     EIGEN_DEBUG_VAR(JointAlignment)
    108     EIGEN_DEBUG_VAR(InnerSize)
    109     EIGEN_DEBUG_VAR(InnerMaxSize)
    110     EIGEN_DEBUG_VAR(PacketSize)
    111     EIGEN_DEBUG_VAR(StorageOrdersAgree)
    112     EIGEN_DEBUG_VAR(MightVectorize)
    113     EIGEN_DEBUG_VAR(MayLinearize)
    114     EIGEN_DEBUG_VAR(MayInnerVectorize)
    115     EIGEN_DEBUG_VAR(MayLinearVectorize)
    116     EIGEN_DEBUG_VAR(MaySliceVectorize)
    117     EIGEN_DEBUG_VAR(Traversal)
    118     EIGEN_DEBUG_VAR(UnrollingLimit)
    119     EIGEN_DEBUG_VAR(MayUnrollCompletely)
    120     EIGEN_DEBUG_VAR(MayUnrollInner)
    121     EIGEN_DEBUG_VAR(Unrolling)
    122   }
    123 #endif
    124 };
    125 
    126 /***************************************************************************
    127 * Part 2 : meta-unrollers
    128 ***************************************************************************/
    129 
    130 /************************
    131 *** Default traversal ***
    132 ************************/
    133 
    134 template<typename Derived1, typename Derived2, int Index, int Stop>
    135 struct assign_DefaultTraversal_CompleteUnrolling
    136 {
    137   enum {
    138     outer = Index / Derived1::InnerSizeAtCompileTime,
    139     inner = Index % Derived1::InnerSizeAtCompileTime
    140   };
    141 
    142   static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src)
    143   {
    144     dst.copyCoeffByOuterInner(outer, inner, src);
    145     assign_DefaultTraversal_CompleteUnrolling<Derived1, Derived2, Index+1, Stop>::run(dst, src);
    146   }
    147 };
    148 
    149 template<typename Derived1, typename Derived2, int Stop>
    150 struct assign_DefaultTraversal_CompleteUnrolling<Derived1, Derived2, Stop, Stop>
    151 {
    152   static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &) {}
    153 };
    154 
    155 template<typename Derived1, typename Derived2, int Index, int Stop>
    156 struct assign_DefaultTraversal_InnerUnrolling
    157 {
    158   static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src, int outer)
    159   {
    160     dst.copyCoeffByOuterInner(outer, Index, src);
    161     assign_DefaultTraversal_InnerUnrolling<Derived1, Derived2, Index+1, Stop>::run(dst, src, outer);
    162   }
    163 };
    164 
    165 template<typename Derived1, typename Derived2, int Stop>
    166 struct assign_DefaultTraversal_InnerUnrolling<Derived1, Derived2, Stop, Stop>
    167 {
    168   static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &, int) {}
    169 };
    170 
    171 /***********************
    172 *** Linear traversal ***
    173 ***********************/
    174 
    175 template<typename Derived1, typename Derived2, int Index, int Stop>
    176 struct assign_LinearTraversal_CompleteUnrolling
    177 {
    178   static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src)
    179   {
    180     dst.copyCoeff(Index, src);
    181     assign_LinearTraversal_CompleteUnrolling<Derived1, Derived2, Index+1, Stop>::run(dst, src);
    182   }
    183 };
    184 
    185 template<typename Derived1, typename Derived2, int Stop>
    186 struct assign_LinearTraversal_CompleteUnrolling<Derived1, Derived2, Stop, Stop>
    187 {
    188   static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &) {}
    189 };
    190 
    191 /**************************
    192 *** Inner vectorization ***
    193 **************************/
    194 
    195 template<typename Derived1, typename Derived2, int Index, int Stop>
    196 struct assign_innervec_CompleteUnrolling
    197 {
    198   enum {
    199     outer = Index / Derived1::InnerSizeAtCompileTime,
    200     inner = Index % Derived1::InnerSizeAtCompileTime,
    201     JointAlignment = assign_traits<Derived1,Derived2>::JointAlignment
    202   };
    203 
    204   static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src)
    205   {
    206     dst.template copyPacketByOuterInner<Derived2, Aligned, JointAlignment>(outer, inner, src);
    207     assign_innervec_CompleteUnrolling<Derived1, Derived2,
    208       Index+packet_traits<typename Derived1::Scalar>::size, Stop>::run(dst, src);
    209   }
    210 };
    211 
    212 template<typename Derived1, typename Derived2, int Stop>
    213 struct assign_innervec_CompleteUnrolling<Derived1, Derived2, Stop, Stop>
    214 {
    215   static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &) {}
    216 };
    217 
    218 template<typename Derived1, typename Derived2, int Index, int Stop>
    219 struct assign_innervec_InnerUnrolling
    220 {
    221   static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src, int outer)
    222   {
    223     dst.template copyPacketByOuterInner<Derived2, Aligned, Aligned>(outer, Index, src);
    224     assign_innervec_InnerUnrolling<Derived1, Derived2,
    225       Index+packet_traits<typename Derived1::Scalar>::size, Stop>::run(dst, src, outer);
    226   }
    227 };
    228 
    229 template<typename Derived1, typename Derived2, int Stop>
    230 struct assign_innervec_InnerUnrolling<Derived1, Derived2, Stop, Stop>
    231 {
    232   static EIGEN_STRONG_INLINE void run(Derived1 &, const Derived2 &, int) {}
    233 };
    234 
    235 /***************************************************************************
    236 * Part 3 : implementation of all cases
    237 ***************************************************************************/
    238 
    239 template<typename Derived1, typename Derived2,
    240          int Traversal = assign_traits<Derived1, Derived2>::Traversal,
    241          int Unrolling = assign_traits<Derived1, Derived2>::Unrolling,
    242          int Version = Specialized>
    243 struct assign_impl;
    244 
    245 /************************
    246 *** Default traversal ***
    247 ************************/
    248 
    249 template<typename Derived1, typename Derived2, int Unrolling, int Version>
    250 struct assign_impl<Derived1, Derived2, InvalidTraversal, Unrolling, Version>
    251 {
    252   static inline void run(Derived1 &, const Derived2 &) { }
    253 };
    254 
    255 template<typename Derived1, typename Derived2, int Version>
    256 struct assign_impl<Derived1, Derived2, DefaultTraversal, NoUnrolling, Version>
    257 {
    258   typedef typename Derived1::Index Index;
    259   static inline void run(Derived1 &dst, const Derived2 &src)
    260   {
    261     const Index innerSize = dst.innerSize();
    262     const Index outerSize = dst.outerSize();
    263     for(Index outer = 0; outer < outerSize; ++outer)
    264       for(Index inner = 0; inner < innerSize; ++inner)
    265         dst.copyCoeffByOuterInner(outer, inner, src);
    266   }
    267 };
    268 
    269 template<typename Derived1, typename Derived2, int Version>
    270 struct assign_impl<Derived1, Derived2, DefaultTraversal, CompleteUnrolling, Version>
    271 {
    272   static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src)
    273   {
    274     assign_DefaultTraversal_CompleteUnrolling<Derived1, Derived2, 0, Derived1::SizeAtCompileTime>
    275       ::run(dst, src);
    276   }
    277 };
    278 
    279 template<typename Derived1, typename Derived2, int Version>
    280 struct assign_impl<Derived1, Derived2, DefaultTraversal, InnerUnrolling, Version>
    281 {
    282   typedef typename Derived1::Index Index;
    283   static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src)
    284   {
    285     const Index outerSize = dst.outerSize();
    286     for(Index outer = 0; outer < outerSize; ++outer)
    287       assign_DefaultTraversal_InnerUnrolling<Derived1, Derived2, 0, Derived1::InnerSizeAtCompileTime>
    288         ::run(dst, src, outer);
    289   }
    290 };
    291 
    292 /***********************
    293 *** Linear traversal ***
    294 ***********************/
    295 
    296 template<typename Derived1, typename Derived2, int Version>
    297 struct assign_impl<Derived1, Derived2, LinearTraversal, NoUnrolling, Version>
    298 {
    299   typedef typename Derived1::Index Index;
    300   static inline void run(Derived1 &dst, const Derived2 &src)
    301   {
    302     const Index size = dst.size();
    303     for(Index i = 0; i < size; ++i)
    304       dst.copyCoeff(i, src);
    305   }
    306 };
    307 
    308 template<typename Derived1, typename Derived2, int Version>
    309 struct assign_impl<Derived1, Derived2, LinearTraversal, CompleteUnrolling, Version>
    310 {
    311   static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src)
    312   {
    313     assign_LinearTraversal_CompleteUnrolling<Derived1, Derived2, 0, Derived1::SizeAtCompileTime>
    314       ::run(dst, src);
    315   }
    316 };
    317 
    318 /**************************
    319 *** Inner vectorization ***
    320 **************************/
    321 
    322 template<typename Derived1, typename Derived2, int Version>
    323 struct assign_impl<Derived1, Derived2, InnerVectorizedTraversal, NoUnrolling, Version>
    324 {
    325   typedef typename Derived1::Index Index;
    326   static inline void run(Derived1 &dst, const Derived2 &src)
    327   {
    328     const Index innerSize = dst.innerSize();
    329     const Index outerSize = dst.outerSize();
    330     const Index packetSize = packet_traits<typename Derived1::Scalar>::size;
    331     for(Index outer = 0; outer < outerSize; ++outer)
    332       for(Index inner = 0; inner < innerSize; inner+=packetSize)
    333         dst.template copyPacketByOuterInner<Derived2, Aligned, Aligned>(outer, inner, src);
    334   }
    335 };
    336 
    337 template<typename Derived1, typename Derived2, int Version>
    338 struct assign_impl<Derived1, Derived2, InnerVectorizedTraversal, CompleteUnrolling, Version>
    339 {
    340   static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src)
    341   {
    342     assign_innervec_CompleteUnrolling<Derived1, Derived2, 0, Derived1::SizeAtCompileTime>
    343       ::run(dst, src);
    344   }
    345 };
    346 
    347 template<typename Derived1, typename Derived2, int Version>
    348 struct assign_impl<Derived1, Derived2, InnerVectorizedTraversal, InnerUnrolling, Version>
    349 {
    350   typedef typename Derived1::Index Index;
    351   static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src)
    352   {
    353     const Index outerSize = dst.outerSize();
    354     for(Index outer = 0; outer < outerSize; ++outer)
    355       assign_innervec_InnerUnrolling<Derived1, Derived2, 0, Derived1::InnerSizeAtCompileTime>
    356         ::run(dst, src, outer);
    357   }
    358 };
    359 
    360 /***************************
    361 *** Linear vectorization ***
    362 ***************************/
    363 
    364 template <bool IsAligned = false>
    365 struct unaligned_assign_impl
    366 {
    367   template <typename Derived, typename OtherDerived>
    368   static EIGEN_STRONG_INLINE void run(const Derived&, OtherDerived&, typename Derived::Index, typename Derived::Index) {}
    369 };
    370 
    371 template <>
    372 struct unaligned_assign_impl<false>
    373 {
    374   // MSVC must not inline this functions. If it does, it fails to optimize the
    375   // packet access path.
    376 #ifdef _MSC_VER
    377   template <typename Derived, typename OtherDerived>
    378   static EIGEN_DONT_INLINE void run(const Derived& src, OtherDerived& dst, typename Derived::Index start, typename Derived::Index end)
    379 #else
    380   template <typename Derived, typename OtherDerived>
    381   static EIGEN_STRONG_INLINE void run(const Derived& src, OtherDerived& dst, typename Derived::Index start, typename Derived::Index end)
    382 #endif
    383   {
    384     for (typename Derived::Index index = start; index < end; ++index)
    385       dst.copyCoeff(index, src);
    386   }
    387 };
    388 
    389 template<typename Derived1, typename Derived2, int Version>
    390 struct assign_impl<Derived1, Derived2, LinearVectorizedTraversal, NoUnrolling, Version>
    391 {
    392   typedef typename Derived1::Index Index;
    393   static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src)
    394   {
    395     const Index size = dst.size();
    396     typedef packet_traits<typename Derived1::Scalar> PacketTraits;
    397     enum {
    398       packetSize = PacketTraits::size,
    399       dstAlignment = PacketTraits::AlignedOnScalar ? Aligned : int(assign_traits<Derived1,Derived2>::DstIsAligned) ,
    400       srcAlignment = assign_traits<Derived1,Derived2>::JointAlignment
    401     };
    402     const Index alignedStart = assign_traits<Derived1,Derived2>::DstIsAligned ? 0
    403                              : internal::first_aligned(&dst.coeffRef(0), size);
    404     const Index alignedEnd = alignedStart + ((size-alignedStart)/packetSize)*packetSize;
    405 
    406     unaligned_assign_impl<assign_traits<Derived1,Derived2>::DstIsAligned!=0>::run(src,dst,0,alignedStart);
    407 
    408     for(Index index = alignedStart; index < alignedEnd; index += packetSize)
    409     {
    410       dst.template copyPacket<Derived2, dstAlignment, srcAlignment>(index, src);
    411     }
    412 
    413     unaligned_assign_impl<>::run(src,dst,alignedEnd,size);
    414   }
    415 };
    416 
    417 template<typename Derived1, typename Derived2, int Version>
    418 struct assign_impl<Derived1, Derived2, LinearVectorizedTraversal, CompleteUnrolling, Version>
    419 {
    420   typedef typename Derived1::Index Index;
    421   static EIGEN_STRONG_INLINE void run(Derived1 &dst, const Derived2 &src)
    422   {
    423     enum { size = Derived1::SizeAtCompileTime,
    424            packetSize = packet_traits<typename Derived1::Scalar>::size,
    425            alignedSize = (size/packetSize)*packetSize };
    426 
    427     assign_innervec_CompleteUnrolling<Derived1, Derived2, 0, alignedSize>::run(dst, src);
    428     assign_DefaultTraversal_CompleteUnrolling<Derived1, Derived2, alignedSize, size>::run(dst, src);
    429   }
    430 };
    431 
    432 /**************************
    433 *** Slice vectorization ***
    434 ***************************/
    435 
    436 template<typename Derived1, typename Derived2, int Version>
    437 struct assign_impl<Derived1, Derived2, SliceVectorizedTraversal, NoUnrolling, Version>
    438 {
    439   typedef typename Derived1::Index Index;
    440   static inline void run(Derived1 &dst, const Derived2 &src)
    441   {
    442     typedef packet_traits<typename Derived1::Scalar> PacketTraits;
    443     enum {
    444       packetSize = PacketTraits::size,
    445       alignable = PacketTraits::AlignedOnScalar,
    446       dstAlignment = alignable ? Aligned : int(assign_traits<Derived1,Derived2>::DstIsAligned) ,
    447       srcAlignment = assign_traits<Derived1,Derived2>::JointAlignment
    448     };
    449     const Index packetAlignedMask = packetSize - 1;
    450     const Index innerSize = dst.innerSize();
    451     const Index outerSize = dst.outerSize();
    452     const Index alignedStep = alignable ? (packetSize - dst.outerStride() % packetSize) & packetAlignedMask : 0;
    453     Index alignedStart = ((!alignable) || assign_traits<Derived1,Derived2>::DstIsAligned) ? 0
    454                        : internal::first_aligned(&dst.coeffRef(0,0), innerSize);
    455 
    456     for(Index outer = 0; outer < outerSize; ++outer)
    457     {
    458       const Index alignedEnd = alignedStart + ((innerSize-alignedStart) & ~packetAlignedMask);
    459       // do the non-vectorizable part of the assignment
    460       for(Index inner = 0; inner<alignedStart ; ++inner)
    461         dst.copyCoeffByOuterInner(outer, inner, src);
    462 
    463       // do the vectorizable part of the assignment
    464       for(Index inner = alignedStart; inner<alignedEnd; inner+=packetSize)
    465         dst.template copyPacketByOuterInner<Derived2, dstAlignment, Unaligned>(outer, inner, src);
    466 
    467       // do the non-vectorizable part of the assignment
    468       for(Index inner = alignedEnd; inner<innerSize ; ++inner)
    469         dst.copyCoeffByOuterInner(outer, inner, src);
    470 
    471       alignedStart = std::min<Index>((alignedStart+alignedStep)%packetSize, innerSize);
    472     }
    473   }
    474 };
    475 
    476 } // end namespace internal
    477 
    478 /***************************************************************************
    479 * Part 4 : implementation of DenseBase methods
    480 ***************************************************************************/
    481 
    482 template<typename Derived>
    483 template<typename OtherDerived>
    484 EIGEN_STRONG_INLINE Derived& DenseBase<Derived>
    485   ::lazyAssign(const DenseBase<OtherDerived>& other)
    486 {
    487   enum{
    488     SameType = internal::is_same<typename Derived::Scalar,typename OtherDerived::Scalar>::value
    489   };
    490 
    491   EIGEN_STATIC_ASSERT_LVALUE(Derived)
    492   EIGEN_STATIC_ASSERT_SAME_MATRIX_SIZE(Derived,OtherDerived)
    493   EIGEN_STATIC_ASSERT(SameType,YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY)
    494 
    495 #ifdef EIGEN_DEBUG_ASSIGN
    496   internal::assign_traits<Derived, OtherDerived>::debug();
    497 #endif
    498   eigen_assert(rows() == other.rows() && cols() == other.cols());
    499   internal::assign_impl<Derived, OtherDerived, int(SameType) ? int(internal::assign_traits<Derived, OtherDerived>::Traversal)
    500                                                        : int(InvalidTraversal)>::run(derived(),other.derived());
    501 #ifndef EIGEN_NO_DEBUG
    502   checkTransposeAliasing(other.derived());
    503 #endif
    504   return derived();
    505 }
    506 
    507 namespace internal {
    508 
    509 template<typename Derived, typename OtherDerived,
    510          bool EvalBeforeAssigning = (int(OtherDerived::Flags) & EvalBeforeAssigningBit) != 0,
    511          bool NeedToTranspose = Derived::IsVectorAtCompileTime
    512                 && OtherDerived::IsVectorAtCompileTime
    513                 && ((int(Derived::RowsAtCompileTime) == 1 && int(OtherDerived::ColsAtCompileTime) == 1)
    514                       |  // FIXME | instead of || to please GCC 4.4.0 stupid warning "suggest parentheses around &&".
    515                          // revert to || as soon as not needed anymore.
    516                     (int(Derived::ColsAtCompileTime) == 1 && int(OtherDerived::RowsAtCompileTime) == 1))
    517                 && int(Derived::SizeAtCompileTime) != 1>
    518 struct assign_selector;
    519 
    520 template<typename Derived, typename OtherDerived>
    521 struct assign_selector<Derived,OtherDerived,false,false> {
    522   static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.derived()); }
    523 };
    524 template<typename Derived, typename OtherDerived>
    525 struct assign_selector<Derived,OtherDerived,true,false> {
    526   static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.eval()); }
    527 };
    528 template<typename Derived, typename OtherDerived>
    529 struct assign_selector<Derived,OtherDerived,false,true> {
    530   static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.transpose()); }
    531 };
    532 template<typename Derived, typename OtherDerived>
    533 struct assign_selector<Derived,OtherDerived,true,true> {
    534   static EIGEN_STRONG_INLINE Derived& run(Derived& dst, const OtherDerived& other) { return dst.lazyAssign(other.transpose().eval()); }
    535 };
    536 
    537 } // end namespace internal
    538 
    539 template<typename Derived>
    540 template<typename OtherDerived>
    541 EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::operator=(const DenseBase<OtherDerived>& other)
    542 {
    543   return internal::assign_selector<Derived,OtherDerived>::run(derived(), other.derived());
    544 }
    545 
    546 template<typename Derived>
    547 EIGEN_STRONG_INLINE Derived& DenseBase<Derived>::operator=(const DenseBase& other)
    548 {
    549   return internal::assign_selector<Derived,Derived>::run(derived(), other.derived());
    550 }
    551 
    552 template<typename Derived>
    553 EIGEN_STRONG_INLINE Derived& MatrixBase<Derived>::operator=(const MatrixBase& other)
    554 {
    555   return internal::assign_selector<Derived,Derived>::run(derived(), other.derived());
    556 }
    557 
    558 template<typename Derived>
    559 template <typename OtherDerived>
    560 EIGEN_STRONG_INLINE Derived& MatrixBase<Derived>::operator=(const DenseBase<OtherDerived>& other)
    561 {
    562   return internal::assign_selector<Derived,OtherDerived>::run(derived(), other.derived());
    563 }
    564 
    565 template<typename Derived>
    566 template <typename OtherDerived>
    567 EIGEN_STRONG_INLINE Derived& MatrixBase<Derived>::operator=(const EigenBase<OtherDerived>& other)
    568 {
    569   other.derived().evalTo(derived());
    570   return derived();
    571 }
    572 
    573 template<typename Derived>
    574 template<typename OtherDerived>
    575 EIGEN_STRONG_INLINE Derived& MatrixBase<Derived>::operator=(const ReturnByValue<OtherDerived>& other)
    576 {
    577   other.evalTo(derived());
    578   return derived();
    579 }
    580 
    581 } // end namespace Eigen
    582 
    583 #endif // EIGEN_ASSIGN_H
    584