Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2025-05-04 22:50:31

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