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