Logo ROOT   6.18/05
Reference Guide
RField.cxx
Go to the documentation of this file.
1/// \file RField.cxx
2/// \ingroup NTuple ROOT7
3/// \author Jakob Blomer <jblomer@cern.ch>
4/// \date 2018-10-15
5/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
6/// is welcome!
7
8/*************************************************************************
9 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
10 * All rights reserved. *
11 * *
12 * For the licensing terms see $ROOTSYS/LICENSE. *
13 * For the list of contributors see $ROOTSYS/README/CREDITS. *
14 *************************************************************************/
15
16#include <ROOT/RColumn.hxx>
17#include <ROOT/RColumnModel.hxx>
18#include <ROOT/REntry.hxx>
19#include <ROOT/RField.hxx>
20#include <ROOT/RFieldValue.hxx>
21#include <ROOT/RNTuple.hxx>
22#include <ROOT/RNTupleModel.hxx>
23
24#include <TClass.h>
25#include <TCollection.h>
26#include <TDataMember.h>
27#include <TError.h>
28#include <TList.h>
29
30#include <algorithm>
31#include <cctype> // for isspace
32#include <cstdlib> // for malloc, free
33#include <exception>
34#include <iostream>
35#include <utility>
36
39 : fName(name), fType(type), fStructure(structure), fIsSimple(isSimple), fParent(nullptr), fPrincipalColumn(nullptr)
40{
41}
42
44{
45}
46
48ROOT::Experimental::Detail::RFieldBase::Create(const std::string &fieldName, const std::string &typeName)
49{
50 std::string normalizedType(typeName);
51 normalizedType.erase(remove_if(normalizedType.begin(), normalizedType.end(), isspace), normalizedType.end());
52 // TODO(jblomer): use a type translation map
53 if (normalizedType == "Float_t") normalizedType = "float";
54 if (normalizedType == "Double_t") normalizedType = "double";
55 if (normalizedType == "Int_t") normalizedType = "std::int32_t";
56 if (normalizedType == "int") normalizedType = "std::int32_t";
57 if (normalizedType == "unsigned") normalizedType = "std::uint32_t";
58 if (normalizedType == "unsigned int") normalizedType = "std::uint32_t";
59 if (normalizedType == "UInt_t") normalizedType = "std::uint32_t";
60 if (normalizedType == "ULong64_t") normalizedType = "std::uint64_t";
61 if (normalizedType == "string") normalizedType = "std::string";
62 if (normalizedType.substr(0, 7) == "vector<") normalizedType = "std::" + normalizedType;
63
64 if (normalizedType == "ROOT::Experimental::ClusterSize_t") return new RField<ClusterSize_t>(fieldName);
65 if (normalizedType == "std::int32_t") return new RField<std::int32_t>(fieldName);
66 if (normalizedType == "std::uint32_t") return new RField<std::uint32_t>(fieldName);
67 if (normalizedType == "std::uint64_t") return new RField<std::uint64_t>(fieldName);
68 if (normalizedType == "float") return new RField<float>(fieldName);
69 if (normalizedType == "double") return new RField<double>(fieldName);
70 if (normalizedType == "std::string") return new RField<std::string>(fieldName);
71 if (normalizedType.substr(0, 12) == "std::vector<") {
72 std::string itemTypeName = normalizedType.substr(12, normalizedType.length() - 13);
73 auto itemField = Create(GetCollectionName(fieldName), itemTypeName);
74 return new RFieldVector(fieldName, std::unique_ptr<Detail::RFieldBase>(itemField));
75 }
76 // For the time being, we silently read RVec fields as std::vector
77 if (normalizedType.substr(0, 19) == "ROOT::VecOps::RVec<") {
78 std::string itemTypeName = normalizedType.substr(19, normalizedType.length() - 20);
79 auto itemField = Create(GetCollectionName(fieldName), itemTypeName);
80 return new RFieldVector(fieldName, std::unique_ptr<Detail::RFieldBase>(itemField));
81 }
82 // TODO: create an RFieldCollection?
83 if (normalizedType == ":Collection:") return new RField<ClusterSize_t>(fieldName);
84 auto cl = TClass::GetClass(normalizedType.c_str());
85 if (cl != nullptr) {
86 return new RFieldClass(fieldName, normalizedType);
87 }
88 R__ASSERT(false);
89 return nullptr;
90}
91
93 R__ASSERT(false);
94}
95
98 RFieldValue* /*value*/)
99{
100 R__ASSERT(false);
101}
102
106 void* /*dst*/)
107{
108 R__ASSERT(false);
109}
110
112{
113 void *where = malloc(GetValueSize());
114 R__ASSERT(where != nullptr);
115 return GenerateValue(where);
116}
117
119{
120 if (!dtorOnly)
121 free(value.GetRawPtr());
122}
123
125 std::unique_ptr<ROOT::Experimental::Detail::RFieldBase> child)
126{
127 child->fParent = this;
128 fSubFields.emplace_back(std::move(child));
129}
130
131std::string ROOT::Experimental::Detail::RFieldBase::GetLeafName(const std::string &fullName)
132{
133 auto idx = fullName.find_last_of(kCollectionSeparator);
134 return (idx == std::string::npos) ? fullName : fullName.substr(idx + 1);
135}
136
137std::string ROOT::Experimental::Detail::RFieldBase::GetCollectionName(const std::string &parentName)
138{
139 std::string result(parentName);
140 result.push_back(kCollectionSeparator);
141 result.append(GetLeafName(parentName));
142 return result;
143}
144
146{
147 for (auto& column : fColumns) {
148 column->Flush();
149 }
150}
151
153{
154 if (fColumns.empty()) DoGenerateColumns();
155 for (auto& column : fColumns) {
156 if ((fParent != nullptr) && (column->GetOffsetColumn() == nullptr))
157 column->SetOffsetColumn(fParent->fPrincipalColumn);
158 column->Connect(pageStorage);
159 }
160}
161
163{
164 if (fSubFields.empty()) return RIterator(this, -1);
165 return RIterator(this->fSubFields[0].get(), 0);
166}
167
169{
170 return RIterator(this, -1);
171}
172
173
174//-----------------------------------------------------------------------------
175
176
178{
179 auto itr = fStack.rbegin();
180 if (!itr->fFieldPtr->fSubFields.empty()) {
181 fStack.emplace_back(Position(itr->fFieldPtr->fSubFields[0].get(), 0));
182 return;
183 }
184
185 unsigned int nextIdxInParent = ++(itr->fIdxInParent);
186 while (nextIdxInParent >= itr->fFieldPtr->fParent->fSubFields.size()) {
187 if (fStack.size() == 1) {
188 itr->fFieldPtr = itr->fFieldPtr->fParent;
189 itr->fIdxInParent = -1;
190 return;
191 }
192 fStack.pop_back();
193 itr = fStack.rbegin();
194 nextIdxInParent = ++(itr->fIdxInParent);
195 }
196 itr->fFieldPtr = itr->fFieldPtr->fParent->fSubFields[nextIdxInParent].get();
197}
198
199
200//------------------------------------------------------------------------------
201
202
204{
205 Detail::RFieldBase* result = new RFieldRoot();
206 for (auto& f : fSubFields) {
207 auto clone = f->Clone(f->GetName());
208 result->Attach(std::unique_ptr<RFieldBase>(clone));
209 }
210 return result;
211}
212
213
215{
216 auto entry = new REntry();
217 for (auto& f : fSubFields) {
218 entry->AddValue(f->GenerateValue());
219 }
220 return entry;
221}
222
223
224//------------------------------------------------------------------------------
225
226
228{
229 RColumnModel model(GetName(), EColumnType::kIndex, true /* isSorted*/);
230 fColumns.emplace_back(std::make_unique<Detail::RColumn>(model));
231 fPrincipalColumn = fColumns[0].get();
232}
233
234
235//------------------------------------------------------------------------------
236
237
239{
240 RColumnModel model(GetName(), EColumnType::kReal32, false /* isSorted*/);
241 fColumns.emplace_back(std::make_unique<Detail::RColumn>(model));
242 fPrincipalColumn = fColumns[0].get();
243}
244
245//------------------------------------------------------------------------------
246
248{
249 RColumnModel model(GetName(), EColumnType::kReal64, false /* isSorted*/);
250 fColumns.emplace_back(std::make_unique<Detail::RColumn>(model));
251 fPrincipalColumn = fColumns[0].get();
252}
253
254
255//------------------------------------------------------------------------------
256
258{
259 RColumnModel model(GetName(), EColumnType::kInt32, false /* isSorted*/);
260 fColumns.emplace_back(std::make_unique<Detail::RColumn>(model));
261 fPrincipalColumn = fColumns[0].get();
262}
263
264//------------------------------------------------------------------------------
265
267{
268 RColumnModel model(GetName(), EColumnType::kInt32, false /* isSorted*/);
269 fColumns.emplace_back(std::make_unique<Detail::RColumn>(model));
270 fPrincipalColumn = fColumns[0].get();
271}
272
273//------------------------------------------------------------------------------
274
276{
277 RColumnModel model(GetName(), EColumnType::kInt64, false /* isSorted*/);
278 fColumns.emplace_back(std::make_unique<Detail::RColumn>(model));
279 fPrincipalColumn = fColumns[0].get();
280}
281
282//------------------------------------------------------------------------------
283
284
286{
287 RColumnModel modelIndex(GetName(), EColumnType::kIndex, true /* isSorted*/);
288 fColumns.emplace_back(std::make_unique<Detail::RColumn>(modelIndex));
289
290 RColumnModel modelChars(GetCollectionName(GetName()), EColumnType::kByte, false /* isSorted*/);
291 fColumns.emplace_back(std::make_unique<Detail::RColumn>(modelChars));
292 fPrincipalColumn = fColumns[0].get();
293 fColumns[1]->SetOffsetColumn(fPrincipalColumn);
294}
295
297{
298 auto typedValue = value.Get<std::string>();
299 auto length = typedValue->length();
300 Detail::RColumnElement<char, EColumnType::kByte> elemChars(const_cast<char*>(typedValue->data()));
301 fColumns[1]->AppendV(elemChars, length);
302 fIndex += length;
303 fColumns[0]->Append(fElemIndex);
304}
305
308{
309 auto typedValue = value->Get<std::string>();
310 NTupleSize_t idxStart;
311 ClusterSize_t nChars;
312 fPrincipalColumn->GetCollectionInfo(index, &idxStart, &nChars);
313 typedValue->resize(nChars);
314 Detail::RColumnElement<char, EColumnType::kByte> elemChars(const_cast<char*>(typedValue->data()));
315 fColumns[1]->ReadV(idxStart, nChars, &elemChars);
316}
317
319{
320 fIndex = 0;
321}
322
323
324//------------------------------------------------------------------------------
325
326
328 : ROOT::Experimental::Detail::RFieldBase(fieldName, className, ENTupleStructure::kRecord, false /* isSimple */)
329 , fClass(TClass::GetClass(std::string(className).c_str()))
330{
331 if (fClass == nullptr) {
332 throw std::runtime_error("RField: no I/O support for type " + std::string(className));
333 }
335 while (auto dataMember = static_cast<TDataMember *>(next())) {
336 //printf("Now looking at %s %s\n", dataMember->GetName(), dataMember->GetFullTypeName());
337 auto subField = Detail::RFieldBase::Create(
338 GetName() + "." + dataMember->GetName(), dataMember->GetFullTypeName());
339 Attach(std::unique_ptr<Detail::RFieldBase>(subField));
340 }
341}
342
344{
345 return new RFieldClass(newName, GetType());
346}
347
349 TIter next(fClass->GetListOfDataMembers());
350 unsigned i = 0;
351 while (auto dataMember = static_cast<TDataMember *>(next())) {
352 auto memberValue = fSubFields[i]->CaptureValue(value.Get<unsigned char>() + dataMember->GetOffset());
353 fSubFields[i]->Append(memberValue);
354 i++;
355 }
356}
357
359 TIter next(fClass->GetListOfDataMembers());
360 unsigned i = 0;
361 while (auto dataMember = static_cast<TDataMember *>(next())) {
362 auto memberValue = fSubFields[i]->GenerateValue(value->Get<unsigned char>() + dataMember->GetOffset());
363 fSubFields[i]->Read(index, &memberValue);
364 i++;
365 }
366}
367
369{
370}
371
373{
374 return 0;
375}
376
378{
379 return Detail::RFieldValue(true /* captureFlag */, this, fClass->New(where));
380}
381
383{
384 fClass->Destructor(value.GetRawPtr(), true /* dtorOnly */);
385 if (!dtorOnly)
386 free(value.GetRawPtr());
387}
388
390{
391 return Detail::RFieldValue(true /* captureFlat */, this, where);
392}
393
395{
396 return fClass->GetClassSize();
397}
398
399
400//------------------------------------------------------------------------------
401
402
404 std::string_view fieldName, std::unique_ptr<Detail::RFieldBase> itemField)
405 : ROOT::Experimental::Detail::RFieldBase(
406 fieldName, "std::vector<" + itemField->GetType() + ">", ENTupleStructure::kCollection, false /* isSimple */)
407 , fItemSize(itemField->GetValueSize()), fNWritten(0)
408{
409 Attach(std::move(itemField));
410}
411
413{
414 auto newItemField = fSubFields[0]->Clone(GetCollectionName(std::string(newName)));
415 return new RFieldVector(newName, std::unique_ptr<Detail::RFieldBase>(newItemField));
416}
417
419 auto typedValue = value.Get<std::vector<char>>();
420 R__ASSERT((typedValue->size() % fItemSize) == 0);
421 auto count = typedValue->size() / fItemSize;
422 for (unsigned i = 0; i < count; ++i) {
423 auto itemValue = fSubFields[0]->CaptureValue(typedValue->data() + (i * fItemSize));
424 fSubFields[0]->Append(itemValue);
425 }
427 fNWritten += count;
428 fColumns[0]->Append(elemIndex);
429}
430
432 auto typedValue = value->Get<std::vector<char>>();
433
434 ClusterSize_t nItems;
435 NTupleSize_t idxStart;
436 fPrincipalColumn->GetCollectionInfo(index, &idxStart, &nItems);
437
438 typedValue->resize(nItems * fItemSize);
439 for (unsigned i = 0; i < nItems; ++i) {
440 auto itemValue = fSubFields[0]->GenerateValue(typedValue->data() + (i * fItemSize));
441 fSubFields[0]->Read(idxStart + i, &itemValue);
442 }
443}
444
446{
447 RColumnModel modelIndex(GetName(), EColumnType::kIndex, true /* isSorted*/);
448 fColumns.emplace_back(std::make_unique<Detail::RColumn>(modelIndex));
449 fPrincipalColumn = fColumns[0].get();
450}
451
453{
454 return 1;
455}
456
458{
459 // The memory location can be used as a vector of any type except bool (TODO)
460 return Detail::RFieldValue(this, reinterpret_cast<std::vector<char>*>(where));
461}
462
464{
465 auto vec = static_cast<std::vector<char>*>(value.GetRawPtr());
466 R__ASSERT((vec->size() % fItemSize) == 0);
467 auto nItems = vec->size() / fItemSize;
468 for (unsigned i = 0; i < nItems; ++i) {
469 auto itemValue = fSubFields[0]->CaptureValue(vec->data() + (i * fItemSize));
470 fSubFields[0]->DestroyValue(itemValue, true /* dtorOnly */);
471 }
472 vec->~vector();
473 if (!dtorOnly)
474 free(vec);
475}
476
478{
479 return Detail::RFieldValue(true /* captureFlag */, this, where);
480}
481
483{
484 return sizeof(std::vector<char>);
485}
486
488{
489 fNWritten = 0;
490}
491
492
493//------------------------------------------------------------------------------
494
495
498 std::shared_ptr<RCollectionNTuple> collectionNTuple,
499 std::unique_ptr<RNTupleModel> collectionModel)
500 : RFieldBase(name, ":Collection:", ENTupleStructure::kCollection, true /* isSimple */)
501 , fCollectionNTuple(collectionNTuple)
502{
503 std::string namePrefix(name);
504 namePrefix.push_back(kCollectionSeparator);
505 for (unsigned i = 0; i < collectionModel->GetRootField()->fSubFields.size(); ++i) {
506 auto& subField = collectionModel->GetRootField()->fSubFields[i];
507 subField->fName = namePrefix + subField->fName;
508 for (auto& grandChild : subField->fSubFields) {
509 grandChild->fName = namePrefix + grandChild->fName;
510 }
511 Attach(std::move(subField));
512 }
513}
514
515
517{
518 RColumnModel modelIndex(GetName(), EColumnType::kIndex, true /* isSorted*/);
519 fColumns.emplace_back(std::make_unique<Detail::RColumn>(modelIndex));
520 fPrincipalColumn = fColumns[0].get();
521}
522
523
525{
526 // TODO(jblomer)
527 return nullptr;
528 //auto result = new RFieldCollection(newName, fCollectionNTuple, RNTupleModel::Create());
529 //for (auto& f : fSubFields) {
530 // // switch the name prefix for the new parent name
531 // std::string cloneName = std::string(newName) + f->GetName().substr(GetName().length());
532 // auto clone = f->Clone(cloneName);
533 // result->Attach(std::unique_ptr<RFieldBase>(clone));
534 //}
535 //return result;
536}
537
539 *fCollectionNTuple->GetOffsetPtr() = 0;
540}
541
PyObject * fType
#define f(i)
Definition: RSha256.hxx:104
#define R__ASSERT(e)
Definition: TError.h:96
char name[80]
Definition: TGX11.cxx:109
int type
Definition: TGX11.cxx:120
#define free
Definition: civetweb.c:1539
#define malloc
Definition: civetweb.c:1536
Iterates over the sub fields in depth-first search order.
Definition: RField.hxx:103
void Advance()
Given that the iterator points to a valid field which is not the end iterator, go to the next field i...
Definition: RField.cxx:177
static std::string GetCollectionName(const std::string &parentName)
Get the name for an item sub field that is part of a collection, e.g. the float field of std::vector<...
Definition: RField.cxx:137
virtual void DoReadV(NTupleSize_t index, NTupleSize_t count, void *dst)
Definition: RField.cxx:103
std::vector< std::unique_ptr< RFieldBase > > fSubFields
Collections and classes own sub fields.
Definition: RField.hxx:81
RFieldBase(std::string_view name, std::string_view type, ENTupleStructure structure, bool isSimple)
The constructor creates the underlying column objects and connects them to either a sink or a source.
Definition: RField.cxx:37
virtual void DoAppend(const RFieldValue &value)
Operations on values of complex types, e.g.
Definition: RField.cxx:92
static constexpr char kCollectionSeparator
Field names convey the level of subfields; sub fields (nested collections) are separated by a dot.
Definition: RField.hxx:100
virtual void DestroyValue(const RFieldValue &value, bool dtorOnly=false)
Releases the resources acquired during GenerateValue (memory and constructor) This implementation wor...
Definition: RField.cxx:118
static std::string GetLeafName(const std::string &fullName)
Get the tail of the field name up to the last dot.
Definition: RField.cxx:131
void Flush() const
Ensure that all received items are written from page buffers to the storage.
Definition: RField.cxx:145
virtual void CommitCluster()
Perform housekeeping tasks for global to cluster-local index translation.
Definition: RField.hxx:203
void ConnectColumns(Detail::RPageStorage *pageStorage)
Registeres (or re-registers) the backing columns with the physical storage.
Definition: RField.cxx:152
virtual void DoRead(NTupleSize_t index, RFieldValue *value)
Definition: RField.cxx:96
static RFieldBase * Create(const std::string &fieldName, const std::string &typeName)
Factory method to resurrect a field from the stored on-disk type information.
Definition: RField.cxx:48
void Attach(std::unique_ptr< Detail::RFieldBase > child)
Definition: RField.cxx:124
RFieldValue GenerateValue()
Generates a tree value of the field type and allocates new initialized memory according to the type.
Definition: RField.cxx:111
Manages tree meta-data, which is common for sinks and sources.
Holds the static meta-data of a column in a tree.
The REntry is a collection of values in an ntuple corresponding to a complete row in the data set.
Definition: REntry.hxx:42
A field translates read and write calls from/to underlying columns to/from tree values.
Definition: RField.hxx:53
The field for a class with dictionary.
Definition: RField.hxx:242
void DoGenerateColumns() final
Creates the backing columns corresponsing to the field type and name.
Definition: RField.cxx:368
Detail::RFieldValue CaptureValue(void *where) final
Creates a value from a memory location with an already constructed object.
Definition: RField.cxx:389
void DoRead(NTupleSize_t index, Detail::RFieldValue *value) final
Definition: RField.cxx:358
void DoAppend(const Detail::RFieldValue &value) final
Operations on values of complex types, e.g.
Definition: RField.cxx:348
RFieldClass(std::string_view fieldName, std::string_view className)
Definition: RField.cxx:327
size_t GetValueSize() const override
The number of bytes taken by a value of the appropriate type.
Definition: RField.cxx:394
void DestroyValue(const Detail::RFieldValue &value, bool dtorOnly=false) final
Releases the resources acquired during GenerateValue (memory and constructor) This implementation wor...
Definition: RField.cxx:382
RFieldBase * Clone(std::string_view newName) final
Definition: RField.cxx:343
unsigned int GetNColumns() const final
Returns the number of columns generated to store data for the field; defaults to 1.
Definition: RField.cxx:372
RFieldCollection(std::string_view name, std::shared_ptr< RCollectionNTuple > collectionNTuple, std::unique_ptr< RNTupleModel > collectionModel)
Definition: RField.cxx:496
void DoGenerateColumns() final
Creates the backing columns corresponsing to the field type and name.
Definition: RField.cxx:516
void CommitCluster() final
Perform housekeeping tasks for global to cluster-local index translation.
Definition: RField.cxx:538
RFieldBase * Clone(std::string_view newName) final
Definition: RField.cxx:524
The container field for a tree model, which itself has no physical representation.
Definition: RField.hxx:225
RFieldBase * Clone(std::string_view newName)
Definition: RField.cxx:203
REntry * GenerateEntry()
Generates managed values for the top-level sub fields.
Definition: RField.cxx:214
The generic field for a (nested) std::vector<Type>
Definition: RField.hxx:265
size_t GetValueSize() const override
The number of bytes taken by a value of the appropriate type.
Definition: RField.cxx:482
void DoAppend(const Detail::RFieldValue &value) final
Operations on values of complex types, e.g.
Definition: RField.cxx:418
void CommitCluster() final
Perform housekeeping tasks for global to cluster-local index translation.
Definition: RField.cxx:487
void DoGenerateColumns() final
Creates the backing columns corresponsing to the field type and name.
Definition: RField.cxx:445
RFieldBase * Clone(std::string_view newName) final
Definition: RField.cxx:412
RFieldVector(std::string_view fieldName, std::unique_ptr< Detail::RFieldBase > itemField)
Definition: RField.cxx:403
void DestroyValue(const Detail::RFieldValue &value, bool dtorOnly=false) final
Releases the resources acquired during GenerateValue (memory and constructor) This implementation wor...
Definition: RField.cxx:463
Detail::RFieldValue CaptureValue(void *where) override
Creates a value from a memory location with an already constructed object.
Definition: RField.cxx:477
void DoRead(NTupleSize_t index, Detail::RFieldValue *value) final
Definition: RField.cxx:431
unsigned int GetNColumns() const final
Returns the number of columns generated to store data for the field; defaults to 1.
Definition: RField.cxx:452
Template specializations for concrete C++ types.
Definition: RField.hxx:350
Classes with dictionaries that can be inspected by TClass.
Definition: RField.hxx:294
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition: TClass.h:75
TList * GetListOfDataMembers(Bool_t load=kTRUE)
Return list containing the TDataMembers of a class.
Definition: TClass.cxx:3635
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition: TClass.cxx:2895
All ROOT classes may have RTTI (run time type identification) support added.
Definition: TDataMember.h:31
basic_string_view< char > string_view
std::string GetName(const std::string &scope_name)
Definition: Cppyy.cxx:146
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.
Definition: RNTupleUtil.hxx:44
RClusterSize ClusterSize_t
Definition: RNTupleUtil.hxx:57
ENTupleStructure
The fields in the ntuple model tree can carry different structural information about the type system.
Definition: RNTupleUtil.hxx:33
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21
TClass * GetClass(T *)
Definition: TClass.h:608
Type GetType(const std::string &Name)
Definition: Systematics.cxx:34
Wrap the 32bit integer in a struct in order to avoid template specialization clash with std::uint32_t...
Definition: RNTupleUtil.hxx:47