CMS 3D CMS Logo

SoALayout.h
Go to the documentation of this file.
1 #ifndef DataFormats_SoATemplate_interface_SoALayout_h
2 #define DataFormats_SoATemplate_interface_SoALayout_h
3 
4 /*
5  * Structure-of-Arrays template with "columns" and "scalars", defined through preprocessor macros,
6  * with compile-time size and alignment, and accessors to the "rows" and "columns".
7  */
8 
9 #include <cassert>
10 
12 
13 #include "SoACommon.h"
14 #include "SoAView.h"
15 
16 /* dump SoA fields information; these should expand to, for columns:
17  * Example:
18  * GENERATE_SOA_LAYOUT(SoA,
19  * // predefined static scalars
20  * // size_t size;
21  * // size_t alignment;
22  *
23  * // columns: one value per element
24  * SOA_COLUMN(double, x),
25  * SOA_COLUMN(double, y),
26  * SOA_COLUMN(double, z),
27  * SOA_EIGEN_COLUMN(Eigen::Vector3d, a),
28  * SOA_EIGEN_COLUMN(Eigen::Vector3d, b),
29  * SOA_EIGEN_COLUMN(Eigen::Vector3d, r),
30  * SOA_COLUMN(uint16_t, colour),
31  * SOA_COLUMN(int32_t, value),
32  * SOA_COLUMN(double *, py),
33  * SOA_COLUMN(uint32_t, count),
34  * SOA_COLUMN(uint32_t, anotherCount),
35  *
36  * // scalars: one value for the whole structure
37  * SOA_SCALAR(const char *, description),
38  * SOA_SCALAR(uint32_t, someNumber)
39  * );
40  *
41  * dumps as:
42  * SoA(32, 64):
43  * sizeof(SoA): 152
44  * Column x_ at offset 0 has size 256 and padding 0
45  * Column y_ at offset 256 has size 256 and padding 0
46  * Column z_ at offset 512 has size 256 and padding 0
47  * Eigen value a_ at offset 768 has dimension (3 x 1) and per column size 256 and padding 0
48  * Eigen value b_ at offset 1536 has dimension (3 x 1) and per column size 256 and padding 0
49  * Eigen value r_ at offset 2304 has dimension (3 x 1) and per column size 256 and padding 0
50  * Column colour_ at offset 3072 has size 64 and padding 0
51  * Column value_ at offset 3136 has size 128 and padding 0
52  * Column py_ at offset 3264 has size 256 and padding 0
53  * Column count_ at offset 3520 has size 128 and padding 0
54  * Column anotherCount_ at offset 3648 has size 128 and padding 0
55  * Scalar description_ at offset 3776 has size 8 and padding 56
56  * Scalar someNumber_ at offset 3840 has size 4 and padding 60
57  * Final offset = 3904 computeDataSize(...): 3904
58  *
59  */
60 
61 // clang-format off
62 #define _DECLARE_SOA_STREAM_INFO_IMPL(VALUE_TYPE, CPP_TYPE, NAME) \
63  _SWITCH_ON_TYPE( \
64  VALUE_TYPE, \
65  /* Dump scalar */ \
66  _soa_impl_os << " Scalar " BOOST_PP_STRINGIZE(NAME) " at offset " << _soa_impl_offset \
67  << " has size " << sizeof(CPP_TYPE) \
68  << " and padding " << ((sizeof(CPP_TYPE) - 1) / alignment + 1) * alignment - sizeof(CPP_TYPE) \
69  << std::endl; \
70  _soa_impl_offset += ((sizeof(CPP_TYPE) - 1) / alignment + 1) * alignment; \
71  , \
72  /* Dump column */ \
73  _soa_impl_os << " Column " BOOST_PP_STRINGIZE(NAME) " at offset " << _soa_impl_offset << " has size " \
74  << sizeof(CPP_TYPE) * elements_ << " and padding " \
75  << cms::soa::alignSize(elements_ * sizeof(CPP_TYPE), alignment) - (elements_ * sizeof(CPP_TYPE)) \
76  << std::endl; \
77  _soa_impl_offset += cms::soa::alignSize(elements_ * sizeof(CPP_TYPE), alignment); \
78  , \
79  /* Dump Eigen column */ \
80  _soa_impl_os << " Eigen value " BOOST_PP_STRINGIZE(NAME) " at offset " << _soa_impl_offset << " has dimension " \
81  << "(" << CPP_TYPE::RowsAtCompileTime << " x " << CPP_TYPE::ColsAtCompileTime << ")" \
82  << " and per column size " \
83  << sizeof(CPP_TYPE::Scalar) * elements_ \
84  << " and padding " \
85  << cms::soa::alignSize(elements_ * sizeof(CPP_TYPE::Scalar), alignment) \
86  - (elements_ * sizeof(CPP_TYPE::Scalar)) \
87  << std::endl; \
88  _soa_impl_offset += cms::soa::alignSize(elements_ * sizeof(CPP_TYPE::Scalar), alignment) \
89  * CPP_TYPE::RowsAtCompileTime * CPP_TYPE::ColsAtCompileTime; \
90  )
91 // clang-format on
92 
93 #define _DECLARE_SOA_STREAM_INFO(R, DATA, TYPE_NAME) BOOST_PP_EXPAND(_DECLARE_SOA_STREAM_INFO_IMPL TYPE_NAME)
94 
98 // clang-format off
99 #define _DEFINE_METADATA_MEMBERS_IMPL(VALUE_TYPE, CPP_TYPE, NAME) \
100  _SWITCH_ON_TYPE(VALUE_TYPE, \
101  /* Scalar */ \
102  byte_size_type BOOST_PP_CAT(NAME, Pitch()) const { \
103  return cms::soa::alignSize(sizeof(CPP_TYPE), ParentClass::alignment); \
104  } \
105  using BOOST_PP_CAT(TypeOf_, NAME) = CPP_TYPE; \
106  constexpr static cms::soa::SoAColumnType BOOST_PP_CAT(ColumnTypeOf_, NAME) = cms::soa::SoAColumnType::scalar; \
107  SOA_HOST_DEVICE SOA_INLINE \
108  CPP_TYPE const* BOOST_PP_CAT(addressOf_, NAME)() const { \
109  return parent_.metadata().BOOST_PP_CAT(parametersOf_, NAME)().addr_; \
110  } \
111  using BOOST_PP_CAT(ParametersTypeOf_, NAME) = \
112  cms::soa::SoAParameters_ColumnType<cms::soa::SoAColumnType::scalar>::DataType<CPP_TYPE>; \
113  SOA_HOST_DEVICE SOA_INLINE \
114  BOOST_PP_CAT(ParametersTypeOf_, NAME) BOOST_PP_CAT(parametersOf_, NAME)() const { \
115  return BOOST_PP_CAT(ParametersTypeOf_, NAME) (parent_.BOOST_PP_CAT(NAME, _)); \
116  } \
117  SOA_HOST_DEVICE SOA_INLINE \
118  CPP_TYPE* BOOST_PP_CAT(addressOf_, NAME)() { \
119  return parent_.metadata().BOOST_PP_CAT(parametersOf_, NAME)().addr_; \
120  }, \
121  /* Column */ \
122  using BOOST_PP_CAT(ParametersTypeOf_, NAME) = \
123  cms::soa::SoAParameters_ColumnType<cms::soa::SoAColumnType::column>::DataType<CPP_TYPE>; \
124  SOA_HOST_DEVICE SOA_INLINE \
125  BOOST_PP_CAT(ParametersTypeOf_, NAME) BOOST_PP_CAT(parametersOf_, NAME)() const { \
126  return BOOST_PP_CAT(ParametersTypeOf_, NAME) (parent_.BOOST_PP_CAT(NAME, _)); \
127  } \
128  SOA_HOST_DEVICE SOA_INLINE \
129  CPP_TYPE const* BOOST_PP_CAT(addressOf_, NAME)() const { \
130  return parent_.metadata().BOOST_PP_CAT(parametersOf_, NAME)().addr_; \
131  } \
132  SOA_HOST_DEVICE SOA_INLINE \
133  CPP_TYPE* BOOST_PP_CAT(addressOf_, NAME)() { \
134  return parent_.metadata().BOOST_PP_CAT(parametersOf_, NAME)().addr_; \
135  } \
136  SOA_HOST_DEVICE SOA_INLINE \
137  byte_size_type BOOST_PP_CAT(NAME, Pitch()) const { \
138  return cms::soa::alignSize(parent_.elements_ * sizeof(CPP_TYPE), ParentClass::alignment); \
139  } \
140  using BOOST_PP_CAT(TypeOf_, NAME) = CPP_TYPE; \
141  constexpr static cms::soa::SoAColumnType BOOST_PP_CAT(ColumnTypeOf_, NAME) = cms::soa::SoAColumnType::column;, \
142  /* Eigen column */ \
143  using BOOST_PP_CAT(ParametersTypeOf_, NAME) = \
144  cms::soa::SoAParameters_ColumnType<cms::soa::SoAColumnType::eigen>::DataType<CPP_TYPE>; \
145  SOA_HOST_DEVICE SOA_INLINE \
146  BOOST_PP_CAT(ParametersTypeOf_, NAME) BOOST_PP_CAT(parametersOf_, NAME)() const { \
147  return BOOST_PP_CAT(ParametersTypeOf_, NAME) ( \
148  parent_.BOOST_PP_CAT(NAME, _), \
149  parent_.BOOST_PP_CAT(NAME, Stride_)); \
150  } \
151  SOA_HOST_DEVICE SOA_INLINE \
152  byte_size_type BOOST_PP_CAT(NAME, Pitch()) const { \
153  return cms::soa::alignSize(parent_.elements_ * sizeof(CPP_TYPE::Scalar), ParentClass::alignment) \
154  * CPP_TYPE::RowsAtCompileTime * CPP_TYPE::ColsAtCompileTime; \
155  } \
156  using BOOST_PP_CAT(TypeOf_, NAME) = CPP_TYPE ; \
157  constexpr static cms::soa::SoAColumnType BOOST_PP_CAT(ColumnTypeOf_, NAME) = cms::soa::SoAColumnType::eigen; \
158  SOA_HOST_DEVICE SOA_INLINE \
159  CPP_TYPE::Scalar const* BOOST_PP_CAT(addressOf_, NAME)() const { \
160  return parent_.metadata().BOOST_PP_CAT(parametersOf_, NAME)().addr_; \
161  } \
162  SOA_HOST_DEVICE SOA_INLINE \
163  CPP_TYPE::Scalar* BOOST_PP_CAT(addressOf_, NAME)() { \
164  return parent_.metadata().BOOST_PP_CAT(parametersOf_, NAME)().addr_; \
165  } \
166 )
167 // clang-format on
168 #define _DEFINE_METADATA_MEMBERS(R, DATA, TYPE_NAME) _DEFINE_METADATA_MEMBERS_IMPL TYPE_NAME
169 
170 // clang-format off
171 #define _DECLARE_MEMBER_TRIVIAL_CONSTRUCTION_IMPL(VALUE_TYPE, CPP_TYPE, NAME) \
172  _SWITCH_ON_TYPE(VALUE_TYPE, \
173  /* Scalar */ \
174  (BOOST_PP_CAT(NAME, _)(nullptr)), \
175  /* Column */ \
176  (BOOST_PP_CAT(NAME, _)(nullptr)), \
177  /* Eigen column */ \
178  (BOOST_PP_CAT(NAME, ElementsWithPadding_)(0)) \
179  (BOOST_PP_CAT(NAME, _)(nullptr)) \
180  (BOOST_PP_CAT(NAME, Stride_)(0)) \
181  )
182 // clang-format on
183 
184 #define _DECLARE_MEMBER_TRIVIAL_CONSTRUCTION(R, DATA, TYPE_NAME) \
185  BOOST_PP_EXPAND(_DECLARE_MEMBER_TRIVIAL_CONSTRUCTION_IMPL TYPE_NAME)
186 
187 // clang-format off
188 #define _DECLARE_MEMBER_COPY_CONSTRUCTION_IMPL(VALUE_TYPE, CPP_TYPE, NAME) \
189  _SWITCH_ON_TYPE(VALUE_TYPE, \
190  /* Scalar */ \
191  (BOOST_PP_CAT(NAME, _){_soa_impl_other.BOOST_PP_CAT(NAME, _)}), \
192  /* Column */ \
193  (BOOST_PP_CAT(NAME, _){_soa_impl_other.BOOST_PP_CAT(NAME, _)}), \
194  /* Eigen column */ \
195  (BOOST_PP_CAT(NAME, ElementsWithPadding_){_soa_impl_other.BOOST_PP_CAT(NAME, ElementsWithPadding_)}) \
196  (BOOST_PP_CAT(NAME, _){_soa_impl_other.BOOST_PP_CAT(NAME, _)}) \
197  (BOOST_PP_CAT(NAME, Stride_){_soa_impl_other.BOOST_PP_CAT(NAME, Stride_)}) \
198  )
199 // clang-format on
200 
201 #define _DECLARE_MEMBER_COPY_CONSTRUCTION(R, DATA, TYPE_NAME) \
202  BOOST_PP_EXPAND(_DECLARE_MEMBER_COPY_CONSTRUCTION_IMPL TYPE_NAME)
203 
204 // clang-format off
205 #define _DECLARE_MEMBER_ASSIGNMENT_IMPL(VALUE_TYPE, CPP_TYPE, NAME) \
206  _SWITCH_ON_TYPE(VALUE_TYPE, \
207  /* Scalar */ \
208  BOOST_PP_CAT(NAME, _) = _soa_impl_other.BOOST_PP_CAT(NAME, _);, \
209  /* Column */ \
210  BOOST_PP_CAT(NAME, _) = _soa_impl_other.BOOST_PP_CAT(NAME, _);, \
211  /* Eigen column */ \
212  BOOST_PP_CAT(NAME, ElementsWithPadding_) = _soa_impl_other.BOOST_PP_CAT(NAME, ElementsWithPadding_); \
213  BOOST_PP_CAT(NAME, _) = _soa_impl_other.BOOST_PP_CAT(NAME, _); \
214  BOOST_PP_CAT(NAME, Stride_) = _soa_impl_other.BOOST_PP_CAT(NAME, Stride_); \
215  )
216 // clang-format on
217 
218 #define _DECLARE_MEMBER_ASSIGNMENT(R, DATA, TYPE_NAME) BOOST_PP_EXPAND(_DECLARE_MEMBER_ASSIGNMENT_IMPL TYPE_NAME)
219 
223 // clang-format off
224 #define _DEFINE_VALUE_ELEMENT_MEMBERS_IMPL(VALUE_TYPE, CPP_TYPE, NAME) \
225  _SWITCH_ON_TYPE(VALUE_TYPE, \
226  /* Scalar (empty) */ \
227  , \
228  /* Column */ \
229  CPP_TYPE NAME; \
230  , \
231  /* Eigen column */ \
232  CPP_TYPE NAME; \
233  )
234 // clang-format on
235 
236 #define _DEFINE_VALUE_ELEMENT_MEMBERS(R, DATA, TYPE_NAME) _DEFINE_VALUE_ELEMENT_MEMBERS_IMPL TYPE_NAME
237 
241 // clang-format off
242 #define _VALUE_ELEMENT_CTOR_ARGS_IMPL(VALUE_TYPE, CPP_TYPE, NAME) \
243  _SWITCH_ON_TYPE(VALUE_TYPE, \
244  /* Scalar (empty) */ \
245  , \
246  /* Column */ \
247  (CPP_TYPE NAME), \
248  /* Eigen column */ \
249  (CPP_TYPE NAME) \
250  )
251 // clang-format on
252 
253 #define _VALUE_ELEMENT_CTOR_ARGS(R, DATA, TYPE_NAME) BOOST_PP_EXPAND(_VALUE_ELEMENT_CTOR_ARGS_IMPL TYPE_NAME)
254 
258 // clang-format off
259 #define _VALUE_ELEMENT_INITIALIZERS_IMPL(VALUE_TYPE, CPP_TYPE, NAME) \
260  _SWITCH_ON_TYPE(VALUE_TYPE, \
261  /* Scalar (empty) */ \
262  , \
263  /* Column */ \
264  (NAME{NAME}), \
265  /* Eigen column */ \
266  (NAME{NAME}) \
267  )
268 // clang-format on
269 
270 #define _VALUE_ELEMENT_INITIALIZERS(R, DATA, TYPE_NAME) BOOST_PP_EXPAND(_VALUE_ELEMENT_INITIALIZERS_IMPL TYPE_NAME)
271 
275 // clang-format off
276 #define _ROOT_FREE_SOA_COLUMN_OR_SCALAR_IMPL(VALUE_TYPE, CPP_TYPE, NAME) \
277  delete[] BOOST_PP_CAT(NAME, _); \
278  BOOST_PP_CAT(NAME, _) = nullptr; \
279  // clang-format on
280 
281 #define _ROOT_FREE_SOA_COLUMN_OR_SCALAR(R, DATA, TYPE_NAME) _ROOT_FREE_SOA_COLUMN_OR_SCALAR_IMPL TYPE_NAME
282 
286 // clang-format off
287 #define _ASSIGN_SOA_COLUMN_OR_SCALAR_IMPL(VALUE_TYPE, CPP_TYPE, NAME) \
288  _SWITCH_ON_TYPE(VALUE_TYPE, \
289  /* Scalar */ \
290  BOOST_PP_CAT(NAME, _) = reinterpret_cast<CPP_TYPE*>(_soa_impl_curMem); \
291  _soa_impl_curMem += cms::soa::alignSize(sizeof(CPP_TYPE), alignment); \
292  , \
293  /* Column */ \
294  BOOST_PP_CAT(NAME, _) = reinterpret_cast<CPP_TYPE*>(_soa_impl_curMem); \
295  _soa_impl_curMem += cms::soa::alignSize(elements_ * sizeof(CPP_TYPE), alignment); \
296  , \
297  /* Eigen column */ \
298  BOOST_PP_CAT(NAME, Stride_) = cms::soa::alignSize(elements_ * sizeof(CPP_TYPE::Scalar), alignment) \
299  / sizeof(CPP_TYPE::Scalar); \
300  BOOST_PP_CAT(NAME, ElementsWithPadding_) = BOOST_PP_CAT(NAME, Stride_) \
301  * CPP_TYPE::RowsAtCompileTime * CPP_TYPE::ColsAtCompileTime; \
302  BOOST_PP_CAT(NAME, _) = reinterpret_cast<CPP_TYPE::Scalar*>(_soa_impl_curMem); \
303  _soa_impl_curMem += cms::soa::alignSize(elements_ * sizeof(CPP_TYPE::Scalar), alignment) \
304  * CPP_TYPE::RowsAtCompileTime * CPP_TYPE::ColsAtCompileTime; \
305  ) \
306  if constexpr (alignmentEnforcement == AlignmentEnforcement::enforced) \
307  if (reinterpret_cast<intptr_t>(BOOST_PP_CAT(NAME, _)) % alignment) \
308  throw std::runtime_error("In layout constructor: misaligned column: " #NAME);
309 // clang-format on
310 
311 #define _ASSIGN_SOA_COLUMN_OR_SCALAR(R, DATA, TYPE_NAME) _ASSIGN_SOA_COLUMN_OR_SCALAR_IMPL TYPE_NAME
312 
316 // clang-format off
317 #define _ACCUMULATE_SOA_ELEMENT_IMPL(VALUE_TYPE, CPP_TYPE, NAME) \
318  _SWITCH_ON_TYPE(VALUE_TYPE, \
319  /* Scalar */ \
320  _soa_impl_ret += cms::soa::alignSize(sizeof(CPP_TYPE), alignment); \
321  , \
322  /* Column */ \
323  _soa_impl_ret += cms::soa::alignSize(elements * sizeof(CPP_TYPE), alignment); \
324  , \
325  /* Eigen column */ \
326  _soa_impl_ret += cms::soa::alignSize(elements * sizeof(CPP_TYPE::Scalar), alignment) \
327  * CPP_TYPE::RowsAtCompileTime * CPP_TYPE::ColsAtCompileTime; \
328  )
329 // clang-format on
330 
331 #define _ACCUMULATE_SOA_ELEMENT(R, DATA, TYPE_NAME) _ACCUMULATE_SOA_ELEMENT_IMPL TYPE_NAME
332 
336 // clang-format off
337 #define _DECLARE_SOA_ACCESSOR_IMPL(VALUE_TYPE, CPP_TYPE, NAME) \
338  _SWITCH_ON_TYPE(VALUE_TYPE, \
339  /* Scalar */ \
340  SOA_HOST_DEVICE SOA_INLINE CPP_TYPE& NAME() { return *BOOST_PP_CAT(NAME, _); } \
341  , \
342  /* Column */ \
343  SOA_HOST_DEVICE SOA_INLINE CPP_TYPE* NAME() { return BOOST_PP_CAT(NAME, _); } \
344  SOA_HOST_DEVICE SOA_INLINE CPP_TYPE& NAME(size_type _soa_impl_index) { \
345  return BOOST_PP_CAT(NAME, _)[_soa_impl_index]; \
346  } \
347  , \
348  /* Eigen column */ \
349  /* TODO: implement*/ \
350  BOOST_PP_EMPTY() \
351  )
352 // clang-format on
353 
354 #define _DECLARE_SOA_ACCESSOR(R, DATA, TYPE_NAME) BOOST_PP_EXPAND(_DECLARE_SOA_ACCESSOR_IMPL TYPE_NAME)
355 
359 // clang-format off
360 #define _DECLARE_SOA_CONST_ACCESSOR_IMPL(VALUE_TYPE, CPP_TYPE, NAME) \
361  _SWITCH_ON_TYPE(VALUE_TYPE, \
362  /* Scalar */ \
363  SOA_HOST_DEVICE SOA_INLINE CPP_TYPE NAME() const { return *(BOOST_PP_CAT(NAME, _)); } \
364  , \
365  /* Column */ \
366  SOA_HOST_DEVICE SOA_INLINE CPP_TYPE const* NAME() const { return BOOST_PP_CAT(NAME, _); } \
367  SOA_HOST_DEVICE SOA_INLINE CPP_TYPE NAME(size_type _soa_impl_index) const { \
368  return *(BOOST_PP_CAT(NAME, _) + _soa_impl_index); \
369  } \
370  , \
371  /* Eigen column */ \
372  SOA_HOST_DEVICE SOA_INLINE CPP_TYPE::Scalar const* NAME() const { return BOOST_PP_CAT(NAME, _); } \
373  SOA_HOST_DEVICE SOA_INLINE size_type BOOST_PP_CAT(NAME, Stride)() { return BOOST_PP_CAT(NAME, Stride_); } \
374  )
375 // clang-format on
376 
377 #define _DECLARE_SOA_CONST_ACCESSOR(R, DATA, TYPE_NAME) BOOST_PP_EXPAND(_DECLARE_SOA_CONST_ACCESSOR_IMPL TYPE_NAME)
378 
382 // clang-format off
383 #define _STREAMER_READ_SOA_DATA_MEMBER_IMPL(VALUE_TYPE, CPP_TYPE, NAME) \
384  _SWITCH_ON_TYPE(VALUE_TYPE, \
385  /* Scalar */ \
386  memcpy(BOOST_PP_CAT(NAME, _), onfile.BOOST_PP_CAT(NAME, _), sizeof(CPP_TYPE)); \
387  , \
388  /* Column */ \
389  memcpy(BOOST_PP_CAT(NAME, _), onfile.BOOST_PP_CAT(NAME, _), sizeof(CPP_TYPE) * onfile.elements_); \
390  , \
391  /* Eigen column */ \
392  memcpy(BOOST_PP_CAT(NAME, _), onfile.BOOST_PP_CAT(NAME, _), \
393  sizeof(CPP_TYPE::Scalar) * BOOST_PP_CAT(NAME, ElementsWithPadding_)); \
394  )
395 // clang-format on
396 
397 #define _STREAMER_READ_SOA_DATA_MEMBER(R, DATA, TYPE_NAME) \
398  BOOST_PP_EXPAND(_STREAMER_READ_SOA_DATA_MEMBER_IMPL TYPE_NAME)
399 
403 // clang-format off
404 #define _DECLARE_SOA_DATA_MEMBER_IMPL(VALUE_TYPE, CPP_TYPE, NAME) \
405  _SWITCH_ON_TYPE(VALUE_TYPE, \
406  /* Scalar */ \
407  CPP_TYPE* BOOST_PP_CAT(NAME, _) EDM_REFLEX_SIZE(scalar_) = nullptr; \
408  , \
409  /* Column */ \
410  CPP_TYPE * BOOST_PP_CAT(NAME, _) EDM_REFLEX_SIZE(elements_) = nullptr; \
411  , \
412  /* Eigen column */ \
413  size_type BOOST_PP_CAT(NAME, ElementsWithPadding_) = 0; /* For ROOT serialization */ \
414  CPP_TYPE::Scalar * BOOST_PP_CAT(NAME, _) EDM_REFLEX_SIZE(BOOST_PP_CAT(NAME, ElementsWithPadding_)) = nullptr; \
415  byte_size_type BOOST_PP_CAT(NAME, Stride_) = 0; \
416  )
417 // clang-format on
418 
419 #define _DECLARE_SOA_DATA_MEMBER(R, DATA, TYPE_NAME) BOOST_PP_EXPAND(_DECLARE_SOA_DATA_MEMBER_IMPL TYPE_NAME)
420 
421 #ifdef DEBUG
422 #define _DO_RANGECHECK true
423 #else
424 #define _DO_RANGECHECK false
425 #endif
426 
427 /*
428  * A macro defining a SoA layout (collection of scalars and columns of equal lengths)
429  */
430 // clang-format off
431 #define GENERATE_SOA_LAYOUT(CLASS, ...) \
432  template <CMS_SOA_BYTE_SIZE_TYPE ALIGNMENT = cms::soa::CacheLineSize::defaultSize, \
433  bool ALIGNMENT_ENFORCEMENT = cms::soa::AlignmentEnforcement::relaxed> \
434  struct CLASS { \
435  /* these could be moved to an external type trait to free up the symbol names */ \
436  using self_type = CLASS; \
437  using AlignmentEnforcement = cms::soa::AlignmentEnforcement; \
438  \
439  /* For CUDA applications, we align to the 128 bytes of the cache lines. \
440  * See https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#global-memory-3-0 this is still valid \
441  * up to compute capability 8.X. \
442  */ \
443  using size_type = cms::soa::size_type; \
444  using byte_size_type = cms::soa::byte_size_type; \
445  constexpr static byte_size_type defaultAlignment = 128; \
446  constexpr static byte_size_type alignment = ALIGNMENT; \
447  constexpr static bool alignmentEnforcement = ALIGNMENT_ENFORCEMENT; \
448  constexpr static byte_size_type conditionalAlignment = \
449  alignmentEnforcement == cms::soa::AlignmentEnforcement::enforced ? alignment : 0; \
450  /* Those typedefs avoid having commas in macros (which is problematic) */ \
451  template <cms::soa::SoAColumnType COLUMN_TYPE, class C> \
452  using SoAValueWithConf = cms::soa::SoAValue<COLUMN_TYPE, C, conditionalAlignment>; \
453  \
454  template <cms::soa::SoAColumnType COLUMN_TYPE, class C> \
455  using SoAConstValueWithConf = cms::soa::SoAConstValue<COLUMN_TYPE, C, conditionalAlignment>; \
456  \
457  template <CMS_SOA_BYTE_SIZE_TYPE VIEW_ALIGNMENT = cms::soa::CacheLineSize::defaultSize, \
458  bool VIEW_ALIGNMENT_ENFORCEMENT = cms::soa::AlignmentEnforcement::relaxed, \
459  bool RESTRICT_QUALIFY = cms::soa::RestrictQualify::enabled, \
460  bool RANGE_CHECKING = cms::soa::RangeChecking::disabled> \
461  struct ViewTemplateFreeParams; \
462  \
463  /* dump the SoA internal structure */ \
464  SOA_HOST_ONLY \
465  void soaToStreamInternal(std::ostream & _soa_impl_os) const { \
466  _soa_impl_os << #CLASS "(" << elements_ << " elements, byte alignement= " << alignment << ", @"<< mem_ <<"): " \
467  << std::endl; \
468  _soa_impl_os << " sizeof(" #CLASS "): " << sizeof(CLASS) << std::endl; \
469  byte_size_type _soa_impl_offset = 0; \
470  _ITERATE_ON_ALL(_DECLARE_SOA_STREAM_INFO, ~, __VA_ARGS__) \
471  _soa_impl_os << "Final offset = " << _soa_impl_offset << " computeDataSize(...): " << computeDataSize(elements_) \
472  << std::endl; \
473  _soa_impl_os << std::endl; \
474  } \
475  \
476  /* Helper function used by caller to externally allocate the storage */ \
477  static constexpr byte_size_type computeDataSize(size_type elements) { \
478  byte_size_type _soa_impl_ret = 0; \
479  _ITERATE_ON_ALL(_ACCUMULATE_SOA_ELEMENT, ~, __VA_ARGS__) \
480  return _soa_impl_ret; \
481  } \
482  \
483  \
486  struct Metadata { \
487  friend CLASS; \
488  SOA_HOST_DEVICE SOA_INLINE size_type size() const { return parent_.elements_; } \
489  SOA_HOST_DEVICE SOA_INLINE byte_size_type byteSize() const { return parent_.byteSize_; } \
490  SOA_HOST_DEVICE SOA_INLINE byte_size_type alignment() const { return CLASS::alignment; } \
491  SOA_HOST_DEVICE SOA_INLINE std::byte* data() { return parent_.mem_; } \
492  SOA_HOST_DEVICE SOA_INLINE const std::byte* data() const { return parent_.mem_; } \
493  SOA_HOST_DEVICE SOA_INLINE std::byte* nextByte() const { return parent_.mem_ + parent_.byteSize_; } \
494  SOA_HOST_DEVICE SOA_INLINE CLASS cloneToNewAddress(std::byte* _soa_impl_addr) const { \
495  return CLASS(_soa_impl_addr, parent_.elements_); \
496  } \
497  \
498  _ITERATE_ON_ALL(_DEFINE_METADATA_MEMBERS, ~, __VA_ARGS__) \
499  \
500  struct value_element { \
501  SOA_HOST_DEVICE SOA_INLINE value_element \
502  BOOST_PP_IF( \
503  BOOST_PP_SEQ_SIZE(_ITERATE_ON_ALL(_VALUE_ELEMENT_CTOR_ARGS, ~, __VA_ARGS__) ), \
504  (_ITERATE_ON_ALL_COMMA(_VALUE_ELEMENT_CTOR_ARGS, ~, __VA_ARGS__)):, \
505  ()) \
506  BOOST_PP_TUPLE_ENUM(BOOST_PP_IF( \
507  BOOST_PP_SEQ_SIZE(_ITERATE_ON_ALL(_VALUE_ELEMENT_CTOR_ARGS, ~, __VA_ARGS__)), \
508  BOOST_PP_SEQ_TO_TUPLE(_ITERATE_ON_ALL(_VALUE_ELEMENT_INITIALIZERS, ~, __VA_ARGS__)), \
509  () \
510  ) \
511  ) \
512  {} \
513  \
514  _ITERATE_ON_ALL(_DEFINE_VALUE_ELEMENT_MEMBERS, ~, __VA_ARGS__) \
515  }; \
516  \
517  Metadata& operator=(const Metadata&) = delete; \
518  Metadata(const Metadata&) = delete; \
519  \
520  private: \
521  SOA_HOST_DEVICE SOA_INLINE Metadata(const CLASS& _soa_impl_parent) : parent_(_soa_impl_parent) {} \
522  const CLASS& parent_; \
523  using ParentClass = CLASS; \
524  }; \
525  \
526  friend Metadata; \
527  \
528  SOA_HOST_DEVICE SOA_INLINE const Metadata metadata() const { return Metadata(*this); } \
529  SOA_HOST_DEVICE SOA_INLINE Metadata metadata() { return Metadata(*this); } \
530  \
531  /* Generate the ConstView template */ \
532  _GENERATE_SOA_TRIVIAL_CONST_VIEW(CLASS, \
533  SOA_VIEW_LAYOUT_LIST( \
534  SOA_VIEW_LAYOUT(BOOST_PP_CAT(CLASS, _parametrized) , BOOST_PP_CAT(instance_, CLASS))), \
535  SOA_VIEW_VALUE_LIST(_ITERATE_ON_ALL_COMMA( \
536  _VIEW_FIELD_FROM_LAYOUT, BOOST_PP_CAT(instance_, CLASS), __VA_ARGS__))) \
537  \
538  template <bool RESTRICT_QUALIFY, bool RANGE_CHECKING> \
539  using ConstViewTemplate = ConstViewTemplateFreeParams<ALIGNMENT, ALIGNMENT_ENFORCEMENT, RESTRICT_QUALIFY, \
540  RANGE_CHECKING>; \
541  \
542  using ConstView = ConstViewTemplate<cms::soa::RestrictQualify::enabled, cms::soa::RangeChecking::disabled>; \
543  \
544  /* Generate the mutable View template */ \
545  _GENERATE_SOA_TRIVIAL_VIEW(CLASS, \
546  SOA_VIEW_LAYOUT_LIST( \
547  SOA_VIEW_LAYOUT(BOOST_PP_CAT(CLASS, _parametrized), BOOST_PP_CAT(instance_, CLASS))), \
548  SOA_VIEW_VALUE_LIST(_ITERATE_ON_ALL_COMMA( \
549  _VIEW_FIELD_FROM_LAYOUT, BOOST_PP_CAT(instance_, CLASS), __VA_ARGS__)), \
550  __VA_ARGS__) \
551  \
552  template <bool RESTRICT_QUALIFY, bool RANGE_CHECKING> \
553  using ViewTemplate = ViewTemplateFreeParams<ALIGNMENT, ALIGNMENT_ENFORCEMENT, RESTRICT_QUALIFY, RANGE_CHECKING>; \
554  \
555  using View = ViewTemplate<cms::soa::RestrictQualify::enabled, cms::soa::RangeChecking::disabled>; \
556  \
557  /* Trivial constuctor */ \
558  CLASS() \
559  : mem_(nullptr), \
560  elements_(0), \
561  byteSize_(0), \
562  _ITERATE_ON_ALL_COMMA(_DECLARE_MEMBER_TRIVIAL_CONSTRUCTION, ~, __VA_ARGS__) {} \
563  \
564  /* Constructor relying on user provided storage (implementation shared with ROOT streamer) */ \
565  SOA_HOST_ONLY CLASS(std::byte* mem, size_type elements) : mem_(mem), elements_(elements), byteSize_(0) { \
566  organizeColumnsFromBuffer(); \
567  } \
568  \
569  /* Explicit copy constructor and assignment operator */ \
570  SOA_HOST_ONLY CLASS(CLASS const& _soa_impl_other) \
571  : mem_(_soa_impl_other.mem_), \
572  elements_(_soa_impl_other.elements_), \
573  byteSize_(_soa_impl_other.byteSize_), \
574  _ITERATE_ON_ALL_COMMA(_DECLARE_MEMBER_COPY_CONSTRUCTION, ~, __VA_ARGS__) {} \
575  \
576  SOA_HOST_ONLY CLASS& operator=(CLASS const& _soa_impl_other) { \
577  mem_ = _soa_impl_other.mem_; \
578  elements_ = _soa_impl_other.elements_; \
579  byteSize_ = _soa_impl_other.byteSize_; \
580  _ITERATE_ON_ALL(_DECLARE_MEMBER_ASSIGNMENT, ~, __VA_ARGS__) \
581  return *this; \
582  } \
583  \
584  /* ROOT read streamer */ \
585  template <typename T> \
586  void ROOTReadStreamer(T & onfile) { \
587  _ITERATE_ON_ALL(_STREAMER_READ_SOA_DATA_MEMBER, ~, __VA_ARGS__) \
588  } \
589  \
590  /* ROOT allocation cleanup */ \
591  void ROOTStreamerCleaner() { \
592  /* This function should only be called from the PortableCollection ROOT streamer */ \
593  _ITERATE_ON_ALL(_ROOT_FREE_SOA_COLUMN_OR_SCALAR, ~, __VA_ARGS__) \
594  } \
595  \
596  /* Dump the SoA internal structure */ \
597  template <typename T> \
598  SOA_HOST_ONLY friend void dump(); \
599  \
600  private: \
601  /* Helper method for the user provided storage constructor and ROOT streamer */ \
602  void organizeColumnsFromBuffer() { \
603  if constexpr (alignmentEnforcement == cms::soa::AlignmentEnforcement::enforced) \
604  if (reinterpret_cast<intptr_t>(mem_) % alignment) \
605  throw std::runtime_error("In " #CLASS "::" #CLASS ": misaligned buffer"); \
606  auto _soa_impl_curMem = mem_; \
607  _ITERATE_ON_ALL(_ASSIGN_SOA_COLUMN_OR_SCALAR, ~, __VA_ARGS__) \
608  /* Sanity check: we should have reached the computed size, only on host code */ \
609  byteSize_ = computeDataSize(elements_); \
610  if (mem_ + byteSize_ != _soa_impl_curMem) \
611  throw std::runtime_error("In " #CLASS "::" #CLASS ": unexpected end pointer."); \
612  } \
613  \
614  /* Data members */ \
615  std::byte* mem_ EDM_REFLEX_TRANSIENT; \
616  size_type elements_; \
617  size_type const scalar_ = 1; \
618  byte_size_type byteSize_ EDM_REFLEX_TRANSIENT; \
619  _ITERATE_ON_ALL(_DECLARE_SOA_DATA_MEMBER, ~, __VA_ARGS__) \
620  /* Making the code conditional is problematic in macros as the commas will interfere with parameter lisings */ \
621  /* So instead we make the code unconditional with paceholder names which are protected by a private protection. */ \
622  /* This will be handled later as we handle the integration of the view as a subclass of the layout. */ \
623  \
624  };
625 // clang-format on
626 
627 #endif // DataFormats_SoATemplate_interface_SoALayout_h