Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RNTupleSerialize.cxx
Go to the documentation of this file.
1/// \file RNTupleSerialize.cxx
2/// \author Jakob Blomer <jblomer@cern.ch>
3/// \author Javier Lopez-Gomez <javier.lopez.gomez@cern.ch>
4/// \date 2021-08-02
5
6/*************************************************************************
7 * Copyright (C) 1995-2021, Rene Brun and Fons Rademakers. *
8 * All rights reserved. *
9 * *
10 * For the licensing terms see $ROOTSYS/LICENSE. *
11 * For the list of contributors see $ROOTSYS/README/CREDITS. *
12 *************************************************************************/
13
15#include <ROOT/RError.hxx>
18#include <ROOT/RNTupleTypes.hxx>
19#include <ROOT/RNTupleUtils.hxx>
20#include <ROOT/BitUtils.hxx>
21#include <ROOT/RVersion.hxx>
22
23#include <TBufferFile.h>
24#include <TClass.h>
25#include <TList.h>
26#include <TStreamerInfo.h>
28#include <xxhash.h>
29
30#include <cassert>
31#include <cmath>
32#include <cstring> // for memcpy
33#include <deque>
34#include <functional>
35#include <limits>
36#include <set>
37#include <unordered_map>
38
45
46namespace {
47using RNTupleSerializer = ROOT::Internal::RNTupleSerializer;
48
49ROOT::RResult<std::uint32_t> SerializeField(const ROOT::RFieldDescriptor &fieldDesc,
50 ROOT::DescriptorId_t onDiskParentId,
51 ROOT::DescriptorId_t onDiskProjectionSourceId, void *buffer)
52{
53
54 auto base = reinterpret_cast<unsigned char *>(buffer);
55 auto pos = base;
56 void **where = (buffer == nullptr) ? &buffer : reinterpret_cast<void **>(&pos);
57
58 pos += RNTupleSerializer::SerializeRecordFramePreamble(*where);
59
60 pos += RNTupleSerializer::SerializeUInt32(fieldDesc.GetFieldVersion(), *where);
61 pos += RNTupleSerializer::SerializeUInt32(fieldDesc.GetTypeVersion(), *where);
62 pos += RNTupleSerializer::SerializeUInt32(onDiskParentId, *where);
63 if (auto res = RNTupleSerializer::SerializeFieldStructure(fieldDesc.GetStructure(), *where)) {
64 pos += res.Unwrap();
65 } else {
66 return R__FORWARD_ERROR(res);
67 }
68
69 std::uint16_t flags = 0;
70 if (fieldDesc.GetNRepetitions() > 0)
71 flags |= RNTupleSerializer::kFlagRepetitiveField;
72 if (fieldDesc.IsProjectedField())
73 flags |= RNTupleSerializer::kFlagProjectedField;
74 if (fieldDesc.GetTypeChecksum().has_value())
75 flags |= RNTupleSerializer::kFlagHasTypeChecksum;
76 if (fieldDesc.IsSoACollection())
77 flags |= RNTupleSerializer::kFlagIsSoACollection;
78 pos += RNTupleSerializer::SerializeUInt16(flags, *where);
79
80 pos += RNTupleSerializer::SerializeString(fieldDesc.GetFieldName(), *where);
81 pos += RNTupleSerializer::SerializeString(fieldDesc.GetTypeName(), *where);
82 pos += RNTupleSerializer::SerializeString(fieldDesc.GetTypeAlias(), *where);
83 pos += RNTupleSerializer::SerializeString(fieldDesc.GetFieldDescription(), *where);
84
85 if (flags & RNTupleSerializer::kFlagRepetitiveField) {
86 pos += RNTupleSerializer::SerializeUInt64(fieldDesc.GetNRepetitions(), *where);
87 }
88 if (flags & RNTupleSerializer::kFlagProjectedField) {
89 pos += RNTupleSerializer::SerializeUInt32(onDiskProjectionSourceId, *where);
90 }
91 if (flags & RNTupleSerializer::kFlagHasTypeChecksum) {
92 pos += RNTupleSerializer::SerializeUInt32(fieldDesc.GetTypeChecksum().value(), *where);
93 }
94
95 auto size = pos - base;
96 RNTupleSerializer::SerializeFramePostscript(base, size);
97
98 return size;
99}
100
101// clang-format off
102/// Serialize, in order, fields enumerated in `fieldList` to `buffer`. `firstOnDiskId` specifies the on-disk ID for the
103/// first element in the `fieldList` sequence. Before calling this function `RContext::MapSchema()` should have been
104/// called on `context` in order to map in-memory field IDs to their on-disk counterpart.
105/// \return The number of bytes written to the output buffer; if `buffer` is `nullptr` no data is serialized and the
106/// required buffer size is returned
107// clang-format on
109SerializeFieldList(const ROOT::RNTupleDescriptor &desc, std::span<const ROOT::DescriptorId_t> fieldList,
110 std::size_t firstOnDiskId, const ROOT::Internal::RNTupleSerializer::RContext &context, void *buffer)
111{
112 auto base = reinterpret_cast<unsigned char *>(buffer);
113 auto pos = base;
114 void **where = (buffer == nullptr) ? &buffer : reinterpret_cast<void **>(&pos);
115
116 auto fieldZeroId = desc.GetFieldZeroId();
117 ROOT::DescriptorId_t onDiskFieldId = firstOnDiskId;
118 for (auto fieldId : fieldList) {
119 const auto &f = desc.GetFieldDescriptor(fieldId);
120 auto onDiskParentId =
121 (f.GetParentId() == fieldZeroId) ? onDiskFieldId : context.GetOnDiskFieldId(f.GetParentId());
122 auto onDiskProjectionSourceId =
123 f.IsProjectedField() ? context.GetOnDiskFieldId(f.GetProjectionSourceId()) : ROOT::kInvalidDescriptorId;
124 if (auto res = SerializeField(f, onDiskParentId, onDiskProjectionSourceId, *where)) {
125 pos += res.Unwrap();
126 } else {
127 return R__FORWARD_ERROR(res);
128 }
129 ++onDiskFieldId;
130 }
131
132 return pos - base;
133}
134
136DeserializeField(const void *buffer, std::uint64_t bufSize, ROOT::Internal::RFieldDescriptorBuilder &fieldDesc)
137{
138 using ENTupleStructure = ROOT::ENTupleStructure;
139
140 auto base = reinterpret_cast<const unsigned char *>(buffer);
141 auto bytes = base;
142 std::uint64_t frameSize;
143 auto fnFrameSizeLeft = [&]() { return frameSize - (bytes - base); };
144 if (auto res = RNTupleSerializer::DeserializeFrameHeader(bytes, bufSize, frameSize)) {
145 bytes += res.Unwrap();
146 } else {
147 return R__FORWARD_ERROR(res);
148 }
149
150 std::uint32_t fieldVersion;
151 std::uint32_t typeVersion;
152 std::uint32_t parentId;
153 // initialize properly for call to SerializeFieldStructure()
154 ENTupleStructure structure{ENTupleStructure::kPlain};
155 std::uint16_t flags;
156 std::uint32_t result;
157 if (auto res = RNTupleSerializer::SerializeFieldStructure(structure, nullptr)) {
158 result = res.Unwrap();
159 } else {
160 return R__FORWARD_ERROR(res);
161 }
162 if (fnFrameSizeLeft() < 3 * sizeof(std::uint32_t) + result + sizeof(std::uint16_t)) {
163 return R__FAIL("field record frame too short");
164 }
165 bytes += RNTupleSerializer::DeserializeUInt32(bytes, fieldVersion);
166 bytes += RNTupleSerializer::DeserializeUInt32(bytes, typeVersion);
167 bytes += RNTupleSerializer::DeserializeUInt32(bytes, parentId);
168 if (auto res = RNTupleSerializer::DeserializeFieldStructure(bytes, structure)) {
169 bytes += res.Unwrap();
170 } else {
171 return R__FORWARD_ERROR(res);
172 }
173 bytes += RNTupleSerializer::DeserializeUInt16(bytes, flags);
174 fieldDesc.FieldVersion(fieldVersion).TypeVersion(typeVersion).ParentId(parentId).Structure(structure);
175
176 std::string fieldName;
177 std::string typeName;
178 std::string aliasName;
179 std::string description;
180 if (auto res = RNTupleSerializer::DeserializeString(bytes, fnFrameSizeLeft(), fieldName)) {
181 bytes += res.Unwrap();
182 } else {
183 return R__FORWARD_ERROR(res);
184 }
185 if (auto res = RNTupleSerializer::DeserializeString(bytes, fnFrameSizeLeft(), typeName)) {
186 bytes += res.Unwrap();
187 } else {
188 return R__FORWARD_ERROR(res);
189 }
190 if (auto res = RNTupleSerializer::DeserializeString(bytes, fnFrameSizeLeft(), aliasName)) {
191 bytes += res.Unwrap();
192 } else {
193 return R__FORWARD_ERROR(res);
194 }
195 if (auto res = RNTupleSerializer::DeserializeString(bytes, fnFrameSizeLeft(), description)) {
196 bytes += res.Unwrap();
197 } else {
198 return R__FORWARD_ERROR(res);
199 }
200 fieldDesc.FieldName(fieldName).TypeName(typeName).TypeAlias(aliasName).FieldDescription(description);
201
202 if (flags & RNTupleSerializer::kFlagRepetitiveField) {
203 if (fnFrameSizeLeft() < sizeof(std::uint64_t))
204 return R__FAIL("field record frame too short");
205 std::uint64_t nRepetitions;
206 bytes += RNTupleSerializer::DeserializeUInt64(bytes, nRepetitions);
207 fieldDesc.NRepetitions(nRepetitions);
208 }
209
210 if (flags & RNTupleSerializer::kFlagProjectedField) {
211 if (fnFrameSizeLeft() < sizeof(std::uint32_t))
212 return R__FAIL("field record frame too short");
213 std::uint32_t projectionSourceId;
214 bytes += RNTupleSerializer::DeserializeUInt32(bytes, projectionSourceId);
215 fieldDesc.ProjectionSourceId(projectionSourceId);
216 }
217
218 if (flags & RNTupleSerializer::kFlagHasTypeChecksum) {
219 if (fnFrameSizeLeft() < sizeof(std::uint32_t))
220 return R__FAIL("field record frame too short");
221 std::uint32_t typeChecksum;
222 bytes += RNTupleSerializer::DeserializeUInt32(bytes, typeChecksum);
223 fieldDesc.TypeChecksum(typeChecksum);
224 }
225
226 if (flags & RNTupleSerializer::kFlagIsSoACollection) {
227 fieldDesc.IsSoACollection(true);
228 }
229
230 return frameSize;
231}
232
233ROOT::RResult<std::uint32_t> SerializePhysicalColumn(const ROOT::RColumnDescriptor &columnDesc,
235 void *buffer)
236{
237 R__ASSERT(!columnDesc.IsAliasColumn());
238
239 auto base = reinterpret_cast<unsigned char *>(buffer);
240 auto pos = base;
241 void **where = (buffer == nullptr) ? &buffer : reinterpret_cast<void **>(&pos);
242
243 pos += RNTupleSerializer::SerializeRecordFramePreamble(*where);
244
245 if (auto res = RNTupleSerializer::SerializeColumnType(columnDesc.GetType(), *where)) {
246 pos += res.Unwrap();
247 } else {
248 return R__FORWARD_ERROR(res);
249 }
250 pos += RNTupleSerializer::SerializeUInt16(columnDesc.GetBitsOnStorage(), *where);
251 pos += RNTupleSerializer::SerializeUInt32(context.GetOnDiskFieldId(columnDesc.GetFieldId()), *where);
252 std::uint16_t flags = 0;
253 if (columnDesc.IsDeferredColumn())
254 flags |= RNTupleSerializer::kFlagDeferredColumn;
255 if (columnDesc.GetValueRange().has_value())
256 flags |= RNTupleSerializer::kFlagHasValueRange;
257 std::int64_t firstElementIdx = columnDesc.GetFirstElementIndex();
258 if (columnDesc.IsSuppressedDeferredColumn())
259 firstElementIdx = -firstElementIdx;
260 pos += RNTupleSerializer::SerializeUInt16(flags, *where);
261 pos += RNTupleSerializer::SerializeUInt16(columnDesc.GetRepresentationIndex(), *where);
262 if (flags & RNTupleSerializer::kFlagDeferredColumn)
263 pos += RNTupleSerializer::SerializeInt64(firstElementIdx, *where);
264 if (flags & RNTupleSerializer::kFlagHasValueRange) {
265 auto [min, max] = *columnDesc.GetValueRange();
266 std::uint64_t intMin, intMax;
267 static_assert(sizeof(min) == sizeof(intMin) && sizeof(max) == sizeof(intMax));
268 memcpy(&intMin, &min, sizeof(min));
269 memcpy(&intMax, &max, sizeof(max));
270 pos += RNTupleSerializer::SerializeUInt64(intMin, *where);
271 pos += RNTupleSerializer::SerializeUInt64(intMax, *where);
272 }
273
274 if (auto res = RNTupleSerializer::SerializeFramePostscript(buffer ? base : nullptr, pos - base)) {
275 pos += res.Unwrap();
276 } else {
277 return R__FORWARD_ERROR(res);
278 }
279
280 return pos - base;
281}
282
283ROOT::RResult<std::uint32_t> SerializeColumnsOfFields(const ROOT::RNTupleDescriptor &desc,
284 std::span<const ROOT::DescriptorId_t> fieldList,
286 void *buffer, bool forHeaderExtension)
287{
288 auto base = reinterpret_cast<unsigned char *>(buffer);
289 auto pos = base;
290 void **where = (buffer == nullptr) ? &buffer : reinterpret_cast<void **>(&pos);
291
292 const auto *xHeader = !forHeaderExtension ? desc.GetHeaderExtension() : nullptr;
293
294 std::vector<const ROOT::RColumnDescriptor *> columnsToSerialize;
295 for (auto parentId : fieldList) {
296 // If we're serializing the non-extended header and we already have a header extension (which may happen if
297 // we load an RNTuple for incremental merging), we need to skip all the extended fields, as they need to be
298 // written in the header extension, not in the regular header.
299 if (xHeader && xHeader->ContainsField(parentId))
300 continue;
301
302 for (const auto &c : desc.GetColumnIterable(parentId)) {
303 if (c.IsAliasColumn() || (xHeader && xHeader->ContainsExtendedColumnRepresentation(c.GetLogicalId())))
304 continue;
305 columnsToSerialize.push_back(&c);
306 }
307 }
308
309 // Make sure the columns are sorted by physical ID.
310 // This is usually the case already, but it may not be true if we have a late-model-extended column in one
311 // of the fields.
312 std::sort(columnsToSerialize.begin(), columnsToSerialize.end(), [&context](const auto *a, const auto *b) {
313 return context.GetOnDiskColumnId(a->GetPhysicalId()) < context.GetOnDiskColumnId(b->GetPhysicalId());
314 });
315
316 for (const auto *c : columnsToSerialize) {
317 if (auto res = SerializePhysicalColumn(*c, context, *where)) {
318 pos += res.Unwrap();
319 } else {
320 return R__FORWARD_ERROR(res);
321 }
322 }
323
324 return pos - base;
325}
326
328DeserializeColumn(const void *buffer, std::uint64_t bufSize, ROOT::Internal::RColumnDescriptorBuilder &columnDesc)
329{
331
332 auto base = reinterpret_cast<const unsigned char *>(buffer);
333 auto bytes = base;
334 std::uint64_t frameSize;
335 auto fnFrameSizeLeft = [&]() { return frameSize - (bytes - base); };
336 if (auto res = RNTupleSerializer::DeserializeFrameHeader(bytes, bufSize, frameSize)) {
337 bytes += res.Unwrap();
338 } else {
339 return R__FORWARD_ERROR(res);
340 }
341
342 // Initialize properly for SerializeColumnType
343 ENTupleColumnType type{ENTupleColumnType::kIndex32};
344 std::uint16_t bitsOnStorage;
345 std::uint32_t fieldId;
346 std::uint16_t flags;
347 std::uint16_t representationIndex;
348 std::int64_t firstElementIdx = 0;
349 if (fnFrameSizeLeft() < RNTupleSerializer::SerializeColumnType(type, nullptr).Unwrap() + sizeof(std::uint16_t) +
350 2 * sizeof(std::uint32_t)) {
351 return R__FAIL("column record frame too short");
352 }
353 if (auto res = RNTupleSerializer::DeserializeColumnType(bytes, type)) {
354 bytes += res.Unwrap();
355 } else {
356 return R__FORWARD_ERROR(res);
357 }
358 bytes += RNTupleSerializer::DeserializeUInt16(bytes, bitsOnStorage);
359 bytes += RNTupleSerializer::DeserializeUInt32(bytes, fieldId);
360 bytes += RNTupleSerializer::DeserializeUInt16(bytes, flags);
361 bytes += RNTupleSerializer::DeserializeUInt16(bytes, representationIndex);
362 if (flags & RNTupleSerializer::kFlagDeferredColumn) {
363 if (fnFrameSizeLeft() < sizeof(std::uint64_t))
364 return R__FAIL("column record frame too short");
365 bytes += RNTupleSerializer::DeserializeInt64(bytes, firstElementIdx);
366 }
367 if (flags & RNTupleSerializer::kFlagHasValueRange) {
368 if (fnFrameSizeLeft() < 2 * sizeof(std::uint64_t))
369 return R__FAIL("field record frame too short");
370 std::uint64_t minInt, maxInt;
371 bytes += RNTupleSerializer::DeserializeUInt64(bytes, minInt);
372 bytes += RNTupleSerializer::DeserializeUInt64(bytes, maxInt);
373 double min, max;
374 memcpy(&min, &minInt, sizeof(min));
375 memcpy(&max, &maxInt, sizeof(max));
376 columnDesc.ValueRange(min, max);
377 }
378
379 columnDesc.FieldId(fieldId).BitsOnStorage(bitsOnStorage).Type(type).RepresentationIndex(representationIndex);
380 columnDesc.FirstElementIndex(std::abs(firstElementIdx));
381 if (firstElementIdx < 0)
382 columnDesc.SetSuppressedDeferred();
383
384 return frameSize;
385}
386
387ROOT::RResult<std::uint32_t> SerializeExtraTypeInfo(const ROOT::RExtraTypeInfoDescriptor &desc, void *buffer)
388{
389 auto base = reinterpret_cast<unsigned char *>(buffer);
390 auto pos = base;
391 void **where = (buffer == nullptr) ? &buffer : reinterpret_cast<void **>(&pos);
392
393 pos += RNTupleSerializer::SerializeRecordFramePreamble(*where);
394
395 if (auto res = RNTupleSerializer::SerializeExtraTypeInfoId(desc.GetContentId(), *where)) {
396 pos += res.Unwrap();
397 } else {
398 return R__FORWARD_ERROR(res);
399 }
400 pos += RNTupleSerializer::SerializeUInt32(desc.GetTypeVersion(), *where);
401 pos += RNTupleSerializer::SerializeString(desc.GetTypeName(), *where);
402 pos += RNTupleSerializer::SerializeString(desc.GetContent(), *where);
403
404 auto size = pos - base;
405 RNTupleSerializer::SerializeFramePostscript(base, size);
406
407 return size;
408}
409
410ROOT::RResult<std::uint32_t> SerializeExtraTypeInfoList(const ROOT::RNTupleDescriptor &ntplDesc, void *buffer)
411{
412 auto base = reinterpret_cast<unsigned char *>(buffer);
413 auto pos = base;
414 void **where = (buffer == nullptr) ? &buffer : reinterpret_cast<void **>(&pos);
415
416 for (const auto &extraTypeInfoDesc : ntplDesc.GetExtraTypeInfoIterable()) {
417 if (auto res = SerializeExtraTypeInfo(extraTypeInfoDesc, *where)) {
418 pos += res.Unwrap();
419 } else {
420 return R__FORWARD_ERROR(res);
421 }
422 }
423
424 return pos - base;
425}
426
427ROOT::RResult<std::uint32_t> DeserializeExtraTypeInfo(const void *buffer, std::uint64_t bufSize,
429{
431
432 auto base = reinterpret_cast<const unsigned char *>(buffer);
433 auto bytes = base;
434 std::uint64_t frameSize;
435 auto fnFrameSizeLeft = [&]() { return frameSize - (bytes - base); };
436 auto result = RNTupleSerializer::DeserializeFrameHeader(bytes, bufSize, frameSize);
437 if (!result)
438 return R__FORWARD_ERROR(result);
439 bytes += result.Unwrap();
440
441 EExtraTypeInfoIds contentId{EExtraTypeInfoIds::kInvalid};
442 std::uint32_t typeVersion;
443 if (fnFrameSizeLeft() < 2 * sizeof(std::uint32_t)) {
444 return R__FAIL("extra type info record frame too short");
445 }
446 result = RNTupleSerializer::DeserializeExtraTypeInfoId(bytes, contentId);
447 if (!result)
448 return R__FORWARD_ERROR(result);
449 bytes += result.Unwrap();
450 bytes += RNTupleSerializer::DeserializeUInt32(bytes, typeVersion);
451
452 std::string typeName;
453 std::string content;
454 result = RNTupleSerializer::DeserializeString(bytes, fnFrameSizeLeft(), typeName).Unwrap();
455 if (!result)
456 return R__FORWARD_ERROR(result);
457 bytes += result.Unwrap();
458 result = RNTupleSerializer::DeserializeString(bytes, fnFrameSizeLeft(), content).Unwrap();
459 if (!result)
460 return R__FORWARD_ERROR(result);
461 bytes += result.Unwrap();
462
463 desc.ContentId(contentId).TypeVersion(typeVersion).TypeName(typeName).Content(content);
464
465 return frameSize;
466}
467
468std::uint32_t SerializeLocatorPayloadLarge(const ROOT::RNTupleLocator &locator, unsigned char *buffer)
469{
470 if (buffer) {
471 RNTupleSerializer::SerializeUInt64(locator.GetNBytesOnStorage(), buffer);
472 RNTupleSerializer::SerializeUInt64(locator.GetPosition<std::uint64_t>(), buffer + sizeof(std::uint64_t));
473 }
474 return sizeof(std::uint64_t) + sizeof(std::uint64_t);
475}
476
477void DeserializeLocatorPayloadLarge(const unsigned char *buffer, ROOT::RNTupleLocator &locator)
478{
479 std::uint64_t nBytesOnStorage;
480 std::uint64_t position;
481 RNTupleSerializer::DeserializeUInt64(buffer, nBytesOnStorage);
482 RNTupleSerializer::DeserializeUInt64(buffer + sizeof(std::uint64_t), position);
483 locator.SetNBytesOnStorage(nBytesOnStorage);
484 locator.SetPosition(position);
485}
486
487std::uint32_t SerializeLocatorPayloadObject64(const ROOT::RNTupleLocator &locator, unsigned char *buffer)
488{
489 const auto &data = locator.GetPosition<ROOT::RNTupleLocatorObject64>();
490 const uint32_t sizeofNBytesOnStorage = (locator.GetNBytesOnStorage() > std::numeric_limits<std::uint32_t>::max())
491 ? sizeof(std::uint64_t)
492 : sizeof(std::uint32_t);
493 if (buffer) {
494 if (sizeofNBytesOnStorage == sizeof(std::uint32_t)) {
495 RNTupleSerializer::SerializeUInt32(locator.GetNBytesOnStorage(), buffer);
496 } else {
497 RNTupleSerializer::SerializeUInt64(locator.GetNBytesOnStorage(), buffer);
498 }
499 RNTupleSerializer::SerializeUInt64(data.GetLocation(), buffer + sizeofNBytesOnStorage);
500 }
501 return sizeofNBytesOnStorage + sizeof(std::uint64_t);
502}
503
504ROOT::RResult<void> DeserializeLocatorPayloadObject64(const unsigned char *buffer, std::uint32_t sizeofLocatorPayload,
505 ROOT::RNTupleLocator &locator)
506{
507 std::uint64_t location;
508 if (sizeofLocatorPayload == 12) {
509 std::uint32_t nBytesOnStorage;
510 RNTupleSerializer::DeserializeUInt32(buffer, nBytesOnStorage);
511 locator.SetNBytesOnStorage(nBytesOnStorage);
512 RNTupleSerializer::DeserializeUInt64(buffer + sizeof(std::uint32_t), location);
513 } else if (sizeofLocatorPayload == 16) {
514 std::uint64_t nBytesOnStorage;
515 RNTupleSerializer::DeserializeUInt64(buffer, nBytesOnStorage);
516 locator.SetNBytesOnStorage(nBytesOnStorage);
517 RNTupleSerializer::DeserializeUInt64(buffer + sizeof(std::uint64_t), location);
518 } else {
519 return R__FAIL("invalid Object64 locator payload size: " + std::to_string(sizeofLocatorPayload));
520 }
521 locator.SetPosition(ROOT::RNTupleLocatorObject64{location});
523}
524
525std::uint32_t SerializeLocatorPayloadMulti(const ROOT::RNTupleLocator &locator, unsigned char *buffer)
526{
527 const auto &data = locator.GetPosition<ROOT::RNTupleLocatorMulti>();
528
529 void *bufferVoid = buffer;
530 auto base = buffer;
531 auto pos = base;
532 void **where = (buffer == nullptr) ? &bufferVoid : reinterpret_cast<void **>(&pos);
533
534 if (locator.GetNBytesOnStorage() > std::numeric_limits<std::uint32_t>::max()) {
535 pos += RNTupleSerializer::SerializeUInt64(locator.GetNBytesOnStorage(), *where);
536 } else {
537 pos += RNTupleSerializer::SerializeUInt32(locator.GetNBytesOnStorage(), *where);
538 }
539 pos += RNTupleSerializer::SerializeUInt32(data.GetObjectId(), *where);
540 pos += RNTupleSerializer::SerializeUInt32(data.GetOffset(), *where);
541
542 return pos - base;
543}
544
545ROOT::RResult<void> DeserializeLocatorPayloadMulti(const unsigned char *buffer, std::uint32_t sizeofLocatorPayload,
546 ROOT::RNTupleLocator &locator)
547{
548 const unsigned char *pos = buffer;
549 if (sizeofLocatorPayload == 12) {
550 std::uint32_t nBytesOnStorage;
551 pos += RNTupleSerializer::DeserializeUInt32(pos, nBytesOnStorage);
552 locator.SetNBytesOnStorage(nBytesOnStorage);
553 } else if (sizeofLocatorPayload == 16) {
554 std::uint64_t nBytesOnStorage;
555 pos += RNTupleSerializer::DeserializeUInt64(pos, nBytesOnStorage);
556 locator.SetNBytesOnStorage(nBytesOnStorage);
557 } else {
558 return R__FAIL("invalid Multi locator payload size: " + std::to_string(sizeofLocatorPayload));
559 }
560 std::uint32_t objectId;
561 std::uint32_t offset;
562 pos += RNTupleSerializer::DeserializeUInt32(pos, objectId);
563 RNTupleSerializer::DeserializeUInt32(pos, offset);
564 locator.SetPosition(ROOT::RNTupleLocatorMulti(objectId, offset));
566}
567
568std::uint32_t SerializeAliasColumn(const ROOT::RColumnDescriptor &columnDesc,
569 const ROOT::Internal::RNTupleSerializer::RContext &context, void *buffer)
570{
571 R__ASSERT(columnDesc.IsAliasColumn());
572
573 auto base = reinterpret_cast<unsigned char *>(buffer);
574 auto pos = base;
575 void **where = (buffer == nullptr) ? &buffer : reinterpret_cast<void **>(&pos);
576
577 pos += RNTupleSerializer::SerializeRecordFramePreamble(*where);
578
579 pos += RNTupleSerializer::SerializeUInt32(context.GetOnDiskColumnId(columnDesc.GetPhysicalId()), *where);
580 pos += RNTupleSerializer::SerializeUInt32(context.GetOnDiskFieldId(columnDesc.GetFieldId()), *where);
581
582 pos += RNTupleSerializer::SerializeFramePostscript(buffer ? base : nullptr, pos - base).Unwrap();
583
584 return pos - base;
585}
586
587std::uint32_t SerializeAliasColumnsOfFields(const ROOT::RNTupleDescriptor &desc,
588 std::span<const ROOT::DescriptorId_t> fieldList,
589 const ROOT::Internal::RNTupleSerializer::RContext &context, void *buffer,
590 bool forHeaderExtension)
591{
592 auto base = reinterpret_cast<unsigned char *>(buffer);
593 auto pos = base;
594 void **where = (buffer == nullptr) ? &buffer : reinterpret_cast<void **>(&pos);
595
596 const auto *xHeader = !forHeaderExtension ? desc.GetHeaderExtension() : nullptr;
597
598 for (auto parentId : fieldList) {
599 if (xHeader && xHeader->ContainsField(parentId))
600 continue;
601
602 for (const auto &c : desc.GetColumnIterable(parentId)) {
603 if (!c.IsAliasColumn() || (xHeader && xHeader->ContainsExtendedColumnRepresentation(c.GetLogicalId())))
604 continue;
605
606 pos += SerializeAliasColumn(c, context, *where);
607 }
608 }
609
610 return pos - base;
611}
612
613ROOT::RResult<std::uint32_t> DeserializeAliasColumn(const void *buffer, std::uint64_t bufSize,
614 std::uint32_t &physicalColumnId, std::uint32_t &fieldId)
615{
616 auto base = reinterpret_cast<const unsigned char *>(buffer);
617 auto bytes = base;
618 std::uint64_t frameSize;
619 auto fnFrameSizeLeft = [&]() { return frameSize - (bytes - base); };
620 auto result = RNTupleSerializer::DeserializeFrameHeader(bytes, bufSize, frameSize);
621 if (!result)
622 return R__FORWARD_ERROR(result);
623 bytes += result.Unwrap();
624
625 if (fnFrameSizeLeft() < 2 * sizeof(std::uint32_t)) {
626 return R__FAIL("alias column record frame too short");
627 }
628
629 bytes += RNTupleSerializer::DeserializeUInt32(bytes, physicalColumnId);
630 bytes += RNTupleSerializer::DeserializeUInt32(bytes, fieldId);
631
632 return frameSize;
633}
634
635} // anonymous namespace
636
637std::uint32_t ROOT::Internal::RNTupleSerializer::SerializeXxHash3(const unsigned char *data, std::uint64_t length,
638 std::uint64_t &xxhash3, void *buffer)
639{
640 if (buffer != nullptr) {
641 xxhash3 = XXH3_64bits(data, length);
642 SerializeUInt64(xxhash3, buffer);
643 }
644 return 8;
645}
646
648 std::uint64_t &xxhash3)
649{
650 auto checksumReal = XXH3_64bits(data, length);
651 DeserializeUInt64(data + length, xxhash3);
652 if (xxhash3 != checksumReal)
653 return R__FAIL("XxHash-3 checksum mismatch");
654 return RResult<void>::Success();
655}
656
658{
659 std::uint64_t xxhash3;
660 return R__FORWARD_RESULT(VerifyXxHash3(data, length, xxhash3));
661}
662
663std::uint32_t ROOT::Internal::RNTupleSerializer::SerializeInt16(std::int16_t val, void *buffer)
664{
665 if (buffer != nullptr) {
666 auto bytes = reinterpret_cast<unsigned char *>(buffer);
667 bytes[0] = (val & 0x00FF);
668 bytes[1] = (val & 0xFF00) >> 8;
669 }
670 return 2;
671}
672
673std::uint32_t ROOT::Internal::RNTupleSerializer::DeserializeInt16(const void *buffer, std::int16_t &val)
674{
675 auto bytes = reinterpret_cast<const unsigned char *>(buffer);
676 val = std::int16_t(bytes[0]) + (std::int16_t(bytes[1]) << 8);
677 return 2;
678}
679
680std::uint32_t ROOT::Internal::RNTupleSerializer::SerializeUInt16(std::uint16_t val, void *buffer)
681{
682 return SerializeInt16(val, buffer);
683}
684
685std::uint32_t ROOT::Internal::RNTupleSerializer::DeserializeUInt16(const void *buffer, std::uint16_t &val)
686{
687 return DeserializeInt16(buffer, *reinterpret_cast<std::int16_t *>(&val));
688}
689
690std::uint32_t ROOT::Internal::RNTupleSerializer::SerializeInt32(std::int32_t val, void *buffer)
691{
692 if (buffer != nullptr) {
693 auto bytes = reinterpret_cast<unsigned char *>(buffer);
694 bytes[0] = (val & 0x000000FF);
695 bytes[1] = (val & 0x0000FF00) >> 8;
696 bytes[2] = (val & 0x00FF0000) >> 16;
697 bytes[3] = (val & 0xFF000000) >> 24;
698 }
699 return 4;
700}
701
702std::uint32_t ROOT::Internal::RNTupleSerializer::DeserializeInt32(const void *buffer, std::int32_t &val)
703{
704 auto bytes = reinterpret_cast<const unsigned char *>(buffer);
705 val = std::int32_t(bytes[0]) + (std::int32_t(bytes[1]) << 8) + (std::int32_t(bytes[2]) << 16) +
706 (std::int32_t(bytes[3]) << 24);
707 return 4;
708}
709
710std::uint32_t ROOT::Internal::RNTupleSerializer::SerializeUInt32(std::uint32_t val, void *buffer)
711{
712 return SerializeInt32(val, buffer);
713}
714
715std::uint32_t ROOT::Internal::RNTupleSerializer::DeserializeUInt32(const void *buffer, std::uint32_t &val)
716{
717 return DeserializeInt32(buffer, *reinterpret_cast<std::int32_t *>(&val));
718}
719
720std::uint32_t ROOT::Internal::RNTupleSerializer::SerializeInt64(std::int64_t val, void *buffer)
721{
722 if (buffer != nullptr) {
723 auto bytes = reinterpret_cast<unsigned char *>(buffer);
724 bytes[0] = (val & 0x00000000000000FF);
725 bytes[1] = (val & 0x000000000000FF00) >> 8;
726 bytes[2] = (val & 0x0000000000FF0000) >> 16;
727 bytes[3] = (val & 0x00000000FF000000) >> 24;
728 bytes[4] = (val & 0x000000FF00000000) >> 32;
729 bytes[5] = (val & 0x0000FF0000000000) >> 40;
730 bytes[6] = (val & 0x00FF000000000000) >> 48;
731 bytes[7] = (val & 0xFF00000000000000) >> 56;
732 }
733 return 8;
734}
735
736std::uint32_t ROOT::Internal::RNTupleSerializer::DeserializeInt64(const void *buffer, std::int64_t &val)
737{
738 auto bytes = reinterpret_cast<const unsigned char *>(buffer);
739 val = std::int64_t(bytes[0]) + (std::int64_t(bytes[1]) << 8) + (std::int64_t(bytes[2]) << 16) +
740 (std::int64_t(bytes[3]) << 24) + (std::int64_t(bytes[4]) << 32) + (std::int64_t(bytes[5]) << 40) +
741 (std::int64_t(bytes[6]) << 48) + (std::int64_t(bytes[7]) << 56);
742 return 8;
743}
744
745std::uint32_t ROOT::Internal::RNTupleSerializer::SerializeUInt64(std::uint64_t val, void *buffer)
746{
747 return SerializeInt64(val, buffer);
748}
749
750std::uint32_t ROOT::Internal::RNTupleSerializer::DeserializeUInt64(const void *buffer, std::uint64_t &val)
751{
752 return DeserializeInt64(buffer, *reinterpret_cast<std::int64_t *>(&val));
753}
754
755std::uint32_t ROOT::Internal::RNTupleSerializer::SerializeString(const std::string &val, void *buffer)
756{
757 if (buffer) {
758 auto pos = reinterpret_cast<unsigned char *>(buffer);
759 pos += SerializeUInt32(val.length(), pos);
760 memcpy(pos, val.data(), val.length());
761 }
762 return sizeof(std::uint32_t) + val.length();
763}
764
766ROOT::Internal::RNTupleSerializer::DeserializeString(const void *buffer, std::uint64_t bufSize, std::string &val)
767{
768 if (bufSize < sizeof(std::uint32_t))
769 return R__FAIL("string buffer too short");
770 bufSize -= sizeof(std::uint32_t);
771
772 auto base = reinterpret_cast<const unsigned char *>(buffer);
773 auto bytes = base;
774 std::uint32_t length;
775 bytes += DeserializeUInt32(buffer, length);
776 if (bufSize < length)
777 return R__FAIL("string buffer too short");
778
779 val.resize(length);
780 memcpy(&val[0], bytes, length);
781 return sizeof(std::uint32_t) + length;
782}
783
786{
787 switch (type) {
788 case ENTupleColumnType::kBit: return SerializeUInt16(0x00, buffer);
789 case ENTupleColumnType::kByte: return SerializeUInt16(0x01, buffer);
790 case ENTupleColumnType::kChar: return SerializeUInt16(0x02, buffer);
791 case ENTupleColumnType::kInt8: return SerializeUInt16(0x03, buffer);
792 case ENTupleColumnType::kUInt8: return SerializeUInt16(0x04, buffer);
793 case ENTupleColumnType::kInt16: return SerializeUInt16(0x05, buffer);
794 case ENTupleColumnType::kUInt16: return SerializeUInt16(0x06, buffer);
795 case ENTupleColumnType::kInt32: return SerializeUInt16(0x07, buffer);
796 case ENTupleColumnType::kUInt32: return SerializeUInt16(0x08, buffer);
797 case ENTupleColumnType::kInt64: return SerializeUInt16(0x09, buffer);
798 case ENTupleColumnType::kUInt64: return SerializeUInt16(0x0A, buffer);
799 case ENTupleColumnType::kReal16: return SerializeUInt16(0x0B, buffer);
800 case ENTupleColumnType::kReal32: return SerializeUInt16(0x0C, buffer);
801 case ENTupleColumnType::kReal64: return SerializeUInt16(0x0D, buffer);
802 case ENTupleColumnType::kIndex32: return SerializeUInt16(0x0E, buffer);
803 case ENTupleColumnType::kIndex64: return SerializeUInt16(0x0F, buffer);
804 case ENTupleColumnType::kSwitch: return SerializeUInt16(0x10, buffer);
805 case ENTupleColumnType::kSplitInt16: return SerializeUInt16(0x11, buffer);
806 case ENTupleColumnType::kSplitUInt16: return SerializeUInt16(0x12, buffer);
807 case ENTupleColumnType::kSplitInt32: return SerializeUInt16(0x13, buffer);
808 case ENTupleColumnType::kSplitUInt32: return SerializeUInt16(0x14, buffer);
809 case ENTupleColumnType::kSplitInt64: return SerializeUInt16(0x15, buffer);
810 case ENTupleColumnType::kSplitUInt64: return SerializeUInt16(0x16, buffer);
811 case ENTupleColumnType::kSplitReal32: return SerializeUInt16(0x18, buffer);
812 case ENTupleColumnType::kSplitReal64: return SerializeUInt16(0x19, buffer);
813 case ENTupleColumnType::kSplitIndex32: return SerializeUInt16(0x1A, buffer);
814 case ENTupleColumnType::kSplitIndex64: return SerializeUInt16(0x1B, buffer);
815 case ENTupleColumnType::kReal32Trunc: return SerializeUInt16(0x1C, buffer);
816 case ENTupleColumnType::kReal32Quant: return SerializeUInt16(0x1D, buffer);
817 default:
819 return SerializeUInt16(0x99, buffer);
820 return R__FAIL("unexpected column type");
821 }
822}
823
826{
827 std::uint16_t onDiskType;
828 auto result = DeserializeUInt16(buffer, onDiskType);
829
830 switch (onDiskType) {
831 case 0x00: type = ENTupleColumnType::kBit; break;
832 case 0x01: type = ENTupleColumnType::kByte; break;
833 case 0x02: type = ENTupleColumnType::kChar; break;
834 case 0x03: type = ENTupleColumnType::kInt8; break;
835 case 0x04: type = ENTupleColumnType::kUInt8; break;
836 case 0x05: type = ENTupleColumnType::kInt16; break;
837 case 0x06: type = ENTupleColumnType::kUInt16; break;
838 case 0x07: type = ENTupleColumnType::kInt32; break;
839 case 0x08: type = ENTupleColumnType::kUInt32; break;
840 case 0x09: type = ENTupleColumnType::kInt64; break;
841 case 0x0A: type = ENTupleColumnType::kUInt64; break;
842 case 0x0B: type = ENTupleColumnType::kReal16; break;
843 case 0x0C: type = ENTupleColumnType::kReal32; break;
844 case 0x0D: type = ENTupleColumnType::kReal64; break;
845 case 0x0E: type = ENTupleColumnType::kIndex32; break;
846 case 0x0F: type = ENTupleColumnType::kIndex64; break;
847 case 0x10: type = ENTupleColumnType::kSwitch; break;
848 case 0x11: type = ENTupleColumnType::kSplitInt16; break;
849 case 0x12: type = ENTupleColumnType::kSplitUInt16; break;
850 case 0x13: type = ENTupleColumnType::kSplitInt32; break;
851 case 0x14: type = ENTupleColumnType::kSplitUInt32; break;
852 case 0x15: type = ENTupleColumnType::kSplitInt64; break;
853 case 0x16: type = ENTupleColumnType::kSplitUInt64; break;
854 case 0x18: type = ENTupleColumnType::kSplitReal32; break;
855 case 0x19: type = ENTupleColumnType::kSplitReal64; break;
856 case 0x1A: type = ENTupleColumnType::kSplitIndex32; break;
857 case 0x1B: type = ENTupleColumnType::kSplitIndex64; break;
858 case 0x1C: type = ENTupleColumnType::kReal32Trunc; break;
859 case 0x1D: type = ENTupleColumnType::kReal32Quant; break;
860 // case 0x99 => kTestFutureColumnType missing on purpose
861 default:
862 // may be a column type introduced by a future version
864 break;
865 }
866 return result;
867}
868
871{
873 switch (structure) {
874 case ENTupleStructure::kPlain: return SerializeUInt16(0x00, buffer);
875 case ENTupleStructure::kCollection: return SerializeUInt16(0x01, buffer);
876 case ENTupleStructure::kRecord: return SerializeUInt16(0x02, buffer);
877 case ENTupleStructure::kVariant: return SerializeUInt16(0x03, buffer);
878 case ENTupleStructure::kStreamer: return SerializeUInt16(0x04, buffer);
879 default:
881 return SerializeUInt16(0x99, buffer);
882 return R__FAIL("unexpected field structure type");
883 }
884}
885
888{
890 std::uint16_t onDiskValue;
891 auto result = DeserializeUInt16(buffer, onDiskValue);
892 switch (onDiskValue) {
893 case 0x00: structure = ENTupleStructure::kPlain; break;
894 case 0x01: structure = ENTupleStructure::kCollection; break;
895 case 0x02: structure = ENTupleStructure::kRecord; break;
896 case 0x03: structure = ENTupleStructure::kVariant; break;
897 case 0x04: structure = ENTupleStructure::kStreamer; break;
898 // case 0x99 => kTestFutureFieldStructure intentionally missing
899 default: structure = ENTupleStructure::kUnknown;
900 }
901 return result;
902}
903
906{
907 switch (id) {
908 case ROOT::EExtraTypeInfoIds::kStreamerInfo: return SerializeUInt32(0x00, buffer);
909 default: return R__FAIL("unexpected extra type info id");
910 }
911}
912
915{
916 std::uint32_t onDiskValue;
917 auto result = DeserializeUInt32(buffer, onDiskValue);
918 switch (onDiskValue) {
919 case 0x00: id = ROOT::EExtraTypeInfoIds::kStreamerInfo; break;
920 default:
922 R__LOG_DEBUG(0, ROOT::Internal::NTupleLog()) << "Unknown extra type info id: " << onDiskValue;
923 }
924 return result;
925}
926
927std::uint32_t ROOT::Internal::RNTupleSerializer::SerializeEnvelopePreamble(std::uint16_t envelopeType, void *buffer)
928{
929 auto base = reinterpret_cast<unsigned char *>(buffer);
930 auto pos = base;
931 void **where = (buffer == nullptr) ? &buffer : reinterpret_cast<void **>(&pos);
932
933 pos += SerializeUInt64(envelopeType, *where);
934 // The 48bits size information is filled in the postscript
935 return pos - base;
936}
937
939 std::uint64_t size,
940 std::uint64_t &xxhash3)
941{
942 if (size < sizeof(std::uint64_t))
943 return R__FAIL("envelope size too small");
944 if (size >= static_cast<uint64_t>(1) << 48)
945 return R__FAIL("envelope size too big");
946 if (envelope) {
947 std::uint64_t typeAndSize;
948 DeserializeUInt64(envelope, typeAndSize);
949 typeAndSize |= (size + 8) << 16;
950 SerializeUInt64(typeAndSize, envelope);
951 }
952 return SerializeXxHash3(envelope, size, xxhash3, envelope ? (envelope + size) : nullptr);
953}
954
957{
958 std::uint64_t xxhash3;
959 return R__FORWARD_RESULT(SerializeEnvelopePostscript(envelope, size, xxhash3));
960}
961
963ROOT::Internal::RNTupleSerializer::DeserializeEnvelope(const void *buffer, std::uint64_t bufSize,
964 std::uint16_t expectedType, std::uint64_t &xxhash3)
965{
966 const std::uint64_t minEnvelopeSize = sizeof(std::uint64_t) + sizeof(std::uint64_t);
967 if (bufSize < minEnvelopeSize)
968 return R__FAIL("invalid envelope buffer, too short");
969
970 const auto *bytes = reinterpret_cast<const unsigned char *>(buffer);
971 const auto *base = bytes;
972
973 std::uint64_t typeAndSize;
974 DeserializeUInt64(bytes, typeAndSize);
975
976 std::uint16_t envelopeType = typeAndSize & 0xFFFF;
977 if (envelopeType != expectedType) {
978 return R__FAIL("envelope type mismatch: expected " + std::to_string(expectedType) + ", found " +
979 std::to_string(envelopeType));
980 }
981
982 std::uint64_t envelopeSize = typeAndSize >> 16;
983 if (bufSize < envelopeSize)
984 return R__FAIL("envelope buffer size too small");
985 if (envelopeSize < minEnvelopeSize)
986 return R__FAIL("invalid envelope, too short");
987
988 auto result = VerifyXxHash3(base, envelopeSize - 8, xxhash3);
989 if (!result)
990 return R__FORWARD_ERROR(result);
991
992 return sizeof(typeAndSize);
993}
994
996 std::uint64_t bufSize,
997 std::uint16_t expectedType)
998{
999 std::uint64_t xxhash3;
1000 return R__FORWARD_RESULT(DeserializeEnvelope(buffer, bufSize, expectedType, xxhash3));
1001}
1002
1004{
1005 // Marker: multiply the final size with 1
1006 return SerializeInt64(1, buffer);
1007}
1008
1010{
1011 auto base = reinterpret_cast<unsigned char *>(buffer);
1012 auto pos = base;
1013 void **where = (buffer == nullptr) ? &buffer : reinterpret_cast<void **>(&pos);
1014
1015 // Marker: multiply the final size with -1
1016 pos += SerializeInt64(-1, *where);
1017 pos += SerializeUInt32(nitems, *where);
1018 return pos - base;
1019}
1020
1023{
1024 auto preambleSize = sizeof(std::int64_t);
1025 if (size < preambleSize)
1026 return R__FAIL("frame too short: " + std::to_string(size));
1027 if (frame) {
1028 std::int64_t marker;
1029 DeserializeInt64(frame, marker);
1030 if ((marker < 0) && (size < (sizeof(std::uint32_t) + preambleSize)))
1031 return R__FAIL("frame too short: " + std::to_string(size));
1032 SerializeInt64(marker * static_cast<int64_t>(size), frame);
1033 }
1034 return 0;
1035}
1036
1038ROOT::Internal::RNTupleSerializer::DeserializeFrameHeader(const void *buffer, std::uint64_t bufSize,
1039 std::uint64_t &frameSize, std::uint32_t &nitems)
1040{
1041 std::uint64_t minSize = sizeof(std::int64_t);
1042 if (bufSize < minSize)
1043 return R__FAIL("frame too short");
1044
1045 std::int64_t *ssize = reinterpret_cast<std::int64_t *>(&frameSize);
1046 DeserializeInt64(buffer, *ssize);
1047
1048 auto bytes = reinterpret_cast<const unsigned char *>(buffer);
1049 bytes += minSize;
1050
1051 if (*ssize >= 0) {
1052 // Record frame
1053 nitems = 1;
1054 } else {
1055 // List frame
1056 minSize += sizeof(std::uint32_t);
1057 if (bufSize < minSize)
1058 return R__FAIL("frame too short");
1059 bytes += DeserializeUInt32(bytes, nitems);
1060 *ssize = -(*ssize);
1061 }
1062
1063 if (frameSize < minSize)
1064 return R__FAIL("corrupt frame size");
1065 if (bufSize < frameSize)
1066 return R__FAIL("frame too short");
1067
1068 return bytes - reinterpret_cast<const unsigned char *>(buffer);
1069}
1070
1072 std::uint64_t bufSize,
1073 std::uint64_t &frameSize)
1074{
1075 std::uint32_t nitems;
1076 return R__FORWARD_RESULT(DeserializeFrameHeader(buffer, bufSize, frameSize, nitems));
1077}
1078
1080ROOT::Internal::RNTupleSerializer::SerializeFeatureFlags(const std::vector<std::uint64_t> &flags, void *buffer)
1081{
1082 if (flags.empty())
1083 return SerializeUInt64(0, buffer);
1084
1085 if (buffer) {
1086 auto bytes = reinterpret_cast<unsigned char *>(buffer);
1087
1088 for (unsigned i = 0; i < flags.size(); ++i) {
1089 if (flags[i] & 0x8000000000000000)
1090 return R__FAIL("feature flag out of bounds");
1091
1092 // The MSb indicates that another Int64 follows; set this bit to 1 for all except the last element
1093 if (i == (flags.size() - 1))
1094 SerializeUInt64(flags[i], bytes);
1095 else
1096 bytes += SerializeUInt64(flags[i] | 0x8000000000000000, bytes);
1097 }
1098 }
1099 return (flags.size() * sizeof(std::int64_t));
1100}
1101
1103ROOT::Internal::RNTupleSerializer::DeserializeFeatureFlags(const void *buffer, std::uint64_t bufSize,
1104 std::vector<std::uint64_t> &flags)
1105{
1106 auto bytes = reinterpret_cast<const unsigned char *>(buffer);
1107
1108 flags.clear();
1109 std::uint64_t f;
1110 do {
1111 if (bufSize < sizeof(std::uint64_t))
1112 return R__FAIL("feature flag buffer too short");
1113 bytes += DeserializeUInt64(bytes, f);
1114 bufSize -= sizeof(std::uint64_t);
1115 flags.emplace_back(f & ~0x8000000000000000);
1116 } while (f & 0x8000000000000000);
1117
1118 return (flags.size() * sizeof(std::uint64_t));
1119}
1120
1123{
1125 return R__FAIL("locator is not serializable");
1126
1127 std::uint32_t size = 0;
1128 if ((locator.GetType() == RNTupleLocator::kTypeFile) &&
1129 (locator.GetNBytesOnStorage() <= std::numeric_limits<std::int32_t>::max())) {
1130 size += SerializeUInt32(locator.GetNBytesOnStorage(), buffer);
1131 size += SerializeUInt64(locator.GetPosition<std::uint64_t>(),
1132 buffer ? reinterpret_cast<unsigned char *>(buffer) + size : nullptr);
1133 return size;
1134 }
1135
1136 std::uint8_t locatorType = 0;
1137 auto payloadp = buffer ? reinterpret_cast<unsigned char *>(buffer) + sizeof(std::int32_t) : nullptr;
1138 switch (locator.GetType()) {
1140 size += SerializeLocatorPayloadLarge(locator, payloadp);
1141 locatorType = 0x01;
1142 break;
1144 size += SerializeLocatorPayloadObject64(locator, payloadp);
1145 locatorType = 0x02;
1146 break;
1148 size += SerializeLocatorPayloadMulti(locator, payloadp);
1149 locatorType = 0x03;
1150 break;
1151 default:
1152 if (locator.GetType() == ROOT::Internal::kTestLocatorType) {
1153 // For the testing locator, use the same payload format as Object64. We won't read it back anyway.
1154 RNTupleLocator dummy;
1156 size += SerializeLocatorPayloadObject64(dummy, payloadp);
1157 locatorType = 0x7e;
1158 } else {
1159 return R__FAIL("locator has unknown type");
1160 }
1161 }
1162 std::int32_t head = sizeof(std::int32_t) + size;
1163 head |= locator.GetReserved() << 16;
1164 head |= static_cast<int>(locatorType & 0x7F) << 24;
1165 head = -head;
1166 size += RNTupleSerializer::SerializeInt32(head, buffer);
1167 return size;
1168}
1169
1171 std::uint64_t bufSize,
1172 RNTupleLocator &locator)
1173{
1174 if (bufSize < sizeof(std::int32_t))
1175 return R__FAIL("too short locator");
1176
1177 auto bytes = reinterpret_cast<const unsigned char *>(buffer);
1178 std::int32_t head;
1179
1180 bytes += DeserializeInt32(bytes, head);
1181 bufSize -= sizeof(std::int32_t);
1182 if (head < 0) {
1183 head = -head;
1184 const int type = head >> 24;
1185 const std::uint32_t payloadSize = (static_cast<std::uint32_t>(head) & 0x0000FFFF) - sizeof(std::int32_t);
1186 if (bufSize < payloadSize)
1187 return R__FAIL("too short locator");
1188
1189 locator.SetReserved(static_cast<std::uint32_t>(head >> 16) & 0xFF);
1190 switch (type) {
1191 case 0x01:
1193 DeserializeLocatorPayloadLarge(bytes, locator);
1194 break;
1195 case 0x02: {
1197 auto res = DeserializeLocatorPayloadObject64(bytes, payloadSize, locator);
1198 if (!res)
1199 return R__FORWARD_ERROR(res);
1200 break;
1201 }
1202 case 0x03: {
1204 auto res = DeserializeLocatorPayloadMulti(bytes, payloadSize, locator);
1205 if (!res)
1206 return R__FORWARD_ERROR(res);
1207 break;
1208 }
1209 default: locator.SetType(RNTupleLocator::kTypeUnknown);
1210 }
1211 bytes += payloadSize;
1212 } else {
1213 if (bufSize < sizeof(std::uint64_t))
1214 return R__FAIL("too short locator");
1215 std::uint64_t offset;
1216 bytes += DeserializeUInt64(bytes, offset);
1218 locator.SetNBytesOnStorage(head);
1219 locator.SetPosition(offset);
1220 }
1221
1222 return bytes - reinterpret_cast<const unsigned char *>(buffer);
1223}
1224
1227{
1228 auto size = SerializeUInt64(envelopeLink.fLength, buffer);
1229 auto res =
1230 SerializeLocator(envelopeLink.fLocator, buffer ? reinterpret_cast<unsigned char *>(buffer) + size : nullptr);
1231 if (res)
1232 size += res.Unwrap();
1233 else
1234 return R__FORWARD_ERROR(res);
1235 return size;
1236}
1237
1239 std::uint64_t bufSize,
1240 REnvelopeLink &envelopeLink)
1241{
1242 if (bufSize < sizeof(std::int64_t))
1243 return R__FAIL("too short envelope link");
1244
1245 auto bytes = reinterpret_cast<const unsigned char *>(buffer);
1246 bytes += DeserializeUInt64(bytes, envelopeLink.fLength);
1247 bufSize -= sizeof(std::uint64_t);
1248 if (auto res = DeserializeLocator(bytes, bufSize, envelopeLink.fLocator)) {
1249 bytes += res.Unwrap();
1250 } else {
1251 return R__FORWARD_ERROR(res);
1252 }
1253 return bytes - reinterpret_cast<const unsigned char *>(buffer);
1254}
1255
1258{
1259 if (clusterSummary.fNEntries >= (static_cast<std::uint64_t>(1) << 56)) {
1260 return R__FAIL("number of entries in cluster exceeds maximum of 2^56");
1261 }
1262
1263 auto base = reinterpret_cast<unsigned char *>(buffer);
1264 auto pos = base;
1265 void **where = (buffer == nullptr) ? &buffer : reinterpret_cast<void **>(&pos);
1266
1267 auto frame = pos;
1268 pos += SerializeRecordFramePreamble(*where);
1269 pos += SerializeUInt64(clusterSummary.fFirstEntry, *where);
1270 const std::uint64_t nEntriesAndFlags =
1271 (static_cast<std::uint64_t>(clusterSummary.fFlags) << 56) | clusterSummary.fNEntries;
1272 pos += SerializeUInt64(nEntriesAndFlags, *where);
1273
1274 auto size = pos - frame;
1275 if (auto res = SerializeFramePostscript(frame, size)) {
1276 pos += res.Unwrap();
1277 } else {
1278 return R__FORWARD_ERROR(res);
1279 }
1280 return size;
1281}
1282
1285 RClusterSummary &clusterSummary)
1286{
1287 auto base = reinterpret_cast<const unsigned char *>(buffer);
1288 auto bytes = base;
1289 std::uint64_t frameSize;
1290 if (auto res = DeserializeFrameHeader(bytes, bufSize, frameSize)) {
1291 bytes += res.Unwrap();
1292 } else {
1293 return R__FORWARD_ERROR(res);
1294 }
1295
1296 auto fnFrameSizeLeft = [&]() { return frameSize - (bytes - base); };
1297 if (fnFrameSizeLeft() < 2 * sizeof(std::uint64_t))
1298 return R__FAIL("too short cluster summary");
1299
1300 bytes += DeserializeUInt64(bytes, clusterSummary.fFirstEntry);
1301 std::uint64_t nEntriesAndFlags;
1302 bytes += DeserializeUInt64(bytes, nEntriesAndFlags);
1303
1304 const std::uint64_t nEntries = (nEntriesAndFlags << 8) >> 8;
1305 const std::uint8_t flags = nEntriesAndFlags >> 56;
1306
1307 if (flags & 0x01) {
1308 return R__FAIL("sharded cluster flag set in cluster summary; sharded clusters are currently unsupported.");
1309 }
1310
1311 clusterSummary.fNEntries = nEntries;
1312 clusterSummary.fFlags = flags;
1313
1314 return frameSize;
1315}
1316
1319{
1320 auto base = reinterpret_cast<unsigned char *>(buffer);
1321 auto pos = base;
1322 void **where = (buffer == nullptr) ? &buffer : reinterpret_cast<void **>(&pos);
1323
1324 auto frame = pos;
1325 pos += SerializeRecordFramePreamble(*where);
1326 pos += SerializeUInt64(clusterGroup.fMinEntry, *where);
1327 pos += SerializeUInt64(clusterGroup.fEntrySpan, *where);
1328 pos += SerializeUInt32(clusterGroup.fNClusters, *where);
1329 if (auto res = SerializeEnvelopeLink(clusterGroup.fPageListEnvelopeLink, *where)) {
1330 pos += res.Unwrap();
1331 } else {
1332 return R__FORWARD_ERROR(res);
1333 }
1334 auto size = pos - frame;
1335 if (auto res = SerializeFramePostscript(frame, size)) {
1336 return size;
1337 } else {
1338 return R__FORWARD_ERROR(res);
1339 }
1340}
1341
1343 std::uint64_t bufSize,
1344 RClusterGroup &clusterGroup)
1345{
1346 auto base = reinterpret_cast<const unsigned char *>(buffer);
1347 auto bytes = base;
1348
1349 std::uint64_t frameSize;
1350 if (auto res = DeserializeFrameHeader(bytes, bufSize, frameSize)) {
1351 bytes += res.Unwrap();
1352 } else {
1353 return R__FORWARD_ERROR(res);
1354 }
1355
1356 auto fnFrameSizeLeft = [&]() { return frameSize - (bytes - base); };
1357 if (fnFrameSizeLeft() < sizeof(std::uint32_t) + 2 * sizeof(std::uint64_t))
1358 return R__FAIL("too short cluster group");
1359
1360 bytes += DeserializeUInt64(bytes, clusterGroup.fMinEntry);
1361 bytes += DeserializeUInt64(bytes, clusterGroup.fEntrySpan);
1362 bytes += DeserializeUInt32(bytes, clusterGroup.fNClusters);
1363 if (auto res = DeserializeEnvelopeLink(bytes, fnFrameSizeLeft(), clusterGroup.fPageListEnvelopeLink)) {
1364 bytes += res.Unwrap();
1365 } else {
1366 return R__FORWARD_ERROR(res);
1367 }
1368
1369 return frameSize;
1370}
1371
1373 bool forHeaderExtension)
1374{
1375 auto fieldZeroId = desc.GetFieldZeroId();
1376 auto depthFirstTraversal = [&](std::span<ROOT::DescriptorId_t> fieldTrees, auto doForEachField) {
1377 std::deque<ROOT::DescriptorId_t> idQueue{fieldTrees.begin(), fieldTrees.end()};
1378 while (!idQueue.empty()) {
1379 auto fieldId = idQueue.front();
1380 idQueue.pop_front();
1381 // Field zero has no physical representation nor columns of its own; recurse over its subfields only
1382 if (fieldId != fieldZeroId)
1383 doForEachField(fieldId);
1384 unsigned i = 0;
1385 for (const auto &f : desc.GetFieldIterable(fieldId))
1386 idQueue.insert(idQueue.begin() + i++, f.GetId());
1387 }
1388 };
1389
1390 R__ASSERT(desc.GetNFields() > 0); // we must have at least a zero field
1391
1392 std::vector<ROOT::DescriptorId_t> fieldTrees;
1393 if (!forHeaderExtension) {
1394 fieldTrees.emplace_back(fieldZeroId);
1395 } else if (auto xHeader = desc.GetHeaderExtension()) {
1396 fieldTrees = xHeader->GetTopMostFields(desc);
1397 }
1398 depthFirstTraversal(fieldTrees, [&](ROOT::DescriptorId_t fieldId) { MapFieldId(fieldId); });
1399 depthFirstTraversal(fieldTrees, [&](ROOT::DescriptorId_t fieldId) {
1400 for (const auto &c : desc.GetColumnIterable(fieldId)) {
1401 if (!c.IsAliasColumn()) {
1402 MapPhysicalColumnId(c.GetPhysicalId());
1403 }
1404 }
1405 });
1406
1407 if (forHeaderExtension) {
1408 // Create physical IDs for column representations that extend fields of the regular header.
1409 // First the physical columns then the alias columns.
1410 for (auto memId : desc.GetHeaderExtension()->GetExtendedColumnRepresentations()) {
1411 const auto &columnDesc = desc.GetColumnDescriptor(memId);
1412 if (!columnDesc.IsAliasColumn()) {
1413 MapPhysicalColumnId(columnDesc.GetPhysicalId());
1414 }
1415 }
1416 }
1417}
1418
1421 const RContext &context, bool forHeaderExtension)
1422{
1423 auto base = reinterpret_cast<unsigned char *>(buffer);
1424 auto pos = base;
1425 void **where = (buffer == nullptr) ? &buffer : reinterpret_cast<void **>(&pos);
1426
1427 std::size_t nFields = 0, nColumns = 0, nAliasColumns = 0, fieldListOffset = 0;
1428 // Columns in the extension header that are attached to a field of the regular header
1429 std::vector<std::reference_wrapper<const ROOT::RColumnDescriptor>> extraColumns;
1430 if (forHeaderExtension) {
1431 // A call to `RNTupleDescriptorBuilder::BeginHeaderExtension()` is not strictly required after serializing the
1432 // header, which may happen, e.g., in unit tests. Ensure an empty schema extension is serialized in this case
1433 if (auto xHeader = desc.GetHeaderExtension()) {
1434 nFields = xHeader->GetNFields();
1435 nColumns = xHeader->GetNPhysicalColumns();
1436 nAliasColumns = xHeader->GetNLogicalColumns() - xHeader->GetNPhysicalColumns();
1437 fieldListOffset = desc.GetNFields() - nFields - 1;
1438
1439 extraColumns.reserve(xHeader->GetExtendedColumnRepresentations().size());
1440 for (auto columnId : xHeader->GetExtendedColumnRepresentations()) {
1441 extraColumns.emplace_back(desc.GetColumnDescriptor(columnId));
1442 }
1443 }
1444 } else {
1445 if (auto xHeader = desc.GetHeaderExtension()) {
1446 nFields = desc.GetNFields() - xHeader->GetNFields() - 1;
1447 nColumns = desc.GetNPhysicalColumns() - xHeader->GetNPhysicalColumns();
1448 nAliasColumns = desc.GetNLogicalColumns() - desc.GetNPhysicalColumns() -
1449 (xHeader->GetNLogicalColumns() - xHeader->GetNPhysicalColumns());
1450 } else {
1451 nFields = desc.GetNFields() - 1;
1452 nColumns = desc.GetNPhysicalColumns();
1453 nAliasColumns = desc.GetNLogicalColumns() - desc.GetNPhysicalColumns();
1454 }
1455 }
1456 const auto nExtraTypeInfos = desc.GetNExtraTypeInfos();
1457 const auto &onDiskFields = context.GetOnDiskFieldList();
1458 R__ASSERT(onDiskFields.size() >= fieldListOffset);
1459 std::span<const ROOT::DescriptorId_t> fieldList{onDiskFields.data() + fieldListOffset, nFields};
1460
1461 auto frame = pos;
1462 pos += SerializeListFramePreamble(nFields, *where);
1463 if (auto res = SerializeFieldList(desc, fieldList, /*firstOnDiskId=*/fieldListOffset, context, *where)) {
1464 pos += res.Unwrap();
1465 } else {
1466 return R__FORWARD_ERROR(res);
1467 }
1468 if (auto res = SerializeFramePostscript(buffer ? frame : nullptr, pos - frame)) {
1469 pos += res.Unwrap();
1470 } else {
1471 return R__FORWARD_ERROR(res);
1472 }
1473
1474 frame = pos;
1475 pos += SerializeListFramePreamble(nColumns, *where);
1476 if (auto res = SerializeColumnsOfFields(desc, fieldList, context, *where, forHeaderExtension)) {
1477 pos += res.Unwrap();
1478 } else {
1479 return R__FORWARD_ERROR(res);
1480 }
1481 for (const auto &c : extraColumns) {
1482 if (!c.get().IsAliasColumn()) {
1483 if (auto res = SerializePhysicalColumn(c.get(), context, *where)) {
1484 pos += res.Unwrap();
1485 } else {
1486 return R__FORWARD_ERROR(res);
1487 }
1488 }
1489 }
1490 if (auto res = SerializeFramePostscript(buffer ? frame : nullptr, pos - frame)) {
1491 pos += res.Unwrap();
1492 } else {
1493 return R__FORWARD_ERROR(res);
1494 }
1495
1496 frame = pos;
1497 pos += SerializeListFramePreamble(nAliasColumns, *where);
1498 pos += SerializeAliasColumnsOfFields(desc, fieldList, context, *where, forHeaderExtension);
1499 for (const auto &c : extraColumns) {
1500 if (c.get().IsAliasColumn()) {
1501 pos += SerializeAliasColumn(c.get(), context, *where);
1502 }
1503 }
1504 if (auto res = SerializeFramePostscript(buffer ? frame : nullptr, pos - frame)) {
1505 pos += res.Unwrap();
1506 } else {
1507 return R__FORWARD_ERROR(res);
1508 }
1509
1510 frame = pos;
1511 // We only serialize the extra type info list in the header extension.
1512 if (forHeaderExtension) {
1513 pos += SerializeListFramePreamble(nExtraTypeInfos, *where);
1514 if (auto res = SerializeExtraTypeInfoList(desc, *where)) {
1515 pos += res.Unwrap();
1516 } else {
1517 return R__FORWARD_ERROR(res);
1518 }
1519 } else {
1520 pos += SerializeListFramePreamble(0, *where);
1521 }
1522 if (auto res = SerializeFramePostscript(buffer ? frame : nullptr, pos - frame)) {
1523 pos += res.Unwrap();
1524 } else {
1525 return R__FORWARD_ERROR(res);
1526 }
1527
1528 return static_cast<std::uint32_t>(pos - base);
1529}
1530
1533 RNTupleDescriptorBuilder &descBuilder)
1534{
1535 auto base = reinterpret_cast<const unsigned char *>(buffer);
1536 auto bytes = base;
1537 auto fnBufSizeLeft = [&]() { return bufSize - (bytes - base); };
1538
1539 std::uint64_t frameSize;
1540 auto frame = bytes;
1541 auto fnFrameSizeLeft = [&]() { return frameSize - (bytes - frame); };
1542
1543 std::uint32_t nFields;
1544 if (auto res = DeserializeFrameHeader(bytes, fnBufSizeLeft(), frameSize, nFields)) {
1545 bytes += res.Unwrap();
1546 } else {
1547 return R__FORWARD_ERROR(res);
1548 }
1549 // The zero field is always added before `DeserializeSchemaDescription()` is called
1550 const std::uint32_t fieldIdRangeBegin = descBuilder.GetDescriptor().GetNFields() - 1;
1551 for (unsigned i = 0; i < nFields; ++i) {
1552 std::uint32_t fieldId = fieldIdRangeBegin + i;
1553 RFieldDescriptorBuilder fieldBuilder(descBuilder.GetStringPool());
1554 if (auto res = DeserializeField(bytes, fnFrameSizeLeft(), fieldBuilder)) {
1555 bytes += res.Unwrap();
1556 } else {
1557 return R__FORWARD_ERROR(res);
1558 }
1559 if (fieldId == fieldBuilder.GetParentId())
1560 fieldBuilder.ParentId(kZeroFieldId);
1561 auto fieldDesc = fieldBuilder.FieldId(fieldId).MoveDescriptor();
1562 if (!fieldDesc)
1563 return R__FORWARD_ERROR(fieldDesc);
1564 const auto parentId = fieldDesc.Inspect().GetParentId();
1565 const auto projectionSourceId = fieldDesc.Inspect().GetProjectionSourceId();
1566 descBuilder.AddField(fieldDesc.Unwrap());
1567 auto resVoid = descBuilder.AddFieldLink(parentId, fieldId);
1568 if (!resVoid)
1569 return R__FORWARD_ERROR(resVoid);
1570 if (projectionSourceId != ROOT::kInvalidDescriptorId) {
1571 resVoid = descBuilder.AddFieldProjection(projectionSourceId, fieldId);
1572 if (!resVoid)
1573 return R__FORWARD_ERROR(resVoid);
1574 }
1575 }
1576 bytes = frame + frameSize;
1577
1578 // As columns are added in order of representation index and column index, determine the column index
1579 // for the currently deserialized column from the columns already added.
1580 auto fnNextColumnIndex = [&descBuilder](ROOT::DescriptorId_t fieldId,
1581 std::uint16_t representationIndex) -> std::uint32_t {
1582 const auto &existingColumns = descBuilder.GetDescriptor().GetFieldDescriptor(fieldId).GetLogicalColumnIds();
1583 if (existingColumns.empty())
1584 return 0;
1585 const auto &lastColumnDesc = descBuilder.GetDescriptor().GetColumnDescriptor(existingColumns.back());
1586 return (representationIndex == lastColumnDesc.GetRepresentationIndex()) ? (lastColumnDesc.GetIndex() + 1) : 0;
1587 };
1588
1589 std::uint32_t nColumns;
1590 frame = bytes;
1591 if (auto res = DeserializeFrameHeader(bytes, fnBufSizeLeft(), frameSize, nColumns)) {
1592 bytes += res.Unwrap();
1593 } else {
1594 return R__FORWARD_ERROR(res);
1595 }
1596
1597 if (descBuilder.GetDescriptor().GetNLogicalColumns() > descBuilder.GetDescriptor().GetNPhysicalColumns())
1598 descBuilder.ShiftAliasColumns(nColumns);
1599
1600 const std::uint32_t columnIdRangeBegin = descBuilder.GetDescriptor().GetNPhysicalColumns();
1601 for (unsigned i = 0; i < nColumns; ++i) {
1602 std::uint32_t columnId = columnIdRangeBegin + i;
1603 RColumnDescriptorBuilder columnBuilder;
1604 if (auto res = DeserializeColumn(bytes, fnFrameSizeLeft(), columnBuilder)) {
1605 bytes += res.Unwrap();
1606 } else {
1607 return R__FORWARD_ERROR(res);
1608 }
1609
1610 columnBuilder.Index(fnNextColumnIndex(columnBuilder.GetFieldId(), columnBuilder.GetRepresentationIndex()));
1611 columnBuilder.LogicalColumnId(columnId);
1612 columnBuilder.PhysicalColumnId(columnId);
1613 auto columnDesc = columnBuilder.MoveDescriptor();
1614 if (!columnDesc)
1615 return R__FORWARD_ERROR(columnDesc);
1616 auto resVoid = descBuilder.AddColumn(columnDesc.Unwrap());
1617 if (!resVoid)
1618 return R__FORWARD_ERROR(resVoid);
1619 }
1620 bytes = frame + frameSize;
1621
1622 std::uint32_t nAliasColumns;
1623 frame = bytes;
1624 if (auto res = DeserializeFrameHeader(bytes, fnBufSizeLeft(), frameSize, nAliasColumns)) {
1625 bytes += res.Unwrap();
1626 } else {
1627 return R__FORWARD_ERROR(res);
1628 }
1629 const std::uint32_t aliasColumnIdRangeBegin = descBuilder.GetDescriptor().GetNLogicalColumns();
1630 for (unsigned i = 0; i < nAliasColumns; ++i) {
1631 std::uint32_t physicalId;
1632 std::uint32_t fieldId;
1633 if (auto res = DeserializeAliasColumn(bytes, fnFrameSizeLeft(), physicalId, fieldId)) {
1634 bytes += res.Unwrap();
1635 } else {
1636 return R__FORWARD_ERROR(res);
1637 }
1638
1639 RColumnDescriptorBuilder columnBuilder;
1640 columnBuilder.LogicalColumnId(aliasColumnIdRangeBegin + i).PhysicalColumnId(physicalId).FieldId(fieldId);
1641 const auto &physicalColumnDesc = descBuilder.GetDescriptor().GetColumnDescriptor(physicalId);
1642 columnBuilder.BitsOnStorage(physicalColumnDesc.GetBitsOnStorage());
1643 columnBuilder.ValueRange(physicalColumnDesc.GetValueRange());
1644 columnBuilder.Type(physicalColumnDesc.GetType());
1645 columnBuilder.RepresentationIndex(physicalColumnDesc.GetRepresentationIndex());
1646 columnBuilder.Index(fnNextColumnIndex(columnBuilder.GetFieldId(), columnBuilder.GetRepresentationIndex()));
1647
1648 auto aliasColumnDesc = columnBuilder.MoveDescriptor();
1649 if (!aliasColumnDesc)
1650 return R__FORWARD_ERROR(aliasColumnDesc);
1651 auto resVoid = descBuilder.AddColumn(aliasColumnDesc.Unwrap());
1652 if (!resVoid)
1653 return R__FORWARD_ERROR(resVoid);
1654 }
1655 bytes = frame + frameSize;
1656
1657 std::uint32_t nExtraTypeInfos;
1658 frame = bytes;
1659 if (auto res = DeserializeFrameHeader(bytes, fnBufSizeLeft(), frameSize, nExtraTypeInfos)) {
1660 bytes += res.Unwrap();
1661 } else {
1662 return R__FORWARD_ERROR(res);
1663 }
1664 for (unsigned i = 0; i < nExtraTypeInfos; ++i) {
1665 RExtraTypeInfoDescriptorBuilder extraTypeInfoBuilder;
1666 if (auto res = DeserializeExtraTypeInfo(bytes, fnFrameSizeLeft(), extraTypeInfoBuilder)) {
1667 bytes += res.Unwrap();
1668 } else {
1669 return R__FORWARD_ERROR(res);
1670 }
1671
1672 auto extraTypeInfoDesc = extraTypeInfoBuilder.MoveDescriptor();
1673 // We ignore unknown extra type information
1674 if (extraTypeInfoDesc)
1675 descBuilder.AddExtraTypeInfo(extraTypeInfoDesc.Unwrap());
1676 }
1677 bytes = frame + frameSize;
1678
1679 return bytes - base;
1680}
1681
1684{
1685 RContext context;
1686
1687 auto base = reinterpret_cast<unsigned char *>(buffer);
1688 auto pos = base;
1689 void **where = (buffer == nullptr) ? &buffer : reinterpret_cast<void **>(&pos);
1690
1691 pos += SerializeEnvelopePreamble(kEnvelopeTypeHeader, *where);
1692 if (auto res = SerializeFeatureFlags(desc.GetFeatureFlags(), *where)) {
1693 pos += res.Unwrap();
1694 } else {
1695 return R__FORWARD_ERROR(res);
1696 }
1697 pos += SerializeString(desc.GetName(), *where);
1698 pos += SerializeString(desc.GetDescription(), *where);
1699 pos += SerializeString(std::string("ROOT v") + ROOT_RELEASE, *where);
1700
1701 context.MapSchema(desc, /*forHeaderExtension=*/false);
1702
1703 if (auto res = SerializeSchemaDescription(*where, desc, context)) {
1704 pos += res.Unwrap();
1705 } else {
1706 return R__FORWARD_ERROR(res);
1707 }
1708
1709 std::uint64_t size = pos - base;
1710 std::uint64_t xxhash3 = 0;
1711 if (auto res = SerializeEnvelopePostscript(base, size, xxhash3)) {
1712 size += res.Unwrap();
1713 } else {
1714 return R__FORWARD_ERROR(res);
1715 }
1716
1717 context.SetHeaderSize(size);
1718 context.SetHeaderXxHash3(xxhash3);
1719 return context;
1720}
1721
1724 std::span<ROOT::DescriptorId_t> physClusterIDs,
1725 const RContext &context)
1726{
1727 auto base = reinterpret_cast<unsigned char *>(buffer);
1728 auto pos = base;
1729 void **where = (buffer == nullptr) ? &buffer : reinterpret_cast<void **>(&pos);
1730
1731 pos += SerializeEnvelopePreamble(kEnvelopeTypePageList, *where);
1732
1733 pos += SerializeUInt64(context.GetHeaderXxHash3(), *where);
1734
1735 // Cluster summaries
1736 const auto nClusters = physClusterIDs.size();
1737 auto clusterSummaryFrame = pos;
1738 pos += SerializeListFramePreamble(nClusters, *where);
1739 for (auto clusterId : physClusterIDs) {
1740 const auto &clusterDesc = desc.GetClusterDescriptor(context.GetMemClusterId(clusterId));
1741 RClusterSummary summary{clusterDesc.GetFirstEntryIndex(), clusterDesc.GetNEntries(), 0};
1742 if (auto res = SerializeClusterSummary(summary, *where)) {
1743 pos += res.Unwrap();
1744 } else {
1745 return R__FORWARD_ERROR(res);
1746 }
1747 }
1748 if (auto res = SerializeFramePostscript(buffer ? clusterSummaryFrame : nullptr, pos - clusterSummaryFrame)) {
1749 pos += res.Unwrap();
1750 } else {
1751 return R__FORWARD_ERROR(res);
1752 }
1753
1754 // Page locations
1755 auto topMostFrame = pos;
1756 pos += SerializeListFramePreamble(nClusters, *where);
1757
1758 for (auto clusterId : physClusterIDs) {
1759 const auto &clusterDesc = desc.GetClusterDescriptor(context.GetMemClusterId(clusterId));
1760 // Get an ordered set of physical column ids
1761 std::set<ROOT::DescriptorId_t> onDiskColumnIds;
1762 for (const auto &columnRange : clusterDesc.GetColumnRangeIterable())
1763 onDiskColumnIds.insert(context.GetOnDiskColumnId(columnRange.GetPhysicalColumnId()));
1764
1765 auto outerFrame = pos;
1766 pos += SerializeListFramePreamble(onDiskColumnIds.size(), *where);
1767 for (auto onDiskId : onDiskColumnIds) {
1768 auto memId = context.GetMemColumnId(onDiskId);
1769 const auto &columnRange = clusterDesc.GetColumnRange(memId);
1770
1771 auto innerFrame = pos;
1772 if (columnRange.IsSuppressed()) {
1773 // Empty page range
1774 pos += SerializeListFramePreamble(0, *where);
1775 pos += SerializeInt64(kSuppressedColumnMarker, *where);
1776 } else {
1777 const auto &pageRange = clusterDesc.GetPageRange(memId);
1778 pos += SerializeListFramePreamble(pageRange.GetPageInfos().size(), *where);
1779
1780 for (const auto &pi : pageRange.GetPageInfos()) {
1781 std::int32_t nElements =
1782 pi.HasChecksum() ? -static_cast<std::int32_t>(pi.GetNElements()) : pi.GetNElements();
1783 pos += SerializeUInt32(nElements, *where);
1784 if (auto res = SerializeLocator(pi.GetLocator(), *where)) {
1785 pos += res.Unwrap();
1786 } else {
1787 return R__FORWARD_ERROR(res);
1788 }
1789 }
1790 pos += SerializeInt64(columnRange.GetFirstElementIndex(), *where);
1791 pos += SerializeUInt32(columnRange.GetCompressionSettings().value(), *where);
1792 }
1793
1794 if (auto res = SerializeFramePostscript(buffer ? innerFrame : nullptr, pos - innerFrame)) {
1795 pos += res.Unwrap();
1796 } else {
1797 return R__FORWARD_ERROR(res);
1798 }
1799 }
1800 if (auto res = SerializeFramePostscript(buffer ? outerFrame : nullptr, pos - outerFrame)) {
1801 pos += res.Unwrap();
1802 } else {
1803 return R__FORWARD_ERROR(res);
1804 }
1805 }
1806
1807 if (auto res = SerializeFramePostscript(buffer ? topMostFrame : nullptr, pos - topMostFrame)) {
1808 pos += res.Unwrap();
1809 } else {
1810 return R__FORWARD_ERROR(res);
1811 }
1812 std::uint64_t size = pos - base;
1813 if (auto res = SerializeEnvelopePostscript(base, size)) {
1814 size += res.Unwrap();
1815 } else {
1816 return R__FORWARD_ERROR(res);
1817 }
1818 return size;
1819}
1820
1822 const ROOT::RNTupleDescriptor &desc,
1823 const RContext &context)
1824{
1825 auto base = reinterpret_cast<unsigned char *>(buffer);
1826 auto pos = base;
1827 void **where = (buffer == nullptr) ? &buffer : reinterpret_cast<void **>(&pos);
1828
1829 pos += SerializeEnvelopePreamble(kEnvelopeTypeFooter, *where);
1830
1831 // NOTE: we currently serialize all feature flags in the footer, even those that were already written in the
1832 // header. This is fine, as they will be logically OR-ed together during deserialization.
1833 if (auto res = SerializeFeatureFlags(desc.GetFeatureFlags(), *where)) {
1834 pos += res.Unwrap();
1835 } else {
1836 return R__FORWARD_ERROR(res);
1837 }
1838 pos += SerializeUInt64(context.GetHeaderXxHash3(), *where);
1839
1840 // Schema extension, i.e. incremental changes with respect to the header
1841 auto frame = pos;
1842 pos += SerializeRecordFramePreamble(*where);
1843 if (auto res = SerializeSchemaDescription(*where, desc, context, /*forHeaderExtension=*/true)) {
1844 pos += res.Unwrap();
1845 } else {
1846 return R__FORWARD_ERROR(res);
1847 }
1848 if (auto res = SerializeFramePostscript(buffer ? frame : nullptr, pos - frame)) {
1849 pos += res.Unwrap();
1850 } else {
1851 return R__FORWARD_ERROR(res);
1852 }
1853
1854 // Cluster groups
1855 frame = pos;
1856 const auto nClusterGroups = desc.GetNClusterGroups();
1857 pos += SerializeListFramePreamble(nClusterGroups, *where);
1858 for (unsigned int i = 0; i < nClusterGroups; ++i) {
1859 const auto &cgDesc = desc.GetClusterGroupDescriptor(context.GetMemClusterGroupId(i));
1860 RClusterGroup clusterGroup;
1861 clusterGroup.fMinEntry = cgDesc.GetMinEntry();
1862 clusterGroup.fEntrySpan = cgDesc.GetEntrySpan();
1863 clusterGroup.fNClusters = cgDesc.GetNClusters();
1864 clusterGroup.fPageListEnvelopeLink.fLength = cgDesc.GetPageListLength();
1865 clusterGroup.fPageListEnvelopeLink.fLocator = cgDesc.GetPageListLocator();
1866 if (auto res = SerializeClusterGroup(clusterGroup, *where)) {
1867 pos += res.Unwrap();
1868 } else {
1869 return R__FORWARD_ERROR(res);
1870 }
1871 }
1872 if (auto res = SerializeFramePostscript(buffer ? frame : nullptr, pos - frame)) {
1873 pos += res.Unwrap();
1874 } else {
1875 return R__FORWARD_ERROR(res);
1876 }
1877
1878 // Attributes
1879 frame = pos;
1880 const auto nAttributeSets = desc.GetNAttributeSets();
1881 if (nAttributeSets > 0) {
1882 R__LOG_WARNING(NTupleLog()) << "RNTuple Attributes are experimental. They are not guaranteed to be readable "
1883 "back in the future (but your main data is)";
1884 }
1885 pos += SerializeListFramePreamble(nAttributeSets, *where);
1886 for (const auto &attrSet : desc.GetAttrSetIterable()) {
1887 if (auto res = SerializeAttributeSet(attrSet, *where)) {
1888 pos += res.Unwrap();
1889 } else {
1890 return R__FORWARD_ERROR(res);
1891 }
1892 }
1893 if (auto res = SerializeFramePostscript(buffer ? frame : nullptr, pos - frame)) {
1894 pos += res.Unwrap();
1895 } else {
1896 return R__FORWARD_ERROR(res);
1897 }
1898
1899 std::uint32_t size = pos - base;
1900 if (auto res = SerializeEnvelopePostscript(base, size)) {
1901 size += res.Unwrap();
1902 } else {
1903 return R__FORWARD_ERROR(res);
1904 }
1905 return size;
1906}
1907
1910 void *buffer)
1911{
1912 auto base = reinterpret_cast<unsigned char *>(buffer);
1913 auto pos = base;
1914 void **where = (buffer == nullptr) ? &buffer : reinterpret_cast<void **>(&pos);
1915
1916 auto frame = pos;
1918 pos += SerializeUInt16(attrDesc.GetSchemaVersionMajor(), *where);
1919 pos += SerializeUInt16(attrDesc.GetSchemaVersionMinor(), *where);
1920 pos += SerializeUInt32(attrDesc.GetAnchorLength(), *where);
1921 if (auto res = SerializeLocator(attrDesc.GetAnchorLocator(), *where)) {
1922 pos += res.Unwrap();
1923 } else {
1924 return R__FORWARD_ERROR(res);
1925 }
1926 pos += SerializeString(attrDesc.GetName(), *where);
1927 auto size = pos - frame;
1928 if (auto res = SerializeFramePostscript(buffer ? frame : nullptr, size)) {
1929 return size;
1930 } else {
1931 return R__FORWARD_ERROR(res);
1932 }
1933}
1934
1935static ROOT::RResult<void> CheckFeatureFlags(const std::vector<std::uint64_t> &featureFlags)
1936{
1937 for (std::size_t i = 0; i < featureFlags.size(); ++i) {
1938 if (!featureFlags[i])
1939 continue;
1940 // NOTE: this assumes all valid feature flags are consecutive, thus we can just check the highest one set.
1941 unsigned int highestBitSet = 64 * i + (63 - ROOT::Internal::LeadingZeroes(featureFlags[i]));
1943 return R__FAIL("unsupported format feature: " + std::to_string(highestBitSet));
1944 }
1946}
1947
1949 RNTupleDescriptorBuilder &descBuilder)
1950{
1951 auto base = reinterpret_cast<const unsigned char *>(buffer);
1952 auto bytes = base;
1953 auto fnBufSizeLeft = [&]() { return bufSize - (bytes - base); };
1954
1955 std::uint64_t xxhash3{0};
1956 if (auto res = DeserializeEnvelope(bytes, fnBufSizeLeft(), kEnvelopeTypeHeader, xxhash3)) {
1957 bytes += res.Unwrap();
1958 } else {
1959 return R__FORWARD_ERROR(res);
1960 }
1961 descBuilder.SetOnDiskHeaderXxHash3(xxhash3);
1962
1963 std::vector<std::uint64_t> featureFlags;
1964 if (auto res = DeserializeFeatureFlags(bytes, fnBufSizeLeft(), featureFlags)) {
1965 bytes += res.Unwrap();
1966 } else {
1967 return R__FORWARD_ERROR(res);
1968 }
1969 if (auto res = CheckFeatureFlags(featureFlags); !res) {
1970 return R__FORWARD_ERROR(res);
1971 }
1972
1973 std::string name;
1974 std::string description;
1975 std::string writer;
1976 if (auto res = DeserializeString(bytes, fnBufSizeLeft(), name)) {
1977 bytes += res.Unwrap();
1978 } else {
1979 return R__FORWARD_ERROR(res);
1980 }
1981 if (auto res = DeserializeString(bytes, fnBufSizeLeft(), description)) {
1982 bytes += res.Unwrap();
1983 } else {
1984 return R__FORWARD_ERROR(res);
1985 }
1986 if (auto res = DeserializeString(bytes, fnBufSizeLeft(), writer)) {
1987 bytes += res.Unwrap();
1988 } else {
1989 return R__FORWARD_ERROR(res);
1990 }
1991 descBuilder.SetNTuple(name, description);
1992
1993 // Zero field
1994 descBuilder.AddField(RFieldDescriptorBuilder(descBuilder.GetStringPool())
1995 .FieldId(kZeroFieldId)
1998 .Unwrap());
1999 if (auto res = DeserializeSchemaDescription(bytes, fnBufSizeLeft(), descBuilder)) {
2000 return RResult<void>::Success();
2001 } else {
2002 return R__FORWARD_ERROR(res);
2003 }
2004}
2005
2007 RNTupleDescriptorBuilder &descBuilder)
2008{
2009 auto base = reinterpret_cast<const unsigned char *>(buffer);
2010 auto bytes = base;
2011 auto fnBufSizeLeft = [&]() { return bufSize - (bytes - base); };
2012 if (auto res = DeserializeEnvelope(bytes, fnBufSizeLeft(), kEnvelopeTypeFooter)) {
2013 bytes += res.Unwrap();
2014 } else {
2015 return R__FORWARD_ERROR(res);
2016 }
2017
2018 std::vector<std::uint64_t> featureFlags;
2019 if (auto res = DeserializeFeatureFlags(bytes, fnBufSizeLeft(), featureFlags)) {
2020 bytes += res.Unwrap();
2021 } else {
2022 return R__FORWARD_ERROR(res);
2023 }
2024 if (auto res = CheckFeatureFlags(featureFlags); !res) {
2025 return R__FORWARD_ERROR(res);
2026 }
2027
2028 std::uint64_t xxhash3{0};
2029 if (fnBufSizeLeft() < static_cast<int>(sizeof(std::uint64_t)))
2030 return R__FAIL("footer too short");
2031 bytes += DeserializeUInt64(bytes, xxhash3);
2032 if (xxhash3 != descBuilder.GetDescriptor().GetOnDiskHeaderXxHash3())
2033 return R__FAIL("XxHash-3 mismatch between header and footer");
2034
2035 std::uint64_t frameSize;
2036 auto frame = bytes;
2037 auto fnFrameSizeLeft = [&]() { return frameSize - (bytes - frame); };
2038
2039 if (auto res = DeserializeFrameHeader(bytes, fnBufSizeLeft(), frameSize)) {
2040 bytes += res.Unwrap();
2041 } else {
2042 return R__FORWARD_ERROR(res);
2043 }
2044 if (fnFrameSizeLeft() > 0) {
2045 descBuilder.BeginHeaderExtension();
2046 if (auto res = DeserializeSchemaDescription(bytes, fnFrameSizeLeft(), descBuilder); !res) {
2047 return R__FORWARD_ERROR(res);
2048 }
2049 }
2050 bytes = frame + frameSize;
2051
2052 {
2053 std::uint32_t nClusterGroups;
2054 frame = bytes;
2055 if (auto res = DeserializeFrameHeader(bytes, fnBufSizeLeft(), frameSize, nClusterGroups)) {
2056 bytes += res.Unwrap();
2057 } else {
2058 return R__FORWARD_ERROR(res);
2059 }
2060 for (std::uint32_t groupId = 0; groupId < nClusterGroups; ++groupId) {
2061 RClusterGroup clusterGroup;
2062 if (auto res = DeserializeClusterGroup(bytes, fnFrameSizeLeft(), clusterGroup)) {
2063 bytes += res.Unwrap();
2064 } else {
2065 return R__FORWARD_ERROR(res);
2066 }
2067
2069 RClusterGroupDescriptorBuilder clusterGroupBuilder;
2070 clusterGroupBuilder.ClusterGroupId(groupId)
2073 .MinEntry(clusterGroup.fMinEntry)
2074 .EntrySpan(clusterGroup.fEntrySpan)
2075 .NClusters(clusterGroup.fNClusters);
2076 descBuilder.AddClusterGroup(clusterGroupBuilder.MoveDescriptor().Unwrap());
2077 }
2078 bytes = frame + frameSize;
2079 }
2080
2081 // NOTE: Attributes were introduced in v1.0.1.0, so this section may be missing.
2082 // Testing for > 8 because bufSize includes the checksum.
2083 if (fnBufSizeLeft() > 8) {
2084 std::uint32_t nAttributeSets;
2085 frame = bytes;
2086 if (auto res = DeserializeFrameHeader(bytes, fnBufSizeLeft(), frameSize, nAttributeSets)) {
2087 bytes += res.Unwrap();
2088 } else {
2089 return R__FORWARD_ERROR(res);
2090 }
2091 if (nAttributeSets > 0) {
2092 R__LOG_WARNING(NTupleLog()) << "RNTuple Attributes are experimental. They are not guaranteed to be readable "
2093 "back in the future (but your main data is)";
2094 }
2095 for (std::uint32_t attrSetId = 0; attrSetId < nAttributeSets; ++attrSetId) {
2097 if (auto res = DeserializeAttributeSet(bytes, fnBufSizeLeft(), attrSetDescBld)) {
2098 descBuilder.AddAttributeSet(attrSetDescBld.MoveDescriptor().Unwrap());
2099 bytes += res.Unwrap();
2100 } else {
2101 return R__FORWARD_ERROR(res);
2102 }
2103 }
2104 bytes = frame + frameSize;
2105 }
2106
2107 return RResult<void>::Success();
2108}
2109
2111 const void *buffer, std::uint64_t bufSize, Experimental::Internal::RNTupleAttrSetDescriptorBuilder &attrSetDescBld)
2112{
2113 auto base = reinterpret_cast<const unsigned char *>(buffer);
2114 auto bytes = base;
2115 auto fnBufSizeLeft = [&]() { return bufSize - (bytes - base); };
2116
2117 std::uint64_t frameSize;
2118 if (auto res = DeserializeFrameHeader(bytes, fnBufSizeLeft(), frameSize)) {
2119 bytes += res.Unwrap();
2120 } else {
2121 return R__FORWARD_ERROR(res);
2122 }
2123 if (fnBufSizeLeft() < static_cast<int>(sizeof(std::uint64_t)))
2124 return R__FAIL("record frame too short");
2125 std::uint16_t vMajor, vMinor;
2126 bytes += DeserializeUInt16(bytes, vMajor);
2127 bytes += DeserializeUInt16(bytes, vMinor);
2128 std::uint32_t anchorLen;
2129 bytes += DeserializeUInt32(bytes, anchorLen);
2130 RNTupleLocator anchorLoc;
2131 if (auto res = DeserializeLocator(bytes, fnBufSizeLeft(), anchorLoc)) {
2132 bytes += res.Unwrap();
2133 } else {
2134 return R__FORWARD_ERROR(res);
2135 }
2136 std::string name;
2137 if (auto res = DeserializeString(bytes, fnBufSizeLeft(), name)) {
2138 bytes += res.Unwrap();
2139 } else {
2140 return R__FORWARD_ERROR(res);
2141 }
2142
2143 attrSetDescBld.SchemaVersion(vMajor, vMinor).AnchorLength(anchorLen).AnchorLocator(anchorLoc).Name(name);
2144
2145 return frameSize;
2146}
2147
2149ROOT::Internal::RNTupleSerializer::DeserializePageListRaw(const void *buffer, std::uint64_t bufSize,
2150 ROOT::DescriptorId_t clusterGroupId,
2151 const ROOT::RNTupleDescriptor &desc)
2152{
2153 auto base = reinterpret_cast<const unsigned char *>(buffer);
2154 auto bytes = base;
2155 auto fnBufSizeLeft = [&]() { return bufSize - (bytes - base); };
2156
2157 if (auto res = DeserializeEnvelope(bytes, fnBufSizeLeft(), kEnvelopeTypePageList)) {
2158 bytes += res.Unwrap();
2159 } else {
2160 return R__FORWARD_ERROR(res);
2161 }
2162
2163 std::uint64_t xxhash3{0};
2164 if (fnBufSizeLeft() < static_cast<int>(sizeof(std::uint64_t)))
2165 return R__FAIL("page list too short");
2166 bytes += DeserializeUInt64(bytes, xxhash3);
2167 if (xxhash3 != desc.GetOnDiskHeaderXxHash3())
2168 return R__FAIL("XxHash-3 mismatch between header and page list");
2169
2170 std::vector<RClusterDescriptorBuilder> clusterBuilders;
2171 ROOT::DescriptorId_t firstClusterId{0};
2172 for (ROOT::DescriptorId_t i = 0; i < clusterGroupId; ++i) {
2173 firstClusterId = firstClusterId + desc.GetClusterGroupDescriptor(i).GetNClusters();
2174 }
2175
2176 std::uint64_t clusterSummaryFrameSize;
2177 auto clusterSummaryFrame = bytes;
2178 auto fnClusterSummaryFrameSizeLeft = [&]() { return clusterSummaryFrameSize - (bytes - clusterSummaryFrame); };
2179
2180 std::uint32_t nClusterSummaries;
2181 if (auto res = DeserializeFrameHeader(bytes, fnBufSizeLeft(), clusterSummaryFrameSize, nClusterSummaries)) {
2182 bytes += res.Unwrap();
2183 } else {
2184 return R__FORWARD_ERROR(res);
2185 }
2186 for (auto clusterId = firstClusterId; clusterId < firstClusterId + nClusterSummaries; ++clusterId) {
2187 RClusterSummary clusterSummary;
2188 if (auto res = DeserializeClusterSummary(bytes, fnClusterSummaryFrameSizeLeft(), clusterSummary)) {
2189 bytes += res.Unwrap();
2190 } else {
2191 return R__FORWARD_ERROR(res);
2192 }
2193
2195 builder.ClusterId(clusterId).FirstEntryIndex(clusterSummary.fFirstEntry).NEntries(clusterSummary.fNEntries);
2196 clusterBuilders.emplace_back(std::move(builder));
2197 }
2198 bytes = clusterSummaryFrame + clusterSummaryFrameSize;
2199
2200 std::uint64_t topMostFrameSize;
2201 auto topMostFrame = bytes;
2202 auto fnTopMostFrameSizeLeft = [&]() { return topMostFrameSize - (bytes - topMostFrame); };
2203
2204 std::uint32_t nClusters;
2205 if (auto res = DeserializeFrameHeader(bytes, fnBufSizeLeft(), topMostFrameSize, nClusters)) {
2206 bytes += res.Unwrap();
2207 } else {
2208 return R__FORWARD_ERROR(res);
2209 }
2210
2211 if (nClusters != nClusterSummaries)
2212 return R__FAIL("mismatch between number of clusters and number of cluster summaries");
2213
2214 for (std::uint32_t i = 0; i < nClusters; ++i) {
2215 std::uint64_t outerFrameSize;
2216 auto outerFrame = bytes;
2217 auto fnOuterFrameSizeLeft = [&]() { return outerFrameSize - (bytes - outerFrame); };
2218
2219 std::uint32_t nColumns;
2220 if (auto res = DeserializeFrameHeader(bytes, fnTopMostFrameSizeLeft(), outerFrameSize, nColumns)) {
2221 bytes += res.Unwrap();
2222 } else {
2223 return R__FORWARD_ERROR(res);
2224 }
2225
2226 for (std::uint32_t j = 0; j < nColumns; ++j) {
2227 std::uint64_t innerFrameSize;
2228 auto innerFrame = bytes;
2229 auto fnInnerFrameSizeLeft = [&]() { return innerFrameSize - (bytes - innerFrame); };
2230
2231 std::uint32_t nPages;
2232 if (auto res = DeserializeFrameHeader(bytes, fnOuterFrameSizeLeft(), innerFrameSize, nPages)) {
2233 bytes += res.Unwrap();
2234 } else {
2235 return R__FORWARD_ERROR(res);
2236 }
2237
2239 pageRange.SetPhysicalColumnId(j);
2240 for (std::uint32_t k = 0; k < nPages; ++k) {
2241 if (fnInnerFrameSizeLeft() < static_cast<int>(sizeof(std::uint32_t)))
2242 return R__FAIL("inner frame too short");
2243 std::int32_t nElements;
2244 bool hasChecksum = false;
2245 RNTupleLocator locator;
2246 bytes += DeserializeInt32(bytes, nElements);
2247 if (nElements < 0) {
2248 nElements = -nElements;
2249 hasChecksum = true;
2250 }
2251 if (auto res = DeserializeLocator(bytes, fnInnerFrameSizeLeft(), locator)) {
2252 bytes += res.Unwrap();
2253 } else {
2254 return R__FORWARD_ERROR(res);
2255 }
2256 pageRange.GetPageInfos().push_back({static_cast<std::uint32_t>(nElements), locator, hasChecksum});
2257 }
2258
2259 if (fnInnerFrameSizeLeft() < static_cast<int>(sizeof(std::int64_t)))
2260 return R__FAIL("page list frame too short");
2261 std::int64_t columnOffset;
2262 bytes += DeserializeInt64(bytes, columnOffset);
2263 if (columnOffset < 0) {
2264 if (nPages > 0)
2265 return R__FAIL("unexpected non-empty page list");
2266 clusterBuilders[i].MarkSuppressedColumnRange(j);
2267 } else {
2268 if (fnInnerFrameSizeLeft() < static_cast<int>(sizeof(std::uint32_t)))
2269 return R__FAIL("page list frame too short");
2270 std::uint32_t compressionSettings;
2271 bytes += DeserializeUInt32(bytes, compressionSettings);
2272 clusterBuilders[i].CommitColumnRange(j, columnOffset, compressionSettings, pageRange);
2273 }
2274
2275 bytes = innerFrame + innerFrameSize;
2276 } // loop over columns
2277
2278 bytes = outerFrame + outerFrameSize;
2279 } // loop over clusters
2280
2281 return clusterBuilders;
2282}
2283
2285 ROOT::DescriptorId_t clusterGroupId,
2288{
2289 auto clusterBuildersRes = RNTupleSerializer::DeserializePageListRaw(buffer, bufSize, clusterGroupId, desc);
2290 if (!clusterBuildersRes)
2291 return R__FORWARD_ERROR(clusterBuildersRes);
2292
2293 auto clusterBuilders = clusterBuildersRes.Unwrap();
2294
2295 std::vector<ROOT::RClusterDescriptor> clusters;
2296 clusters.reserve(clusterBuilders.size());
2297
2298 // Conditionally fixup the clusters depending on the attach purpose
2299 switch (mode) {
2300 case EDescriptorDeserializeMode::kForReading:
2301 for (auto &builder : clusterBuilders) {
2302 if (auto res = builder.CommitSuppressedColumnRanges(desc); !res)
2303 return R__FORWARD_RESULT(res);
2304 builder.AddExtendedColumnRanges(desc);
2305 clusters.emplace_back(builder.MoveDescriptor().Unwrap());
2306 }
2307 break;
2308 case EDescriptorDeserializeMode::kForWriting:
2309 for (auto &builder : clusterBuilders) {
2310 if (auto res = builder.CommitSuppressedColumnRanges(desc); !res)
2311 return R__FORWARD_RESULT(res);
2312 clusters.emplace_back(builder.MoveDescriptor().Unwrap());
2313 }
2314 break;
2315 case EDescriptorDeserializeMode::kRaw:
2316 for (auto &builder : clusterBuilders)
2317 clusters.emplace_back(builder.MoveDescriptor().Unwrap());
2318 break;
2319 }
2320
2321 desc.AddClusterGroupDetails(clusterGroupId, clusters);
2322
2323 return RResult<void>::Success();
2324}
2325
2327{
2328 TList streamerInfos;
2329 for (auto si : infos) {
2330 assert(si.first == si.second->GetNumber());
2331 streamerInfos.Add(si.second);
2332 }
2334 buffer.WriteObject(&streamerInfos);
2335 assert(buffer.Length() > 0);
2336 return std::string{buffer.Buffer(), static_cast<UInt_t>(buffer.Length())};
2337}
2338
2341{
2342 StreamerInfoMap_t infoMap;
2343
2344 TBufferFile buffer(TBuffer::kRead, extraTypeInfoContent.length(), const_cast<char *>(extraTypeInfoContent.data()),
2345 false /* adopt */);
2346 auto infoList = reinterpret_cast<TList *>(buffer.ReadObject(TList::Class()));
2347
2348 TObjLink *lnk = infoList->FirstLink();
2349 while (lnk) {
2350 auto info = reinterpret_cast<TStreamerInfo *>(lnk->GetObject());
2351 info->BuildCheck();
2352 infoMap[info->GetNumber()] = info->GetClass()->GetStreamerInfo(info->GetClassVersion());
2353 assert(info->GetNumber() == infoMap[info->GetNumber()]->GetNumber());
2354 lnk = lnk->Next();
2355 }
2356
2357 delete infoList;
2358
2359 return infoMap;
2360}
#define R__FORWARD_ERROR(res)
Short-hand to return an RResult<T> in an error state (i.e. after checking)
Definition RError.hxx:326
#define R__FORWARD_RESULT(res)
Short-hand to return an RResult<T> value from a subroutine to the calling stack frame.
Definition RError.hxx:324
#define R__FAIL(msg)
Short-hand to return an RResult<T> in an error state; the RError is implicitly converted into RResult...
Definition RError.hxx:322
#define R__LOG_WARNING(...)
Definition RLogger.hxx:357
#define R__LOG_DEBUG(DEBUGLEVEL,...)
Definition RLogger.hxx:359
static ROOT::RResult< void > CheckFeatureFlags(const std::vector< std::uint64_t > &featureFlags)
#define b(i)
Definition RSha256.hxx:100
#define f(i)
Definition RSha256.hxx:104
#define c(i)
Definition RSha256.hxx:101
#define a(i)
Definition RSha256.hxx:99
#define ROOT_RELEASE
Definition RVersion.hxx:47
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:139
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h offset
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h length
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t nitems
Option_t Option_t TPoint TPoint const char mode
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t bytes
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
char name[80]
Definition TGX11.cxx:142
The available trivial, native content types of a column.
RNTupleAttrSetDescriptorBuilder & AnchorLocator(const RNTupleLocator &loc)
RNTupleAttrSetDescriptorBuilder & SchemaVersion(std::uint16_t major, std::uint16_t minor)
RResult< ROOT::Experimental::RNTupleAttrSetDescriptor > MoveDescriptor()
Attempt to make an AttributeSet descriptor.
RNTupleAttrSetDescriptorBuilder & Name(std::string_view name)
RNTupleAttrSetDescriptorBuilder & AnchorLength(std::uint32_t length)
Metadata stored for every Attribute Set linked to an RNTuple.
const RNTupleLocator & GetAnchorLocator() const
A helper class for piece-wise construction of an RClusterDescriptor.
RClusterDescriptorBuilder & NEntries(std::uint64_t nEntries)
RClusterDescriptorBuilder & ClusterId(ROOT::DescriptorId_t clusterId)
RClusterDescriptorBuilder & FirstEntryIndex(std::uint64_t firstEntryIndex)
A helper class for piece-wise construction of an RClusterGroupDescriptor.
RClusterGroupDescriptorBuilder & EntrySpan(std::uint64_t entrySpan)
RClusterGroupDescriptorBuilder & PageListLocator(const RNTupleLocator &pageListLocator)
RClusterGroupDescriptorBuilder & PageListLength(std::uint64_t pageListLength)
RClusterGroupDescriptorBuilder & MinEntry(std::uint64_t minEntry)
RResult< RClusterGroupDescriptor > MoveDescriptor()
RClusterGroupDescriptorBuilder & ClusterGroupId(ROOT::DescriptorId_t clusterGroupId)
RClusterGroupDescriptorBuilder & NClusters(std::uint32_t nClusters)
A helper class for piece-wise construction of an RColumnDescriptor.
ROOT::DescriptorId_t GetRepresentationIndex() const
RColumnDescriptorBuilder & SetSuppressedDeferred()
RColumnDescriptorBuilder & LogicalColumnId(ROOT::DescriptorId_t logicalColumnId)
RColumnDescriptorBuilder & FieldId(ROOT::DescriptorId_t fieldId)
RColumnDescriptorBuilder & BitsOnStorage(std::uint16_t bitsOnStorage)
RColumnDescriptorBuilder & ValueRange(double min, double max)
RColumnDescriptorBuilder & Type(ROOT::ENTupleColumnType type)
RColumnDescriptorBuilder & PhysicalColumnId(ROOT::DescriptorId_t physicalColumnId)
RColumnDescriptorBuilder & FirstElementIndex(std::uint64_t firstElementIdx)
RColumnDescriptorBuilder & Index(std::uint32_t index)
RColumnDescriptorBuilder & RepresentationIndex(std::uint16_t representationIndex)
RResult< RColumnDescriptor > MoveDescriptor()
Attempt to make a column descriptor.
A helper class for piece-wise construction of an RExtraTypeInfoDescriptor.
RResult< RExtraTypeInfoDescriptor > MoveDescriptor()
RExtraTypeInfoDescriptorBuilder & ContentId(EExtraTypeInfoIds contentId)
RExtraTypeInfoDescriptorBuilder & TypeName(const std::string &typeName)
RExtraTypeInfoDescriptorBuilder & Content(const std::string &content)
RExtraTypeInfoDescriptorBuilder & TypeVersion(std::uint32_t typeVersion)
A helper class for piece-wise construction of an RFieldDescriptor.
RResult< RFieldDescriptor > MoveDescriptor()
Attempt to make a field descriptor.
RFieldDescriptorBuilder & NRepetitions(std::uint64_t nRepetitions)
RFieldDescriptorBuilder & Structure(const ROOT::ENTupleStructure &structure)
RFieldDescriptorBuilder & TypeAlias(const std::string &typeAlias)
RFieldDescriptorBuilder & ProjectionSourceId(ROOT::DescriptorId_t id)
RFieldDescriptorBuilder & TypeVersion(std::uint32_t typeVersion)
RFieldDescriptorBuilder & IsSoACollection(bool val)
RFieldDescriptorBuilder & TypeChecksum(const std::optional< std::uint32_t > typeChecksum)
RFieldDescriptorBuilder & ParentId(ROOT::DescriptorId_t id)
RFieldDescriptorBuilder & FieldDescription(const std::string &fieldDescription)
RFieldDescriptorBuilder & FieldVersion(std::uint32_t fieldVersion)
RFieldDescriptorBuilder & FieldName(const std::string &fieldName)
RFieldDescriptorBuilder & FieldId(ROOT::DescriptorId_t fieldId)
RFieldDescriptorBuilder & TypeName(const std::string &typeName)
A helper class for piece-wise construction of an RNTupleDescriptor.
void SetNTuple(std::string_view name, std::string_view description)
RResult< void > AddColumn(RColumnDescriptor &&columnDesc)
void AddField(RFieldDescriptor fieldDesc)
RResult< void > AddAttributeSet(Experimental::RNTupleAttrSetDescriptor &&attrSetDesc)
RResult< void > AddFieldProjection(ROOT::DescriptorId_t sourceId, ROOT::DescriptorId_t targetId)
RResult< void > AddExtraTypeInfo(RExtraTypeInfoDescriptor &&extraTypeInfoDesc)
void ShiftAliasColumns(std::uint32_t offset)
Shift column IDs of alias columns by offset
const RNTupleDescriptor & GetDescriptor() const
void BeginHeaderExtension()
Mark the beginning of the header extension; any fields and columns added after a call to this functio...
RResult< void > AddFieldLink(ROOT::DescriptorId_t fieldId, ROOT::DescriptorId_t linkId)
RResult< void > AddClusterGroup(RClusterGroupDescriptor &&clusterGroup)
void SetOnDiskHeaderXxHash3(std::uint64_t xxhash3)
void AddToOnDiskFooterSize(std::uint64_t size)
The real footer size also include the page list envelopes.
The serialization context is used for the piecewise serialization of a descriptor.
ROOT::DescriptorId_t GetOnDiskFieldId(ROOT::DescriptorId_t memId) const
ROOT::DescriptorId_t GetMemColumnId(ROOT::DescriptorId_t onDiskId) const
ROOT::DescriptorId_t GetMemClusterGroupId(ROOT::DescriptorId_t onDiskId) const
ROOT::DescriptorId_t GetOnDiskColumnId(ROOT::DescriptorId_t memId) const
void MapSchema(const RNTupleDescriptor &desc, bool forHeaderExtension)
Map in-memory field and column IDs to their on-disk counterparts.
ROOT::DescriptorId_t GetMemClusterId(ROOT::DescriptorId_t onDiskId) const
const std::vector< ROOT::DescriptorId_t > & GetOnDiskFieldList() const
Return a vector containing the in-memory field ID for each on-disk counterpart, in order,...
A helper class for serializing and deserialization of the RNTuple binary format.
static std::uint32_t SerializeXxHash3(const unsigned char *data, std::uint64_t length, std::uint64_t &xxhash3, void *buffer)
Writes a XxHash-3 64bit checksum of the byte range given by data and length.
static RResult< std::vector< ROOT::Internal::RClusterDescriptorBuilder > > DeserializePageListRaw(const void *buffer, std::uint64_t bufSize, ROOT::DescriptorId_t clusterGroupId, const RNTupleDescriptor &desc)
static RResult< std::uint32_t > SerializeSchemaDescription(void *buffer, const RNTupleDescriptor &desc, const RContext &context, bool forHeaderExtension=false)
Serialize the schema description in desc into buffer.
static RResult< std::uint32_t > DeserializeString(const void *buffer, std::uint64_t bufSize, std::string &val)
static RResult< std::uint32_t > SerializeEnvelopeLink(const REnvelopeLink &envelopeLink, void *buffer)
static std::uint32_t SerializeInt32(std::int32_t val, void *buffer)
static RResult< std::uint32_t > DeserializeEnvelopeLink(const void *buffer, std::uint64_t bufSize, REnvelopeLink &envelopeLink)
static std::uint32_t SerializeUInt32(std::uint32_t val, void *buffer)
static RResult< std::uint32_t > SerializeAttributeSet(const Experimental::RNTupleAttrSetDescriptor &attrSetDesc, void *buffer)
static RResult< std::uint32_t > SerializeFieldStructure(ROOT::ENTupleStructure structure, void *buffer)
While we could just interpret the enums as ints, we make the translation explicit in order to avoid a...
static RResult< std::uint32_t > SerializeEnvelopePostscript(unsigned char *envelope, std::uint64_t size)
static RResult< std::uint32_t > SerializeFeatureFlags(const std::vector< std::uint64_t > &flags, void *buffer)
static std::uint32_t DeserializeUInt32(const void *buffer, std::uint32_t &val)
static RResult< std::uint32_t > DeserializeFrameHeader(const void *buffer, std::uint64_t bufSize, std::uint64_t &frameSize, std::uint32_t &nitems)
static RResult< std::uint32_t > DeserializeAttributeSet(const void *buffer, std::uint64_t bufSize, Experimental::Internal::RNTupleAttrSetDescriptorBuilder &attrSetDescBld)
static RResult< std::uint32_t > DeserializeEnvelope(const void *buffer, std::uint64_t bufSize, std::uint16_t expectedType)
static RResult< std::uint32_t > SerializeColumnType(ROOT::ENTupleColumnType type, void *buffer)
static std::uint32_t SerializeListFramePreamble(std::uint32_t nitems, void *buffer)
static std::uint32_t SerializeInt16(std::int16_t val, void *buffer)
static RResult< std::uint32_t > SerializeFramePostscript(void *frame, std::uint64_t size)
static RResult< std::uint32_t > DeserializeClusterGroup(const void *buffer, std::uint64_t bufSize, RClusterGroup &clusterGroup)
static RResult< std::uint32_t > DeserializeLocator(const void *buffer, std::uint64_t bufSize, RNTupleLocator &locator)
static std::uint32_t SerializeUInt16(std::uint16_t val, void *buffer)
static RResult< void > DeserializePageList(const void *buffer, std::uint64_t bufSize, ROOT::DescriptorId_t clusterGroupId, RNTupleDescriptor &desc, EDescriptorDeserializeMode mode)
static RResult< void > DeserializeFooter(const void *buffer, std::uint64_t bufSize, ROOT::Internal::RNTupleDescriptorBuilder &descBuilder)
static std::uint32_t DeserializeInt64(const void *buffer, std::int64_t &val)
static std::uint32_t SerializeEnvelopePreamble(std::uint16_t envelopeType, void *buffer)
static std::uint32_t DeserializeInt32(const void *buffer, std::int32_t &val)
static std::uint32_t SerializeString(const std::string &val, void *buffer)
std::map< Int_t, TVirtualStreamerInfo * > StreamerInfoMap_t
static RResult< std::uint32_t > SerializeExtraTypeInfoId(ROOT::EExtraTypeInfoIds id, void *buffer)
static RResult< StreamerInfoMap_t > DeserializeStreamerInfos(const std::string &extraTypeInfoContent)
static std::uint32_t DeserializeUInt16(const void *buffer, std::uint16_t &val)
static RResult< void > VerifyXxHash3(const unsigned char *data, std::uint64_t length, std::uint64_t &xxhash3)
Expects an xxhash3 checksum in the 8 bytes following data + length and verifies it.
static RResult< std::uint32_t > SerializeClusterSummary(const RClusterSummary &clusterSummary, void *buffer)
static RResult< std::uint32_t > DeserializeColumnType(const void *buffer, ROOT::ENTupleColumnType &type)
static std::uint32_t DeserializeInt16(const void *buffer, std::int16_t &val)
static RResult< std::uint32_t > DeserializeExtraTypeInfoId(const void *buffer, ROOT::EExtraTypeInfoIds &id)
static RResult< std::uint32_t > DeserializeClusterSummary(const void *buffer, std::uint64_t bufSize, RClusterSummary &clusterSummary)
static RResult< std::uint32_t > SerializeClusterGroup(const RClusterGroup &clusterGroup, void *buffer)
static std::uint32_t SerializeRecordFramePreamble(void *buffer)
static RResult< std::uint32_t > SerializePageList(void *buffer, const RNTupleDescriptor &desc, std::span< ROOT::DescriptorId_t > physClusterIDs, const RContext &context)
static RResult< std::uint32_t > DeserializeFieldStructure(const void *buffer, ROOT::ENTupleStructure &structure)
static std::uint32_t SerializeInt64(std::int64_t val, void *buffer)
static RResult< void > DeserializeHeader(const void *buffer, std::uint64_t bufSize, ROOT::Internal::RNTupleDescriptorBuilder &descBuilder)
static RResult< std::uint32_t > SerializeFooter(void *buffer, const RNTupleDescriptor &desc, const RContext &context)
static std::uint32_t DeserializeUInt64(const void *buffer, std::uint64_t &val)
static RResult< std::uint32_t > SerializeLocator(const RNTupleLocator &locator, void *buffer)
static RResult< std::uint32_t > DeserializeSchemaDescription(const void *buffer, std::uint64_t bufSize, ROOT::Internal::RNTupleDescriptorBuilder &descBuilder)
static std::uint32_t SerializeUInt64(std::uint64_t val, void *buffer)
static RResult< std::uint32_t > DeserializeFeatureFlags(const void *buffer, std::uint64_t bufSize, std::vector< std::uint64_t > &flags)
static RResult< RContext > SerializeHeader(void *buffer, const RNTupleDescriptor &desc)
static std::string SerializeStreamerInfos(const StreamerInfoMap_t &infos)
Records the partition of data into pages for a particular column in a particular cluster.
const std::vector< RPageInfo > & GetPageInfos() const
void SetPhysicalColumnId(ROOT::DescriptorId_t id)
Metadata stored for every column of an RNTuple.
std::optional< RValueRange > GetValueRange() const
std::uint64_t GetFirstElementIndex() const
ROOT::DescriptorId_t GetFieldId() const
ROOT::ENTupleColumnType GetType() const
ROOT::DescriptorId_t GetPhysicalId() const
std::uint16_t GetRepresentationIndex() const
std::uint16_t GetBitsOnStorage() const
Field specific extra type information from the header / extenstion header.
const std::string & GetContent() const
const std::string & GetTypeName() const
EExtraTypeInfoIds GetContentId() const
Metadata stored for every field of an RNTuple.
const std::string & GetTypeAlias() const
std::uint32_t GetFieldVersion() const
const std::vector< ROOT::DescriptorId_t > & GetLogicalColumnIds() const
ROOT::ENTupleStructure GetStructure() const
std::uint64_t GetNRepetitions() const
const std::string & GetFieldDescription() const
std::optional< std::uint32_t > GetTypeChecksum() const
std::uint32_t GetTypeVersion() const
const std::string & GetFieldName() const
const std::string & GetTypeName() const
const std::vector< ROOT::DescriptorId_t > & GetExtendedColumnRepresentations() const
The on-storage metadata of an RNTuple.
const RClusterGroupDescriptor & GetClusterGroupDescriptor(ROOT::DescriptorId_t clusterGroupId) const
const RColumnDescriptor & GetColumnDescriptor(ROOT::DescriptorId_t columnId) const
RFieldDescriptorIterable GetFieldIterable(const RFieldDescriptor &fieldDesc) const
const RFieldDescriptor & GetFieldDescriptor(ROOT::DescriptorId_t fieldId) const
std::size_t GetNExtraTypeInfos() const
RColumnDescriptorIterable GetColumnIterable() const
const std::string & GetName() const
ROOT::NTupleSize_t R__DEPRECATED(6, 46, "This function is ill-conceived in the descriptor " "as not all cluster descriptors may be present. This interface is no longer publicly exposed.") GetNElements(ROOT ROOT::DescriptorId_t GetFieldZeroId() const
Returns the logical parent of all top-level RNTuple data fields.
std::vector< std::uint64_t > GetFeatureFlags() const
std::size_t GetNAttributeSets() const
std::size_t GetNPhysicalColumns() const
const RHeaderExtension * GetHeaderExtension() const
Return header extension information; if the descriptor does not have a header extension,...
const RClusterDescriptor & GetClusterDescriptor(ROOT::DescriptorId_t clusterId) const
std::uint64_t GetOnDiskHeaderXxHash3() const
std::size_t GetNFields() const
RResult< void > AddClusterGroupDetails(ROOT::DescriptorId_t clusterGroupId, std::vector< RClusterDescriptor > &clusterDescs)
Methods to load and drop cluster group details (cluster IDs and page locations)
ROOT::Experimental::RNTupleAttrSetDescriptorIterable GetAttrSetIterable() const
std::size_t GetNLogicalColumns() const
std::size_t GetNClusterGroups() const
const std::string & GetDescription() const
RNTupleLocator payload for the kTypeMulti locator (type 0x03).
RNTupleLocator payload that is common for object stores using 64bit location information.
Generic information about the physical location of data.
std::uint64_t GetNBytesOnStorage() const
ELocatorType GetType() const
For non-disk locators, the value for the Type field.
std::uint8_t GetReserved() const
We currently only support one of the 8 available reserved bits (none are used so far).
T GetPosition() const
Note that for GetPosition() / SetPosition(), the locator type must correspond (kTypeFile,...
void SetType(ELocatorType type)
void SetPosition(std::uint64_t position)
void SetReserved(std::uint8_t reserved)
See GetReserved(): we ignore the reserved flag since we don't use it anywhere currently.
void SetNBytesOnStorage(std::uint64_t nBytesOnStorage)
The class is used as a return type for operations that can fail; wraps a value of type T or an RError...
Definition RError.hxx:222
The concrete implementation of TBuffer for writing/reading to/from a ROOT file or socket.
Definition TBufferFile.h:47
TObject * ReadObject(const TClass *cl) override
Read object from I/O buffer.
void WriteObject(const TObject *obj, Bool_t cacheReuse=kTRUE) override
Write object to I/O buffer.
@ kWrite
Definition TBuffer.h:73
@ kRead
Definition TBuffer.h:73
Int_t Length() const
Definition TBuffer.h:100
char * Buffer() const
Definition TBuffer.h:96
A doubly linked list.
Definition TList.h:38
static TClass * Class()
void Add(TObject *obj) override
Definition TList.h:81
Describes a persistent version of a class.
void BuildCheck(TFile *file=nullptr, Bool_t load=kTRUE) override
Check if built and consistent with the class dictionary.
constexpr ROOT::ENTupleStructure kTestFutureFieldStructure
std::size_t LeadingZeroes(T x)
Given an integer x, returns the number of leading 0-bits starting at the most significant bit positio...
Definition BitUtils.hxx:64
ROOT::RLogChannel & NTupleLog()
Log channel for RNTuple diagnostics.
constexpr ENTupleColumnType kTestFutureColumnType
constexpr RNTupleLocator::ELocatorType kTestLocatorType
EExtraTypeInfoIds
Used in RExtraTypeInfoDescriptor.
std::uint64_t DescriptorId_t
Distriniguishes elements of the same type within a descriptor, e.g. different fields.
constexpr DescriptorId_t kInvalidDescriptorId
ENTupleStructure
The fields in the RNTuple data model tree can carry different structural information about the type s...
ENTupleColumnType