diff --git a/tree/ntuple/inc/ROOT/RFieldBase.hxx b/tree/ntuple/inc/ROOT/RFieldBase.hxx index 6f92760e4b618..2f1621b4ed3de 100644 --- a/tree/ntuple/inc/ROOT/RFieldBase.hxx +++ b/tree/ntuple/inc/ROOT/RFieldBase.hxx @@ -27,6 +27,7 @@ #include #include #include +#include namespace ROOT { @@ -727,9 +728,31 @@ public: return std::static_pointer_cast(fObjPtr); } + /** + * Get object reference, already casted to template type + * \note If a the passed template type does not match the field base type name, an exception is thrown + */ template const T &GetRef() const { + const auto templName = typeid(T).name(); + auto typeName = fField ? fField->GetTypeName() : ""; + // if (typeName.substr(0, 25) == "ROOT::RNTupleCardinality<") + // typeName = ROOT::Internal::GetCanonicalTypePrefix(ROOT::Internal::TokenizeTypeList(typeName.substr(25, typeName.length() - 26)).at(0)); + if ((std::strncmp(templName, "c", 1) == 0 && typeName != "char" && typeName != "std::int8_t") || + (std::strncmp(templName, "h", 1) == 0 && typeName != "unsigned char" && typeName != "std::uint8_t" && typeName != "std::byte") || + (std::strncmp(templName, "s", 1) == 0 && typeName != "short" && typeName != "std::int16_t") || + (std::strncmp(templName, "t", 1) == 0 && typeName != "unsigned short" && typeName != "std::uint16_t") || + (std::strncmp(templName, "i", 1) == 0 && typeName != "int" && typeName != "std::int32_t") || + (std::strncmp(templName, "j", 1) == 0 && typeName != "unsigned int" && typeName != "std::uint32_t" && typeName != "ROOT::RNTupleCardinality") || + (std::strncmp(templName, "l", 1) == 0 && typeName != "long" && typeName != "std::int64_t") || + (std::strncmp(templName, "m", 1) == 0 && typeName != "unsigned long" && typeName != "std::uint64_t" && typeName != "ROOT::RNTupleCardinality") || + (std::strncmp(templName, "f", 1) == 0 && typeName != "float") || + (std::strncmp(templName, "d", 1) == 0 && typeName != "double") || + (std::strncmp(templName, "e", 1) == 0 && typeName != "long double")) { + throw RException( + R__FAIL("Mismatch between type name `" + typeName + "` and template type `" + templName + "`.")); + } return *static_cast(fObjPtr.get()); } diff --git a/tree/ntuple/test/ntuple_view.cxx b/tree/ntuple/test/ntuple_view.cxx index 0af0c959555c5..88b4204ffed6f 100644 --- a/tree/ntuple/test/ntuple_view.cxx +++ b/tree/ntuple/test/ntuple_view.cxx @@ -217,6 +217,57 @@ TEST(RNTuple, VoidView) EXPECT_STREQ("pt", viewPt.GetField().GetFieldName().c_str()); } +TEST(RNTuple, VoidViewThrow) +{ + FileRaii fileGuard("test_ntuple_voidview_throw.root"); + + auto model = RNTupleModel::Create(); + *model->MakeField("c") = 42; + *model->MakeField("h") = 42; + *model->MakeField("s") = 42; + *model->MakeField("t") = 42; + *model->MakeField("i") = 42; + *model->MakeField("j") = 42; + *model->MakeField("l") = 42; + *model->MakeField("m") = 42; + *model->MakeField("f") = 42.f; + *model->MakeField("d") = 42.; + { + auto writer = RNTupleWriter::Recreate(std::move(model), "ntpl", fileGuard.GetPath()); + writer->Fill(); + } + + auto reader = RNTupleReader::Open("ntpl", fileGuard.GetPath()); + EXPECT_EQ(1u, reader->GetNEntries()); + auto vc = reader->GetView("c"); + auto vh = reader->GetView("h"); + auto vs = reader->GetView("s"); + auto vt = reader->GetView("t"); + auto vi = reader->GetView("i"); + auto vj = reader->GetView("j"); + auto vl = reader->GetView("l"); + auto vm = reader->GetView("m"); + auto vf = reader->GetView("f"); + auto vd = reader->GetView("d"); + EXPECT_THROW(vc.GetValue().GetRef(), ROOT::RException); + EXPECT_THROW(vh.GetValue().GetRef(), ROOT::RException); + EXPECT_THROW(vs.GetValue().GetRef(), ROOT::RException); + EXPECT_THROW(vt.GetValue().GetRef(), ROOT::RException); + EXPECT_THROW(vi.GetValue().GetRef(), ROOT::RException); + EXPECT_THROW(vj.GetValue().GetRef(), ROOT::RException); + EXPECT_THROW(vl.GetValue().GetRef(), ROOT::RException); + EXPECT_THROW(vm.GetValue().GetRef(), ROOT::RException); + EXPECT_THROW(vf.GetValue().GetRef(), ROOT::RException); + EXPECT_THROW(vf.GetValue().GetRef(), ROOT::RException); + EXPECT_THROW(vd.GetValue().GetRef(), ROOT::RException); + EXPECT_THROW(vd.GetValue().GetRef(), ROOT::RException); + EXPECT_THROW(vd.GetValue().GetRef(), ROOT::RException); + vf(0); + EXPECT_FLOAT_EQ(vf.GetValue().GetRef(), 42.f); + vd(0); + EXPECT_FLOAT_EQ(vd.GetValue().GetRef(), 42.); +} + TEST(RNTuple, MissingViewNames) { FileRaii fileGuard("test_ntuple_missing_view_names.root");