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