Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2025-06-26 23:26:39

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