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