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