Skip to content

Commit

Permalink
DPL: add support for converting various containers to vectors
Browse files Browse the repository at this point in the history
  • Loading branch information
ktf committed Oct 13, 2023
1 parent c4099d5 commit bdbbb05
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 7 deletions.
28 changes: 21 additions & 7 deletions Framework/Core/include/Framework/DataAllocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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<T>::value == true && has_messageable_value_type<T>::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<unsigned char*>(payloadMessage->GetData());
for (auto const& entry : object) {
memcpy(target, (void*)&entry, elementSizeInBytes);
target += elementSizeInBytes;
}
serializationType = o2::header::gSerializationMethodNone;
} else if constexpr (has_root_dictionary<T>::value == true || is_specialization_v<T, ROOTSerialized> == true) {
// Serialize a snapshot of an object with root dictionary
payloadMessage = proxy.createOutputMessage(routeIndex);
Expand Down
13 changes: 13 additions & 0 deletions Framework/Core/test/test_DataAllocator.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <vector>
#include <chrono>
#include <cstring>
#include <deque>
#include <utility> // std::declval
#include <TNamed.h>

Expand Down Expand Up @@ -76,6 +77,8 @@ DataProcessorSpec getSourceSpec()
o2::test::TriviallyCopyable a(42, 23, 0xdead);
o2::test::Polymorphic b(0xbeef);
std::vector<o2::test::Polymorphic> c{{0xaffe}, {0xd00f}};
std::deque<int> 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};
Expand All @@ -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<char, const char> d(*((char*)&c), "vector<o2::test::Polymorphic>");
pc.outputs().snapshot(Output{"TST", "ROOTSERLZDVEC", 0, Lifetime::Timeframe}, d);
Expand Down Expand Up @@ -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},
Expand Down Expand Up @@ -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<std::vector<int>>("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<gsl::span<o2::test::TriviallyCopyable>>("inputPMR");
ASSERT_ERROR((pmrspan[0] == o2::test::TriviallyCopyable{1, 2, 3}));
Expand Down Expand Up @@ -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}},
Expand Down

0 comments on commit bdbbb05

Please sign in to comment.