Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:13:13

0001 #ifndef FWCore_Utilities_SoATupleHelper_h
0002 #define FWCore_Utilities_SoATupleHelper_h
0003 // -*- C++ -*-
0004 //
0005 // Package:     Package
0006 // Class  :     SoATupleHelper
0007 //
0008 /**\class SoATupleHelper SoATupleHelper.h "SoATupleHelper.h"
0009 
0010  Description: Helper classes for SoATuple
0011 
0012  Usage:
0013     These classes are an internal detail of SoATuple.
0014 
0015 */
0016 //
0017 // Original Author:  Chris Jones
0018 //         Created:  Tue, 16 Apr 2013 21:06:08 GMT
0019 //
0020 
0021 // system include files
0022 #include <tuple>
0023 #include <algorithm>
0024 
0025 // user include files
0026 
0027 // forward declarations
0028 namespace edm {
0029   namespace soahelper {
0030 
0031     /**Given a leading memory size, iSizeSoFar, and an alignment boundary requirement of iBoundary, returns how much additional memory padding is needed.
0032      This function assumes that when iSizeSoFar==0 that we are already properly aligned.*/
0033     constexpr unsigned int padding_needed(size_t iSizeSoFar, unsigned int iBoundary) {
0034       return (iBoundary - iSizeSoFar % iBoundary) % iBoundary;
0035     }
0036 
0037     /**
0038      Given a starting value of I=0, and the index to the argument you want to get, J,
0039      will recursively step through the arguments, Args, until it hits the one you want, Jth, and then will return it as return type Ret.
0040      */
0041 
0042     template <unsigned int I, unsigned int J, typename Ret, typename... Args>
0043     struct arg_puller;
0044 
0045     /**Given a variable number of arguments, returns the 'J'th one. The first caller must use I=0.*/
0046     template <unsigned int I, unsigned int J, typename Ret, typename F, typename... Args>
0047     struct arg_puller<I, J, Ret, F, Args...> {
0048       static Ret pull(F const&, const Args&... args) { return arg_puller<I + 1, J, Ret, Args...>::pull(args...); }
0049     };
0050 
0051     /**End condition of the template recursion */
0052     template <unsigned int I, typename Ret, typename F, typename... Args>
0053     struct arg_puller<I, I, Ret, F, Args...> {
0054       static Ret pull(F const& iV, const Args&...) { return iV; }
0055     };
0056 
0057     /** A decorator class used in SoATuple's template argument list to denote that
0058      the type T should be stored with an unusual byte alignment given by ALIGNMENT.
0059      NOTE: It is up to the user to be sure sizeof(T) >= ALIGNMENT.
0060      */
0061     template <typename T, unsigned int ALIGNMENT>
0062     struct Aligned {
0063       static const unsigned int kAlignment = ALIGNMENT;
0064       typedef T Type;
0065     };
0066 
0067     /** Class used by SoATupleHelper to determine the proper alignment of the requested type.
0068      The default is to just use 'alignof(T)'. Users can change the alignment by instead using
0069      Aligned<T,ALIGNMENT> for which AlignmentHelper has a specialization.
0070      */
0071     template <typename T>
0072     struct AlignmentHelper {
0073       static const std::size_t kAlignment = alignof(T);
0074       typedef T Type;
0075     };
0076 
0077     /** Specialization of ALignmentHelper for Aligned<T, ALIGNMENT>. This allows users
0078      to specify non-default alignment values for the internal arrays of SoATuple.
0079      */
0080     template <typename T, unsigned int ALIGNMENT>
0081     struct AlignmentHelper<Aligned<T, ALIGNMENT>> {
0082       static const std::size_t kAlignment = ALIGNMENT;
0083       typedef T Type;
0084     };
0085 
0086     /**Implements most of the internal functions used by SoATuple. The argument I is used to recursively step
0087      through each arugment Args when doing the work. SoATupleHelper<I,Args> actually operates on the I-1 argument.
0088      There is a specialization of SoATulpeHelper with I=0 which is used to stop the template recursion.
0089      */
0090     template <unsigned int I, typename... Args>
0091     struct SoATupleHelper {
0092       typedef AlignmentHelper<typename std::tuple_element<I - 1, std::tuple<Args...>>::type> AlignmentInfo;
0093       typedef typename AlignmentInfo::Type Type;
0094       typedef SoATupleHelper<I - 1, Args...> NextHelper;
0095 
0096       static const std::size_t max_alignment =
0097           AlignmentInfo::kAlignment > NextHelper::max_alignment ? AlignmentInfo::kAlignment : NextHelper::max_alignment;
0098 
0099       // ---------- static member functions --------------------
0100       static size_t moveToNew(char* iNewMemory, size_t iSize, size_t iReserve, void** oToSet);
0101       static size_t copyToNew(char* iNewMemory, size_t iSize, size_t iReserve, void* const* iFrom, void** oToSet);
0102       static size_t spaceNeededFor(unsigned int iNElements);
0103       static void push_back(void** iToSet, size_t iSize, std::tuple<Args...> const& iValues);
0104       template <typename... FArgs>
0105       static void emplace_back(void** iToSet, size_t iSize, FArgs... iValues);
0106       static void destroy(void** iToSet, size_t iSize);
0107 
0108       // ---------- member functions ---------------------------
0109       SoATupleHelper(const SoATupleHelper&) = delete;  // stop default
0110 
0111       const SoATupleHelper& operator=(const SoATupleHelper&) = delete;  // stop default
0112     };
0113 
0114     //Specialization used to stop recursion
0115     template <typename... Args>
0116     struct SoATupleHelper<0, Args...> {
0117       static const std::size_t max_alignment = 0;
0118       static void destroy(void** /*iToSet*/, size_t /*iSize*/) {}
0119 
0120       static void push_back(void** /*iToSet*/, size_t /*iSize*/, std::tuple<Args...> const& /*values*/) {}
0121 
0122       template <typename... FArgs>
0123       static void emplace_back(void** iToSet, size_t iSize, FArgs... iValues) {}
0124 
0125       static size_t spaceNeededFor(unsigned int /*iNElements*/) { return 0; }
0126 
0127       static size_t moveToNew(char* /*iNewMemory*/, size_t /*iSize*/, size_t /*iReserve*/, void** /*oToSet*/) {
0128         return 0;
0129       }
0130 
0131       static size_t copyToNew(
0132           char* /*iNewMemory*/, size_t /*iSize*/, size_t /*iReserve*/, void* const* /*iFrom*/, void** /*oToSet*/) {
0133         return 0;
0134       }
0135     };
0136 
0137     template <unsigned int I, typename... Args>
0138     size_t SoATupleHelper<I, Args...>::moveToNew(char* iNewMemory, size_t iSize, size_t iReserve, void** oToSet) {
0139       size_t usedSoFar = NextHelper::moveToNew(iNewMemory, iSize, iReserve, oToSet);
0140 
0141       //find new start
0142       const unsigned int boundary = AlignmentInfo::kAlignment;
0143 
0144       Type* newStart = reinterpret_cast<Type*>(iNewMemory + usedSoFar + padding_needed(usedSoFar, boundary));
0145 
0146       void** oldStart = oToSet + I - 1;
0147 
0148       Type* oldValues = static_cast<Type*>(*oldStart);
0149       if (oldValues != nullptr) {
0150         auto ptr = newStart;
0151         for (auto it = oldValues; it != oldValues + iSize; ++it, ++ptr) {
0152           new (ptr) Type(std::move(*it));
0153         }
0154         for (auto it = oldValues; it != oldValues + iSize; ++it) {
0155           it->~Type();
0156         }
0157       }
0158       *oldStart = newStart;
0159       unsigned int additionalSize = padding_needed(usedSoFar, boundary) + iReserve * sizeof(Type);
0160       return usedSoFar + additionalSize;
0161     }
0162 
0163     template <unsigned int I, typename... Args>
0164     size_t SoATupleHelper<I, Args...>::copyToNew(
0165         char* iNewMemory, size_t iSize, size_t iReserve, void* const* iFrom, void** oToSet) {
0166       size_t usedSoFar = NextHelper::copyToNew(iNewMemory, iSize, iReserve, iFrom, oToSet);
0167 
0168       //find new start
0169       const unsigned int boundary = AlignmentInfo::kAlignment;
0170 
0171       Type* newStart = reinterpret_cast<Type*>(iNewMemory + usedSoFar + padding_needed(usedSoFar, boundary));
0172 
0173       void* const* oldStart = iFrom + I - 1;
0174 
0175       Type* oldValues = static_cast<Type*>(*oldStart);
0176       if (oldValues != nullptr) {
0177         auto ptr = newStart;
0178         for (auto it = oldValues; it != oldValues + iSize; ++it, ++ptr) {
0179           new (ptr) Type(*it);
0180         }
0181       }
0182       *(oToSet + I - 1) = newStart;
0183       unsigned int additionalSize = padding_needed(usedSoFar, boundary) + iReserve * sizeof(Type);
0184       return usedSoFar + additionalSize;
0185     }
0186 
0187     template <unsigned int I, typename... Args>
0188     size_t SoATupleHelper<I, Args...>::spaceNeededFor(unsigned int iNElements) {
0189       size_t usedSoFar = NextHelper::spaceNeededFor(iNElements);
0190       const unsigned int boundary = AlignmentInfo::kAlignment;
0191       unsigned int additionalSize = padding_needed(usedSoFar, boundary) + iNElements * sizeof(Type);
0192       return usedSoFar + additionalSize;
0193     }
0194 
0195     template <unsigned int I, typename... Args>
0196     void SoATupleHelper<I, Args...>::push_back(void** iToSet, size_t iSize, std::tuple<Args...> const& iValues) {
0197       new (static_cast<Type*>(*(iToSet + I - 1)) + iSize) Type(std::get<I - 1>(iValues));
0198 
0199       NextHelper::push_back(iToSet, iSize, iValues);
0200     }
0201 
0202     template <unsigned int I, typename... Args>
0203     template <typename... FArgs>
0204     void SoATupleHelper<I, Args...>::emplace_back(void** iToSet, size_t iSize, FArgs... iValues) {
0205       new (static_cast<Type*>(*(iToSet + I - 1)) + iSize)
0206           Type(arg_puller<0, I - 1, Type const&, FArgs...>::pull(std::forward<FArgs>(iValues)...));
0207 
0208       NextHelper::emplace_back(iToSet, iSize, std::forward<FArgs>(iValues)...);
0209     }
0210 
0211     template <unsigned int I, typename... Args>
0212     void SoATupleHelper<I, Args...>::destroy(void** iToSet, size_t iSize) {
0213       void** start = iToSet + I - 1;
0214       Type* values = static_cast<Type*>(*start);
0215 
0216       for (auto it = values; it != values + iSize; ++it) {
0217         it->~Type();
0218       }
0219 
0220       NextHelper::destroy(iToSet, iSize);
0221     }
0222 
0223   }  // namespace soahelper
0224 }  // namespace edm
0225 
0226 #endif