Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RField.cxx
Go to the documentation of this file.
1/// \file RField.cxx
2/// \ingroup NTuple
3/// \author Jakob Blomer <jblomer@cern.ch>
4/// \date 2018-10-15
5
6/*************************************************************************
7 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
8 * All rights reserved. *
9 * *
10 * For the licensing terms see $ROOTSYS/LICENSE. *
11 * For the list of contributors see $ROOTSYS/README/CREDITS. *
12 *************************************************************************/
13
14#include <ROOT/RColumn.hxx>
15#include <ROOT/REntry.hxx>
16#include <ROOT/RError.hxx>
17#include <ROOT/RField.hxx>
19#include <ROOT/RLogger.hxx>
20#include <ROOT/RNTupleModel.hxx>
22#include <ROOT/RNTupleTypes.hxx>
23#include <TClassEdit.h>
24
25#include <algorithm>
26#include <cstdint>
27#include <cstdlib>
28#include <exception>
29#include <functional>
30#include <iostream>
31#include <memory>
32#include <string_view>
33#include <type_traits>
34#include <unordered_set>
35
37{
38 fieldZero.fAllowFieldSubstitutions = val;
39}
40
41void ROOT::RFieldZero::Attach(std::unique_ptr<RFieldBase> child)
42{
43 const std::string childName = child->GetFieldName();
44 if (fSubFieldNames.count(childName) > 0)
45 throw RException(R__FAIL("duplicate field name: " + childName));
46 RFieldBase::Attach(std::move(child), "");
48}
49
54
55std::unique_ptr<ROOT::RFieldBase> ROOT::RFieldZero::CloneImpl(std::string_view /*newName*/) const
56{
57 auto result = std::make_unique<RFieldZero>();
58 for (auto &f : fSubfields) {
59 result->Attach(f->Clone(f->GetFieldName()));
60 result->fSubFieldNames.insert(f->GetFieldName());
61 }
62 return result;
63}
64
65std::vector<std::unique_ptr<ROOT::RFieldBase>> ROOT::RFieldZero::ReleaseSubfields()
66{
67 std::vector<std::unique_ptr<ROOT::RFieldBase>> result;
68 std::swap(fSubfields, result);
69 for (auto &f : result)
70 f->fParent = nullptr;
71 return result;
72}
73
75{
76 visitor.VisitFieldZero(*this);
77}
78
79//------------------------------------------------------------------------------
80
90
95
97{
98 EnsureMatchingOnDiskField(desc, kDiffTypeVersion | kDiffStructure | kDiffTypeName).ThrowOnError();
99
100 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
101 if (fieldDesc.GetStructure() == ENTupleStructure::kPlain) {
102 if (fieldDesc.GetTypeName().rfind("ROOT::RNTupleCardinality<", 0) != 0) {
103 throw RException(R__FAIL("RCardinalityField " + GetQualifiedFieldName() +
104 " expects an on-disk leaf field of the same type\n" +
105 Internal::GetTypeTraceReport(*this, desc)));
106 }
107 } else if (fieldDesc.GetStructure() != ENTupleStructure::kCollection) {
108 throw RException(R__FAIL("invalid on-disk structural role for RCardinalityField " + GetQualifiedFieldName() +
109 "\n" + Internal::GetTypeTraceReport(*this, desc)));
110 }
111}
112
114{
115 visitor.VisitCardinalityField(*this);
116}
117
122
127
128//------------------------------------------------------------------------------
129
130template <typename T>
132{
133 EnsureMatchingOnDiskField(desc, kDiffTypeName);
134
135 const RFieldDescriptor &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
137 SetOnDiskId(desc.FindFieldId("_0", GetOnDiskId()));
138 return;
139 }
140
141 static const std::string gIntegralTypeNames[] = {"bool", "char", "std::int8_t", "std::uint8_t",
142 "std::int16_t", "std::uint16_t", "std::int32_t", "std::uint32_t",
143 "std::int64_t", "std::uint64_t"};
144 if (std::find(std::begin(gIntegralTypeNames), std::end(gIntegralTypeNames), fieldDesc.GetTypeName()) ==
145 std::end(gIntegralTypeNames)) {
146 throw RException(R__FAIL("unexpected on-disk type name '" + fieldDesc.GetTypeName() + "' for field of type '" +
147 GetTypeName() + "'\n" + Internal::GetTypeTraceReport(*this, desc)));
148 }
149}
150
151template <typename T>
153{
154 EnsureMatchingOnDiskField(desc, kDiffTypeName);
155
156 const RFieldDescriptor &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
157 if (!(fieldDesc.GetTypeName() == "float" || fieldDesc.GetTypeName() == "double")) {
158 throw RException(R__FAIL("unexpected on-disk type name '" + fieldDesc.GetTypeName() + "' for field of type '" +
159 GetTypeName() + "'\n" + Internal::GetTypeTraceReport(*this, desc)));
160 }
161}
162
163//------------------------------------------------------------------------------
164
165template class ROOT::RSimpleField<char>;
166
186
188{
189 visitor.VisitCharField(*this);
190}
191
192//------------------------------------------------------------------------------
193
194template class ROOT::RSimpleField<std::byte>;
195
197{
198 static RColumnRepresentations representations({{ENTupleColumnType::kByte}}, {});
199 return representations;
200}
201
203{
204 visitor.VisitByteField(*this);
205}
206
207//------------------------------------------------------------------------------
208
209template class ROOT::RSimpleField<int8_t>;
210
212{
213 static RColumnRepresentations representations({{ENTupleColumnType::kInt8}}, {{ENTupleColumnType::kChar},
228 return representations;
229}
230
232{
233 visitor.VisitInt8Field(*this);
234}
235
236//------------------------------------------------------------------------------
237
238template class ROOT::RSimpleField<uint8_t>;
239
241{
242 static RColumnRepresentations representations({{ENTupleColumnType::kUInt8}}, {{ENTupleColumnType::kChar},
257 return representations;
258}
259
261{
262 visitor.VisitUInt8Field(*this);
263}
264
265//------------------------------------------------------------------------------
266
267template class ROOT::RSimpleField<bool>;
268
288
290{
291 visitor.VisitBoolField(*this);
292}
293
294//------------------------------------------------------------------------------
295
296template class ROOT::RSimpleField<float>;
297
308
310{
311 visitor.VisitFloatField(*this);
312}
313
314//------------------------------------------------------------------------------
315
316template class ROOT::RSimpleField<double>;
317
330
332{
333 visitor.VisitDoubleField(*this);
334}
335
337{
338 fTypeAlias = "Double32_t";
339}
340
341//------------------------------------------------------------------------------
342
343template class ROOT::RSimpleField<int16_t>;
344
346{
362 return representations;
363}
364
366{
367 visitor.VisitInt16Field(*this);
368}
369
370//------------------------------------------------------------------------------
371
372template class ROOT::RSimpleField<uint16_t>;
373
375{
391 return representations;
392}
393
395{
396 visitor.VisitUInt16Field(*this);
397}
398
399//------------------------------------------------------------------------------
400
401template class ROOT::RSimpleField<int32_t>;
402
404{
420 return representations;
421}
422
424{
425 visitor.VisitInt32Field(*this);
426}
427
428//------------------------------------------------------------------------------
429
430template class ROOT::RSimpleField<uint32_t>;
431
433{
449 return representations;
450}
451
453{
454 visitor.VisitUInt32Field(*this);
455}
456
457//------------------------------------------------------------------------------
458
459template class ROOT::RSimpleField<uint64_t>;
460
462{
478 return representations;
479}
480
482{
483 visitor.VisitUInt64Field(*this);
484}
485
486//------------------------------------------------------------------------------
487
488template class ROOT::RSimpleField<int64_t>;
489
491{
507 return representations;
508}
509
511{
512 visitor.VisitInt64Field(*this);
513}
514
515//------------------------------------------------------------------------------
516
518{
523 {});
524 return representations;
525}
526
528{
530}
531
533{
535}
536
537std::size_t ROOT::RField<std::string>::AppendImpl(const void *from)
538{
539 auto typedValue = static_cast<const std::string *>(from);
540 auto length = typedValue->length();
541 fAuxiliaryColumn->AppendV(typedValue->data(), length);
542 fIndex += length;
543 fPrincipalColumn->Append(&fIndex);
544 return length + fPrincipalColumn->GetElement()->GetPackedSize();
545}
546
548{
549 auto typedValue = static_cast<std::string *>(to);
550 RNTupleLocalIndex collectionStart;
552 fPrincipalColumn->GetCollectionInfo(globalIndex, &collectionStart, &nChars);
553 if (nChars == 0) {
554 typedValue->clear();
555 } else {
556 typedValue->resize(nChars);
557 fAuxiliaryColumn->ReadV(collectionStart, nChars, const_cast<char *>(typedValue->data()));
558 }
559}
560
562{
563 visitor.VisitStringField(*this);
564}
565
566//------------------------------------------------------------------------------
567
569 : ROOT::RFieldBase(name, source.GetTypeName(), ROOT::ENTupleStructure::kRecord, false /* isSimple */),
570 fMaxAlignment(source.fMaxAlignment),
572 fOffsets(source.fOffsets)
573{
574 for (const auto &f : source.GetConstSubfields())
575 Attach(f->Clone(f->GetFieldName()));
576 fSubfieldNames = source.fSubfieldNames;
577 fTraits = source.fTraits;
578}
579
580ROOT::RRecordField::RRecordField(std::string_view fieldName, std::string_view typeName)
581 : ROOT::RFieldBase(fieldName, typeName, ROOT::ENTupleStructure::kRecord, false /* isSimple */)
582{
583}
584
585std::unique_ptr<ROOT::RFieldBase>
587 std::vector<std::unique_ptr<RFieldBase>> itemFields,
588 std::string_view emulatedFromType)
589{
590 R__ASSERT(!emulatedFromType.empty());
591 return std::unique_ptr<RFieldBase>(new RRecordField(fieldName, std::move(itemFields), emulatedFromType));
592}
593
594std::unique_ptr<ROOT::RFieldBase> ROOT::Internal::CreateEmulatedVectorField(std::string_view fieldName,
595 std::unique_ptr<RFieldBase> itemField,
596 std::string_view emulatedFromType)
597{
598 R__ASSERT(!emulatedFromType.empty());
599 return std::unique_ptr<RFieldBase>(new RVectorField(fieldName, std::move(itemField), emulatedFromType));
600}
601
602ROOT::RRecordField::RRecordField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields,
603 std::string_view emulatedFromType)
605{
606 AttachItemFields(std::move(itemFields));
608}
609
610ROOT::RRecordField::RRecordField(std::string_view fieldName, std::vector<std::unique_ptr<RFieldBase>> itemFields)
612{
614}
615
616void ROOT::RRecordField::AddItem(std::unique_ptr<RFieldBase> item)
617{
618 fSize += GetItemPadding(fSize, item->GetAlignment());
619 if (!IsPairOrTuple()) {
620 fOffsets.emplace_back(fSize);
621 }
622 fSize += item->GetValueSize();
623 fMaxAlignment = std::max(fMaxAlignment, item->GetAlignment());
624 fTraits &= item->GetTraits() | (fTraits & kTraitExtensible); // may be called by AddItemToRecord()
625
626 if (IsPairOrTuple()) {
627 Attach(std::move(item), "_" + std::to_string(fSubfields.size()));
628 } else {
629 const std::string itemName = item->GetFieldName();
630 if (fSubfieldNames.count(itemName) > 0)
631 throw RException(R__FAIL("duplicate field name: " + itemName));
632 Attach(std::move(item));
633 fSubfieldNames.insert(itemName);
634 }
635}
636
638{
639 // Only supported for untyped records
640 assert(record.GetTypeName().empty());
641 record.AddItem(std::move(newItem));
642}
643
644std::size_t ROOT::RRecordField::GetItemPadding(std::size_t baseOffset, std::size_t itemAlignment) const
645{
646 if (itemAlignment > 1) {
647 auto remainder = baseOffset % itemAlignment;
648 if (remainder != 0)
649 return itemAlignment - remainder;
650 }
651 return 0;
652}
653
654std::unique_ptr<ROOT::RFieldBase> ROOT::RRecordField::CloneImpl(std::string_view newName) const
655{
656 return std::unique_ptr<RRecordField>(new RRecordField(newName, *this));
657}
658
659std::size_t ROOT::RRecordField::AppendImpl(const void *from)
660{
661 std::size_t nbytes = 0;
662 for (unsigned i = 0; i < fSubfields.size(); ++i) {
663 nbytes += CallAppendOn(*fSubfields[i], static_cast<const unsigned char *>(from) + fOffsets[i]);
664 }
665 return nbytes;
666}
667
669{
670 for (unsigned i = 0; i < fSubfields.size(); ++i) {
671 CallReadOn(*fSubfields[i], globalIndex, static_cast<unsigned char *>(to) + fOffsets[i]);
672 }
673}
674
676{
677 for (unsigned i = 0; i < fSubfields.size(); ++i) {
678 CallReadOn(*fSubfields[i], localIndex, static_cast<unsigned char *>(to) + fOffsets[i]);
679 }
680}
681
683{
684 if (fTraits & kTraitEmulatedField) {
685 // The field has been explicitly constructed following the on-disk information. No further reconcilation needed.
686 return;
687 }
688 // Note that the RPairField and RTupleField descendants have their own reconcilation logic
689 R__ASSERT(GetTypeName().empty());
690
691 EnsureMatchingOnDiskField(desc, kDiffTypeName | kDiffTypeVersion).ThrowOnError();
692
693 // The on-disk ID of subfields is matched by field name. So we inherently support reordering of fields
694 // and we will ignore extra on-disk fields.
695 // It remains to mark the extra in-memory fields as artificial.
696 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
697 std::unordered_set<std::string_view> onDiskSubfields;
698 for (const auto &subField : desc.GetFieldIterable(fieldDesc)) {
699 onDiskSubfields.insert(subField.GetFieldName());
700 }
701 for (auto &f : fSubfields) {
702 if (onDiskSubfields.count(f->GetFieldName()) == 0)
703 CallSetArtificialOn(*f);
704 }
705}
706
708{
709 for (unsigned i = 0; i < fSubfields.size(); ++i) {
710 CallConstructValueOn(*fSubfields[i], static_cast<unsigned char *>(where) + fOffsets[i]);
711 }
712}
713
715{
716 for (unsigned i = 0; i < fItemDeleters.size(); ++i) {
717 fItemDeleters[i]->operator()(reinterpret_cast<unsigned char *>(objPtr) + fOffsets[i], true /* dtorOnly */);
718 }
719 RDeleter::operator()(objPtr, dtorOnly);
720}
721
722std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RRecordField::GetDeleter() const
723{
724 std::vector<std::unique_ptr<RDeleter>> itemDeleters;
725 itemDeleters.reserve(fOffsets.size());
726 for (const auto &f : fSubfields) {
727 itemDeleters.emplace_back(GetDeleterOf(*f));
728 }
729 return std::make_unique<RRecordDeleter>(std::move(itemDeleters), fOffsets);
730}
731
732std::vector<ROOT::RFieldBase::RValue> ROOT::RRecordField::SplitValue(const RValue &value) const
733{
734 auto valuePtr = value.GetPtr<void>();
735 auto charPtr = static_cast<unsigned char *>(valuePtr.get());
736 std::vector<RValue> result;
737 result.reserve(fSubfields.size());
738 for (unsigned i = 0; i < fSubfields.size(); ++i) {
739 result.emplace_back(fSubfields[i]->BindValue(std::shared_ptr<void>(valuePtr, charPtr + fOffsets[i])));
740 }
741 return result;
742}
743
745{
746 visitor.VisitRecordField(*this);
747}
748
749//------------------------------------------------------------------------------
750
751ROOT::RBitsetField::RBitsetField(std::string_view fieldName, std::size_t N)
752 : ROOT::RFieldBase(fieldName, "std::bitset<" + std::to_string(N) + ">", ROOT::ENTupleStructure::kPlain,
753 false /* isSimple */, N),
754 fN(N)
755{
757}
758
764
769
774
775template <typename FUlong, typename FUlonglong, typename... Args>
777{
778 if (WordSize() == sizeof(unsigned long)) {
779 fUlong(std::forward<Args>(args)..., fN, *fPrincipalColumn);
780 } else if (WordSize() == sizeof(unsigned long long)) {
781 // NOTE: this can only happen on Windows; see the comment on the RBitsetField class.
782 fUlonglong(std::forward<Args>(args)..., fN, *fPrincipalColumn);
783 } else {
784 R__ASSERT(false);
785 }
786}
787
788template <typename Word_t>
789static void BitsetAppendImpl(const void *from, size_t nBits, ROOT::Internal::RColumn &column)
790{
791 constexpr auto kBitsPerWord = sizeof(Word_t) * 8;
792
793 const auto *asWordArray = static_cast<const Word_t *>(from);
794 bool elementValue;
795 std::size_t i = 0;
796 for (std::size_t word = 0; word < (nBits + kBitsPerWord - 1) / kBitsPerWord; ++word) {
797 for (std::size_t mask = 0; (mask < kBitsPerWord) && (i < nBits); ++mask, ++i) {
798 elementValue = (asWordArray[word] & (static_cast<Word_t>(1) << mask)) != 0;
799 column.Append(&elementValue);
800 }
801 }
802}
803
804std::size_t ROOT::RBitsetField::AppendImpl(const void *from)
805{
807 return fN;
808}
809
810template <typename Word_t>
811static void
813{
814 constexpr auto kBitsPerWord = sizeof(Word_t) * 8;
815
816 auto *asWordArray = static_cast<Word_t *>(to);
817 bool elementValue;
818 for (std::size_t i = 0; i < nBits; ++i) {
819 column.Read(globalIndex * nBits + i, &elementValue);
820 Word_t mask = static_cast<Word_t>(1) << (i % kBitsPerWord);
821 Word_t bit = static_cast<Word_t>(elementValue) << (i % kBitsPerWord);
822 asWordArray[i / kBitsPerWord] = (asWordArray[i / kBitsPerWord] & ~mask) | bit;
823 }
824}
825
830
831template <typename Word_t>
832static void
834{
835 constexpr auto kBitsPerWord = sizeof(Word_t) * 8;
836
837 auto *asWordArray = static_cast<Word_t *>(to);
838 bool elementValue;
839 for (std::size_t i = 0; i < nBits; ++i) {
840 column.Read(ROOT::RNTupleLocalIndex(localIndex.GetClusterId(), localIndex.GetIndexInCluster() * nBits) + i,
841 &elementValue);
842 Word_t mask = static_cast<Word_t>(1) << (i % kBitsPerWord);
843 Word_t bit = static_cast<Word_t>(elementValue) << (i % kBitsPerWord);
844 asWordArray[i / kBitsPerWord] = (asWordArray[i / kBitsPerWord] & ~mask) | bit;
845 }
846}
847
852
854{
855 visitor.VisitBitsetField(*this);
856}
857
858//------------------------------------------------------------------------------
859
860ROOT::RNullableField::RNullableField(std::string_view fieldName, const std::string &typePrefix,
861 std::unique_ptr<RFieldBase> itemField)
862 : ROOT::RFieldBase(fieldName, typePrefix + "<" + itemField->GetTypeName() + ">", ROOT::ENTupleStructure::kCollection,
863 false /* isSimple */)
864{
865 if (!itemField->GetTypeAlias().empty())
866 fTypeAlias = typePrefix + "<" + itemField->GetTypeAlias() + ">";
867
868 Attach(std::move(itemField), "_0");
869}
870
880
886
888{
889 if (!fIsEvolvedFromInnerType)
891}
892
894{
895 fPrincipalColumn->Append(&fNWritten);
896 return sizeof(ROOT::Internal::RColumnIndex);
897}
898
899std::size_t ROOT::RNullableField::AppendValue(const void *from)
900{
901 auto nbytesItem = CallAppendOn(*fSubfields[0], from);
902 fNWritten++;
903 fPrincipalColumn->Append(&fNWritten);
905}
906
908{
909 static const std::vector<std::string> prefixes = {"std::optional<", "std::unique_ptr<"};
910
911 auto success = EnsureMatchingOnDiskField(desc, kDiffTypeName);
912 if (!success) {
913 fIsEvolvedFromInnerType = true;
914 } else {
915 success = EnsureMatchingTypePrefix(desc, prefixes);
916 fIsEvolvedFromInnerType = !success;
917 }
918
919 if (fIsEvolvedFromInnerType)
920 fSubfields[0]->SetOnDiskId(GetOnDiskId());
921}
922
930
938
940{
941 visitor.VisitNullableField(*this);
942}
943
944//------------------------------------------------------------------------------
945
946namespace {
947// Dummy class to determine the dynamic type of any polymorphic user object.
948struct PolymorphicClass {
949 virtual ~PolymorphicClass() = default;
950};
951} // namespace
952
953ROOT::RUniquePtrField::RUniquePtrField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField)
954 : RNullableField(fieldName, "std::unique_ptr", std::move(itemField)), fItemDeleter(GetDeleterOf(*fSubfields[0]))
955{
956 if (const auto *classField = dynamic_cast<const ROOT::RClassField *>(fSubfields[0].get())) {
957 fPolymorphicTypeInfo = classField->GetPolymorphicTypeInfo();
958 }
959}
960
961std::unique_ptr<ROOT::RFieldBase> ROOT::RUniquePtrField::CloneImpl(std::string_view newName) const
962{
963 auto newItemField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
964 return std::make_unique<RUniquePtrField>(newName, std::move(newItemField));
965}
966
967std::size_t ROOT::RUniquePtrField::AppendImpl(const void *from)
968{
969 auto typedValue = static_cast<const std::unique_ptr<char> *>(from);
970 if (*typedValue) {
971 const void *obj = typedValue->get();
972 if (fPolymorphicTypeInfo != nullptr) {
973 // This cast allows getting the dynamic type of polymorphic objects. A similar strategy is employed by
974 // TIsAProxy. If one of them needs updating because of changes in C++, also check the other one.
975 const std::type_info &t = typeid(*static_cast<const PolymorphicClass *>(obj));
976 if (t != *fPolymorphicTypeInfo) {
977 std::string msg = "invalid dynamic type of object, expected " + fSubfields[0]->GetTypeName();
978 int err = 0;
980 if (!err) {
981 msg = msg + " but was passed " + demangled;
983 }
984 msg += " and upcasting of polymorphic types is not supported in RNTuple";
985 throw RException(R__FAIL(msg));
986 }
987 }
988 return AppendValue(obj);
989 } else {
990 return AppendNull();
991 }
992}
993
995{
996 auto ptr = static_cast<std::unique_ptr<char> *>(to);
997 bool isValidValue = static_cast<bool>(*ptr);
998
999 void *valuePtr = nullptr;
1000 if (isValidValue)
1001 valuePtr = ptr->get();
1002
1003 if (isValidValue && !hasOnDiskValue) {
1004 ptr->release();
1005 fItemDeleter->operator()(valuePtr, false /* dtorOnly */);
1006 } else if (!isValidValue && hasOnDiskValue) {
1007 valuePtr = CallCreateObjectRawPtrOn(*fSubfields[0]);
1008 ptr->reset(reinterpret_cast<char *>(valuePtr));
1009 }
1010
1011 return valuePtr;
1012}
1013
1015{
1017 if (!fIsEvolvedFromInnerType)
1018 itemIndex = GetItemIndex(globalIndex);
1019 const bool hasOnDiskValue = fIsEvolvedFromInnerType || itemIndex.GetIndexInCluster() != ROOT::kInvalidNTupleIndex;
1020 auto valuePtr = PrepareRead(to, hasOnDiskValue);
1021 if (hasOnDiskValue) {
1022 if (fIsEvolvedFromInnerType) {
1023 CallReadOn(*fSubfields[0], globalIndex, valuePtr);
1024 } else {
1025 CallReadOn(*fSubfields[0], itemIndex, valuePtr);
1026 }
1027 }
1028}
1029
1031{
1033 if (!fIsEvolvedFromInnerType) {
1034 itemIndex = GetItemIndex(localIndex);
1035 } else {
1037 }
1038 const bool hasOnDiskValue = itemIndex.GetIndexInCluster() != ROOT::kInvalidNTupleIndex;
1039 auto valuePtr = PrepareRead(to, hasOnDiskValue);
1040 if (hasOnDiskValue)
1041 CallReadOn(*fSubfields[0], itemIndex, valuePtr);
1042}
1043
1045{
1046 auto typedPtr = static_cast<std::unique_ptr<char> *>(objPtr);
1047 if (*typedPtr) {
1048 fItemDeleter->operator()(typedPtr->get(), false /* dtorOnly */);
1049 typedPtr->release();
1050 }
1051 RDeleter::operator()(objPtr, dtorOnly);
1052}
1053
1054std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::RUniquePtrField::GetDeleter() const
1055{
1056 return std::make_unique<RUniquePtrDeleter>(GetDeleterOf(*fSubfields[0]));
1057}
1058
1059std::vector<ROOT::RFieldBase::RValue> ROOT::RUniquePtrField::SplitValue(const RValue &value) const
1060{
1061 std::vector<RValue> result;
1062 auto valuePtr = value.GetPtr<void>();
1063 const auto &uniquePtr = *static_cast<std::unique_ptr<char> *>(valuePtr.get());
1064 if (uniquePtr) {
1065 result.emplace_back(fSubfields[0]->BindValue(std::shared_ptr<void>(valuePtr, uniquePtr.get())));
1066 }
1067 return result;
1068}
1069
1070//------------------------------------------------------------------------------
1071
1072ROOT::ROptionalField::ROptionalField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField)
1073 : RNullableField(fieldName, "std::optional", std::move(itemField)), fItemDeleter(GetDeleterOf(*fSubfields[0]))
1074{
1077}
1078
1080{
1081 return reinterpret_cast<bool *>(reinterpret_cast<unsigned char *>(optionalPtr) + fSubfields[0]->GetValueSize());
1082}
1083
1085{
1086 return GetEngagementPtr(const_cast<void *>(optionalPtr));
1087}
1088
1089std::unique_ptr<ROOT::RFieldBase> ROOT::ROptionalField::CloneImpl(std::string_view newName) const
1090{
1091 auto newItemField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
1092 return std::make_unique<ROptionalField>(newName, std::move(newItemField));
1093}
1094
1095std::size_t ROOT::ROptionalField::AppendImpl(const void *from)
1096{
1097 if (*GetEngagementPtr(from)) {
1098 return AppendValue(from);
1099 } else {
1100 return AppendNull();
1101 }
1102}
1103
1105{
1106 auto engagementPtr = GetEngagementPtr(to);
1107 if (hasOnDiskValue) {
1108 if (!(*engagementPtr) && !(fSubfields[0]->GetTraits() & kTraitTriviallyConstructible))
1109 CallConstructValueOn(*fSubfields[0], to);
1110 *engagementPtr = true;
1111 } else {
1112 if (*engagementPtr && !(fSubfields[0]->GetTraits() & kTraitTriviallyDestructible))
1113 fItemDeleter->operator()(to, true /* dtorOnly */);
1114 *engagementPtr = false;
1115 }
1116}
1117
1119{
1121 if (!fIsEvolvedFromInnerType)
1122 itemIndex = GetItemIndex(globalIndex);
1123 const bool hasOnDiskValue = fIsEvolvedFromInnerType || itemIndex.GetIndexInCluster() != ROOT::kInvalidNTupleIndex;
1124 PrepareRead(to, hasOnDiskValue);
1125 if (hasOnDiskValue) {
1126 if (fIsEvolvedFromInnerType) {
1127 CallReadOn(*fSubfields[0], globalIndex, to);
1128 } else {
1129 CallReadOn(*fSubfields[0], itemIndex, to);
1130 }
1131 }
1132}
1133
1135{
1137 if (!fIsEvolvedFromInnerType) {
1138 itemIndex = GetItemIndex(localIndex);
1139 } else {
1141 }
1142 const bool hasOnDiskValue = itemIndex.GetIndexInCluster() != ROOT::kInvalidNTupleIndex;
1143 PrepareRead(to, hasOnDiskValue);
1144 if (hasOnDiskValue)
1145 CallReadOn(*fSubfields[0], itemIndex, to);
1146}
1147
1149{
1150 *GetEngagementPtr(where) = false;
1151}
1152
1154{
1155 if (fItemDeleter) {
1156 auto engagementPtr = reinterpret_cast<bool *>(reinterpret_cast<unsigned char *>(objPtr) + fEngagementPtrOffset);
1157 if (*engagementPtr)
1158 fItemDeleter->operator()(objPtr, true /* dtorOnly */);
1159 }
1160 RDeleter::operator()(objPtr, dtorOnly);
1161}
1162
1163std::unique_ptr<ROOT::RFieldBase::RDeleter> ROOT::ROptionalField::GetDeleter() const
1164{
1165 return std::make_unique<ROptionalDeleter>(
1166 (fSubfields[0]->GetTraits() & kTraitTriviallyDestructible) ? nullptr : GetDeleterOf(*fSubfields[0]),
1167 fSubfields[0]->GetValueSize());
1168}
1169
1170std::vector<ROOT::RFieldBase::RValue> ROOT::ROptionalField::SplitValue(const RValue &value) const
1171{
1172 std::vector<RValue> result;
1173 const auto valuePtr = value.GetPtr<void>().get();
1174 if (*GetEngagementPtr(valuePtr)) {
1175 result.emplace_back(fSubfields[0]->BindValue(std::shared_ptr<void>(value.GetPtr<void>(), valuePtr)));
1176 }
1177 return result;
1178}
1179
1181{
1182 const auto alignment = GetAlignment();
1183 // real size is the sum of the value size and the engagement boolean
1184 const auto actualSize = fSubfields[0]->GetValueSize() + sizeof(bool);
1185 auto padding = 0;
1186 if (alignment > 1) {
1187 auto remainder = actualSize % alignment;
1188 if (remainder != 0)
1189 padding = alignment - remainder;
1190 }
1191 return actualSize + padding;
1192}
1193
1195{
1196 return fSubfields[0]->GetAlignment();
1197}
1198
1199//------------------------------------------------------------------------------
1200
1201ROOT::RAtomicField::RAtomicField(std::string_view fieldName, std::unique_ptr<RFieldBase> itemField)
1202 : RFieldBase(fieldName, "std::atomic<" + itemField->GetTypeName() + ">", ROOT::ENTupleStructure::kPlain,
1203 false /* isSimple */)
1204{
1205 if (itemField->GetTraits() & kTraitTriviallyConstructible)
1207 if (itemField->GetTraits() & kTraitTriviallyDestructible)
1209
1210 if (!itemField->GetTypeAlias().empty())
1211 fTypeAlias = "std::atomic<" + itemField->GetTypeAlias() + ">";
1212
1213 Attach(std::move(itemField), "_0");
1214}
1215
1216std::unique_ptr<ROOT::RFieldBase> ROOT::RAtomicField::CloneImpl(std::string_view newName) const
1217{
1218 auto newItemField = fSubfields[0]->Clone(fSubfields[0]->GetFieldName());
1219 return std::make_unique<RAtomicField>(newName, std::move(newItemField));
1220}
1221
1223{
1224 const auto &fieldDesc = desc.GetFieldDescriptor(GetOnDiskId());
1225 if (fieldDesc.GetTypeName().rfind("std::atomic<", 0) == 0) {
1226 EnsureMatchingOnDiskField(desc, kDiffTypeName).ThrowOnError();
1227 } else {
1228 fSubfields[0]->SetOnDiskId(GetOnDiskId());
1229 }
1230}
1231
1232std::vector<ROOT::RFieldBase::RValue> ROOT::RAtomicField::SplitValue(const RValue &value) const
1233{
1234 std::vector<RValue> result;
1235 result.emplace_back(fSubfields[0]->BindValue(value.GetPtr<void>()));
1236 return result;
1237}
1238
1240{
1241 visitor.VisitAtomicField(*this);
1242}
dim_t fSize
#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
static void BitsetReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to, size_t nBits, ROOT::Internal::RColumn &column)
Definition RField.cxx:812
static void BitsetReadInClusterImpl(ROOT::RNTupleLocalIndex localIndex, void *to, size_t nBits, ROOT::Internal::RColumn &column)
Definition RField.cxx:833
static void BitsetAppendImpl(const void *from, size_t nBits, ROOT::Internal::RColumn &column)
Definition RField.cxx:789
#define f(i)
Definition RSha256.hxx:104
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
#define N
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 mask
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 child
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
char name[80]
Definition TGX11.cxx:110
TCanvas * alignment()
Definition alignment.C:1
#define free
Definition civetweb.c:1578
Abstract base class for classes implementing the visitor design pattern.
The in-memory representation of a 32bit or 64bit on-disk index column.
A column is a storage-backed array of a simple, fixed-size type, from which pages can be mapped into ...
Definition RColumn.hxx:38
void Read(const ROOT::NTupleSize_t globalIndex, void *to)
Definition RColumn.hxx:160
void Append(const void *from)
Definition RColumn.hxx:126
void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:1239
RAtomicField(std::string_view fieldName, std::unique_ptr< RFieldBase > itemField)
Definition RField.cxx:1201
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:1216
void ReconcileOnDiskField(const RNTupleDescriptor &desc) final
For non-artificial fields, check compatibility of the in-memory field and the on-disk field.
Definition RField.cxx:1222
std::vector< RValue > SplitValue(const RValue &value) const final
Creates the list of direct child values given an existing value for this field.
Definition RField.cxx:1232
RBitsetField(std::string_view fieldName, std::size_t N)
Definition RField.cxx:751
void ReadInClusterImpl(RNTupleLocalIndex localIndex, void *to) final
Definition RField.cxx:848
void GenerateColumns() final
Implementations in derived classes should create the backing columns corresponding to the field type ...
Definition RField.cxx:765
void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final
Definition RField.cxx:826
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
Definition RField.cxx:804
const RColumnRepresentations & GetColumnRepresentations() const final
Implementations in derived classes should return a static RColumnRepresentations object.
Definition RField.cxx:759
void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:853
void SelectWordSize(FUlong &&fUlong, FUlonglong &&fUlonglong, Args &&...args)
Definition RField.cxx:776
void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:113
const RColumnRepresentations & GetColumnRepresentations() const final
Implementations in derived classes should return a static RColumnRepresentations object.
Definition RField.cxx:81
const RField< RNTupleCardinality< std::uint32_t > > * As32Bit() const
Definition RField.cxx:118
void ReconcileOnDiskField(const RNTupleDescriptor &desc) final
For non-artificial fields, check compatibility of the in-memory field and the on-disk field.
Definition RField.cxx:96
const RField< RNTupleCardinality< std::uint64_t > > * As64Bit() const
Definition RField.cxx:123
void GenerateColumns() final
Implementations in derived classes should create the backing columns corresponding to the field type ...
Definition RField.hxx:371
The field for a class with dictionary.
Definition RField.hxx:138
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final
void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final
Base class for all ROOT issued exceptions.
Definition RError.hxx:79
The list of column representations a field can have.
Points to an object with RNTuple I/O support and keeps a pointer to the corresponding field.
A field translates read and write calls from/to underlying columns to/from tree values.
void Attach(std::unique_ptr< RFieldBase > child, std::string_view expectedChildName="")
Add a new subfield to the list of nested fields.
std::vector< std::unique_ptr< RFieldBase > > fSubfields
Collections and classes own subfields.
virtual const RColumnRepresentations & GetColumnRepresentations() const
Implementations in derived classes should return a static RColumnRepresentations object.
virtual void GenerateColumns()
Implementations in derived classes should create the backing columns corresponding to the field type ...
std::uint32_t fTraits
Properties of the type that allow for optimizations of collections of that type.
std::string fTypeAlias
A typedef or using name that was used when creating the field.
std::uint32_t GetTraits() const
@ kTraitEmulatedField
This field is a user defined type that was missing dictionaries and was reconstructed from the on-dis...
@ kTraitTriviallyDestructible
The type is cleaned up just by freeing its memory. I.e. the destructor performs a no-op.
@ kTraitExtensible
Can attach new item fields even when already connected.
@ kTraitTriviallyConstructible
No constructor needs to be called, i.e.
Metadata stored for every field of an RNTuple.
The container field for an ntuple model, which itself has no physical representation.
Definition RField.hxx:59
std::unordered_set< std::string > fSubFieldNames
Efficient detection of duplicate field names.
Definition RField.hxx:72
void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:74
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:55
std::vector< std::unique_ptr< RFieldBase > > ReleaseSubfields()
Moves all subfields into the returned vector.
Definition RField.cxx:65
void Attach(std::unique_ptr< RFieldBase > child)
A public version of the Attach method that allows piece-wise construction of the zero field.
Definition RField.cxx:41
Classes with dictionaries that can be inspected by TClass.
Definition RField.hxx:323
The on-storage metadata of an RNTuple.
RFieldDescriptorIterable GetFieldIterable(const RFieldDescriptor &fieldDesc) const
const RFieldDescriptor & GetFieldDescriptor(ROOT::DescriptorId_t fieldId) const
ROOT::DescriptorId_t FindFieldId(std::string_view fieldName, ROOT::DescriptorId_t parentId) const
Addresses a column element or field item relative to a particular cluster, instead of a global NTuple...
Template specializations for C++ std::optional and std::unique_ptr.
void ReconcileOnDiskField(const RNTupleDescriptor &desc) final
For non-artificial fields, check compatibility of the in-memory field and the on-disk field.
Definition RField.cxx:907
RNTupleLocalIndex GetItemIndex(NTupleSize_t globalIndex)
Given the global index of the nullable field, returns the corresponding cluster-local index of the su...
Definition RField.cxx:923
RNullableField(std::string_view fieldName, const std::string &typePrefix, std::unique_ptr< RFieldBase > itemField)
Definition RField.cxx:860
std::size_t AppendNull()
Definition RField.cxx:893
std::size_t AppendValue(const void *from)
Definition RField.cxx:899
void GenerateColumns() final
Implementations in derived classes should create the backing columns corresponding to the field type ...
Definition RField.cxx:881
void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:939
const RFieldBase::RColumnRepresentations & GetColumnRepresentations() const final
Implementations in derived classes should return a static RColumnRepresentations object.
Definition RField.cxx:871
void operator()(void *objPtr, bool dtorOnly) final
Definition RField.cxx:1153
void ConstructValue(void *where) const final
Constructs value in a given location of size at least GetValueSize(). Called by the base class' Creat...
Definition RField.cxx:1148
size_t GetAlignment() const final
As a rule of thumb, the alignment is equal to the size of the type.
Definition RField.cxx:1194
std::unique_ptr< RDeleter > GetDeleter() const final
Definition RField.cxx:1163
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:1089
const bool * GetEngagementPtr(const void *optionalPtr) const
Given a pointer to an std::optional<T> in optionalPtr, extract a pointer to the engagement boolean.
Definition RField.cxx:1084
void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final
Definition RField.cxx:1118
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
Definition RField.cxx:1095
void ReadInClusterImpl(ROOT::RNTupleLocalIndex localIndex, void *to) final
Definition RField.cxx:1134
std::vector< RValue > SplitValue(const RValue &value) const final
Creates the list of direct child values given an existing value for this field.
Definition RField.cxx:1170
size_t GetValueSize() const final
The number of bytes taken by a value of the appropriate type.
Definition RField.cxx:1180
void PrepareRead(void *to, bool hasOnDiskValue)
Definition RField.cxx:1104
ROptionalField(std::string_view fieldName, std::unique_ptr< RFieldBase > itemField)
Definition RField.cxx:1072
void operator()(void *objPtr, bool dtorOnly) final
Definition RField.cxx:714
The field for an untyped record.
std::vector< RValue > SplitValue(const RValue &value) const final
Creates the list of direct child values given an existing value for this field.
Definition RField.cxx:732
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const override
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:654
void ReadInClusterImpl(RNTupleLocalIndex localIndex, void *to) final
Definition RField.cxx:675
std::unordered_set< std::string > fSubfieldNames
Efficient detection of duplicate field names.
RRecordField(std::string_view name, const RRecordField &source)
Definition RField.cxx:568
void AcceptVisitor(ROOT::Detail::RFieldVisitor &visitor) const final
Definition RField.cxx:744
void AttachItemFields(ContainerT &&itemFields)
std::unique_ptr< RDeleter > GetDeleter() const final
Definition RField.cxx:722
std::size_t GetItemPadding(std::size_t baseOffset, std::size_t itemAlignment) const
Definition RField.cxx:644
void AddItem(std::unique_ptr< RFieldBase > item)
Adds an additional item field.
Definition RField.cxx:616
void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final
Definition RField.cxx:668
void ConstructValue(void *where) const final
Constructs value in a given location of size at least GetValueSize(). Called by the base class' Creat...
Definition RField.cxx:707
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
Definition RField.cxx:659
void ReconcileOnDiskField(const RNTupleDescriptor &desc) override
For non-artificial fields, check compatibility of the in-memory field and the on-disk field.
Definition RField.cxx:682
void ReconcileIntegralField(const RNTupleDescriptor &desc)
Definition RField.cxx:131
void ReconcileFloatingPointField(const RNTupleDescriptor &desc)
Definition RField.cxx:152
void operator()(void *objPtr, bool dtorOnly) final
Definition RField.cxx:1044
std::vector< RValue > SplitValue(const RValue &value) const final
Creates the list of direct child values given an existing value for this field.
Definition RField.cxx:1059
const std::type_info * fPolymorphicTypeInfo
If the item type is a polymorphic class (that declares or inherits at least one virtual method),...
void * PrepareRead(void *to, bool hasOnDiskValue)
Definition RField.cxx:994
std::unique_ptr< RDeleter > GetDeleter() const final
Definition RField.cxx:1054
void ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *to) final
Definition RField.cxx:1014
std::unique_ptr< RFieldBase > CloneImpl(std::string_view newName) const final
Called by Clone(), which additionally copies the on-disk ID.
Definition RField.cxx:961
RUniquePtrField(std::string_view fieldName, std::unique_ptr< RFieldBase > itemField)
Definition RField.cxx:953
std::size_t AppendImpl(const void *from) final
Operations on values of complex types, e.g.
Definition RField.cxx:967
void ReadInClusterImpl(ROOT::RNTupleLocalIndex localIndex, void *to) final
Definition RField.cxx:1030
Template specializations for C++ std::vector.
void SetAllowFieldSubstitutions(RFieldZero &fieldZero, bool val)
Definition RField.cxx:36
std::unique_ptr< RFieldBase > CreateEmulatedVectorField(std::string_view fieldName, std::unique_ptr< RFieldBase > itemField, std::string_view emulatedFromType)
Definition RField.cxx:594
std::unique_ptr< RFieldBase > CreateEmulatedRecordField(std::string_view fieldName, std::vector< std::unique_ptr< RFieldBase > > itemFields, std::string_view emulatedFromType)
Definition RField.cxx:586
std::string GetTypeTraceReport(const RFieldBase &field, const RNTupleDescriptor &desc)
Prints the hierarchy of types with their field names and field IDs for the given in-memory field and ...
void AddItemToRecord(RRecordField &record, std::unique_ptr< RFieldBase > newItem)
Definition RField.cxx:637
bool IsCustomEnumFieldDesc(const RNTupleDescriptor &desc, const RFieldDescriptor &fieldDesc)
Tells if the field describes a user-defined enum type.
constexpr NTupleSize_t kInvalidNTupleIndex
std::uint64_t NTupleSize_t
Integer type long enough to hold the maximum number of entries in a column.
ENTupleStructure
The fields in the RNTuple data model tree can carry different structural information about the type s...
char * DemangleTypeIdName(const std::type_info &ti, int &errorCode)
Demangle in a portable way the type id name.