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