CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_6_2_5/src/FWCore/Utilities/interface/SoATuple.h

Go to the documentation of this file.
00001 #ifndef FWCore_Utilities_SoATuple_h
00002 #define FWCore_Utilities_SoATuple_h
00003 // -*- C++ -*-
00004 //
00005 // Package:     FWCore/Utilities
00006 // Class  :     SoATuple
00007 // 
00081 //
00082 // Original Author:  Chris Jones
00083 //         Created:  Tue, 16 Apr 2013 20:34:31 GMT
00084 // $Id: SoATuple.h,v 1.4 2013/04/23 20:07:48 chrjones Exp $
00085 //
00086 
00087 // system include files
00088 #include <algorithm>
00089 #include <tuple>
00090 #include <cassert>
00091 
00092 // user include files
00093 #include "FWCore/Utilities/interface/SoATupleHelper.h"
00094 #include "FWCore/Utilities/interface/GCCPrerequisite.h"
00095 
00096 
00097 // forward declarations
00098 
00099 namespace edm {
00100 
00101   //The class Aligned is used to specify a non-default alignment for a class
00102   using edm::soahelper::Aligned;
00103   
00104   //Proper alignment for doing vectorized operations on CPU
00105   template<typename T> using AlignedVec = Aligned<T,16>;
00106   
00107   template <typename... Args>
00108   class SoATuple
00109   {
00110     
00111   public:
00112     typedef typename std::tuple<Args...> element;
00113 
00114     SoATuple(): m_size(0),m_reserved(0){
00115       for(auto& v : m_values) {
00116         v = nullptr;
00117       }
00118     }
00119     SoATuple(const SoATuple<Args...>& iOther):m_size(0),m_reserved(0) {
00120       for(auto& v : m_values) {
00121         v = nullptr;
00122       }
00123       reserve(iOther.m_size);
00124       soahelper::SoATupleHelper<sizeof...(Args),Args...>::copyToNew(static_cast<char*>(m_values[0]),iOther.m_size,m_reserved,iOther.m_values,m_values);
00125       m_size = iOther.m_size;
00126     }
00127 
00128     SoATuple(SoATuple<Args...>&& iOther):m_size(0),m_reserved(0) {
00129       for(auto& v : m_values) {
00130         v = nullptr;
00131       }
00132       this->swap(iOther);
00133     }
00134 
00135     const SoATuple<Args...>& operator=(const SoATuple<Args...>& iRHS) {
00136       SoATuple<Args...> temp(iRHS);
00137       this->swap(temp);
00138       return *this;
00139     }
00140 
00141     ~SoATuple() {
00142       soahelper::SoATupleHelper<sizeof...(Args),Args...>::destroy(m_values,m_size);
00143       typedef std::aligned_storage<soahelper::SoATupleHelper<sizeof...(Args),Args...>::max_alignment,
00144       soahelper::SoATupleHelper<sizeof...(Args),Args...>::max_alignment> AlignedType;
00145 
00146       delete [] static_cast<AlignedType*>(m_values[0]);
00147     }
00148     
00149     // ---------- const member functions ---------------------
00150     size_t size() const { return m_size;}
00151     size_t capacity() const {return m_reserved;}
00152 
00154     template<unsigned int I>
00155     typename soahelper::AlignmentHelper<typename std::tuple_element<I, std::tuple<Args...>>::type>::Type const& get(unsigned int iIndex) const {
00156       typedef typename soahelper::AlignmentHelper<typename std::tuple_element<I, std::tuple<Args...>>::type>::Type ReturnType;
00157       return *(static_cast<ReturnType const*>(m_values[I])+iIndex);
00158     }
00159 
00161     template<unsigned int I>
00162     typename soahelper::AlignmentHelper<typename std::tuple_element<I, std::tuple<Args...>>::type>::Type const* begin() const {
00163       typedef soahelper::AlignmentHelper<typename std::tuple_element<I, std::tuple<Args...>>::type> Helper;
00164       typedef typename Helper::Type ReturnType;
00165 #if GCC_PREREQUISITE(4,7,0)
00166       return static_cast<ReturnType const*>(__builtin_assume_aligned(m_values[I],Helper::kAlignment));
00167 #else
00168       return static_cast<ReturnType const*>(m_values[I]);
00169 #endif
00170     }
00172     template<unsigned int I>
00173     typename soahelper::AlignmentHelper<typename std::tuple_element<I, std::tuple<Args...>>::type>::Type const* end() const {
00174       typedef typename soahelper::AlignmentHelper<typename std::tuple_element<I, std::tuple<Args...>>::type>::Type ReturnType;
00175       return static_cast<ReturnType const*>(m_values[I])+m_size;
00176     }
00177 
00178     // ---------- member functions ---------------------------
00180     void reserve(unsigned int iToSize) {
00181       if(iToSize > m_reserved) {
00182         changeSize(iToSize);
00183       }
00184     }
00185     
00187     void shrink_to_fit() {
00188       if(m_reserved > m_size) {
00189         changeSize(m_size);
00190       }
00191     }
00192 
00194     void push_back(element const& values) {
00195       if(size()+1>capacity()) {
00196         reserve(size()*2+1);
00197       }
00198       soahelper::SoATupleHelper<sizeof...(Args),Args...>::push_back(m_values,m_size,values);
00199       ++m_size;
00200     }
00201 
00203     template< typename... FArgs>
00204     void emplace_back(FArgs&&... values) {
00205       if(size()+1>capacity()) {
00206         reserve(size()*2+1);
00207       }
00208       soahelper::SoATupleHelper<sizeof...(Args),Args...>::emplace_back(m_values,m_size,std::forward<FArgs>(values)...);
00209       ++m_size;
00210     }
00211 
00213     template<unsigned int I>
00214     typename soahelper::AlignmentHelper<typename std::tuple_element<I, std::tuple<Args...>>::type>::Type& get(unsigned int iIndex) {
00215       typedef typename soahelper::AlignmentHelper<typename std::tuple_element<I, std::tuple<Args...>>::type>::Type ReturnType;
00216       return *(static_cast<ReturnType*>(m_values[I])+iIndex);
00217     }
00218     
00220     template<unsigned int I>
00221     typename soahelper::AlignmentHelper<typename std::tuple_element<I, std::tuple<Args...>>::type>::Type* begin() {
00222       typedef soahelper::AlignmentHelper<typename std::tuple_element<I, std::tuple<Args...>>::type> Helper;
00223       typedef typename Helper::Type ReturnType;
00224 #if GCC_PREREQUISITE(4,7,0)
00225       return static_cast<ReturnType*>(__builtin_assume_aligned(m_values[I],Helper::kAlignment));
00226 #else
00227       return static_cast<ReturnType*>(m_values[I]);
00228 #endif
00229     }
00231     template<unsigned int I>
00232     typename soahelper::AlignmentHelper<typename std::tuple_element<I, std::tuple<Args...>>::type>::Type* end() {
00233       typedef typename soahelper::AlignmentHelper<typename std::tuple_element<I, std::tuple<Args...>>::type>::Type ReturnType;
00234       return static_cast<ReturnType*>(m_values[I])+m_size;
00235     }
00236     
00237     void swap(SoATuple<Args...>& iOther) {
00238       std::swap(m_size,iOther.m_size);
00239       std::swap(m_reserved,iOther.m_reserved);
00240       for(unsigned int i=0; i<sizeof...(Args);++i) {
00241         std::swap(m_values[i],iOther.m_values[i]);
00242       }
00243     }
00244   private:
00245         
00246     void changeSize(unsigned int iToSize) {
00247       assert(m_size<=iToSize);
00248       const size_t memoryNeededInBytes = soahelper::SoATupleHelper<sizeof...(Args),Args...>::spaceNeededFor(iToSize);
00249       //align memory of the array to be on the strictest alignment boundary for any type in the Tuple
00250       // This is done by creating an array of a type that has that same alignment restriction and minimum size.
00251       // This has the draw back of possibly padding the array by one extra element if the memoryNeededInBytes is not
00252       // a strict multiple of max_alignment.
00253       // NOTE: using new char[...] would likely cause more padding based on C++11 5.3.4 paragraph 10 where it
00254       // says the alignment will be for the strictest requirement for an object whose size < size of array. So
00255       // if the array were for 64 bytes and the strictest requirement of any object was 8 bytes then the entire
00256       // char array would be aligned on an 8 byte boundary. However, if the SoATuple<char,char> only 1 byte alignment
00257       // is needed. The following algorithm would require only 1 byte alignment
00258       const std::size_t max_alignment = soahelper::SoATupleHelper<sizeof...(Args),Args...>::max_alignment;
00259       typedef std::aligned_storage<soahelper::SoATupleHelper<sizeof...(Args),Args...>::max_alignment,
00260                                    soahelper::SoATupleHelper<sizeof...(Args),Args...>::max_alignment> AlignedType;
00261       //If needed, pad the number of items by 1
00262       const size_t itemsNeeded = (memoryNeededInBytes+max_alignment-1)/sizeof(AlignedType);
00263       char * newMemory = static_cast<char*>(static_cast<void*>(new AlignedType[itemsNeeded]));
00264       void * oldMemory =m_values[0];
00265       soahelper::SoATupleHelper<sizeof...(Args),Args...>::moveToNew(newMemory,m_size, iToSize, m_values);
00266       m_reserved = iToSize;
00267       delete [] static_cast<AlignedType*>(oldMemory);
00268     }
00269     // ---------- member data --------------------------------
00270     //Pointers to where each column starts in the shared memory array
00271     //m_values[0] also points to the beginning of the shared memory area
00272     void* m_values[sizeof...(Args)];
00273     size_t m_size;
00274     size_t m_reserved;
00275   };
00276 }
00277 
00278 
00279 #endif