Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2022-07-26 22:25:07

0001 #ifndef DataFormats_SoATemplate_interface_SoACommon_h
0002 #define DataFormats_SoATemplate_interface_SoACommon_h
0003 
0004 /*
0005  * Definitions of SoA common parameters for SoA class generators
0006  */
0007 
0008 #include <cstdint>
0009 #include <cassert>
0010 #include <ostream>
0011 #include <tuple>
0012 #include <type_traits>
0013 
0014 #include <boost/preprocessor.hpp>
0015 
0016 #include "FWCore/Utilities/interface/typedefs.h"
0017 
0018 // CUDA attributes
0019 #ifdef __CUDACC__
0020 #define SOA_HOST_ONLY __host__
0021 #define SOA_DEVICE_ONLY __device__
0022 #define SOA_HOST_DEVICE __host__ __device__
0023 #define SOA_INLINE __forceinline__
0024 #else
0025 #define SOA_HOST_ONLY
0026 #define SOA_DEVICE_ONLY
0027 #define SOA_HOST_DEVICE
0028 #define SOA_INLINE inline __attribute__((always_inline))
0029 #endif
0030 
0031 // Exception throwing (or willful crash in kernels)
0032 #if defined(__CUDACC__) && defined(__CUDA_ARCH__)
0033 #define SOA_THROW_OUT_OF_RANGE(A) \
0034   {                               \
0035     printf("%s\n", (A));          \
0036     __trap();                     \
0037   }
0038 #else
0039 #define SOA_THROW_OUT_OF_RANGE(A) \
0040   { throw std::out_of_range(A); }
0041 #endif
0042 
0043 /* declare "scalars" (one value shared across the whole SoA) and "columns" (one value per element) */
0044 #define _VALUE_TYPE_SCALAR 0
0045 #define _VALUE_TYPE_COLUMN 1
0046 #define _VALUE_TYPE_EIGEN_COLUMN 2
0047 
0048 /* The size type need to be "hardcoded" in the template parameters for classes serialized by ROOT */
0049 #define CMS_SOA_BYTE_SIZE_TYPE std::size_t
0050 
0051 namespace cms::soa {
0052 
0053   // size_type for indices. Compatible with ROOT Int_t, but limited to 2G entries
0054   using size_type = cms_int32_t;
0055   // byte_size_type for byte counts. Not creating an artificial limit (and not ROOT serialized).
0056   using byte_size_type = CMS_SOA_BYTE_SIZE_TYPE;
0057 
0058   enum class SoAColumnType {
0059     scalar = _VALUE_TYPE_SCALAR,
0060     column = _VALUE_TYPE_COLUMN,
0061     eigen = _VALUE_TYPE_EIGEN_COLUMN
0062   };
0063 
0064   namespace RestrictQualify {
0065     constexpr bool enabled = true;
0066     constexpr bool disabled = false;
0067     constexpr bool Default = disabled;
0068   }  // namespace RestrictQualify
0069 
0070   namespace RangeChecking {
0071     constexpr bool enabled = true;
0072     constexpr bool disabled = false;
0073     constexpr bool Default = disabled;
0074   }  // namespace RangeChecking
0075 
0076   template <typename T, bool RESTRICT_QUALIFY>
0077   struct add_restrict {};
0078 
0079   template <typename T>
0080   struct add_restrict<T, RestrictQualify::enabled> {
0081     using Value = T;
0082     using Pointer = T* __restrict__;
0083     using Reference = T& __restrict__;
0084     using ConstValue = const T;
0085     using PointerToConst = const T* __restrict__;
0086     using ReferenceToConst = const T& __restrict__;
0087   };
0088 
0089   template <typename T>
0090   struct add_restrict<T, RestrictQualify::disabled> {
0091     using Value = T;
0092     using Pointer = T*;
0093     using Reference = T&;
0094     using ConstValue = const T;
0095     using PointerToConst = const T*;
0096     using ReferenceToConst = const T&;
0097   };
0098 
0099   // Forward declarations
0100   template <SoAColumnType COLUMN_TYPE, typename T>
0101   struct SoAConstParametersImpl;
0102 
0103   template <SoAColumnType COLUMN_TYPE, typename T>
0104   struct SoAParametersImpl;
0105 
0106   // Templated const parameter sets for scalars, columns and Eigen columns
0107   template <SoAColumnType COLUMN_TYPE, typename T>
0108   struct SoAConstParametersImpl {
0109     static constexpr SoAColumnType columnType = COLUMN_TYPE;
0110 
0111     using ValueType = T;
0112     using ScalarType = T;
0113     using TupleOrPointerType = const ValueType*;
0114 
0115     // default constructor
0116     SoAConstParametersImpl() = default;
0117 
0118     // constructor from an address
0119     SOA_HOST_DEVICE SOA_INLINE constexpr SoAConstParametersImpl(ValueType const* addr) : addr_(addr) {}
0120 
0121     // constructor from a non-const parameter set
0122     SOA_HOST_DEVICE SOA_INLINE constexpr SoAConstParametersImpl(SoAParametersImpl<columnType, ValueType> const& o)
0123         : addr_{o.addr_} {}
0124 
0125     static constexpr bool checkAlignment(ValueType* addr, byte_size_type alignment) {
0126       return reinterpret_cast<intptr_t>(addr) % alignment;
0127     }
0128 
0129   public:
0130     // scalar or column
0131     ValueType const* addr_ = nullptr;
0132   };
0133 
0134   // Templated const parameter specialisation for Eigen columns
0135   template <typename T>
0136   struct SoAConstParametersImpl<SoAColumnType::eigen, T> {
0137     static constexpr SoAColumnType columnType = SoAColumnType::eigen;
0138 
0139     using ValueType = T;
0140     using ScalarType = typename T::Scalar;
0141     using TupleOrPointerType = std::tuple<ScalarType*, byte_size_type>;
0142 
0143     // default constructor
0144     SoAConstParametersImpl() = default;
0145 
0146     // constructor from individual address and stride
0147     SOA_HOST_DEVICE SOA_INLINE constexpr SoAConstParametersImpl(ScalarType const* addr, byte_size_type stride)
0148         : addr_(addr), stride_(stride) {}
0149 
0150     // constructor from address and stride packed in a tuple
0151     SOA_HOST_DEVICE SOA_INLINE constexpr SoAConstParametersImpl(TupleOrPointerType const& tuple)
0152         : addr_(std::get<0>(tuple)), stride_(std::get<1>(tuple)) {}
0153 
0154     // constructor from a non-const parameter set
0155     SOA_HOST_DEVICE SOA_INLINE constexpr SoAConstParametersImpl(SoAParametersImpl<columnType, ValueType> const& o)
0156         : addr_{o.addr_}, stride_{o.stride_} {}
0157 
0158     static constexpr bool checkAlignment(TupleOrPointerType const& tuple, byte_size_type alignment) {
0159       const auto& [addr, stride] = tuple;
0160       return reinterpret_cast<intptr_t>(addr) % alignment;
0161     }
0162 
0163   public:
0164     // address and stride
0165     ScalarType const* addr_ = nullptr;
0166     byte_size_type stride_ = 0;
0167   };
0168 
0169   // Matryoshka template to avoid commas inside macros
0170   template <SoAColumnType COLUMN_TYPE>
0171   struct SoAConstParameters_ColumnType {
0172     template <typename T>
0173     using DataType = SoAConstParametersImpl<COLUMN_TYPE, T>;
0174   };
0175 
0176   // Templated parameter sets for scalars, columns and Eigen columns
0177   template <SoAColumnType COLUMN_TYPE, typename T>
0178   struct SoAParametersImpl {
0179     static constexpr SoAColumnType columnType = COLUMN_TYPE;
0180 
0181     using ValueType = T;
0182     using ScalarType = T;
0183     using TupleOrPointerType = ValueType*;
0184 
0185     using ConstType = SoAConstParametersImpl<columnType, ValueType>;
0186     friend ConstType;
0187 
0188     // default constructor
0189     SoAParametersImpl() = default;
0190 
0191     // constructor from an address
0192     SOA_HOST_DEVICE SOA_INLINE constexpr SoAParametersImpl(ValueType* addr) : addr_(addr) {}
0193 
0194     static constexpr bool checkAlignment(ValueType* addr, byte_size_type alignment) {
0195       return reinterpret_cast<intptr_t>(addr) % alignment;
0196     }
0197 
0198   public:
0199     // scalar or column
0200     ValueType* addr_ = nullptr;
0201   };
0202 
0203   // Templated parameter specialisation for Eigen columns
0204   template <typename T>
0205   struct SoAParametersImpl<SoAColumnType::eigen, T> {
0206     static constexpr SoAColumnType columnType = SoAColumnType::eigen;
0207 
0208     using ValueType = T;
0209     using ScalarType = typename T::Scalar;
0210     using TupleOrPointerType = std::tuple<ScalarType*, byte_size_type>;
0211 
0212     using ConstType = SoAConstParametersImpl<columnType, ValueType>;
0213     friend ConstType;
0214 
0215     // default constructor
0216     SoAParametersImpl() = default;
0217 
0218     // constructor from individual address and stride
0219     SOA_HOST_DEVICE SOA_INLINE constexpr SoAParametersImpl(ScalarType* addr, byte_size_type stride)
0220         : addr_(addr), stride_(stride) {}
0221 
0222     // constructor from address and stride packed in a tuple
0223     SOA_HOST_DEVICE SOA_INLINE constexpr SoAParametersImpl(TupleOrPointerType const& tuple)
0224         : addr_(std::get<0>(tuple)), stride_(std::get<1>(tuple)) {}
0225 
0226     static constexpr bool checkAlignment(TupleOrPointerType const& tuple, byte_size_type alignment) {
0227       const auto& [addr, stride] = tuple;
0228       return reinterpret_cast<intptr_t>(addr) % alignment;
0229     }
0230 
0231   public:
0232     // address and stride
0233     ScalarType* addr_ = nullptr;
0234     byte_size_type stride_ = 0;
0235   };
0236 
0237   // Matryoshka template to avoid commas inside macros
0238   template <SoAColumnType COLUMN_TYPE>
0239   struct SoAParameters_ColumnType {
0240     template <typename T>
0241     using DataType = SoAParametersImpl<COLUMN_TYPE, T>;
0242   };
0243 
0244   // Helper converting a const parameter set to a non-const parameter set, to be used only in the constructor of non-const "element"
0245   namespace {
0246     template <typename T>
0247     constexpr inline std::remove_const_t<T>* non_const_ptr(T* p) {
0248       return const_cast<std::remove_const_t<T>*>(p);
0249     }
0250   }  // namespace
0251 
0252   template <SoAColumnType COLUMN_TYPE, typename T>
0253   SOA_HOST_DEVICE SOA_INLINE constexpr SoAParametersImpl<COLUMN_TYPE, T> const_cast_SoAParametersImpl(
0254       SoAConstParametersImpl<COLUMN_TYPE, T> const& o) {
0255     return SoAParametersImpl<COLUMN_TYPE, T>{non_const_ptr(o.addr_)};
0256   }
0257 
0258   template <typename T>
0259   SOA_HOST_DEVICE SOA_INLINE constexpr SoAParametersImpl<SoAColumnType::eigen, T> const_cast_SoAParametersImpl(
0260       SoAConstParametersImpl<SoAColumnType::eigen, T> const& o) {
0261     return SoAParametersImpl<SoAColumnType::eigen, T>{non_const_ptr(o.addr_), o.stride_};
0262   }
0263 
0264   // Helper template managing the value at index idx within a column.
0265   // The optional compile time alignment parameter enables informing the
0266   // compiler of alignment (enforced by caller).
0267   template <SoAColumnType COLUMN_TYPE,
0268             typename T,
0269             byte_size_type ALIGNMENT,
0270             bool RESTRICT_QUALIFY = RestrictQualify::disabled>
0271   class SoAValue {
0272     // Eigen is implemented in a specialization
0273     static_assert(COLUMN_TYPE != SoAColumnType::eigen);
0274 
0275   public:
0276     using Restr = add_restrict<T, RESTRICT_QUALIFY>;
0277     using Val = typename Restr::Value;
0278     using Ptr = typename Restr::Pointer;
0279     using Ref = typename Restr::Reference;
0280     using PtrToConst = typename Restr::PointerToConst;
0281     using RefToConst = typename Restr::ReferenceToConst;
0282 
0283     SOA_HOST_DEVICE SOA_INLINE SoAValue(size_type i, T* col) : idx_(i), col_(col) {}
0284 
0285     SOA_HOST_DEVICE SOA_INLINE SoAValue(size_type i, SoAParametersImpl<COLUMN_TYPE, T> params)
0286         : idx_(i), col_(params.addr_) {}
0287 
0288     SOA_HOST_DEVICE SOA_INLINE Ref operator()() {
0289       // Ptr type will add the restrict qualifyer if needed
0290       Ptr col = alignedCol();
0291       return col[idx_];
0292     }
0293 
0294     SOA_HOST_DEVICE SOA_INLINE RefToConst operator()() const {
0295       // PtrToConst type will add the restrict qualifyer if needed
0296       PtrToConst col = alignedCol();
0297       return col[idx_];
0298     }
0299 
0300     SOA_HOST_DEVICE SOA_INLINE Ptr operator&() { return &alignedCol()[idx_]; }
0301 
0302     SOA_HOST_DEVICE SOA_INLINE PtrToConst operator&() const { return &alignedCol()[idx_]; }
0303 
0304     /* This was an attempt to implement the syntax
0305      *
0306      *     old_value = view.x
0307      *     view.x = new_value
0308      *
0309      * instead of
0310      *
0311      *     old_value = view.x()
0312      *     view.x() = new_value
0313      *
0314      *  but it was found to break in some corner cases.
0315      *  We keep them commented out for the time being.
0316 
0317     SOA_HOST_DEVICE SOA_INLINE operator T&() { return col_[idx_]; }
0318 
0319     template <typename T2>
0320     SOA_HOST_DEVICE SOA_INLINE Ref operator=(const T2& v) {
0321       return alignedCol()[idx_] = v;
0322     }
0323     */
0324 
0325     using valueType = Val;
0326 
0327     static constexpr auto valueSize = sizeof(T);
0328 
0329   private:
0330     SOA_HOST_DEVICE SOA_INLINE Ptr alignedCol() const {
0331       if constexpr (ALIGNMENT) {
0332         return reinterpret_cast<Ptr>(__builtin_assume_aligned(col_, ALIGNMENT));
0333       }
0334       return reinterpret_cast<Ptr>(col_);
0335     }
0336 
0337     size_type idx_;
0338     T* col_;
0339   };
0340 
0341   // Eigen/Core should be pre-included before the SoA headers to enable support for Eigen columns.
0342 #ifdef EIGEN_WORLD_VERSION
0343   // Helper template managing an Eigen-type value at index idx within a column.
0344   template <class C, byte_size_type ALIGNMENT, bool RESTRICT_QUALIFY>
0345   class SoAValue<SoAColumnType::eigen, C, ALIGNMENT, RESTRICT_QUALIFY> {
0346   public:
0347     using Type = C;
0348     using MapType = Eigen::Map<C, 0, Eigen::InnerStride<Eigen::Dynamic>>;
0349     using CMapType = const Eigen::Map<const C, 0, Eigen::InnerStride<Eigen::Dynamic>>;
0350     using Restr = add_restrict<typename C::Scalar, RESTRICT_QUALIFY>;
0351     using Val = typename Restr::Value;
0352     using Ptr = typename Restr::Pointer;
0353     using Ref = typename Restr::Reference;
0354     using PtrToConst = typename Restr::PointerToConst;
0355     using RefToConst = typename Restr::ReferenceToConst;
0356 
0357     SOA_HOST_DEVICE SOA_INLINE SoAValue(size_type i, typename C::Scalar* col, byte_size_type stride)
0358         : val_(col + i, C::RowsAtCompileTime, C::ColsAtCompileTime, Eigen::InnerStride<Eigen::Dynamic>(stride)),
0359           crCol_(col),
0360           cVal_(crCol_ + i, C::RowsAtCompileTime, C::ColsAtCompileTime, Eigen::InnerStride<Eigen::Dynamic>(stride)),
0361           stride_(stride) {}
0362 
0363     SOA_HOST_DEVICE SOA_INLINE SoAValue(size_type i, SoAParametersImpl<SoAColumnType::eigen, C> params)
0364         : val_(params.addr_ + i,
0365                C::RowsAtCompileTime,
0366                C::ColsAtCompileTime,
0367                Eigen::InnerStride<Eigen::Dynamic>(params.stride_)),
0368           crCol_(params.addr_),
0369           cVal_(crCol_ + i,
0370                 C::RowsAtCompileTime,
0371                 C::ColsAtCompileTime,
0372                 Eigen::InnerStride<Eigen::Dynamic>(params.stride_)),
0373           stride_(params.stride_) {}
0374 
0375     SOA_HOST_DEVICE SOA_INLINE MapType& operator()() { return val_; }
0376 
0377     SOA_HOST_DEVICE SOA_INLINE const CMapType& operator()() const { return cVal_; }
0378 
0379     SOA_HOST_DEVICE SOA_INLINE operator C() { return val_; }
0380 
0381     SOA_HOST_DEVICE SOA_INLINE operator const C() const { return cVal_; }
0382 
0383     SOA_HOST_DEVICE SOA_INLINE C* operator&() { return &val_; }
0384 
0385     SOA_HOST_DEVICE SOA_INLINE const C* operator&() const { return &cVal_; }
0386 
0387     template <class C2>
0388     SOA_HOST_DEVICE SOA_INLINE MapType& operator=(const C2& v) {
0389       return val_ = v;
0390     }
0391 
0392     using ValueType = typename C::Scalar;
0393     static constexpr auto valueSize = sizeof(C::Scalar);
0394     SOA_HOST_DEVICE SOA_INLINE byte_size_type stride() const { return stride_; }
0395 
0396   private:
0397     MapType val_;
0398     const Ptr crCol_;
0399     CMapType cVal_;
0400     byte_size_type stride_;
0401   };
0402 #else
0403   // Raise a compile-time error
0404   template <class C, byte_size_type ALIGNMENT, bool RESTRICT_QUALIFY>
0405   class SoAValue<SoAColumnType::eigen, C, ALIGNMENT, RESTRICT_QUALIFY> {
0406     static_assert(!sizeof(C),
0407                   "Eigen/Core should be pre-included before the SoA headers to enable support for Eigen columns.");
0408   };
0409 #endif
0410 
0411   // Helper template managing a const value at index idx within a column.
0412   template <SoAColumnType COLUMN_TYPE,
0413             typename T,
0414             byte_size_type ALIGNMENT,
0415             bool RESTRICT_QUALIFY = RestrictQualify::disabled>
0416   class SoAConstValue {
0417     // Eigen is implemented in a specialization
0418     static_assert(COLUMN_TYPE != SoAColumnType::eigen);
0419 
0420   public:
0421     using Restr = add_restrict<T, RESTRICT_QUALIFY>;
0422     using Val = typename Restr::Value;
0423     using Ptr = typename Restr::Pointer;
0424     using Ref = typename Restr::Reference;
0425     using PtrToConst = typename Restr::PointerToConst;
0426     using RefToConst = typename Restr::ReferenceToConst;
0427     using Params = SoAParametersImpl<COLUMN_TYPE, T>;
0428     using ConstParams = SoAConstParametersImpl<COLUMN_TYPE, T>;
0429 
0430     SOA_HOST_DEVICE SOA_INLINE SoAConstValue(size_type i, const T* col) : idx_(i), col_(col) {}
0431 
0432     SOA_HOST_DEVICE SOA_INLINE SoAConstValue(size_type i, SoAParametersImpl<COLUMN_TYPE, T> params)
0433         : idx_(i), col_(params.addr_) {}
0434 
0435     SOA_HOST_DEVICE SOA_INLINE SoAConstValue(size_type i, SoAConstParametersImpl<COLUMN_TYPE, T> params)
0436         : idx_(i), col_(params.addr_) {}
0437 
0438     SOA_HOST_DEVICE SOA_INLINE RefToConst operator()() const {
0439       // Ptr type will add the restrict qualifyer if needed
0440       PtrToConst col = alignedCol();
0441       return col[idx_];
0442     }
0443 
0444     SOA_HOST_DEVICE SOA_INLINE const T* operator&() const { return &alignedCol()[idx_]; }
0445 
0446     /* This was an attempt to implement the syntax
0447      *
0448      *     old_value = view.x
0449      *
0450      * instead of
0451      *
0452      *     old_value = view.x()
0453      *
0454      *  but it was found to break in some corner cases.
0455      *  We keep them commented out for the time being.
0456 
0457     SOA_HOST_DEVICE SOA_INLINE operator T&() { return col_[idx_]; }
0458     */
0459 
0460     using valueType = T;
0461     static constexpr auto valueSize = sizeof(T);
0462 
0463   private:
0464     SOA_HOST_DEVICE SOA_INLINE PtrToConst alignedCol() const {
0465       if constexpr (ALIGNMENT) {
0466         return reinterpret_cast<PtrToConst>(__builtin_assume_aligned(col_, ALIGNMENT));
0467       }
0468       return reinterpret_cast<PtrToConst>(col_);
0469     }
0470 
0471     size_type idx_;
0472     const T* col_;
0473   };
0474 
0475   // Eigen/Core should be pre-included before the SoA headers to enable support for Eigen columns.
0476 #ifdef EIGEN_WORLD_VERSION
0477   // Helper template managing a const Eigen-type value at index idx within a column.
0478   template <class C, byte_size_type ALIGNMENT, bool RESTRICT_QUALIFY>
0479   class SoAConstValue<SoAColumnType::eigen, C, ALIGNMENT, RESTRICT_QUALIFY> {
0480   public:
0481     using Type = C;
0482     using CMapType = Eigen::Map<const C, 0, Eigen::InnerStride<Eigen::Dynamic>>;
0483     using RefToConst = const CMapType&;
0484     using ConstParams = SoAConstParametersImpl<SoAColumnType::eigen, C>;
0485 
0486     SOA_HOST_DEVICE SOA_INLINE SoAConstValue(size_type i, typename C::Scalar* col, byte_size_type stride)
0487         : crCol_(col),
0488           cVal_(crCol_ + i, C::RowsAtCompileTime, C::ColsAtCompileTime, Eigen::InnerStride<Eigen::Dynamic>(stride)),
0489           stride_(stride) {}
0490 
0491     SOA_HOST_DEVICE SOA_INLINE SoAConstValue(size_type i, SoAConstParametersImpl<SoAColumnType::eigen, C> params)
0492         : crCol_(params.addr_),
0493           cVal_(crCol_ + i,
0494                 C::RowsAtCompileTime,
0495                 C::ColsAtCompileTime,
0496                 Eigen::InnerStride<Eigen::Dynamic>(params.stride_)),
0497           stride_(params.stride_) {}
0498 
0499     SOA_HOST_DEVICE SOA_INLINE const CMapType& operator()() const { return cVal_; }
0500 
0501     SOA_HOST_DEVICE SOA_INLINE operator const C() const { return cVal_; }
0502 
0503     SOA_HOST_DEVICE SOA_INLINE const C* operator&() const { return &cVal_; }
0504 
0505     using ValueType = typename C::Scalar;
0506     static constexpr auto valueSize = sizeof(C::Scalar);
0507 
0508     SOA_HOST_DEVICE SOA_INLINE byte_size_type stride() const { return stride_; }
0509 
0510   private:
0511     const typename C::Scalar* __restrict__ crCol_;
0512     CMapType cVal_;
0513     byte_size_type stride_;
0514   };
0515 #else
0516   // Raise a compile-time error
0517   template <class C, byte_size_type ALIGNMENT, bool RESTRICT_QUALIFY>
0518   class SoAConstValue<SoAColumnType::eigen, C, ALIGNMENT, RESTRICT_QUALIFY> {
0519     static_assert(!sizeof(C),
0520                   "Eigen/Core should be pre-included before the SoA headers to enable support for Eigen columns.");
0521   };
0522 #endif
0523 
0524   // Helper template to avoid commas inside macros
0525 #ifdef EIGEN_WORLD_VERSION
0526   template <class C>
0527   struct EigenConstMapMaker {
0528     using Type = Eigen::Map<const C, Eigen::AlignmentType::Unaligned, Eigen::InnerStride<Eigen::Dynamic>>;
0529 
0530     class DataHolder {
0531     public:
0532       DataHolder(const typename C::Scalar* data) : data_(data) {}
0533 
0534       EigenConstMapMaker::Type withStride(byte_size_type stride) {
0535         return EigenConstMapMaker::Type(
0536             data_, C::RowsAtCompileTime, C::ColsAtCompileTime, Eigen::InnerStride<Eigen::Dynamic>(stride));
0537       }
0538 
0539     private:
0540       const typename C::Scalar* const data_;
0541     };
0542 
0543     static DataHolder withData(const typename C::Scalar* data) { return DataHolder(data); }
0544   };
0545 #else
0546   template <class C>
0547   struct EigenConstMapMaker {
0548     // Eigen/Core should be pre-included before the SoA headers to enable support for Eigen columns.
0549     static_assert(!sizeof(C),
0550                   "Eigen/Core should be pre-included before the SoA headers to enable support for Eigen columns.");
0551   };
0552 #endif
0553 
0554   // Helper function to compute aligned size
0555   constexpr inline byte_size_type alignSize(byte_size_type size, byte_size_type alignment) {
0556     return ((size + alignment - 1) / alignment) * alignment;
0557   }
0558 
0559 }  // namespace cms::soa
0560 
0561 #define SOA_SCALAR(TYPE, NAME) (_VALUE_TYPE_SCALAR, TYPE, NAME)
0562 #define SOA_COLUMN(TYPE, NAME) (_VALUE_TYPE_COLUMN, TYPE, NAME)
0563 #define SOA_EIGEN_COLUMN(TYPE, NAME) (_VALUE_TYPE_EIGEN_COLUMN, TYPE, NAME)
0564 
0565 /* Iterate on the macro MACRO and return the result as a comma separated list */
0566 #define _ITERATE_ON_ALL_COMMA(MACRO, DATA, ...) \
0567   BOOST_PP_TUPLE_ENUM(BOOST_PP_SEQ_TO_TUPLE(_ITERATE_ON_ALL(MACRO, DATA, __VA_ARGS__)))
0568 
0569 /* Iterate MACRO on all elements */
0570 #define _ITERATE_ON_ALL(MACRO, DATA, ...) BOOST_PP_SEQ_FOR_EACH(MACRO, DATA, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))
0571 
0572 /* Switch on macros depending on scalar / column type */
0573 #define _SWITCH_ON_TYPE(VALUE_TYPE, IF_SCALAR, IF_COLUMN, IF_EIGEN_COLUMN) \
0574   BOOST_PP_IF(                                                             \
0575       BOOST_PP_EQUAL(VALUE_TYPE, _VALUE_TYPE_SCALAR),                      \
0576       IF_SCALAR,                                                           \
0577       BOOST_PP_IF(                                                         \
0578           BOOST_PP_EQUAL(VALUE_TYPE, _VALUE_TYPE_COLUMN),                  \
0579           IF_COLUMN,                                                       \
0580           BOOST_PP_IF(BOOST_PP_EQUAL(VALUE_TYPE, _VALUE_TYPE_EIGEN_COLUMN), IF_EIGEN_COLUMN, BOOST_PP_EMPTY())))
0581 
0582 namespace cms::soa {
0583 
0584   /* Column accessors: templates implementing the global accesors (soa::x() and soa::x(index) */
0585   enum class SoAAccessType : bool { mutableAccess, constAccess };
0586 
0587   template <typename, SoAColumnType, SoAAccessType>
0588   struct SoAColumnAccessorsImpl {};
0589 
0590   // TODO from Eric Cano:
0591   //   - add alignment support
0592   //   - SFINAE-based const/non const variants
0593 
0594   // Column
0595   template <typename T>
0596   struct SoAColumnAccessorsImpl<T, SoAColumnType::column, SoAAccessType::mutableAccess> {
0597     //SOA_HOST_DEVICE SOA_INLINE SoAColumnAccessorsImpl(T* baseAddress) : baseAddress_(baseAddress) {}
0598     SOA_HOST_DEVICE SOA_INLINE SoAColumnAccessorsImpl(const SoAParametersImpl<SoAColumnType::column, T>& params)
0599         : params_(params) {}
0600     SOA_HOST_DEVICE SOA_INLINE T* operator()() { return params_.addr_; }
0601     using NoParamReturnType = T*;
0602     SOA_HOST_DEVICE SOA_INLINE T& operator()(size_type index) { return params_.addr_[index]; }
0603 
0604   private:
0605     SoAParametersImpl<SoAColumnType::column, T> params_;
0606   };
0607 
0608   // Const column
0609   template <typename T>
0610   struct SoAColumnAccessorsImpl<T, SoAColumnType::column, SoAAccessType::constAccess> {
0611     SOA_HOST_DEVICE SOA_INLINE SoAColumnAccessorsImpl(const SoAConstParametersImpl<SoAColumnType::column, T>& params)
0612         : params_(params) {}
0613     SOA_HOST_DEVICE SOA_INLINE const T* operator()() const { return params_.addr_; }
0614     using NoParamReturnType = const T*;
0615     SOA_HOST_DEVICE SOA_INLINE T operator()(size_type index) const { return params_.addr_[index]; }
0616 
0617   private:
0618     SoAConstParametersImpl<SoAColumnType::column, T> params_;
0619   };
0620 
0621   // Scalar
0622   template <typename T>
0623   struct SoAColumnAccessorsImpl<T, SoAColumnType::scalar, SoAAccessType::mutableAccess> {
0624     SOA_HOST_DEVICE SOA_INLINE SoAColumnAccessorsImpl(const SoAParametersImpl<SoAColumnType::scalar, T>& params)
0625         : params_(params) {}
0626     SOA_HOST_DEVICE SOA_INLINE T& operator()() { return *params_.addr_; }
0627     using NoParamReturnType = T&;
0628     SOA_HOST_DEVICE SOA_INLINE void operator()(size_type index) const {
0629       assert(false && "Indexed access impossible for SoA scalars.");
0630     }
0631 
0632   private:
0633     SoAParametersImpl<SoAColumnType::scalar, T> params_;
0634   };
0635 
0636   // Const scalar
0637   template <typename T>
0638   struct SoAColumnAccessorsImpl<T, SoAColumnType::scalar, SoAAccessType::constAccess> {
0639     SOA_HOST_DEVICE SOA_INLINE SoAColumnAccessorsImpl(const SoAConstParametersImpl<SoAColumnType::scalar, T>& params)
0640         : params_(params) {}
0641     SOA_HOST_DEVICE SOA_INLINE T operator()() const { return *params_.addr_; }
0642     using NoParamReturnType = T;
0643     SOA_HOST_DEVICE SOA_INLINE void operator()(size_type index) const {
0644       assert(false && "Indexed access impossible for SoA scalars.");
0645     }
0646 
0647   private:
0648     SoAConstParametersImpl<SoAColumnType::scalar, T> params_;
0649   };
0650 
0651   // Eigen-type
0652   template <typename T>
0653   struct SoAColumnAccessorsImpl<T, SoAColumnType::eigen, SoAAccessType::mutableAccess> {
0654     //SOA_HOST_DEVICE SOA_INLINE SoAColumnAccessorsImpl(T* baseAddress) : baseAddress_(baseAddress) {}
0655     SOA_HOST_DEVICE SOA_INLINE SoAColumnAccessorsImpl(const SoAParametersImpl<SoAColumnType::eigen, T>& params)
0656         : params_(params) {}
0657     SOA_HOST_DEVICE SOA_INLINE typename T::Scalar* operator()() { return params_.addr_; }
0658     using NoParamReturnType = typename T::Scalar*;
0659     //SOA_HOST_DEVICE SOA_INLINE T& operator()(size_type index) { return params_.addr_[index]; }
0660 
0661   private:
0662     SoAParametersImpl<SoAColumnType::eigen, T> params_;
0663   };
0664 
0665   // Const Eigen-type
0666   template <typename T>
0667   struct SoAColumnAccessorsImpl<T, SoAColumnType::eigen, SoAAccessType::constAccess> {
0668     SOA_HOST_DEVICE SOA_INLINE SoAColumnAccessorsImpl(const SoAConstParametersImpl<SoAColumnType::eigen, T>& params)
0669         : params_(params) {}
0670     SOA_HOST_DEVICE SOA_INLINE const typename T::Scalar* operator()() const { return params_.addr_; }
0671     using NoParamReturnType = typename T::Scalar*;
0672     //SOA_HOST_DEVICE SOA_INLINE T operator()(size_type index) const { return params_.addr_[index]; }
0673 
0674   private:
0675     SoAConstParametersImpl<SoAColumnType::eigen, T> params_;
0676   };
0677 
0678   /* A helper template stager to avoid commas inside macros */
0679   template <typename T>
0680   struct SoAAccessors {
0681     template <auto columnType>
0682     struct ColumnType {
0683       template <auto accessType>
0684       struct AccessType : public SoAColumnAccessorsImpl<T, columnType, accessType> {
0685         using SoAColumnAccessorsImpl<T, columnType, accessType>::SoAColumnAccessorsImpl;
0686       };
0687     };
0688   };
0689 
0690   /* Enum parameters allowing templated control of layout/view behaviors */
0691   /* Alignment enforcement verifies every column is aligned, and
0692    * hints the compiler that it can expect column pointers to be aligned */
0693   struct AlignmentEnforcement {
0694     static constexpr bool relaxed = false;
0695     static constexpr bool enforced = true;
0696   };
0697 
0698   struct CacheLineSize {
0699     static constexpr byte_size_type NvidiaGPU = 128;
0700     static constexpr byte_size_type IntelCPU = 64;
0701     static constexpr byte_size_type AMDCPU = 64;
0702     static constexpr byte_size_type ARMCPU = 64;
0703     static constexpr byte_size_type defaultSize = NvidiaGPU;
0704   };
0705 
0706 }  // namespace cms::soa
0707 
0708 // Small wrapper for stream insertion of SoA printing
0709 template <typename SOA,
0710           typename SFINAE =
0711               typename std::enable_if_t<std::is_invocable_v<decltype(&SOA::soaToStreamInternal), SOA&, std::ostream&>>>
0712 SOA_HOST_ONLY std::ostream& operator<<(std::ostream& os, const SOA& soa) {
0713   soa.soaToStreamInternal(os);
0714   return os;
0715 }
0716 
0717 #endif  // DataFormats_SoATemplate_interface_SoACommon_h