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
22#include <RVersion.h>
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
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();
118 for (auto fieldId : fieldList) {
119 const auto &f = desc.GetFieldDescriptor(fieldId);
120 auto onDiskParentId =
121 (f.GetParentId() == fieldZeroId) ? onDiskFieldId : context.GetOnDiskFieldId(f.GetParentId());
123 f.IsProjectedField() ? context.GetOnDiskFieldId(f.GetProjectionSourceId()) : ROOT::kInvalidDescriptorId;
125 pos += res.Unwrap();
126 } else {
127 return R__FORWARD_ERROR(res);
128 }
130 }
131
132 return pos - base;
133}
134
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
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())
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
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
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
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
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()) {
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
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,
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,
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);
566}
567
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
588 std::span<const ROOT::DescriptorId_t> fieldList,
589 const ROOT::Internal::RNTupleSerializer::RContext &context, void *buffer,
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) {
642 SerializeUInt64(xxhash3, buffer);
643 }
644 return 8;
645}
646
648 std::uint64_t &xxhash3)
649{
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
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
964 std::uint16_t expectedType, std::uint64_t &xxhash3)
965{
966 const std::uint64_t minEnvelopeSize = sizeof(std::uint64_t) + sizeof(std::uint64_t);
968 return R__FAIL("invalid envelope buffer, too short");
969
970 auto bytes = reinterpret_cast<const unsigned char *>(buffer);
971 auto base = bytes;
972
973 std::uint64_t typeAndSize;
974 bytes += 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");
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
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
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()) {
1141 locatorType = 0x01;
1142 break;
1145 locatorType = 0x02;
1146 break;
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;
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,
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:
1194 break;
1195 case 0x02: {
1198 if (!res)
1199 return R__FORWARD_ERROR(res);
1200 break;
1201 }
1202 case 0x03: {
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,
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
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,
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)
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 }
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();
1449 (xHeader->GetNLogicalColumns() - xHeader->GetNPhysicalColumns());
1450 } else {
1451 nFields = desc.GetNFields() - 1;
1454 }
1455 }
1456 const auto nExtraTypeInfos = desc.GetNExtraTypeInfos();
1457 const auto &onDiskFields = context.GetOnDiskFieldList();
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);
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
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;
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).MakeDescriptor();
1562 if (!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);
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.
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;
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.MakeDescriptor();
1614 if (!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;
1634 bytes += res.Unwrap();
1635 } else {
1636 return R__FORWARD_ERROR(res);
1637 }
1638
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.MakeDescriptor();
1649 if (!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) {
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
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));
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
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
1995 .FieldId(kZeroFieldId)
1997 .MakeDescriptor()
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
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) {
2062 if (auto res = DeserializeClusterGroup(bytes, fnFrameSizeLeft(), clusterGroup)) {
2063 bytes += res.Unwrap();
2064 } else {
2065 return R__FORWARD_ERROR(res);
2066 }
2067
2068 descBuilder.AddToOnDiskFooterSize(clusterGroup.fPageListEnvelopeLink.fLocator.GetNBytesOnStorage());
2070 clusterGroupBuilder.ClusterGroupId(groupId)
2071 .PageListLocator(clusterGroup.fPageListEnvelopeLink.fLocator)
2072 .PageListLength(clusterGroup.fPageListEnvelopeLink.fLength)
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
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);
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
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;
2172 for (ROOT::DescriptorId_t i = 0; i < clusterGroupId; ++i) {
2173 firstClusterId = firstClusterId + desc.GetClusterGroupDescriptor(i).GetNClusters();
2174 }
2175
2176 std::uint64_t clusterSummaryFrameSize;
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 }
2188 if (auto res = DeserializeClusterSummary(bytes, fnClusterSummaryFrameSizeLeft(), clusterSummary)) {
2189 bytes += res.Unwrap();
2190 } else {
2191 return R__FORWARD_ERROR(res);
2192 }
2193
2196 clusterBuilders.emplace_back(std::move(builder));
2197 }
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
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;
2246 bytes += DeserializeInt32(bytes, nElements);
2247 if (nElements < 0) {
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);
2273 }
2274
2276 } // loop over columns
2277
2279 } // loop over clusters
2280
2281 return clusterBuilders;
2282}
2283
2288{
2290 if (!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
2322
2323 return RResult<void>::Success();
2324}
2325
2327{
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{
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:44
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
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:148
The available trivial, native content types of a column.
Metadata stored for every Attribute Set linked to an RNTuple.
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.
A helper class for piece-wise construction of an RColumnDescriptor.
A helper class for piece-wise construction of an RExtraTypeInfoDescriptor.
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.
A helper class for piece-wise construction of an RNTupleDescriptor.
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.
Metadata stored for every column of an RNTuple.
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.
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
std::vector< std::uint64_t > GetFeatureFlags() const
ROOT::DescriptorId_t GetFieldZeroId() const
Returns the logical parent of all top-level RNTuple data fields.
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.
void SetType(ELocatorType type)
const_iterator begin() const
const_iterator end() const
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()
Describes a persistent version of a class.
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