From 99dc6270933ec41bd4439214135dac27cc1d0a12 Mon Sep 17 00:00:00 2001 From: Giulio Eulisse <10544+ktf@users.noreply.github.com> Date: Tue, 10 Oct 2023 11:31:13 +0200 Subject: [PATCH] DPL: add support for converting various containers to vectors --- .../Core/include/Framework/DataAllocator.h | 28 ++++++++++++++----- Framework/Core/test/test_DataAllocator.cxx | 13 +++++++++ 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/Framework/Core/include/Framework/DataAllocator.h b/Framework/Core/include/Framework/DataAllocator.h index 57c2801b139af..f80d6d0836e28 100644 --- a/Framework/Core/include/Framework/DataAllocator.h +++ b/Framework/Core/include/Framework/DataAllocator.h @@ -58,13 +58,12 @@ namespace o2::framework { struct ServiceRegistry; -#define ERROR_STRING \ - "data type T not supported by API, " \ - "\n specializations available for" \ - "\n - trivially copyable, non-polymorphic structures" \ - "\n - arrays of those" \ - "\n - TObject with additional constructor arguments" \ - "\n - Classes and structs with boost serialization support" \ +#define ERROR_STRING \ + "data type T not supported by API, " \ + "\n specializations available for" \ + "\n - trivially copyable, non-polymorphic structures" \ + "\n - arrays of those" \ + "\n - TObject with additional constructor arguments" \ "\n - std containers of those" /// Helper to allow framework managed objecs to have a callback @@ -339,6 +338,21 @@ class DataAllocator "\n - pointers to those" "\n - types with ROOT dictionary and implementing ROOT ClassDef interface"); } + } else if constexpr (is_container::value == true && has_messageable_value_type::value == true) { + // Serialize a snapshot of a std::container of trivially copyable, non-polymorphic elements + // Note: in most cases it is better to use the `make` function und work with the provided + // reference object + constexpr auto elementSizeInBytes = sizeof(typename T::value_type); + auto sizeInBytes = elementSizeInBytes * object.size(); + payloadMessage = proxy.createOutputMessage(routeIndex, sizeInBytes); + + // serialize vector of pointers to elements + auto target = reinterpret_cast(payloadMessage->GetData()); + for (auto const& entry : object) { + memcpy(target, (void*)&entry, elementSizeInBytes); + target += elementSizeInBytes; + } + serializationType = o2::header::gSerializationMethodNone; } else if constexpr (has_root_dictionary::value == true || is_specialization_v == true) { // Serialize a snapshot of an object with root dictionary payloadMessage = proxy.createOutputMessage(routeIndex); diff --git a/Framework/Core/test/test_DataAllocator.cxx b/Framework/Core/test/test_DataAllocator.cxx index 5536eb1c07684..d880da72d7cb4 100644 --- a/Framework/Core/test/test_DataAllocator.cxx +++ b/Framework/Core/test/test_DataAllocator.cxx @@ -31,6 +31,7 @@ #include #include #include +#include #include // std::declval #include @@ -76,6 +77,8 @@ DataProcessorSpec getSourceSpec() o2::test::TriviallyCopyable a(42, 23, 0xdead); o2::test::Polymorphic b(0xbeef); std::vector c{{0xaffe}, {0xd00f}}; + std::deque testDequePayload{10, 20, 30}; + // class TriviallyCopyable is both messageable and has a dictionary, the default // picked by the framework is no serialization test::MetaHeader meta1{42}; @@ -88,6 +91,8 @@ DataProcessorSpec getSourceSpec() pc.outputs().snapshot(Output{"TST", "ROOTNONTOBJECT", 0, Lifetime::Timeframe}, b); // vector of ROOT serializable class pc.outputs().snapshot(Output{"TST", "ROOTVECTOR", 0, Lifetime::Timeframe}, c); + // deque of simple types + pc.outputs().snapshot(Output{"TST", "DEQUE", 0, Lifetime::Timeframe}, testDequePayload); // likewise, passed anonymously with char type and class name o2::framework::ROOTSerialized d(*((char*)&c), "vector"); pc.outputs().snapshot(Output{"TST", "ROOTSERLZDVEC", 0, Lifetime::Timeframe}, d); @@ -174,6 +179,7 @@ DataProcessorSpec getSourceSpec() OutputSpec{"TST", "MSGBLEROOTSRLZ", 0, Lifetime::Timeframe}, OutputSpec{"TST", "ROOTNONTOBJECT", 0, Lifetime::Timeframe}, OutputSpec{"TST", "ROOTVECTOR", 0, Lifetime::Timeframe}, + OutputSpec{"TST", "DEQUE", 0, Lifetime::Timeframe}, OutputSpec{"TST", "ROOTSERLZDVEC", 0, Lifetime::Timeframe}, OutputSpec{"TST", "ROOTSERLZDVEC2", 0, Lifetime::Timeframe}, OutputSpec{"TST", "PMRTESTVECTOR", 0, Lifetime::Timeframe}, @@ -317,6 +323,12 @@ DataProcessorSpec getSinkSpec() ASSERT_ERROR(object15[0] == o2::test::Polymorphic{0xacdc}); ASSERT_ERROR(object15[1] == o2::test::Polymorphic{0xbeef}); + LOG(info) << "extracting deque to vector from input16"; + auto object16 = pc.inputs().get>("input16"); + LOG(info) << "object16.size() = " << object16.size() << std::endl; + ASSERT_ERROR(object16.size() == 3); + ASSERT_ERROR(object16[0] == 10 && object16[1] == 20 && object16[2] == 30); + LOG(info) << "extracting PMR vector"; auto pmrspan = pc.inputs().get>("inputPMR"); ASSERT_ERROR((pmrspan[0] == o2::test::TriviallyCopyable{1, 2, 3})); @@ -351,6 +363,7 @@ DataProcessorSpec getSinkSpec() InputSpec{"input13", "TST", "MAKETOBJECT", 0, Lifetime::Timeframe}, InputSpec{"input14", "TST", "ROOTSERLZBLOBJ", 0, Lifetime::Timeframe}, InputSpec{"input15", "TST", "ROOTSERLZBLVECT", 0, Lifetime::Timeframe}, + InputSpec{"input16", "TST", "DEQUE", 0, Lifetime::Timeframe}, InputSpec{"inputPMR", "TST", "PMRTESTVECTOR", 0, Lifetime::Timeframe}, InputSpec{"inputPODvector", "TST", "PODVECTOR", 0, Lifetime::Timeframe}, InputSpec{"inputMP", ConcreteDataTypeMatcher{"TST", "MULTIPARTS"}, Lifetime::Timeframe}},