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:157
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 ...
@ 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.
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
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.