src/Utility/Vec.h

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 /***************************************************************************
00003  *
00004  * The IPPL Framework
00005  * 
00006  *
00007  * Visit http://people.web.psi.ch/adelmann/ for more details
00008  *
00009  ***************************************************************************/
00010 
00011 #ifndef VEC_H
00012 #define VEC_H
00013 
00014 // include files
00015 #include "Message/Message.h"
00016 
00018 
00019 template<class T, unsigned Length>
00020 class vec
00021 {
00022 public:
00023   vec() {}
00024   vec(T v0);
00025   vec(T v0, T v1);
00026   vec(T v0, T v1, T v2);
00027 #ifdef IPPL_USE_FUNKY_VEC_COPIES
00028   vec( const vec<T,Length>& );
00029   vec<T,Length>& operator=( const vec<T,Length>& );
00030 #endif
00031   T& operator[](unsigned d) { return Ptr[d]; }
00032   const T& operator[](unsigned d) const { return Ptr[d]; }
00033   Message& putMessage(Message &m) {
00034 #ifdef IPPL_USE_MEMBER_TEMPLATES
00035     m.put(Ptr, Ptr + Length);
00036 #else
00037     putMessage(m,Ptr,Ptr+Length);
00038 #endif
00039     return m;
00040   }
00041   Message& getMessage(Message &m) {
00042 #ifdef IPPL_USE_MEMBER_TEMPLATES
00043     m.get_iter(Ptr);
00044 #else
00045     getMessage_iter(m,Ptr);
00046 #endif
00047     return m;
00048   }
00049 
00050   static T dot(const T*,const T*);
00051 private:
00052   T Ptr[Length];
00053 };
00054 
00056 
00057 #ifdef IPPL_USE_FUNKY_VEC_COPIES
00058 //
00059 // Implementation of copy constructor and op=.
00060 //
00061 // These use a template trick to unroll the loop over elements of the vec.
00062 //
00063 
00064 //
00065 // A tag class to let us unroll this loop.
00066 // It isn't entirely clear this needs to be done, but
00067 // it is an interesting demonstration.
00068 //
00069 // It is just a record of how many elements to copy,
00070 // along with a flag.  The flag has the values:
00071 // 4: If Length>=4.  That means the interval should be split in half.
00072 // 0..3: Call an explicit function for this length.
00073 // 
00074 
00075 template<unsigned Length, int Flag>
00076 class DivideVecCopyTag {
00077 #ifdef IPPL_PURIFY
00078   // Add explicit default/copy constructors and op= to avoid UMR's.
00079 public:
00080   DivideVecCopyTag() {}
00081   DivideVecCopyTag(const DivideVecCopyTag<Length,Flag> &) {}
00082   DivideVecCopyTag<Length,Flag>&
00083   operator=(const DivideVecCopyTag<Length,Flag> &) { return *this; }
00084 #endif
00085 };
00086 
00087 //
00088 // Copy a vector of length 4 or greater.
00089 // Split it in half and copy each half.
00090 // Do it this way so that the depth of inlining is O(log(Length)) 
00091 // instead of O(Length).
00092 //
00093 template<class T1, class T2, unsigned L>
00094 inline void
00095 divide_vec_copy(T1 *p1, T2 *p2, DivideVecCopyTag<L,4> )
00096 {
00097   divide_vec_copy(p1, p2, DivideVecCopyTag< L/2 , (L>=8 ? 4 : L/2)>());
00098   divide_vec_copy(p1+(L/2), p2+(L/2),DivideVecCopyTag<L-L/2,(L>=8?4:L-L/2)>());
00099 }
00100 
00101 //
00102 // Copy a vector of length 0, 1, 2 or 3.  Just move it.
00103 //
00104 template<class T1, class T2>
00105 inline void
00106 divide_vec_copy(T1 *p1, T2 *p2, DivideVecCopyTag<3,3> )
00107 {
00108   p1[0] = p2[0];
00109   p1[1] = p2[1];
00110   p1[2] = p2[2];
00111 }
00112 
00113 template<class T1, class T2>
00114 inline void
00115 divide_vec_copy(T1 *p1, T2 *p2, DivideVecCopyTag<2,2> )
00116 {
00117   p1[0] = p2[0];
00118   p1[1] = p2[1];
00119 }
00120 
00121 template<class T1, class T2>
00122 inline void
00123 divide_vec_copy(T1 *p1, T2 *p2, DivideVecCopyTag<1,1> )
00124 {
00125   *p1 = *p2;
00126 }
00127 
00128 template<class T1, class T2>
00129 inline void
00130 divide_vec_copy(T1 *,T2 *, DivideVecCopyTag<0,0> )
00131 {
00132 }
00133 
00134 //
00135 // The copy ctor and op= just call divide_vec_copy to do the copy
00136 //
00137 
00138 template<class T, unsigned L>
00139 inline 
00140 vec<T,L>::vec( const vec<T,L>& v )
00141 {
00142   divide_vec_copy( Ptr , v.Ptr , DivideVecCopyTag<L,( L>=4 ? 4 : L)>() );
00143 }
00144 
00145 template<class T, unsigned L>
00146 inline vec<T,L>&
00147 vec<T,L>::operator=( const vec<T,L>& v )
00148 {
00149   if ( this != &v )
00150     divide_vec_copy( Ptr , v.Ptr , DivideVecCopyTag<L,( L>=4 ? 4 : L)>() );
00151   return *this;
00152 }
00153 
00154 #endif // IPPL_USE_FUNKY_VEC_COPIES
00155 
00157 
00158 template<class T, unsigned Length>
00159 inline 
00160 vec<T,Length>::vec(T v0)
00161 {
00162   CTAssert(Length==1);
00163   Ptr[0] = v0;
00164 }
00165 
00166 template<class T, unsigned Length>
00167 inline 
00168 vec<T,Length>::vec(T v0, T v1)
00169 {
00170   CTAssert(Length==2);
00171   Ptr[0] = v0;
00172   Ptr[1] = v1;
00173 }
00174 
00175 template<class T, unsigned Length>
00176 inline 
00177 vec<T,Length>::vec(T v0, T v1, T v2)
00178 {
00179   CTAssert(Length==3);
00180   Ptr[0] = v0;
00181   Ptr[1] = v1;
00182   Ptr[2] = v2;
00183 }
00184 
00186 
00187 //
00188 // Define a global function for taking the dot product between two 
00189 // short arrays of objects of type T.
00190 //
00191 template<class T, unsigned Length>
00192 inline T
00193 vec<T,Length>::dot(const T* l, const T* r)
00194 {
00195   T ret = l[0]*r[0];
00196   for (int i=1; i<Length; ++i)
00197     ret += l[i]*r[i];
00198   return ret;
00199 }
00200 
00202 
00203 #endif // VEC_H
00204 
00205 /***************************************************************************
00206  * $RCSfile: Vec.h,v $   $Author: adelmann $
00207  * $Revision: 1.1.1.1 $   $Date: 2003/01/23 07:40:34 $
00208  * IPPL_VERSION_ID: $Id: Vec.h,v 1.1.1.1 2003/01/23 07:40:34 adelmann Exp $ 
00209  ***************************************************************************/

Generated on Mon Jan 16 13:23:59 2006 for IPPL by  doxygen 1.4.6