Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RNTupleSerialize.cxx
Go to the documentation of this file.
1/// \file RNTupleSerialize.cxx
2/// \ingroup NTuple ROOT7
3/// \author Jakob Blomer <jblomer@cern.ch>
4/// \author Javier Lopez-Gomez <javier.lopez.gomez@cern.ch>
5/// \date 2021-08-02
6/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
7/// is welcome!
8
9/*************************************************************************
10 * Copyright (C) 1995-2021, Rene Brun and Fons Rademakers. *
11 * All rights reserved. *
12 * *
13 * For the licensing terms see $ROOTSYS/LICENSE. *
14 * For the list of contributors see $ROOTSYS/README/CREDITS. *
15 *************************************************************************/
16
18#include <ROOT/RError.hxx>
21#include <ROOT/RNTupleUtil.hxx>
22
23#include <RVersion.h>
24#include <TBufferFile.h>
25#include <TClass.h>
26#include <TList.h>
27#include <TStreamerInfo.h>
29#include <xxhash.h>
30
31#include <cassert>
32#include <cmath>
33#include <cstring> // for memcpy
34#include <deque>
35#include <functional>
36#include <limits>
37#include <set>
38#include <unordered_map>
39
40namespace {
42
45{
46
47 auto base = reinterpret_cast<unsigned char *>(buffer);
48 auto pos = base;
49 void **where = (buffer == nullptr) ? &buffer : reinterpret_cast<void **>(&pos);
50
51 pos += RNTupleSerializer::SerializeRecordFramePreamble(*where);
52
53 pos += RNTupleSerializer::SerializeUInt32(fieldDesc.GetFieldVersion(), *where);
54 pos += RNTupleSerializer::SerializeUInt32(fieldDesc.GetTypeVersion(), *where);
55 pos += RNTupleSerializer::SerializeUInt32(onDiskParentId, *where);
56 pos += RNTupleSerializer::SerializeFieldStructure(fieldDesc.GetStructure(), *where);
57
58 std::uint16_t flags = 0;
59 if (fieldDesc.GetNRepetitions() > 0)
60 flags |= RNTupleSerializer::kFlagRepetitiveField;
61 if (fieldDesc.IsProjectedField())
62 flags |= RNTupleSerializer::kFlagProjectedField;
63 if (fieldDesc.GetTypeChecksum().has_value())
64 flags |= RNTupleSerializer::kFlagHasTypeChecksum;
65 pos += RNTupleSerializer::SerializeUInt16(flags, *where);
66
67 pos += RNTupleSerializer::SerializeString(fieldDesc.GetFieldName(), *where);
68 pos += RNTupleSerializer::SerializeString(fieldDesc.GetTypeName(), *where);
69 pos += RNTupleSerializer::SerializeString(fieldDesc.GetTypeAlias(), *where);
70 pos += RNTupleSerializer::SerializeString(fieldDesc.GetFieldDescription(), *where);
71
72 if (flags & RNTupleSerializer::kFlagRepetitiveField) {
73 pos += RNTupleSerializer::SerializeUInt64(fieldDesc.GetNRepetitions(), *where);
74 }
75 if (flags & RNTupleSerializer::kFlagProjectedField) {
76 pos += RNTupleSerializer::SerializeUInt32(onDiskProjectionSourceId, *where);
77 }
78 if (flags & RNTupleSerializer::kFlagHasTypeChecksum) {
79 pos += RNTupleSerializer::SerializeUInt32(fieldDesc.GetTypeChecksum().value(), *where);
80 }
81
82 auto size = pos - base;
83 RNTupleSerializer::SerializeFramePostscript(base, size);
84
85 return size;
86}
87
88// clang-format off
89/// Serialize, in order, fields enumerated in `fieldList` to `buffer`. `firstOnDiskId` specifies the on-disk ID for the
90/// first element in the `fieldList` sequence. Before calling this function `RContext::MapSchema()` should have been
91/// called on `context` in order to map in-memory field IDs to their on-disk counterpart.
92/// \return The number of bytes written to the output buffer; if `buffer` is `nullptr` no data is serialized and the
93/// required buffer size is returned
94// clang-format on
96 std::span<const ROOT::DescriptorId_t> fieldList, std::size_t firstOnDiskId,
98{
99 auto base = reinterpret_cast<unsigned char *>(buffer);
100 auto pos = base;
101 void **where = (buffer == nullptr) ? &buffer : reinterpret_cast<void **>(&pos);
102
103 auto fieldZeroId = desc.GetFieldZeroId();
105 for (auto fieldId : fieldList) {
106 const auto &f = desc.GetFieldDescriptor(fieldId);
107 auto onDiskParentId =
108 (f.GetParentId() == fieldZeroId) ? onDiskFieldId : context.GetOnDiskFieldId(f.GetParentId());
110 f.IsProjectedField() ? context.GetOnDiskFieldId(f.GetProjectionSourceId()) : ROOT::kInvalidDescriptorId;
113 }
114
115 return pos - base;
116}
117
118ROOT::RResult<std::uint32_t> DeserializeField(const void *buffer, std::uint64_t bufSize,
120{
121 using ENTupleStructure = ROOT::ENTupleStructure;
122
123 auto base = reinterpret_cast<const unsigned char *>(buffer);
124 auto bytes = base;
125 std::uint64_t frameSize;
126 auto fnFrameSizeLeft = [&]() { return frameSize - (bytes - base); };
127 auto result = RNTupleSerializer::DeserializeFrameHeader(bytes, bufSize, frameSize);
128 if (!result)
129 return R__FORWARD_ERROR(result);
130 bytes += result.Unwrap();
131
132 std::uint32_t fieldVersion;
133 std::uint32_t typeVersion;
134 std::uint32_t parentId;
135 // initialize properly for call to SerializeFieldStructure()
136 ENTupleStructure structure{ENTupleStructure::kLeaf};
137 std::uint16_t flags;
138 if (fnFrameSizeLeft() < 3 * sizeof(std::uint32_t) + RNTupleSerializer::SerializeFieldStructure(structure, nullptr) +
139 sizeof(std::uint16_t)) {
140 return R__FAIL("field record frame too short");
141 }
142 bytes += RNTupleSerializer::DeserializeUInt32(bytes, fieldVersion);
143 bytes += RNTupleSerializer::DeserializeUInt32(bytes, typeVersion);
144 bytes += RNTupleSerializer::DeserializeUInt32(bytes, parentId);
145 result = RNTupleSerializer::DeserializeFieldStructure(bytes, structure);
146 if (!result)
147 return R__FORWARD_ERROR(result);
148 bytes += result.Unwrap();
149 bytes += RNTupleSerializer::DeserializeUInt16(bytes, flags);
150 fieldDesc.FieldVersion(fieldVersion).TypeVersion(typeVersion).ParentId(parentId).Structure(structure);
151
152 std::string fieldName;
153 std::string typeName;
154 std::string aliasName;
155 std::string description;
156 result = RNTupleSerializer::DeserializeString(bytes, fnFrameSizeLeft(), fieldName).Unwrap();
157 if (!result)
158 return R__FORWARD_ERROR(result);
159 bytes += result.Unwrap();
160 result = RNTupleSerializer::DeserializeString(bytes, fnFrameSizeLeft(), typeName).Unwrap();
161 if (!result)
162 return R__FORWARD_ERROR(result);
163 bytes += result.Unwrap();
164 result = RNTupleSerializer::DeserializeString(bytes, fnFrameSizeLeft(), aliasName).Unwrap();
165 if (!result)
166 return R__FORWARD_ERROR(result);
167 bytes += result.Unwrap();
168 result = RNTupleSerializer::DeserializeString(bytes, fnFrameSizeLeft(), description).Unwrap();
169 if (!result)
170 return R__FORWARD_ERROR(result);
171 bytes += result.Unwrap();
172 fieldDesc.FieldName(fieldName).TypeName(typeName).TypeAlias(aliasName).FieldDescription(description);
173
174 if (flags & RNTupleSerializer::kFlagRepetitiveField) {
175 if (fnFrameSizeLeft() < sizeof(std::uint64_t))
176 return R__FAIL("field record frame too short");
177 std::uint64_t nRepetitions;
178 bytes += RNTupleSerializer::DeserializeUInt64(bytes, nRepetitions);
179 fieldDesc.NRepetitions(nRepetitions);
180 }
181
182 if (flags & RNTupleSerializer::kFlagProjectedField) {
183 if (fnFrameSizeLeft() < sizeof(std::uint32_t))
184 return R__FAIL("field record frame too short");
185 std::uint32_t projectionSourceId;
186 bytes += RNTupleSerializer::DeserializeUInt32(bytes, projectionSourceId);
187 fieldDesc.ProjectionSourceId(projectionSourceId);
188 }
189
190 if (flags & RNTupleSerializer::kFlagHasTypeChecksum) {
191 if (fnFrameSizeLeft() < sizeof(std::uint32_t))
192 return R__FAIL("field record frame too short");
193 std::uint32_t typeChecksum;
194 bytes += RNTupleSerializer::DeserializeUInt32(bytes, typeChecksum);
195 fieldDesc.TypeChecksum(typeChecksum);
196 }
197
198 return frameSize;
199}
200
203 void *buffer)
204{
205 R__ASSERT(!columnDesc.IsAliasColumn());
206
207 auto base = reinterpret_cast<unsigned char *>(buffer);
208 auto pos = base;
209 void **where = (buffer == nullptr) ? &buffer : reinterpret_cast<void **>(&pos);
210
211 pos += RNTupleSerializer::SerializeRecordFramePreamble(*where);
212
213 pos += RNTupleSerializer::SerializeColumnType(columnDesc.GetType(), *where);
214 pos += RNTupleSerializer::SerializeUInt16(columnDesc.GetBitsOnStorage(), *where);
215 pos += RNTupleSerializer::SerializeUInt32(context.GetOnDiskFieldId(columnDesc.GetFieldId()), *where);
216 std::uint16_t flags = 0;
217 if (columnDesc.IsDeferredColumn())
218 flags |= RNTupleSerializer::kFlagDeferredColumn;
219 if (columnDesc.GetValueRange().has_value())
220 flags |= RNTupleSerializer::kFlagHasValueRange;
221 std::int64_t firstElementIdx = columnDesc.GetFirstElementIndex();
222 if (columnDesc.IsSuppressedDeferredColumn())
224 pos += RNTupleSerializer::SerializeUInt16(flags, *where);
225 pos += RNTupleSerializer::SerializeUInt16(columnDesc.GetRepresentationIndex(), *where);
226 if (flags & RNTupleSerializer::kFlagDeferredColumn)
227 pos += RNTupleSerializer::SerializeInt64(firstElementIdx, *where);
228 if (flags & RNTupleSerializer::kFlagHasValueRange) {
229 auto [min, max] = *columnDesc.GetValueRange();
230 std::uint64_t intMin, intMax;
231 static_assert(sizeof(min) == sizeof(intMin) && sizeof(max) == sizeof(intMax));
232 memcpy(&intMin, &min, sizeof(min));
233 memcpy(&intMax, &max, sizeof(max));
234 pos += RNTupleSerializer::SerializeUInt64(intMin, *where);
235 pos += RNTupleSerializer::SerializeUInt64(intMax, *where);
236 }
237
238 pos += RNTupleSerializer::SerializeFramePostscript(buffer ? base : nullptr, pos - base);
239
240 return pos - base;
241}
242
244 std::span<const ROOT::DescriptorId_t> fieldList,
246 void *buffer, bool forHeaderExtension)
247{
248 auto base = reinterpret_cast<unsigned char *>(buffer);
249 auto pos = base;
250 void **where = (buffer == nullptr) ? &buffer : reinterpret_cast<void **>(&pos);
251
252 const auto *xHeader = !forHeaderExtension ? desc.GetHeaderExtension() : nullptr;
253
254 for (auto parentId : fieldList) {
255 // If we're serializing the non-extended header and we already have a header extension (which may happen if
256 // we load an RNTuple for incremental merging), we need to skip all the extended fields, as they need to be
257 // written in the header extension, not in the regular header.
258 if (xHeader && xHeader->ContainsField(parentId))
259 continue;
260
261 for (const auto &c : desc.GetColumnIterable(parentId)) {
262 if (c.IsAliasColumn() || (xHeader && xHeader->ContainsExtendedColumnRepresentation(c.GetLogicalId())))
263 continue;
264
265 pos += SerializePhysicalColumn(c, context, *where);
266 }
267 }
268
269 return pos - base;
270}
271
272ROOT::RResult<std::uint32_t> DeserializeColumn(const void *buffer, std::uint64_t bufSize,
274{
276
277 auto base = reinterpret_cast<const unsigned char *>(buffer);
278 auto bytes = base;
279 std::uint64_t frameSize;
280 auto fnFrameSizeLeft = [&]() { return frameSize - (bytes - base); };
281 auto result = RNTupleSerializer::DeserializeFrameHeader(bytes, bufSize, frameSize);
282 if (!result)
283 return R__FORWARD_ERROR(result);
284 bytes += result.Unwrap();
285
286 // Initialize properly for SerializeColumnType
287 ENTupleColumnType type{ENTupleColumnType::kIndex32};
288 std::uint16_t bitsOnStorage;
289 std::uint32_t fieldId;
290 std::uint16_t flags;
291 std::uint16_t representationIndex;
292 std::int64_t firstElementIdx = 0;
293 if (fnFrameSizeLeft() <
294 RNTupleSerializer::SerializeColumnType(type, nullptr) + sizeof(std::uint16_t) + 2 * sizeof(std::uint32_t)) {
295 return R__FAIL("column record frame too short");
296 }
297 result = RNTupleSerializer::DeserializeColumnType(bytes, type);
298 if (!result)
299 return R__FORWARD_ERROR(result);
300 bytes += result.Unwrap();
301 bytes += RNTupleSerializer::DeserializeUInt16(bytes, bitsOnStorage);
302 bytes += RNTupleSerializer::DeserializeUInt32(bytes, fieldId);
303 bytes += RNTupleSerializer::DeserializeUInt16(bytes, flags);
304 bytes += RNTupleSerializer::DeserializeUInt16(bytes, representationIndex);
305 if (flags & RNTupleSerializer::kFlagDeferredColumn) {
306 if (fnFrameSizeLeft() < sizeof(std::uint64_t))
307 return R__FAIL("column record frame too short");
308 bytes += RNTupleSerializer::DeserializeInt64(bytes, firstElementIdx);
309 }
310 if (flags & RNTupleSerializer::kFlagHasValueRange) {
311 if (fnFrameSizeLeft() < 2 * sizeof(std::uint64_t))
312 return R__FAIL("field record frame too short");
313 std::uint64_t minInt, maxInt;
314 bytes += RNTupleSerializer::DeserializeUInt64(bytes, minInt);
315 bytes += RNTupleSerializer::DeserializeUInt64(bytes, maxInt);
316 double min, max;
317 memcpy(&min, &minInt, sizeof(min));
318 memcpy(&max, &maxInt, sizeof(max));
319 columnDesc.ValueRange(min, max);
320 }
321
322 columnDesc.FieldId(fieldId).BitsOnStorage(bitsOnStorage).Type(type).RepresentationIndex(representationIndex);
323 columnDesc.FirstElementIndex(std::abs(firstElementIdx));
324 if (firstElementIdx < 0)
325 columnDesc.SetSuppressedDeferred();
326
327 return frameSize;
328}
329
330std::uint32_t SerializeExtraTypeInfo(const ROOT::Experimental::RExtraTypeInfoDescriptor &desc, void *buffer)
331{
332 auto base = reinterpret_cast<unsigned char *>(buffer);
333 auto pos = base;
334 void **where = (buffer == nullptr) ? &buffer : reinterpret_cast<void **>(&pos);
335
336 pos += RNTupleSerializer::SerializeRecordFramePreamble(*where);
337
338 pos += RNTupleSerializer::SerializeExtraTypeInfoId(desc.GetContentId(), *where);
339 pos += RNTupleSerializer::SerializeUInt32(desc.GetTypeVersion(), *where);
340 pos += RNTupleSerializer::SerializeString(desc.GetTypeName(), *where);
341 pos += RNTupleSerializer::SerializeString(desc.GetContent(), *where);
342
343 auto size = pos - base;
344 RNTupleSerializer::SerializeFramePostscript(base, size);
345
346 return size;
347}
348
350{
351 auto base = reinterpret_cast<unsigned char *>(buffer);
352 auto pos = base;
353 void **where = (buffer == nullptr) ? &buffer : reinterpret_cast<void **>(&pos);
354
355 for (const auto &extraTypeInfoDesc : ntplDesc.GetExtraTypeInfoIterable()) {
357 }
358
359 return pos - base;
360}
361
363DeserializeExtraTypeInfo(const void *buffer, std::uint64_t bufSize,
365{
367
368 auto base = reinterpret_cast<const unsigned char *>(buffer);
369 auto bytes = base;
370 std::uint64_t frameSize;
371 auto fnFrameSizeLeft = [&]() { return frameSize - (bytes - base); };
372 auto result = RNTupleSerializer::DeserializeFrameHeader(bytes, bufSize, frameSize);
373 if (!result)
374 return R__FORWARD_ERROR(result);
375 bytes += result.Unwrap();
376
377 EExtraTypeInfoIds contentId{EExtraTypeInfoIds::kInvalid};
378 std::uint32_t typeVersion;
379 if (fnFrameSizeLeft() < 2 * sizeof(std::uint32_t)) {
380 return R__FAIL("extra type info record frame too short");
381 }
382 result = RNTupleSerializer::DeserializeExtraTypeInfoId(bytes, contentId);
383 if (!result)
384 return R__FORWARD_ERROR(result);
385 bytes += result.Unwrap();
386 bytes += RNTupleSerializer::DeserializeUInt32(bytes, typeVersion);
387
388 std::string typeName;
389 std::string content;
390 result = RNTupleSerializer::DeserializeString(bytes, fnFrameSizeLeft(), typeName).Unwrap();
391 if (!result)
392 return R__FORWARD_ERROR(result);
393 bytes += result.Unwrap();
394 result = RNTupleSerializer::DeserializeString(bytes, fnFrameSizeLeft(), content).Unwrap();
395 if (!result)
396 return R__FORWARD_ERROR(result);
397 bytes += result.Unwrap();
398
400
401 return frameSize;
402}
403
404std::uint32_t SerializeLocatorPayloadLarge(const ROOT::RNTupleLocator &locator, unsigned char *buffer)
405{
406 if (buffer) {
407 RNTupleSerializer::SerializeUInt64(locator.GetNBytesOnStorage(), buffer);
408 RNTupleSerializer::SerializeUInt64(locator.GetPosition<std::uint64_t>(), buffer + sizeof(std::uint64_t));
409 }
410 return sizeof(std::uint64_t) + sizeof(std::uint64_t);
411}
412
413void DeserializeLocatorPayloadLarge(const unsigned char *buffer, ROOT::RNTupleLocator &locator)
414{
415 std::uint64_t nBytesOnStorage;
416 std::uint64_t position;
417 RNTupleSerializer::DeserializeUInt64(buffer, nBytesOnStorage);
418 RNTupleSerializer::DeserializeUInt64(buffer + sizeof(std::uint64_t), position);
419 locator.SetNBytesOnStorage(nBytesOnStorage);
420 locator.SetPosition(position);
421}
422
423std::uint32_t SerializeLocatorPayloadObject64(const ROOT::RNTupleLocator &locator, unsigned char *buffer)
424{
425 const auto &data = locator.GetPosition<ROOT::RNTupleLocatorObject64>();
426 const uint32_t sizeofNBytesOnStorage = (locator.GetNBytesOnStorage() > std::numeric_limits<std::uint32_t>::max())
427 ? sizeof(std::uint64_t)
428 : sizeof(std::uint32_t);
429 if (buffer) {
430 if (sizeofNBytesOnStorage == sizeof(std::uint32_t)) {
431 RNTupleSerializer::SerializeUInt32(locator.GetNBytesOnStorage(), buffer);
432 } else {
433 RNTupleSerializer::SerializeUInt64(locator.GetNBytesOnStorage(), buffer);
434 }
435 RNTupleSerializer::SerializeUInt64(data.GetLocation(), buffer + sizeofNBytesOnStorage);
436 }
437 return sizeofNBytesOnStorage + sizeof(std::uint64_t);
438}
439
440void DeserializeLocatorPayloadObject64(const unsigned char *buffer, std::uint32_t sizeofLocatorPayload,
442{
443 std::uint64_t location;
444 if (sizeofLocatorPayload == 12) {
445 std::uint32_t nBytesOnStorage;
446 RNTupleSerializer::DeserializeUInt32(buffer, nBytesOnStorage);
447 locator.SetNBytesOnStorage(nBytesOnStorage);
448 RNTupleSerializer::DeserializeUInt64(buffer + sizeof(std::uint32_t), location);
449 } else if (sizeofLocatorPayload == 16) {
450 std::uint64_t nBytesOnStorage;
451 RNTupleSerializer::DeserializeUInt64(buffer, nBytesOnStorage);
452 locator.SetNBytesOnStorage(nBytesOnStorage);
453 RNTupleSerializer::DeserializeUInt64(buffer + sizeof(std::uint64_t), location);
454 } else {
455 throw ROOT::RException(R__FAIL("invalid DAOS locator payload size: " + std::to_string(sizeofLocatorPayload)));
456 }
457 locator.SetPosition(ROOT::RNTupleLocatorObject64{location});
458}
459
462 void *buffer)
463{
464 R__ASSERT(columnDesc.IsAliasColumn());
465
466 auto base = reinterpret_cast<unsigned char *>(buffer);
467 auto pos = base;
468 void **where = (buffer == nullptr) ? &buffer : reinterpret_cast<void **>(&pos);
469
470 pos += RNTupleSerializer::SerializeRecordFramePreamble(*where);
471
472 pos += RNTupleSerializer::SerializeUInt32(context.GetOnDiskColumnId(columnDesc.GetPhysicalId()), *where);
473 pos += RNTupleSerializer::SerializeUInt32(context.GetOnDiskFieldId(columnDesc.GetFieldId()), *where);
474
475 pos += RNTupleSerializer::SerializeFramePostscript(buffer ? base : nullptr, pos - base);
476
477 return pos - base;
478}
479
481 std::span<const ROOT::DescriptorId_t> fieldList,
483 void *buffer, bool forHeaderExtension)
484{
485 auto base = reinterpret_cast<unsigned char *>(buffer);
486 auto pos = base;
487 void **where = (buffer == nullptr) ? &buffer : reinterpret_cast<void **>(&pos);
488
489 const auto *xHeader = !forHeaderExtension ? desc.GetHeaderExtension() : nullptr;
490
491 for (auto parentId : fieldList) {
492 if (xHeader && xHeader->ContainsField(parentId))
493 continue;
494
495 for (const auto &c : desc.GetColumnIterable(parentId)) {
496 if (!c.IsAliasColumn() || (xHeader && xHeader->ContainsExtendedColumnRepresentation(c.GetLogicalId())))
497 continue;
498
499 pos += SerializeAliasColumn(c, context, *where);
500 }
501 }
502
503 return pos - base;
504}
505
506ROOT::RResult<std::uint32_t> DeserializeAliasColumn(const void *buffer, std::uint64_t bufSize,
507 std::uint32_t &physicalColumnId, std::uint32_t &fieldId)
508{
509 auto base = reinterpret_cast<const unsigned char *>(buffer);
510 auto bytes = base;
511 std::uint64_t frameSize;
512 auto fnFrameSizeLeft = [&]() { return frameSize - (bytes - base); };
513 auto result = RNTupleSerializer::DeserializeFrameHeader(bytes, bufSize, frameSize);
514 if (!result)
515 return R__FORWARD_ERROR(result);
516 bytes += result.Unwrap();
517
518 if (fnFrameSizeLeft() < 2 * sizeof(std::uint32_t)) {
519 return R__FAIL("alias column record frame too short");
520 }
521
522 bytes += RNTupleSerializer::DeserializeUInt32(bytes, physicalColumnId);
523 bytes += RNTupleSerializer::DeserializeUInt32(bytes, fieldId);
524
525 return frameSize;
526}
527
528} // anonymous namespace
529
531 std::uint64_t length,
532 std::uint64_t &xxhash3, void *buffer)
533{
534 if (buffer != nullptr) {
536 SerializeUInt64(xxhash3, buffer);
537 }
538 return 8;
539}
540
542 std::uint64_t length,
543 std::uint64_t &xxhash3)
544{
546 DeserializeUInt64(data + length, xxhash3);
547 if (xxhash3 != checksumReal)
548 return R__FAIL("XxHash-3 checksum mismatch");
549 return RResult<void>::Success();
550}
551
554{
555 std::uint64_t xxhash3;
556 return R__FORWARD_RESULT(VerifyXxHash3(data, length, xxhash3));
557}
558
559std::uint32_t ROOT::Experimental::Internal::RNTupleSerializer::SerializeInt16(std::int16_t val, void *buffer)
560{
561 if (buffer != nullptr) {
562 auto bytes = reinterpret_cast<unsigned char *>(buffer);
563 bytes[0] = (val & 0x00FF);
564 bytes[1] = (val & 0xFF00) >> 8;
565 }
566 return 2;
567}
568
569std::uint32_t ROOT::Experimental::Internal::RNTupleSerializer::DeserializeInt16(const void *buffer, std::int16_t &val)
570{
571 auto bytes = reinterpret_cast<const unsigned char *>(buffer);
572 val = std::int16_t(bytes[0]) + (std::int16_t(bytes[1]) << 8);
573 return 2;
574}
575
576std::uint32_t ROOT::Experimental::Internal::RNTupleSerializer::SerializeUInt16(std::uint16_t val, void *buffer)
577{
578 return SerializeInt16(val, buffer);
579}
580
581std::uint32_t ROOT::Experimental::Internal::RNTupleSerializer::DeserializeUInt16(const void *buffer, std::uint16_t &val)
582{
583 return DeserializeInt16(buffer, *reinterpret_cast<std::int16_t *>(&val));
584}
585
586std::uint32_t ROOT::Experimental::Internal::RNTupleSerializer::SerializeInt32(std::int32_t val, void *buffer)
587{
588 if (buffer != nullptr) {
589 auto bytes = reinterpret_cast<unsigned char *>(buffer);
590 bytes[0] = (val & 0x000000FF);
591 bytes[1] = (val & 0x0000FF00) >> 8;
592 bytes[2] = (val & 0x00FF0000) >> 16;
593 bytes[3] = (val & 0xFF000000) >> 24;
594 }
595 return 4;
596}
597
598std::uint32_t ROOT::Experimental::Internal::RNTupleSerializer::DeserializeInt32(const void *buffer, std::int32_t &val)
599{
600 auto bytes = reinterpret_cast<const unsigned char *>(buffer);
601 val = std::int32_t(bytes[0]) + (std::int32_t(bytes[1]) << 8) + (std::int32_t(bytes[2]) << 16) +
602 (std::int32_t(bytes[3]) << 24);
603 return 4;
604}
605
606std::uint32_t ROOT::Experimental::Internal::RNTupleSerializer::SerializeUInt32(std::uint32_t val, void *buffer)
607{
608 return SerializeInt32(val, buffer);
609}
610
611std::uint32_t ROOT::Experimental::Internal::RNTupleSerializer::DeserializeUInt32(const void *buffer, std::uint32_t &val)
612{
613 return DeserializeInt32(buffer, *reinterpret_cast<std::int32_t *>(&val));
614}
615
616std::uint32_t ROOT::Experimental::Internal::RNTupleSerializer::SerializeInt64(std::int64_t val, void *buffer)
617{
618 if (buffer != nullptr) {
619 auto bytes = reinterpret_cast<unsigned char *>(buffer);
620 bytes[0] = (val & 0x00000000000000FF);
621 bytes[1] = (val & 0x000000000000FF00) >> 8;
622 bytes[2] = (val & 0x0000000000FF0000) >> 16;
623 bytes[3] = (val & 0x00000000FF000000) >> 24;
624 bytes[4] = (val & 0x000000FF00000000) >> 32;
625 bytes[5] = (val & 0x0000FF0000000000) >> 40;
626 bytes[6] = (val & 0x00FF000000000000) >> 48;
627 bytes[7] = (val & 0xFF00000000000000) >> 56;
628 }
629 return 8;
630}
631
632std::uint32_t ROOT::Experimental::Internal::RNTupleSerializer::DeserializeInt64(const void *buffer, std::int64_t &val)
633{
634 auto bytes = reinterpret_cast<const unsigned char *>(buffer);
635 val = std::int64_t(bytes[0]) + (std::int64_t(bytes[1]) << 8) + (std::int64_t(bytes[2]) << 16) +
636 (std::int64_t(bytes[3]) << 24) + (std::int64_t(bytes[4]) << 32) + (std::int64_t(bytes[5]) << 40) +
637 (std::int64_t(bytes[6]) << 48) + (std::int64_t(bytes[7]) << 56);
638 return 8;
639}
640
641std::uint32_t ROOT::Experimental::Internal::RNTupleSerializer::SerializeUInt64(std::uint64_t val, void *buffer)
642{
643 return SerializeInt64(val, buffer);
644}
645
646std::uint32_t ROOT::Experimental::Internal::RNTupleSerializer::DeserializeUInt64(const void *buffer, std::uint64_t &val)
647{
648 return DeserializeInt64(buffer, *reinterpret_cast<std::int64_t *>(&val));
649}
650
651std::uint32_t ROOT::Experimental::Internal::RNTupleSerializer::SerializeString(const std::string &val, void *buffer)
652{
653 if (buffer) {
654 auto pos = reinterpret_cast<unsigned char *>(buffer);
655 pos += SerializeUInt32(val.length(), pos);
656 memcpy(pos, val.data(), val.length());
657 }
658 return sizeof(std::uint32_t) + val.length();
659}
660
662 std::uint64_t bufSize,
663 std::string &val)
664{
665 if (bufSize < sizeof(std::uint32_t))
666 return R__FAIL("string buffer too short");
667 bufSize -= sizeof(std::uint32_t);
668
669 auto base = reinterpret_cast<const unsigned char *>(buffer);
670 auto bytes = base;
671 std::uint32_t length;
672 bytes += DeserializeUInt32(buffer, length);
673 if (bufSize < length)
674 return R__FAIL("string buffer too short");
675
676 val.resize(length);
677 memcpy(&val[0], bytes, length);
678 return sizeof(std::uint32_t) + length;
679}
680
682{
683 switch (type) {
684 case ENTupleColumnType::kBit: return SerializeUInt16(0x00, buffer);
685 case ENTupleColumnType::kByte: return SerializeUInt16(0x01, buffer);
686 case ENTupleColumnType::kChar: return SerializeUInt16(0x02, buffer);
687 case ENTupleColumnType::kInt8: return SerializeUInt16(0x03, buffer);
688 case ENTupleColumnType::kUInt8: return SerializeUInt16(0x04, buffer);
689 case ENTupleColumnType::kInt16: return SerializeUInt16(0x05, buffer);
690 case ENTupleColumnType::kUInt16: return SerializeUInt16(0x06, buffer);
691 case ENTupleColumnType::kInt32: return SerializeUInt16(0x07, buffer);
692 case ENTupleColumnType::kUInt32: return SerializeUInt16(0x08, buffer);
693 case ENTupleColumnType::kInt64: return SerializeUInt16(0x09, buffer);
694 case ENTupleColumnType::kUInt64: return SerializeUInt16(0x0A, buffer);
695 case ENTupleColumnType::kReal16: return SerializeUInt16(0x0B, buffer);
696 case ENTupleColumnType::kReal32: return SerializeUInt16(0x0C, buffer);
697 case ENTupleColumnType::kReal64: return SerializeUInt16(0x0D, buffer);
698 case ENTupleColumnType::kIndex32: return SerializeUInt16(0x0E, buffer);
699 case ENTupleColumnType::kIndex64: return SerializeUInt16(0x0F, buffer);
700 case ENTupleColumnType::kSwitch: return SerializeUInt16(0x10, buffer);
701 case ENTupleColumnType::kSplitInt16: return SerializeUInt16(0x11, buffer);
702 case ENTupleColumnType::kSplitUInt16: return SerializeUInt16(0x12, buffer);
703 case ENTupleColumnType::kSplitInt32: return SerializeUInt16(0x13, buffer);
704 case ENTupleColumnType::kSplitUInt32: return SerializeUInt16(0x14, buffer);
705 case ENTupleColumnType::kSplitInt64: return SerializeUInt16(0x15, buffer);
706 case ENTupleColumnType::kSplitUInt64: return SerializeUInt16(0x16, buffer);
707 case ENTupleColumnType::kSplitReal32: return SerializeUInt16(0x18, buffer);
708 case ENTupleColumnType::kSplitReal64: return SerializeUInt16(0x19, buffer);
709 case ENTupleColumnType::kSplitIndex32: return SerializeUInt16(0x1A, buffer);
710 case ENTupleColumnType::kSplitIndex64: return SerializeUInt16(0x1B, buffer);
711 case ENTupleColumnType::kReal32Trunc: return SerializeUInt16(0x1C, buffer);
712 case ENTupleColumnType::kReal32Quant: return SerializeUInt16(0x1D, buffer);
713 default:
714 if (type == kTestFutureType)
715 return SerializeUInt16(0x99, buffer);
716 throw RException(R__FAIL("ROOT bug: unexpected column type"));
717 }
718}
719
722{
723 std::uint16_t onDiskType;
724 auto result = DeserializeUInt16(buffer, onDiskType);
725
726 switch (onDiskType) {
727 case 0x00: type = ENTupleColumnType::kBit; break;
728 case 0x01: type = ENTupleColumnType::kByte; break;
729 case 0x02: type = ENTupleColumnType::kChar; break;
730 case 0x03: type = ENTupleColumnType::kInt8; break;
731 case 0x04: type = ENTupleColumnType::kUInt8; break;
732 case 0x05: type = ENTupleColumnType::kInt16; break;
733 case 0x06: type = ENTupleColumnType::kUInt16; break;
734 case 0x07: type = ENTupleColumnType::kInt32; break;
735 case 0x08: type = ENTupleColumnType::kUInt32; break;
736 case 0x09: type = ENTupleColumnType::kInt64; break;
737 case 0x0A: type = ENTupleColumnType::kUInt64; break;
738 case 0x0B: type = ENTupleColumnType::kReal16; break;
739 case 0x0C: type = ENTupleColumnType::kReal32; break;
740 case 0x0D: type = ENTupleColumnType::kReal64; break;
741 case 0x0E: type = ENTupleColumnType::kIndex32; break;
742 case 0x0F: type = ENTupleColumnType::kIndex64; break;
743 case 0x10: type = ENTupleColumnType::kSwitch; break;
744 case 0x11: type = ENTupleColumnType::kSplitInt16; break;
745 case 0x12: type = ENTupleColumnType::kSplitUInt16; break;
746 case 0x13: type = ENTupleColumnType::kSplitInt32; break;
747 case 0x14: type = ENTupleColumnType::kSplitUInt32; break;
748 case 0x15: type = ENTupleColumnType::kSplitInt64; break;
749 case 0x16: type = ENTupleColumnType::kSplitUInt64; break;
750 case 0x18: type = ENTupleColumnType::kSplitReal32; break;
751 case 0x19: type = ENTupleColumnType::kSplitReal64; break;
752 case 0x1A: type = ENTupleColumnType::kSplitIndex32; break;
753 case 0x1B: type = ENTupleColumnType::kSplitIndex64; break;
754 case 0x1C: type = ENTupleColumnType::kReal32Trunc; break;
755 case 0x1D: type = ENTupleColumnType::kReal32Quant; break;
756 // case 0x99 => kTestFutureType missing on purpose
757 default:
758 // may be a column type introduced by a future version
760 break;
761 }
762 return result;
763}
764
765std::uint32_t
767{
768 using ENTupleStructure = ROOT::ENTupleStructure;
769 switch (structure) {
770 case ENTupleStructure::kLeaf: return SerializeUInt16(0x00, buffer);
771 case ENTupleStructure::kCollection: return SerializeUInt16(0x01, buffer);
772 case ENTupleStructure::kRecord: return SerializeUInt16(0x02, buffer);
773 case ENTupleStructure::kVariant: return SerializeUInt16(0x03, buffer);
774 case ENTupleStructure::kStreamer: return SerializeUInt16(0x04, buffer);
775 default:
777 return SerializeUInt16(0x99, buffer);
778 throw RException(R__FAIL("ROOT bug: unexpected field structure type"));
779 }
780}
781
784 ROOT::ENTupleStructure &structure)
785{
786 using ENTupleStructure = ROOT::ENTupleStructure;
787 std::uint16_t onDiskValue;
788 auto result = DeserializeUInt16(buffer, onDiskValue);
789 switch (onDiskValue) {
790 case 0x00: structure = ENTupleStructure::kLeaf; break;
791 case 0x01: structure = ENTupleStructure::kCollection; break;
792 case 0x02: structure = ENTupleStructure::kRecord; break;
793 case 0x03: structure = ENTupleStructure::kVariant; break;
794 case 0x04: structure = ENTupleStructure::kStreamer; break;
795 // case 0x99 => kTestFutureFieldStructure intentionally missing
796 default: structure = ENTupleStructure::kUnknown;
797 }
798 return result;
799}
800
801std::uint32_t
803 void *buffer)
804{
806 switch (id) {
807 case EExtraTypeInfoIds::kStreamerInfo: return SerializeUInt32(0x00, buffer);
808 default: throw RException(R__FAIL("ROOT bug: unexpected extra type info id"));
809 }
810}
811
815{
817 std::uint32_t onDiskValue;
818 auto result = DeserializeUInt32(buffer, onDiskValue);
819 switch (onDiskValue) {
820 case 0x00: id = EExtraTypeInfoIds::kStreamerInfo; break;
821 default:
823 R__LOG_DEBUG(0, ROOT::Internal::NTupleLog()) << "Unknown extra type info id: " << onDiskValue;
824 }
825 return result;
826}
827
828std::uint32_t
830{
831 auto base = reinterpret_cast<unsigned char *>(buffer);
832 auto pos = base;
833 void **where = (buffer == nullptr) ? &buffer : reinterpret_cast<void **>(&pos);
834
835 pos += SerializeUInt64(envelopeType, *where);
836 // The 48bits size information is filled in the postscript
837 return pos - base;
838}
839
841 std::uint64_t size,
842 std::uint64_t &xxhash3)
843{
844 if (size < sizeof(std::uint64_t))
845 throw RException(R__FAIL("envelope size too small"));
846 if (size >= static_cast<uint64_t>(1) << 48)
847 throw RException(R__FAIL("envelope size too big"));
848 if (envelope) {
849 std::uint64_t typeAndSize;
850 DeserializeUInt64(envelope, typeAndSize);
851 typeAndSize |= (size + 8) << 16;
852 SerializeUInt64(typeAndSize, envelope);
853 }
854 return SerializeXxHash3(envelope, size, xxhash3, envelope ? (envelope + size) : nullptr);
855}
856
858 std::uint64_t size)
859{
860 std::uint64_t xxhash3;
861 return SerializeEnvelopePostscript(envelope, size, xxhash3);
862}
863
866 std::uint16_t expectedType, std::uint64_t &xxhash3)
867{
868 const std::uint64_t minEnvelopeSize = sizeof(std::uint64_t) + sizeof(std::uint64_t);
870 return R__FAIL("invalid envelope buffer, too short");
871
872 auto bytes = reinterpret_cast<const unsigned char *>(buffer);
873 auto base = bytes;
874
875 std::uint64_t typeAndSize;
876 bytes += DeserializeUInt64(bytes, typeAndSize);
877
878 std::uint16_t envelopeType = typeAndSize & 0xFFFF;
879 if (envelopeType != expectedType) {
880 return R__FAIL("envelope type mismatch: expected " + std::to_string(expectedType) + ", found " +
881 std::to_string(envelopeType));
882 }
883
884 std::uint64_t envelopeSize = typeAndSize >> 16;
885 if (bufSize < envelopeSize)
886 return R__FAIL("envelope buffer size too small");
888 return R__FAIL("invalid envelope, too short");
889
890 auto result = VerifyXxHash3(base, envelopeSize - 8, xxhash3);
891 if (!result)
892 return R__FORWARD_ERROR(result);
893
894 return sizeof(typeAndSize);
895}
896
899 std::uint16_t expectedType)
900{
901 std::uint64_t xxhash3;
902 return R__FORWARD_RESULT(DeserializeEnvelope(buffer, bufSize, expectedType, xxhash3));
903}
904
906{
907 // Marker: multiply the final size with 1
908 return SerializeInt64(1, buffer);
909}
910
911std::uint32_t
913{
914 auto base = reinterpret_cast<unsigned char *>(buffer);
915 auto pos = base;
916 void **where = (buffer == nullptr) ? &buffer : reinterpret_cast<void **>(&pos);
917
918 // Marker: multiply the final size with -1
919 pos += SerializeInt64(-1, *where);
920 pos += SerializeUInt32(nitems, *where);
921 return pos - base;
922}
923
925{
926 auto preambleSize = sizeof(std::int64_t);
927 if (size < preambleSize)
928 throw RException(R__FAIL("frame too short: " + std::to_string(size)));
929 if (frame) {
930 std::int64_t marker;
931 DeserializeInt64(frame, marker);
932 if ((marker < 0) && (size < (sizeof(std::uint32_t) + preambleSize)))
933 throw RException(R__FAIL("frame too short: " + std::to_string(size)));
934 SerializeInt64(marker * static_cast<int64_t>(size), frame);
935 }
936 return 0;
937}
938
941 std::uint64_t &frameSize, std::uint32_t &nitems)
942{
943 std::uint64_t minSize = sizeof(std::int64_t);
944 if (bufSize < minSize)
945 return R__FAIL("frame too short");
946
947 std::int64_t *ssize = reinterpret_cast<std::int64_t *>(&frameSize);
948 DeserializeInt64(buffer, *ssize);
949
950 auto bytes = reinterpret_cast<const unsigned char *>(buffer);
951 bytes += minSize;
952
953 if (*ssize >= 0) {
954 // Record frame
955 nitems = 1;
956 } else {
957 // List frame
958 minSize += sizeof(std::uint32_t);
959 if (bufSize < minSize)
960 return R__FAIL("frame too short");
961 bytes += DeserializeUInt32(bytes, nitems);
962 *ssize = -(*ssize);
963 }
964
965 if (frameSize < minSize)
966 return R__FAIL("corrupt frame size");
967 if (bufSize < frameSize)
968 return R__FAIL("frame too short");
969
970 return bytes - reinterpret_cast<const unsigned char *>(buffer);
971}
972
975 std::uint64_t &frameSize)
976{
977 std::uint32_t nitems;
978 return R__FORWARD_RESULT(DeserializeFrameHeader(buffer, bufSize, frameSize, nitems));
979}
980
981std::uint32_t
983 void *buffer)
984{
985 if (flags.empty())
986 return SerializeUInt64(0, buffer);
987
988 if (buffer) {
989 auto bytes = reinterpret_cast<unsigned char *>(buffer);
990
991 for (unsigned i = 0; i < flags.size(); ++i) {
992 if (flags[i] & 0x8000000000000000)
993 throw RException(R__FAIL("feature flag out of bounds"));
994
995 // The MSb indicates that another Int64 follows; set this bit to 1 for all except the last element
996 if (i == (flags.size() - 1))
997 SerializeUInt64(flags[i], bytes);
998 else
999 bytes += SerializeUInt64(flags[i] | 0x8000000000000000, bytes);
1000 }
1001 }
1002 return (flags.size() * sizeof(std::int64_t));
1003}
1004
1007 std::vector<std::uint64_t> &flags)
1008{
1009 auto bytes = reinterpret_cast<const unsigned char *>(buffer);
1010
1011 flags.clear();
1012 std::uint64_t f;
1013 do {
1014 if (bufSize < sizeof(std::uint64_t))
1015 return R__FAIL("feature flag buffer too short");
1016 bytes += DeserializeUInt64(bytes, f);
1017 bufSize -= sizeof(std::uint64_t);
1018 flags.emplace_back(f & ~0x8000000000000000);
1019 } while (f & 0x8000000000000000);
1020
1021 return (flags.size() * sizeof(std::uint64_t));
1022}
1023
1024std::uint32_t
1026{
1028 throw RException(R__FAIL("locator is not serializable"));
1029
1030 std::uint32_t size = 0;
1031 if ((locator.GetType() == RNTupleLocator::kTypeFile) &&
1032 (locator.GetNBytesOnStorage() <= std::numeric_limits<std::int32_t>::max())) {
1033 size += SerializeUInt32(locator.GetNBytesOnStorage(), buffer);
1034 size += SerializeUInt64(locator.GetPosition<std::uint64_t>(),
1035 buffer ? reinterpret_cast<unsigned char *>(buffer) + size : nullptr);
1036 return size;
1037 }
1038
1039 std::uint8_t locatorType = 0;
1040 auto payloadp = buffer ? reinterpret_cast<unsigned char *>(buffer) + sizeof(std::int32_t) : nullptr;
1041 switch (locator.GetType()) {
1044 locatorType = 0x01;
1045 break;
1048 locatorType = 0x02;
1049 break;
1050 default:
1051 if (locator.GetType() == kTestLocatorType) {
1052 // For the testing locator, use the same payload as Object64. We're not gonna really read it back anyway.
1054 locatorType = 0x7e;
1055 } else {
1056 throw RException(R__FAIL("locator has unknown type"));
1057 }
1058 }
1059 std::int32_t head = sizeof(std::int32_t) + size;
1060 head |= locator.GetReserved() << 16;
1061 head |= static_cast<int>(locatorType & 0x7F) << 24;
1062 head = -head;
1063 size += RNTupleSerializer::SerializeInt32(head, buffer);
1064 return size;
1065}
1066
1070{
1071 if (bufSize < sizeof(std::int32_t))
1072 return R__FAIL("too short locator");
1073
1074 auto bytes = reinterpret_cast<const unsigned char *>(buffer);
1075 std::int32_t head;
1076
1077 bytes += DeserializeInt32(bytes, head);
1078 bufSize -= sizeof(std::int32_t);
1079 if (head < 0) {
1080 head = -head;
1081 const int type = head >> 24;
1082 const std::uint32_t payloadSize = (static_cast<std::uint32_t>(head) & 0x0000FFFF) - sizeof(std::int32_t);
1083 if (bufSize < payloadSize)
1084 return R__FAIL("too short locator");
1085
1086 locator.SetReserved(static_cast<std::uint32_t>(head >> 16) & 0xFF);
1087 switch (type) {
1088 case 0x01:
1091 break;
1092 case 0x02:
1095 break;
1096 default: locator.SetType(RNTupleLocator::kTypeUnknown);
1097 }
1098 bytes += payloadSize;
1099 } else {
1100 if (bufSize < sizeof(std::uint64_t))
1101 return R__FAIL("too short locator");
1102 std::uint64_t offset;
1103 bytes += DeserializeUInt64(bytes, offset);
1105 locator.SetNBytesOnStorage(head);
1106 locator.SetPosition(offset);
1107 }
1108
1109 return bytes - reinterpret_cast<const unsigned char *>(buffer);
1110}
1111
1112std::uint32_t
1114{
1115 auto size = SerializeUInt64(envelopeLink.fLength, buffer);
1116 size += SerializeLocator(envelopeLink.fLocator, buffer ? reinterpret_cast<unsigned char *>(buffer) + size : nullptr);
1117 return size;
1118}
1119
1123{
1124 if (bufSize < sizeof(std::int64_t))
1125 return R__FAIL("too short envelope link");
1126
1127 auto bytes = reinterpret_cast<const unsigned char *>(buffer);
1128 bytes += DeserializeUInt64(bytes, envelopeLink.fLength);
1129 bufSize -= sizeof(std::uint64_t);
1130 auto result = DeserializeLocator(bytes, bufSize, envelopeLink.fLocator);
1131 if (!result)
1132 return R__FORWARD_ERROR(result);
1133 bytes += result.Unwrap();
1134 return bytes - reinterpret_cast<const unsigned char *>(buffer);
1135}
1136
1137std::uint32_t
1139 void *buffer)
1140{
1141 if (clusterSummary.fNEntries >= (static_cast<std::uint64_t>(1) << 56)) {
1142 throw RException(R__FAIL("number of entries in cluster exceeds maximum of 2^56"));
1143 }
1144
1145 auto base = reinterpret_cast<unsigned char *>(buffer);
1146 auto pos = base;
1147 void **where = (buffer == nullptr) ? &buffer : reinterpret_cast<void **>(&pos);
1148
1149 auto frame = pos;
1150 pos += SerializeRecordFramePreamble(*where);
1151 pos += SerializeUInt64(clusterSummary.fFirstEntry, *where);
1152 const std::uint64_t nEntriesAndFlags =
1153 (static_cast<std::uint64_t>(clusterSummary.fFlags) << 56) | clusterSummary.fNEntries;
1154 pos += SerializeUInt64(nEntriesAndFlags, *where);
1155
1156 auto size = pos - frame;
1157 pos += SerializeFramePostscript(frame, size);
1158 return size;
1159}
1160
1164{
1165 auto base = reinterpret_cast<const unsigned char *>(buffer);
1166 auto bytes = base;
1167 std::uint64_t frameSize;
1168 auto result = DeserializeFrameHeader(bytes, bufSize, frameSize);
1169 if (!result)
1170 return R__FORWARD_ERROR(result);
1171 bytes += result.Unwrap();
1172
1173 auto fnFrameSizeLeft = [&]() { return frameSize - (bytes - base); };
1174 if (fnFrameSizeLeft() < 2 * sizeof(std::uint64_t))
1175 return R__FAIL("too short cluster summary");
1176
1177 bytes += DeserializeUInt64(bytes, clusterSummary.fFirstEntry);
1178 std::uint64_t nEntriesAndFlags;
1179 bytes += DeserializeUInt64(bytes, nEntriesAndFlags);
1180
1181 const std::uint64_t nEntries = (nEntriesAndFlags << 8) >> 8;
1182 const std::uint8_t flags = nEntriesAndFlags >> 56;
1183
1184 if (flags & 0x01) {
1185 return R__FAIL("sharded cluster flag set in cluster summary; sharded clusters are currently unsupported.");
1186 }
1187
1188 clusterSummary.fNEntries = nEntries;
1189 clusterSummary.fFlags = flags;
1190
1191 return frameSize;
1192}
1193
1194std::uint32_t
1196{
1197 auto base = reinterpret_cast<unsigned char *>(buffer);
1198 auto pos = base;
1199 void **where = (buffer == nullptr) ? &buffer : reinterpret_cast<void **>(&pos);
1200
1201 auto frame = pos;
1202 pos += SerializeRecordFramePreamble(*where);
1203 pos += SerializeUInt64(clusterGroup.fMinEntry, *where);
1204 pos += SerializeUInt64(clusterGroup.fEntrySpan, *where);
1205 pos += SerializeUInt32(clusterGroup.fNClusters, *where);
1206 pos += SerializeEnvelopeLink(clusterGroup.fPageListEnvelopeLink, *where);
1207 auto size = pos - frame;
1208 pos += SerializeFramePostscript(frame, size);
1209 return size;
1210}
1211
1215{
1216 auto base = reinterpret_cast<const unsigned char *>(buffer);
1217 auto bytes = base;
1218
1219 std::uint64_t frameSize;
1220 auto result = DeserializeFrameHeader(bytes, bufSize, frameSize);
1221 if (!result)
1222 return R__FORWARD_ERROR(result);
1223 bytes += result.Unwrap();
1224
1225 auto fnFrameSizeLeft = [&]() { return frameSize - (bytes - base); };
1226 if (fnFrameSizeLeft() < sizeof(std::uint32_t) + 2 * sizeof(std::uint64_t))
1227 return R__FAIL("too short cluster group");
1228
1229 bytes += DeserializeUInt64(bytes, clusterGroup.fMinEntry);
1230 bytes += DeserializeUInt64(bytes, clusterGroup.fEntrySpan);
1231 bytes += DeserializeUInt32(bytes, clusterGroup.fNClusters);
1232 result = DeserializeEnvelopeLink(bytes, fnFrameSizeLeft(), clusterGroup.fPageListEnvelopeLink);
1233 if (!result)
1234 return R__FORWARD_ERROR(result);
1235
1236 return frameSize;
1237}
1238
1240 bool forHeaderExtension)
1241{
1242 auto fieldZeroId = desc.GetFieldZeroId();
1243 auto depthFirstTraversal = [&](std::span<ROOT::DescriptorId_t> fieldTrees, auto doForEachField) {
1244 std::deque<ROOT::DescriptorId_t> idQueue{fieldTrees.begin(), fieldTrees.end()};
1245 while (!idQueue.empty()) {
1246 auto fieldId = idQueue.front();
1247 idQueue.pop_front();
1248 // Field zero has no physical representation nor columns of its own; recurse over its subfields only
1249 if (fieldId != fieldZeroId)
1251 unsigned i = 0;
1252 for (const auto &f : desc.GetFieldIterable(fieldId))
1253 idQueue.insert(idQueue.begin() + i++, f.GetId());
1254 }
1255 };
1256
1257 R__ASSERT(desc.GetNFields() > 0); // we must have at least a zero field
1258
1259 std::vector<ROOT::DescriptorId_t> fieldTrees;
1260 if (!forHeaderExtension) {
1261 fieldTrees.emplace_back(fieldZeroId);
1262 } else if (auto xHeader = desc.GetHeaderExtension()) {
1263 fieldTrees = xHeader->GetTopLevelFields(desc);
1264 }
1267 for (const auto &c : desc.GetColumnIterable(fieldId)) {
1268 if (!c.IsAliasColumn()) {
1269 MapPhysicalColumnId(c.GetPhysicalId());
1270 }
1271 }
1272 });
1273
1274 if (forHeaderExtension) {
1275 // Create physical IDs for column representations that extend fields of the regular header.
1276 // First the physical columns then the alias columns.
1277 for (auto memId : desc.GetHeaderExtension()->GetExtendedColumnRepresentations()) {
1278 const auto &columnDesc = desc.GetColumnDescriptor(memId);
1279 if (!columnDesc.IsAliasColumn()) {
1280 MapPhysicalColumnId(columnDesc.GetPhysicalId());
1281 }
1282 }
1283 }
1284}
1285
1287 const RNTupleDescriptor &desc,
1288 const RContext &context,
1289 bool forHeaderExtension)
1290{
1291 auto base = reinterpret_cast<unsigned char *>(buffer);
1292 auto pos = base;
1293 void **where = (buffer == nullptr) ? &buffer : reinterpret_cast<void **>(&pos);
1294
1295 std::size_t nFields = 0, nColumns = 0, nAliasColumns = 0, fieldListOffset = 0;
1296 // Columns in the extension header that are attached to a field of the regular header
1297 std::vector<std::reference_wrapper<const RColumnDescriptor>> extraColumns;
1298 if (forHeaderExtension) {
1299 // A call to `RNTupleDescriptorBuilder::BeginHeaderExtension()` is not strictly required after serializing the
1300 // header, which may happen, e.g., in unit tests. Ensure an empty schema extension is serialized in this case
1301 if (auto xHeader = desc.GetHeaderExtension()) {
1302 nFields = xHeader->GetNFields();
1303 nColumns = xHeader->GetNPhysicalColumns();
1304 nAliasColumns = xHeader->GetNLogicalColumns() - xHeader->GetNPhysicalColumns();
1305 fieldListOffset = desc.GetNFields() - nFields - 1;
1306
1307 extraColumns.reserve(xHeader->GetExtendedColumnRepresentations().size());
1308 for (auto columnId : xHeader->GetExtendedColumnRepresentations()) {
1309 extraColumns.emplace_back(desc.GetColumnDescriptor(columnId));
1310 }
1311 }
1312 } else {
1313 if (auto xHeader = desc.GetHeaderExtension()) {
1314 nFields = desc.GetNFields() - xHeader->GetNFields() - 1;
1315 nColumns = desc.GetNPhysicalColumns() - xHeader->GetNPhysicalColumns();
1317 (xHeader->GetNLogicalColumns() - xHeader->GetNPhysicalColumns());
1318 } else {
1319 nFields = desc.GetNFields() - 1;
1322 }
1323 }
1324 const auto nExtraTypeInfos = desc.GetNExtraTypeInfos();
1325 const auto &onDiskFields = context.GetOnDiskFieldList();
1327 std::span<const ROOT::DescriptorId_t> fieldList{onDiskFields.data() + fieldListOffset,
1328 onDiskFields.size() - fieldListOffset};
1329
1330 auto frame = pos;
1331 pos += SerializeListFramePreamble(nFields, *where);
1332 pos += SerializeFieldList(desc, fieldList, /*firstOnDiskId=*/fieldListOffset, context, *where);
1333 pos += SerializeFramePostscript(buffer ? frame : nullptr, pos - frame);
1334
1335 frame = pos;
1336 pos += SerializeListFramePreamble(nColumns, *where);
1338 for (const auto &c : extraColumns) {
1339 if (!c.get().IsAliasColumn()) {
1340 pos += SerializePhysicalColumn(c.get(), context, *where);
1341 }
1342 }
1343 pos += SerializeFramePostscript(buffer ? frame : nullptr, pos - frame);
1344
1345 frame = pos;
1346 pos += SerializeListFramePreamble(nAliasColumns, *where);
1348 for (const auto &c : extraColumns) {
1349 if (c.get().IsAliasColumn()) {
1350 pos += SerializeAliasColumn(c.get(), context, *where);
1351 }
1352 }
1353 pos += SerializeFramePostscript(buffer ? frame : nullptr, pos - frame);
1354
1355 frame = pos;
1356 pos += SerializeListFramePreamble(nExtraTypeInfos, *where);
1357 pos += SerializeExtraTypeInfoList(desc, *where);
1358 pos += SerializeFramePostscript(buffer ? frame : nullptr, pos - frame);
1359
1360 return static_cast<std::uint32_t>(pos - base);
1361}
1362
1366{
1367 auto base = reinterpret_cast<const unsigned char *>(buffer);
1368 auto bytes = base;
1369 auto fnBufSizeLeft = [&]() { return bufSize - (bytes - base); };
1371
1372 std::uint64_t frameSize;
1373 auto frame = bytes;
1374 auto fnFrameSizeLeft = [&]() { return frameSize - (bytes - frame); };
1375
1376 std::uint32_t nFields;
1377 result = DeserializeFrameHeader(bytes, fnBufSizeLeft(), frameSize, nFields);
1378 if (!result)
1379 return R__FORWARD_ERROR(result);
1380 bytes += result.Unwrap();
1381 // The zero field is always added before `DeserializeSchemaDescription()` is called
1382 const std::uint32_t fieldIdRangeBegin = descBuilder.GetDescriptor().GetNFields() - 1;
1383 for (unsigned i = 0; i < nFields; ++i) {
1384 std::uint32_t fieldId = fieldIdRangeBegin + i;
1387 if (!result)
1388 return R__FORWARD_ERROR(result);
1389 bytes += result.Unwrap();
1390 if (fieldId == fieldBuilder.GetParentId())
1391 fieldBuilder.ParentId(kZeroFieldId);
1392 auto fieldDesc = fieldBuilder.FieldId(fieldId).MakeDescriptor();
1393 if (!fieldDesc)
1395 const auto parentId = fieldDesc.Inspect().GetParentId();
1396 const auto projectionSourceId = fieldDesc.Inspect().GetProjectionSourceId();
1397 descBuilder.AddField(fieldDesc.Unwrap());
1398 auto resVoid = descBuilder.AddFieldLink(parentId, fieldId);
1399 if (!resVoid)
1400 return R__FORWARD_ERROR(resVoid);
1402 resVoid = descBuilder.AddFieldProjection(projectionSourceId, fieldId);
1403 if (!resVoid)
1404 return R__FORWARD_ERROR(resVoid);
1405 }
1406 }
1407 bytes = frame + frameSize;
1408
1409 // As columns are added in order of representation index and column index, determine the column index
1410 // for the currently deserialized column from the columns already added.
1412 std::uint16_t representationIndex) -> std::uint32_t {
1413 const auto &existingColumns = descBuilder.GetDescriptor().GetFieldDescriptor(fieldId).GetLogicalColumnIds();
1414 if (existingColumns.empty())
1415 return 0;
1416 const auto &lastColumnDesc = descBuilder.GetDescriptor().GetColumnDescriptor(existingColumns.back());
1417 return (representationIndex == lastColumnDesc.GetRepresentationIndex()) ? (lastColumnDesc.GetIndex() + 1) : 0;
1418 };
1419
1420 std::uint32_t nColumns;
1421 frame = bytes;
1422 result = DeserializeFrameHeader(bytes, fnBufSizeLeft(), frameSize, nColumns);
1423 if (!result)
1424 return R__FORWARD_ERROR(result);
1425 bytes += result.Unwrap();
1426
1427 if (descBuilder.GetDescriptor().GetNLogicalColumns() > descBuilder.GetDescriptor().GetNPhysicalColumns())
1428 descBuilder.ShiftAliasColumns(nColumns);
1429
1430 const std::uint32_t columnIdRangeBegin = descBuilder.GetDescriptor().GetNPhysicalColumns();
1431 for (unsigned i = 0; i < nColumns; ++i) {
1432 std::uint32_t columnId = columnIdRangeBegin + i;
1435 if (!result)
1436 return R__FORWARD_ERROR(result);
1437 bytes += result.Unwrap();
1438
1439 columnBuilder.Index(fnNextColumnIndex(columnBuilder.GetFieldId(), columnBuilder.GetRepresentationIndex()));
1440 columnBuilder.LogicalColumnId(columnId);
1441 columnBuilder.PhysicalColumnId(columnId);
1442 auto columnDesc = columnBuilder.MakeDescriptor();
1443 if (!columnDesc)
1445 auto resVoid = descBuilder.AddColumn(columnDesc.Unwrap());
1446 if (!resVoid)
1447 return R__FORWARD_ERROR(resVoid);
1448 }
1449 bytes = frame + frameSize;
1450
1451 std::uint32_t nAliasColumns;
1452 frame = bytes;
1453 result = DeserializeFrameHeader(bytes, fnBufSizeLeft(), frameSize, nAliasColumns);
1454 if (!result)
1455 return R__FORWARD_ERROR(result);
1456 bytes += result.Unwrap();
1457 const std::uint32_t aliasColumnIdRangeBegin = descBuilder.GetDescriptor().GetNLogicalColumns();
1458 for (unsigned i = 0; i < nAliasColumns; ++i) {
1459 std::uint32_t physicalId;
1460 std::uint32_t fieldId;
1462 if (!result)
1463 return R__FORWARD_ERROR(result);
1464 bytes += result.Unwrap();
1465
1467 columnBuilder.LogicalColumnId(aliasColumnIdRangeBegin + i).PhysicalColumnId(physicalId).FieldId(fieldId);
1468 const auto &physicalColumnDesc = descBuilder.GetDescriptor().GetColumnDescriptor(physicalId);
1469 columnBuilder.BitsOnStorage(physicalColumnDesc.GetBitsOnStorage());
1470 columnBuilder.ValueRange(physicalColumnDesc.GetValueRange());
1471 columnBuilder.Type(physicalColumnDesc.GetType());
1472 columnBuilder.RepresentationIndex(physicalColumnDesc.GetRepresentationIndex());
1473 columnBuilder.Index(fnNextColumnIndex(columnBuilder.GetFieldId(), columnBuilder.GetRepresentationIndex()));
1474
1475 auto aliasColumnDesc = columnBuilder.MakeDescriptor();
1476 if (!aliasColumnDesc)
1478 auto resVoid = descBuilder.AddColumn(aliasColumnDesc.Unwrap());
1479 if (!resVoid)
1480 return R__FORWARD_ERROR(resVoid);
1481 }
1482 bytes = frame + frameSize;
1483
1484 std::uint32_t nExtraTypeInfos;
1485 frame = bytes;
1486 result = DeserializeFrameHeader(bytes, fnBufSizeLeft(), frameSize, nExtraTypeInfos);
1487 if (!result)
1488 return R__FORWARD_ERROR(result);
1489 bytes += result.Unwrap();
1490 for (unsigned i = 0; i < nExtraTypeInfos; ++i) {
1493 if (!result)
1494 return R__FORWARD_ERROR(result);
1495 bytes += result.Unwrap();
1496
1497 auto extraTypeInfoDesc = extraTypeInfoBuilder.MoveDescriptor();
1498 // We ignore unknown extra type information
1500 descBuilder.AddExtraTypeInfo(extraTypeInfoDesc.Unwrap());
1501 }
1502 bytes = frame + frameSize;
1503
1504 return bytes - base;
1505}
1506
1510{
1511 RContext context;
1512
1513 auto base = reinterpret_cast<unsigned char *>(buffer);
1514 auto pos = base;
1515 void **where = (buffer == nullptr) ? &buffer : reinterpret_cast<void **>(&pos);
1516
1517 pos += SerializeEnvelopePreamble(kEnvelopeTypeHeader, *where);
1518 // So far we don't make use of feature flags
1519 pos += SerializeFeatureFlags(desc.GetFeatureFlags(), *where);
1520 pos += SerializeString(desc.GetName(), *where);
1521 pos += SerializeString(desc.GetDescription(), *where);
1522 pos += SerializeString(std::string("ROOT v") + ROOT_RELEASE, *where);
1523
1524 context.MapSchema(desc, /*forHeaderExtension=*/false);
1525 pos += SerializeSchemaDescription(*where, desc, context);
1526
1527 std::uint64_t size = pos - base;
1528 std::uint64_t xxhash3 = 0;
1529 size += SerializeEnvelopePostscript(base, size, xxhash3);
1530
1531 context.SetHeaderSize(size);
1532 context.SetHeaderXxHash3(xxhash3);
1533 return context;
1534}
1535
1536std::uint32_t
1538 std::span<ROOT::DescriptorId_t> physClusterIDs,
1539 const RContext &context)
1540{
1541 auto base = reinterpret_cast<unsigned char *>(buffer);
1542 auto pos = base;
1543 void **where = (buffer == nullptr) ? &buffer : reinterpret_cast<void **>(&pos);
1544
1545 pos += SerializeEnvelopePreamble(kEnvelopeTypePageList, *where);
1546
1547 pos += SerializeUInt64(context.GetHeaderXxHash3(), *where);
1548
1549 // Cluster summaries
1550 const auto nClusters = physClusterIDs.size();
1551 auto clusterSummaryFrame = pos;
1552 pos += SerializeListFramePreamble(nClusters, *where);
1553 for (auto clusterId : physClusterIDs) {
1554 const auto &clusterDesc = desc.GetClusterDescriptor(context.GetMemClusterId(clusterId));
1555 RClusterSummary summary{clusterDesc.GetFirstEntryIndex(), clusterDesc.GetNEntries(), 0};
1556 pos += SerializeClusterSummary(summary, *where);
1557 }
1558 pos += SerializeFramePostscript(buffer ? clusterSummaryFrame : nullptr, pos - clusterSummaryFrame);
1559
1560 // Page locations
1561 auto topMostFrame = pos;
1562 pos += SerializeListFramePreamble(nClusters, *where);
1563
1564 for (auto clusterId : physClusterIDs) {
1565 const auto &clusterDesc = desc.GetClusterDescriptor(context.GetMemClusterId(clusterId));
1566 // Get an ordered set of physical column ids
1567 std::set<ROOT::DescriptorId_t> onDiskColumnIds;
1568 for (const auto &columnRange : clusterDesc.GetColumnRangeIterable())
1569 onDiskColumnIds.insert(context.GetOnDiskColumnId(columnRange.fPhysicalColumnId));
1570
1571 auto outerFrame = pos;
1572 pos += SerializeListFramePreamble(onDiskColumnIds.size(), *where);
1573 for (auto onDiskId : onDiskColumnIds) {
1574 auto memId = context.GetMemColumnId(onDiskId);
1575 const auto &columnRange = clusterDesc.GetColumnRange(memId);
1576
1577 auto innerFrame = pos;
1578 if (columnRange.fIsSuppressed) {
1579 // Empty page range
1580 pos += SerializeListFramePreamble(0, *where);
1581 pos += SerializeInt64(kSuppressedColumnMarker, *where);
1582 } else {
1583 const auto &pageRange = clusterDesc.GetPageRange(memId);
1584 pos += SerializeListFramePreamble(pageRange.fPageInfos.size(), *where);
1585
1586 for (const auto &pi : pageRange.fPageInfos) {
1587 std::int32_t nElements = pi.fHasChecksum ? -static_cast<std::int32_t>(pi.fNElements) : pi.fNElements;
1588 pos += SerializeUInt32(nElements, *where);
1589 pos += SerializeLocator(pi.fLocator, *where);
1590 }
1591 pos += SerializeInt64(columnRange.fFirstElementIndex, *where);
1592 pos += SerializeUInt32(columnRange.fCompressionSettings.value(), *where);
1593 }
1594
1595 pos += SerializeFramePostscript(buffer ? innerFrame : nullptr, pos - innerFrame);
1596 }
1597 pos += SerializeFramePostscript(buffer ? outerFrame : nullptr, pos - outerFrame);
1598 }
1599
1600 pos += SerializeFramePostscript(buffer ? topMostFrame : nullptr, pos - topMostFrame);
1601 std::uint64_t size = pos - base;
1602 size += SerializeEnvelopePostscript(base, size);
1603 return size;
1604}
1605
1606std::uint32_t
1609 const RContext &context)
1610{
1611 auto base = reinterpret_cast<unsigned char *>(buffer);
1612 auto pos = base;
1613 void **where = (buffer == nullptr) ? &buffer : reinterpret_cast<void **>(&pos);
1614
1615 pos += SerializeEnvelopePreamble(kEnvelopeTypeFooter, *where);
1616
1617 // So far we don't make use of footer feature flags
1618 pos += SerializeFeatureFlags(std::vector<std::uint64_t>(), *where);
1619 pos += SerializeUInt64(context.GetHeaderXxHash3(), *where);
1620
1621 // Schema extension, i.e. incremental changes with respect to the header
1622 auto frame = pos;
1623 pos += SerializeRecordFramePreamble(*where);
1624 pos += SerializeSchemaDescription(*where, desc, context, /*forHeaderExtension=*/true);
1625 pos += SerializeFramePostscript(buffer ? frame : nullptr, pos - frame);
1626
1627 // Cluster groups
1628 frame = pos;
1629 const auto nClusterGroups = desc.GetNClusterGroups();
1630 pos += SerializeListFramePreamble(nClusterGroups, *where);
1631 for (unsigned int i = 0; i < nClusterGroups; ++i) {
1632 const auto &cgDesc = desc.GetClusterGroupDescriptor(context.GetMemClusterGroupId(i));
1634 clusterGroup.fMinEntry = cgDesc.GetMinEntry();
1635 clusterGroup.fEntrySpan = cgDesc.GetEntrySpan();
1636 clusterGroup.fNClusters = cgDesc.GetNClusters();
1637 clusterGroup.fPageListEnvelopeLink.fLength = cgDesc.GetPageListLength();
1638 clusterGroup.fPageListEnvelopeLink.fLocator = cgDesc.GetPageListLocator();
1639 pos += SerializeClusterGroup(clusterGroup, *where);
1640 }
1641 pos += SerializeFramePostscript(buffer ? frame : nullptr, pos - frame);
1642
1643 std::uint32_t size = pos - base;
1644 size += SerializeEnvelopePostscript(base, size);
1645 return size;
1646}
1647
1651{
1652 auto base = reinterpret_cast<const unsigned char *>(buffer);
1653 auto bytes = base;
1654 auto fnBufSizeLeft = [&]() { return bufSize - (bytes - base); };
1656
1657 std::uint64_t xxhash3{0};
1658 result = DeserializeEnvelope(bytes, fnBufSizeLeft(), kEnvelopeTypeHeader, xxhash3);
1659 if (!result)
1660 return R__FORWARD_ERROR(result);
1661 bytes += result.Unwrap();
1662 descBuilder.SetOnDiskHeaderXxHash3(xxhash3);
1663
1664 std::vector<std::uint64_t> featureFlags;
1665 result = DeserializeFeatureFlags(bytes, fnBufSizeLeft(), featureFlags);
1666 if (!result)
1667 return R__FORWARD_ERROR(result);
1668 bytes += result.Unwrap();
1669 for (std::size_t i = 0; i < featureFlags.size(); ++i) {
1670 if (!featureFlags[i])
1671 continue;
1672 unsigned int bit = 0;
1673 while (!(featureFlags[i] & (static_cast<uint64_t>(1) << bit)))
1674 bit++;
1675 return R__FAIL("unsupported format feature: " + std::to_string(i * 64 + bit));
1676 }
1677
1678 std::string name;
1679 std::string description;
1680 std::string writer;
1681 result = DeserializeString(bytes, fnBufSizeLeft(), name);
1682 if (!result)
1683 return R__FORWARD_ERROR(result);
1684 bytes += result.Unwrap();
1685 result = DeserializeString(bytes, fnBufSizeLeft(), description);
1686 if (!result)
1687 return R__FORWARD_ERROR(result);
1688 bytes += result.Unwrap();
1689 result = DeserializeString(bytes, fnBufSizeLeft(), writer);
1690 if (!result)
1691 return R__FORWARD_ERROR(result);
1692 bytes += result.Unwrap();
1693 descBuilder.SetNTuple(name, description);
1694
1695 // Zero field
1697 .FieldId(kZeroFieldId)
1699 .MakeDescriptor()
1700 .Unwrap());
1701 result = DeserializeSchemaDescription(bytes, fnBufSizeLeft(), descBuilder);
1702 if (!result)
1703 return R__FORWARD_ERROR(result);
1704
1705 return RResult<void>::Success();
1706}
1707
1711{
1712 auto base = reinterpret_cast<const unsigned char *>(buffer);
1713 auto bytes = base;
1714 auto fnBufSizeLeft = [&]() { return bufSize - (bytes - base); };
1716
1717 result = DeserializeEnvelope(bytes, fnBufSizeLeft(), kEnvelopeTypeFooter);
1718 if (!result)
1719 return R__FORWARD_ERROR(result);
1720 bytes += result.Unwrap();
1721
1722 std::vector<std::uint64_t> featureFlags;
1723 result = DeserializeFeatureFlags(bytes, fnBufSizeLeft(), featureFlags);
1724 if (!result)
1725 return R__FORWARD_ERROR(result);
1726 bytes += result.Unwrap();
1727 for (auto f : featureFlags) {
1728 if (f)
1729 R__LOG_WARNING(ROOT::Internal::NTupleLog()) << "Unsupported feature flag! " << f;
1730 }
1731
1732 std::uint64_t xxhash3{0};
1733 if (fnBufSizeLeft() < static_cast<int>(sizeof(std::uint64_t)))
1734 return R__FAIL("footer too short");
1735 bytes += DeserializeUInt64(bytes, xxhash3);
1736 if (xxhash3 != descBuilder.GetDescriptor().GetOnDiskHeaderXxHash3())
1737 return R__FAIL("XxHash-3 mismatch between header and footer");
1738
1739 std::uint64_t frameSize;
1740 auto frame = bytes;
1741 auto fnFrameSizeLeft = [&]() { return frameSize - (bytes - frame); };
1742
1743 result = DeserializeFrameHeader(bytes, fnBufSizeLeft(), frameSize);
1744 if (!result)
1745 return R__FORWARD_ERROR(result);
1746 bytes += result.Unwrap();
1747 if (fnFrameSizeLeft() > 0) {
1748 descBuilder.BeginHeaderExtension();
1749 result = DeserializeSchemaDescription(bytes, fnFrameSizeLeft(), descBuilder);
1750 if (!result)
1751 return R__FORWARD_ERROR(result);
1752 }
1753 bytes = frame + frameSize;
1754
1755 std::uint32_t nClusterGroups;
1756 frame = bytes;
1757 result = DeserializeFrameHeader(bytes, fnBufSizeLeft(), frameSize, nClusterGroups);
1758 if (!result)
1759 return R__FORWARD_ERROR(result);
1760 bytes += result.Unwrap();
1761 for (std::uint32_t groupId = 0; groupId < nClusterGroups; ++groupId) {
1763 result = DeserializeClusterGroup(bytes, fnFrameSizeLeft(), clusterGroup);
1764 if (!result)
1765 return R__FORWARD_ERROR(result);
1766 bytes += result.Unwrap();
1767
1768 descBuilder.AddToOnDiskFooterSize(clusterGroup.fPageListEnvelopeLink.fLocator.GetNBytesOnStorage());
1770 clusterGroupBuilder.ClusterGroupId(groupId)
1771 .PageListLocator(clusterGroup.fPageListEnvelopeLink.fLocator)
1772 .PageListLength(clusterGroup.fPageListEnvelopeLink.fLength)
1773 .MinEntry(clusterGroup.fMinEntry)
1774 .EntrySpan(clusterGroup.fEntrySpan)
1775 .NClusters(clusterGroup.fNClusters);
1776 descBuilder.AddClusterGroup(clusterGroupBuilder.MoveDescriptor().Unwrap());
1777 }
1778 bytes = frame + frameSize;
1779
1780 return RResult<void>::Success();
1781}
1782
1786 const RNTupleDescriptor &desc)
1787{
1788 auto base = reinterpret_cast<const unsigned char *>(buffer);
1789 auto bytes = base;
1790 auto fnBufSizeLeft = [&]() { return bufSize - (bytes - base); };
1792
1793 result = DeserializeEnvelope(bytes, fnBufSizeLeft(), kEnvelopeTypePageList);
1794 if (!result)
1795 return R__FORWARD_ERROR(result);
1796 bytes += result.Unwrap();
1797
1798 std::uint64_t xxhash3{0};
1799 if (fnBufSizeLeft() < static_cast<int>(sizeof(std::uint64_t)))
1800 return R__FAIL("page list too short");
1801 bytes += DeserializeUInt64(bytes, xxhash3);
1802 if (xxhash3 != desc.GetOnDiskHeaderXxHash3())
1803 return R__FAIL("XxHash-3 mismatch between header and page list");
1804
1805 std::vector<RClusterDescriptorBuilder> clusterBuilders;
1807 for (ROOT::DescriptorId_t i = 0; i < clusterGroupId; ++i) {
1808 firstClusterId = firstClusterId + desc.GetClusterGroupDescriptor(i).GetNClusters();
1809 }
1810
1811 std::uint64_t clusterSummaryFrameSize;
1814
1815 std::uint32_t nClusterSummaries;
1817 if (!result)
1818 return R__FORWARD_ERROR(result);
1819 bytes += result.Unwrap();
1822 result = DeserializeClusterSummary(bytes, fnClusterSummaryFrameSizeLeft(), clusterSummary);
1823 if (!result)
1824 return R__FORWARD_ERROR(result);
1825 bytes += result.Unwrap();
1826
1829 clusterBuilders.emplace_back(std::move(builder));
1830 }
1832
1833 std::uint64_t topMostFrameSize;
1834 auto topMostFrame = bytes;
1835 auto fnTopMostFrameSizeLeft = [&]() { return topMostFrameSize - (bytes - topMostFrame); };
1836
1837 std::uint32_t nClusters;
1838 result = DeserializeFrameHeader(bytes, fnBufSizeLeft(), topMostFrameSize, nClusters);
1839 if (!result)
1840 return R__FORWARD_ERROR(result);
1841 bytes += result.Unwrap();
1842
1844 return R__FAIL("mismatch between number of clusters and number of cluster summaries");
1845
1846 for (std::uint32_t i = 0; i < nClusters; ++i) {
1847 std::uint64_t outerFrameSize;
1848 auto outerFrame = bytes;
1849 auto fnOuterFrameSizeLeft = [&]() { return outerFrameSize - (bytes - outerFrame); };
1850
1851 std::uint32_t nColumns;
1852 result = DeserializeFrameHeader(bytes, fnTopMostFrameSizeLeft(), outerFrameSize, nColumns);
1853 if (!result)
1854 return R__FORWARD_ERROR(result);
1855 bytes += result.Unwrap();
1856
1857 for (std::uint32_t j = 0; j < nColumns; ++j) {
1858 std::uint64_t innerFrameSize;
1859 auto innerFrame = bytes;
1860 auto fnInnerFrameSizeLeft = [&]() { return innerFrameSize - (bytes - innerFrame); };
1861
1862 std::uint32_t nPages;
1863 result = DeserializeFrameHeader(bytes, fnOuterFrameSizeLeft(), innerFrameSize, nPages);
1864 if (!result)
1865 return R__FORWARD_ERROR(result);
1866 bytes += result.Unwrap();
1867
1869 pageRange.fPhysicalColumnId = j;
1870 for (std::uint32_t k = 0; k < nPages; ++k) {
1871 if (fnInnerFrameSizeLeft() < static_cast<int>(sizeof(std::uint32_t)))
1872 return R__FAIL("inner frame too short");
1873 std::int32_t nElements;
1874 bool hasChecksum = false;
1876 bytes += DeserializeInt32(bytes, nElements);
1877 if (nElements < 0) {
1879 hasChecksum = true;
1880 }
1881 result = DeserializeLocator(bytes, fnInnerFrameSizeLeft(), locator);
1882 if (!result)
1883 return R__FORWARD_ERROR(result);
1884 pageRange.fPageInfos.push_back({static_cast<std::uint32_t>(nElements), locator, hasChecksum});
1885 bytes += result.Unwrap();
1886 }
1887
1888 if (fnInnerFrameSizeLeft() < static_cast<int>(sizeof(std::int64_t)))
1889 return R__FAIL("page list frame too short");
1890 std::int64_t columnOffset;
1891 bytes += DeserializeInt64(bytes, columnOffset);
1892 if (columnOffset < 0) {
1893 if (nPages > 0)
1894 return R__FAIL("unexpected non-empty page list");
1895 clusterBuilders[i].MarkSuppressedColumnRange(j);
1896 } else {
1897 if (fnInnerFrameSizeLeft() < static_cast<int>(sizeof(std::uint32_t)))
1898 return R__FAIL("page list frame too short");
1899 std::uint32_t compressionSettings;
1900 bytes += DeserializeUInt32(bytes, compressionSettings);
1902 }
1903
1905 } // loop over columns
1906
1908 } // loop over clusters
1909
1910 return clusterBuilders;
1911}
1912
1916 RNTupleDescriptor &desc,
1918{
1920 if (!clusterBuildersRes)
1922
1923 auto clusterBuilders = clusterBuildersRes.Unwrap();
1924
1925 std::vector<RClusterDescriptor> clusters;
1926 clusters.reserve(clusterBuilders.size());
1927
1928 // Conditionally fixup the clusters depending on the attach purpose
1929 switch (mode) {
1930 case EDescriptorDeserializeMode::kForReading:
1931 for (auto &builder : clusterBuilders) {
1932 if (auto res = builder.CommitSuppressedColumnRanges(desc); !res)
1933 return R__FORWARD_RESULT(res);
1934 builder.AddExtendedColumnRanges(desc);
1935 clusters.emplace_back(builder.MoveDescriptor().Unwrap());
1936 }
1937 break;
1938 case EDescriptorDeserializeMode::kForWriting:
1939 for (auto &builder : clusterBuilders) {
1940 if (auto res = builder.CommitSuppressedColumnRanges(desc); !res)
1941 return R__FORWARD_RESULT(res);
1942 clusters.emplace_back(builder.MoveDescriptor().Unwrap());
1943 }
1944 break;
1945 case EDescriptorDeserializeMode::kRaw:
1946 for (auto &builder : clusterBuilders)
1947 clusters.emplace_back(builder.MoveDescriptor().Unwrap());
1948 break;
1949 }
1950
1952
1953 return RResult<void>::Success();
1954}
1955
1957{
1959 for (auto si : infos) {
1960 assert(si.first == si.second->GetNumber());
1961 streamerInfos.Add(si.second);
1962 }
1964 buffer.WriteObject(&streamerInfos);
1965 assert(buffer.Length() > 0);
1966 return std::string{buffer.Buffer(), static_cast<UInt_t>(buffer.Length())};
1967}
1968
1971{
1973
1974 TBufferFile buffer(TBuffer::kRead, extraTypeInfoContent.length(), const_cast<char *>(extraTypeInfoContent.data()),
1975 false /* adopt */);
1976 auto infoList = reinterpret_cast<TList *>(buffer.ReadObject(TList::Class()));
1977 infoList->SetOwner(); // delete the TStreamerInfo items of the list
1978
1979 TObjLink *lnk = infoList->FirstLink();
1980 while (lnk) {
1981 auto info = reinterpret_cast<TStreamerInfo *>(lnk->GetObject());
1982 info->BuildCheck();
1983 infoMap[info->GetNumber()] = info->GetClass()->GetStreamerInfo();
1984 assert(info->GetNumber() == infoMap[info->GetNumber()]->GetNumber());
1985 lnk = lnk->Next();
1986 }
1987
1988 delete infoList;
1989
1990 return infoMap;
1991}
#define R__FORWARD_ERROR(res)
Short-hand to return an RResult<T> in an error state (i.e. after checking)
Definition RError.hxx:303
#define R__FORWARD_RESULT(res)
Short-hand to return an RResult<T> value from a subroutine to the calling stack frame.
Definition RError.hxx:301
#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:299
#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.
A helper class for piece-wise construction of an RClusterDescriptor.
RClusterDescriptorBuilder & NEntries(std::uint64_t nEntries)
RClusterDescriptorBuilder & FirstEntryIndex(std::uint64_t firstEntryIndex)
RClusterDescriptorBuilder & ClusterId(ROOT::DescriptorId_t clusterId)
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 & Content(const std::string &content)
RExtraTypeInfoDescriptorBuilder & TypeVersion(std::uint32_t typeVersion)
RExtraTypeInfoDescriptorBuilder & TypeName(const std::string &typeName)
RExtraTypeInfoDescriptorBuilder & ContentId(EExtraTypeInfoIds contentId)
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 GetMemClusterGroupId(ROOT::DescriptorId_t onDiskId) const
ROOT::DescriptorId_t GetOnDiskFieldId(ROOT::DescriptorId_t memId) const
ROOT::DescriptorId_t GetOnDiskColumnId(ROOT::DescriptorId_t memId) const
ROOT::DescriptorId_t GetMemClusterId(ROOT::DescriptorId_t onDiskId) const
ROOT::DescriptorId_t GetMemColumnId(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,...
void MapSchema(const RNTupleDescriptor &desc, bool forHeaderExtension)
Map in-memory field and column IDs to their on-disk counterparts.
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::uint32_t > DeserializeColumnType(const void *buffer, ROOT::ENTupleColumnType &type)
static std::uint32_t SerializeListFramePreamble(std::uint32_t nitems, void *buffer)
static RResult< std::uint32_t > DeserializeSchemaDescription(const void *buffer, std::uint64_t bufSize, RNTupleDescriptorBuilder &descBuilder)
static RResult< std::uint32_t > DeserializeFieldStructure(const void *buffer, ROOT::ENTupleStructure &structure)
static RResult< StreamerInfoMap_t > DeserializeStreamerInfos(const std::string &extraTypeInfoContent)
static std::uint32_t SerializeEnvelopePostscript(unsigned char *envelope, std::uint64_t size)
static RContext SerializeHeader(void *buffer, const RNTupleDescriptor &desc)
static std::uint32_t SerializeFeatureFlags(const std::vector< std::uint64_t > &flags, void *buffer)
static RResult< std::uint32_t > DeserializeEnvelope(const void *buffer, std::uint64_t bufSize, std::uint16_t expectedType)
static std::uint32_t DeserializeUInt16(const void *buffer, std::uint16_t &val)
static RResult< std::uint32_t > DeserializeString(const void *buffer, std::uint64_t bufSize, std::string &val)
static RResult< std::uint32_t > DeserializeFeatureFlags(const void *buffer, std::uint64_t bufSize, std::vector< std::uint64_t > &flags)
static std::uint32_t SerializeColumnType(ROOT::ENTupleColumnType type, void *buffer)
static std::uint32_t SerializeString(const std::string &val, void *buffer)
static std::string SerializeStreamerInfos(const StreamerInfoMap_t &infos)
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 > DeserializeEnvelopeLink(const void *buffer, std::uint64_t bufSize, REnvelopeLink &envelopeLink)
static std::uint32_t DeserializeUInt32(const void *buffer, std::uint32_t &val)
static std::uint32_t SerializeUInt64(std::uint64_t val, void *buffer)
static std::uint32_t SerializeEnvelopePreamble(std::uint16_t envelopeType, void *buffer)
static std::uint32_t DeserializeInt16(const void *buffer, std::int16_t &val)
static std::uint32_t SerializeClusterSummary(const RClusterSummary &clusterSummary, void *buffer)
static std::uint32_t SerializeFramePostscript(void *frame, std::uint64_t size)
static std::uint32_t SerializeInt16(std::int16_t val, void *buffer)
static std::uint32_t SerializeSchemaDescription(void *buffer, const RNTupleDescriptor &desc, const RContext &context, bool forHeaderExtension=false)
Serialize the schema description in desc into buffer.
std::map< Int_t, TVirtualStreamerInfo * > StreamerInfoMap_t
static std::uint32_t SerializeLocator(const RNTupleLocator &locator, void *buffer)
static std::uint32_t SerializeInt32(std::int32_t val, void *buffer)
static RResult< void > DeserializeFooter(const void *buffer, std::uint64_t bufSize, RNTupleDescriptorBuilder &descBuilder)
static RResult< std::vector< RClusterDescriptorBuilder > > DeserializePageListRaw(const void *buffer, std::uint64_t bufSize, ROOT::DescriptorId_t clusterGroupId, const RNTupleDescriptor &desc)
static std::uint32_t DeserializeUInt64(const void *buffer, std::uint64_t &val)
static RResult< void > DeserializeHeader(const void *buffer, std::uint64_t bufSize, RNTupleDescriptorBuilder &descBuilder)
static std::uint32_t DeserializeInt32(const void *buffer, std::int32_t &val)
static std::uint32_t DeserializeInt64(const void *buffer, std::int64_t &val)
static std::uint32_t SerializePageList(void *buffer, const RNTupleDescriptor &desc, std::span< ROOT::DescriptorId_t > physClusterIDs, const RContext &context)
static RResult< std::uint32_t > DeserializeClusterGroup(const void *buffer, std::uint64_t bufSize, RClusterGroup &clusterGroup)
static RResult< std::uint32_t > DeserializeExtraTypeInfoId(const void *buffer, ROOT::Experimental::EExtraTypeInfoIds &id)
static std::uint32_t SerializeEnvelopeLink(const REnvelopeLink &envelopeLink, void *buffer)
static 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 std::uint32_t SerializeRecordFramePreamble(void *buffer)
static std::uint32_t SerializeUInt16(std::uint16_t val, void *buffer)
static RResult< std::uint32_t > DeserializeLocator(const void *buffer, std::uint64_t bufSize, RNTupleLocator &locator)
static std::uint32_t SerializeClusterGroup(const RClusterGroup &clusterGroup, void *buffer)
static std::uint32_t SerializeFooter(void *buffer, const RNTupleDescriptor &desc, const RContext &context)
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 std::uint32_t SerializeInt64(std::int64_t val, void *buffer)
static RResult< std::uint32_t > DeserializeClusterSummary(const void *buffer, std::uint64_t bufSize, RClusterSummary &clusterSummary)
static std::uint32_t SerializeUInt32(std::uint32_t val, void *buffer)
static RResult< void > DeserializePageList(const void *buffer, std::uint64_t bufSize, ROOT::DescriptorId_t clusterGroupId, RNTupleDescriptor &desc, EDescriptorDeserializeMode mode)
static std::uint32_t SerializeExtraTypeInfoId(ROOT::Experimental::EExtraTypeInfoIds id, void *buffer)
Records the partition of data into pages for a particular column in a particular cluster.
Meta-data stored for every column of an ntuple.
Field specific extra type information from the header / extenstion header.
Meta-data stored for every field of an ntuple.
The on-storage meta-data of an ntuple.
const RClusterGroupDescriptor & GetClusterGroupDescriptor(ROOT::DescriptorId_t clusterGroupId) 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::DescriptorId_t GetFieldZeroId() const
Returns the logical parent of all top-level NTuple data fields.
RColumnDescriptorIterable GetColumnIterable() const
const RColumnDescriptor & GetColumnDescriptor(ROOT::DescriptorId_t columnId) const
const RFieldDescriptor & GetFieldDescriptor(ROOT::DescriptorId_t fieldId) const
const std::string & GetDescription() const
const RClusterDescriptor & GetClusterDescriptor(ROOT::DescriptorId_t clusterId) const
const RHeaderExtension * GetHeaderExtension() const
Return header extension information; if the descriptor does not have a header extension,...
RFieldDescriptorIterable GetFieldIterable(const RFieldDescriptor &fieldDesc) const
std::vector< std::uint64_t > GetFeatureFlags() const
Base class for all ROOT issued exceptions.
Definition RError.hxx:79
RNTupleLocator payload that is common for object stores using 64bit location information.
Generic information about the physical location of data.
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:197
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 RNTupleLocator::ELocatorType kTestLocatorType
constexpr ROOT::ENTupleStructure kTestFutureFieldStructure
EExtraTypeInfoIds
Used in RExtraTypeInfoDescriptor.
ROOT::RLogChannel & NTupleLog()
Log channel for RNTuple diagnostics.
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 ntuple model tree can carry different structural information about the type system.