diff --git a/DataFormats/Headers/include/Headers/Stack.h b/DataFormats/Headers/include/Headers/Stack.h index 259a445f18cf8..418a6d1c2308a 100644 --- a/DataFormats/Headers/include/Headers/Stack.h +++ b/DataFormats/Headers/include/Headers/Stack.h @@ -14,10 +14,7 @@ #include "MemoryResources/MemoryResources.h" #include "Headers/DataHeader.h" -namespace o2 -{ - -namespace header +namespace o2::header { //__________________________________________________________________________________________________ /// @struct Stack @@ -45,7 +42,7 @@ struct Stack { }; public: - using allocator_type = boost::container::pmr::polymorphic_allocator; + using allocator_type = fair::mq::pmr::polymorphic_allocator; using value_type = std::byte; using BufferType = std::unique_ptr; //this gives us proper default move semantics for free @@ -53,12 +50,12 @@ struct Stack { Stack(Stack&&) = default; Stack(Stack&) = delete; Stack& operator=(Stack&) = delete; - Stack& operator=(Stack&&) = default; + Stack& operator=(Stack&&) = delete; - value_type* data() const { return buffer.get(); } - size_t size() const { return bufferSize; } + [[nodiscard]] value_type* data() const { return buffer.get(); } + [[nodiscard]] size_t size() const { return bufferSize; } allocator_type get_allocator() const { return allocator; } - const BaseHeader* first() const { return reinterpret_cast(this->data()); } + [[nodiscard]] const BaseHeader* first() const { return reinterpret_cast(this->data()); } static const BaseHeader* firstHeader(std::byte const* buf) { return BaseHeader::get(buf); } static const BaseHeader* lastHeader(std::byte const* buf) { @@ -90,9 +87,9 @@ struct Stack { /// all headers must derive from BaseHeader, in addition also other stacks can be passed to ctor. template >::value, int> = 0> + !std::is_convertible>::value, int> = 0> Stack(FirstArgType&& firstHeader, Headers&&... headers) - : Stack(boost::container::pmr::new_delete_resource(), std::forward(firstHeader), + : Stack(fair::mq::pmr::new_delete_resource(), std::forward(firstHeader), std::forward(headers)...) { } @@ -143,7 +140,7 @@ struct Stack { constexpr static size_t calculateSize() { return 0; } private: - allocator_type allocator{boost::container::pmr::new_delete_resource()}; + allocator_type allocator{fair::mq::pmr::new_delete_resource()}; size_t bufferSize{0}; BufferType buffer{nullptr, freeobj{allocator.resource()}}; @@ -231,7 +228,6 @@ struct Stack { } }; -} // namespace header -} // namespace o2 +} // namespace o2::header #endif // HEADERS_STACK_H diff --git a/DataFormats/Headers/test/testDataHeader.cxx b/DataFormats/Headers/test/testDataHeader.cxx index 0703fc6c3ae71..a85c9f1581bb0 100644 --- a/DataFormats/Headers/test/testDataHeader.cxx +++ b/DataFormats/Headers/test/testDataHeader.cxx @@ -314,7 +314,7 @@ BOOST_AUTO_TEST_CASE(headerStack_test) BOOST_CHECK(h3->secret == 42); //test constructing from a buffer and an additional header - using namespace boost::container::pmr; + using namespace fair::mq::pmr; Stack s5(new_delete_resource(), s1.data(), Stack{}, meta); BOOST_CHECK(s5.size() == s1.size() + sizeof(meta)); // check if we can find the header even though there was an empty stack in the middle diff --git a/DataFormats/MemoryResources/include/MemoryResources/MemoryResources.h b/DataFormats/MemoryResources/include/MemoryResources/MemoryResources.h index 42dd69aff38e3..eba309e38ad83 100644 --- a/DataFormats/MemoryResources/include/MemoryResources/MemoryResources.h +++ b/DataFormats/MemoryResources/include/MemoryResources/MemoryResources.h @@ -115,7 +115,7 @@ class MessageResource : public FairMQMemoryResource // A spectator pmr memory resource which only watches the memory of the underlying buffer, does not // carry out real allocation. It owns the underlying buffer which is destroyed on deallocation. template -class SpectatorMemoryResource : public boost::container::pmr::memory_resource +class SpectatorMemoryResource : public fair::mq::pmr::memory_resource { public: using buffer_type = BufferType; @@ -183,10 +183,10 @@ class SpectatorMemoryResource : public boost::container::pmr::memory_resource // This in general (as in STL) is a bad idea, but here it is safe to inherit from an allocator since we // have no additional data and only override some methods so we don't get into slicing and other problems. template -class SpectatorAllocator : public boost::container::pmr::polymorphic_allocator +class SpectatorAllocator : public fair::mq::pmr::polymorphic_allocator { public: - using boost::container::pmr::polymorphic_allocator::polymorphic_allocator; + using fair::mq::pmr::polymorphic_allocator::polymorphic_allocator; using propagate_on_container_move_assignment = std::true_type; // skip default construction of empty elements @@ -243,7 +243,7 @@ class OwningMessageSpectatorAllocator return OwningMessageSpectatorAllocator(); } - boost::container::pmr::memory_resource* resource() { return &mResource; } + fair::mq::pmr::memory_resource* resource() { return &mResource; } // skip default construction of empty elements // this is important for two reasons: one: it allows us to adopt an existing buffer (e.g. incoming message) and @@ -269,14 +269,14 @@ class OwningMessageSpectatorAllocator // The NoConstructAllocator behaves like the normal pmr vector but does not call constructors / destructors template -class NoConstructAllocator : public boost::container::pmr::polymorphic_allocator +class NoConstructAllocator : public fair::mq::pmr::polymorphic_allocator { public: - using boost::container::pmr::polymorphic_allocator::polymorphic_allocator; + using fair::mq::pmr::polymorphic_allocator::polymorphic_allocator; using propagate_on_container_move_assignment = std::true_type; template - NoConstructAllocator(Args&&... args) : boost::container::pmr::polymorphic_allocator(std::forward(args)...) + NoConstructAllocator(Args&&... args) : fair::mq::pmr::polymorphic_allocator(std::forward(args)...) { } @@ -302,9 +302,9 @@ class NoConstructAllocator : public boost::container::pmr::polymorphic_allocator //__________________________________________________________________________________________________ using ByteSpectatorAllocator = SpectatorAllocator; -using BytePmrAllocator = boost::container::pmr::polymorphic_allocator; +using BytePmrAllocator = fair::mq::pmr::polymorphic_allocator; template -using vector = std::vector>; +using vector = std::vector>; //__________________________________________________________________________________________________ /// Return a std::vector spanned over the contents of the message, takes ownership of the message diff --git a/DataFormats/MemoryResources/test/testMemoryResources.cxx b/DataFormats/MemoryResources/test/testMemoryResources.cxx index 264fe59b1caac..6bbafa3a82f4f 100644 --- a/DataFormats/MemoryResources/test/testMemoryResources.cxx +++ b/DataFormats/MemoryResources/test/testMemoryResources.cxx @@ -60,7 +60,7 @@ BOOST_AUTO_TEST_CASE(transportallocatormap_test) BOOST_CHECK(_tmp == allocZMQ); } -using namespace boost::container::pmr; +using namespace fair::mq::pmr; BOOST_AUTO_TEST_CASE(allocator_test) { diff --git a/Detectors/TPC/workflow/src/ClusterDecoderRawSpec.cxx b/Detectors/TPC/workflow/src/ClusterDecoderRawSpec.cxx index 9e2e70e8dde46..c5c444e077703 100644 --- a/Detectors/TPC/workflow/src/ClusterDecoderRawSpec.cxx +++ b/Detectors/TPC/workflow/src/ClusterDecoderRawSpec.cxx @@ -43,6 +43,7 @@ namespace o2 { namespace tpc { + /// create the processor spec for TPC raw cluster decoder converting TPC raw to native clusters /// Input: raw pages of TPC raw clusters /// Output: vector of containers with clusters in ClusterNative format, one container per @@ -79,27 +80,18 @@ DataProcessorSpec getClusterDecoderRawSpec(bool sendMC) // init the stacks for forwarding the sector header // FIXME check if there is functionality in the DPL to forward the stack // FIXME make one function - o2::header::Stack rawHeaderStack; - o2::header::Stack mcHeaderStack; o2::tpc::TPCSectorHeader const* sectorHeaderMC = nullptr; if (DataRefUtils::isValid(mclabelref)) { sectorHeaderMC = DataRefUtils::getHeader(mclabelref); - if (sectorHeaderMC) { - o2::header::Stack actual{*sectorHeaderMC}; - std::swap(mcHeaderStack, actual); - if (sectorHeaderMC->sector() < 0) { - pc.outputs().snapshot(Output{gDataOriginTPC, DataDescription("CLNATIVEMCLBL"), fanSpec, std::move(mcHeaderStack)}, fanSpec); - } - } + } + + if (sectorHeaderMC && sectorHeaderMC->sector() < 0) { + pc.outputs().snapshot(Output{gDataOriginTPC, DataDescription("CLNATIVEMCLBL"), fanSpec, {*sectorHeaderMC}}, fanSpec); } auto const* sectorHeader = DataRefUtils::getHeader(ref); - if (sectorHeader) { - o2::header::Stack actual{*sectorHeader}; - std::swap(rawHeaderStack, actual); - if (sectorHeader->sector() < 0) { - pc.outputs().snapshot(Output{gDataOriginTPC, DataDescription("CLUSTERNATIVE"), fanSpec, std::move(rawHeaderStack)}, fanSpec); - return; - } + if (sectorHeader && sectorHeader->sector() < 0) { + pc.outputs().snapshot(Output{gDataOriginTPC, DataDescription("CLUSTERNATIVE"), fanSpec, {*sectorHeader}}, fanSpec); + return; } assert(sectorHeaderMC == nullptr || sectorHeader->sector() == sectorHeaderMC->sector()); @@ -166,8 +158,8 @@ DataProcessorSpec getClusterDecoderRawSpec(bool sendMC) // output of the decoder is sorted in (sector,globalPadRow) coordinates, individual // containers are created for clusters and MC labels per (sector,globalPadRow) address char* outputBuffer = nullptr; - auto outputAllocator = [&pc, &fanSpec, &outputBuffer, &rawHeaderStack](size_t size) -> char* { - outputBuffer = pc.outputs().newChunk(Output{gDataOriginTPC, DataDescription("CLUSTERNATIVE"), fanSpec, std::move(rawHeaderStack)}, size).data(); + auto outputAllocator = [&pc, &fanSpec, &outputBuffer, sectorHeader](size_t size) -> char* { + outputBuffer = pc.outputs().newChunk(Output{gDataOriginTPC, DataDescription("CLUSTERNATIVE"), fanSpec, sectorHeader ? o2::header::Stack{*sectorHeader} : o2::header::Stack{}}, size).data(); return outputBuffer; }; MCLabelContainer mcout; @@ -188,7 +180,7 @@ DataProcessorSpec getClusterDecoderRawSpec(bool sendMC) // serialize the complete list of MC label containers ConstMCLabelContainer labelsFlat; mcout.flatten_to(labelsFlat); - pc.outputs().snapshot(Output{gDataOriginTPC, DataDescription("CLNATIVEMCLBL"), fanSpec, std::move(mcHeaderStack)}, labelsFlat); + pc.outputs().snapshot(Output{gDataOriginTPC, DataDescription("CLNATIVEMCLBL"), fanSpec, sectorHeaderMC ? o2::header::Stack{*sectorHeaderMC} : o2::header::Stack{}}, labelsFlat); } }; diff --git a/Framework/Core/include/Framework/Output.h b/Framework/Core/include/Framework/Output.h index a2abf5f7600a9..b2b8aef3b93f3 100644 --- a/Framework/Core/include/Framework/Output.h +++ b/Framework/Core/include/Framework/Output.h @@ -59,14 +59,7 @@ struct Output { Output& operator=(const Output&) = delete; - Output& operator=(Output&& rhs) - { - origin = rhs.origin; - description = rhs.description; - subSpec = rhs.subSpec; - metaHeader = std::move(rhs.metaHeader); - return *this; - } + Output& operator=(Output&& rhs) = delete; bool operator==(const Output& that) const { diff --git a/Framework/Core/test/test_FairMQ.cxx b/Framework/Core/test/test_FairMQ.cxx index 0ccfbf58f7576..f11d98505298f 100644 --- a/Framework/Core/test/test_FairMQ.cxx +++ b/Framework/Core/test/test_FairMQ.cxx @@ -174,7 +174,7 @@ TEST_CASE("addDataBlockForEach_test") int i; int j; }; - using namespace boost::container::pmr; + using namespace fair::mq::pmr; fair::mq::Parts message; std::vector> vec(polymorphic_allocator{allocZMQ}); vec.reserve(100); diff --git a/Utilities/DataSampling/include/DataSampling/Dispatcher.h b/Utilities/DataSampling/include/DataSampling/Dispatcher.h index 1d34269f87536..c38ece1436bc0 100644 --- a/Utilities/DataSampling/include/DataSampling/Dispatcher.h +++ b/Utilities/DataSampling/include/DataSampling/Dispatcher.h @@ -65,7 +65,6 @@ class Dispatcher : public framework::Task private: DataSamplingHeader prepareDataSamplingHeader(const DataSamplingPolicy& policy, header::DataHeader const& original); - header::Stack extractAdditionalHeaders(const char* inputHeaderStack) const; void reportStats(monitoring::Monitoring& monitoring) const; void send(framework::DataAllocator& dataAllocator, const framework::DataRef& inputData, const framework::Output& output) const; diff --git a/Utilities/DataSampling/src/Dispatcher.cxx b/Utilities/DataSampling/src/Dispatcher.cxx index 38ad15f5fd752..bc79be2771316 100644 --- a/Utilities/DataSampling/src/Dispatcher.cxx +++ b/Utilities/DataSampling/src/Dispatcher.cxx @@ -29,6 +29,7 @@ #include #include +#include using namespace o2::configuration; using namespace o2::monitoring; @@ -77,6 +78,42 @@ void Dispatcher::init(InitContext& ctx) mDeviceID.runtimeInit(spec.id.substr(0, DataSamplingHeader::deviceIDTypeSize).c_str()); } +header::Stack extractAdditionalHeaders(const char* inputHeaderStack) +{ + std::array headers; + int count = 0; + const auto* first = header::BaseHeader::get(reinterpret_cast(inputHeaderStack)); + for (const auto* current = first; current != nullptr; current = current->next()) { + if (current->description != header::DataHeader::sHeaderType && current->description != DataProcessingHeader::sHeaderType) { + headers[count++] = current; + } + } + + // Poor man runtime pack expansion. + switch (count) { + case 0: + return header::Stack{}; + case 1: + return header::Stack{*headers[0]}; + case 2: + return header::Stack{*headers[0], *headers[1]}; + case 3: + return header::Stack{*headers[0], *headers[1], *headers[2]}; + case 4: + return header::Stack{*headers[0], *headers[1], *headers[2], *headers[3]}; + case 5: + return header::Stack{*headers[0], *headers[1], *headers[2], *headers[3], *headers[4]}; + case 6: + return header::Stack{*headers[0], *headers[1], *headers[2], *headers[3], *headers[4], *headers[5]}; + case 7: + return header::Stack{*headers[0], *headers[1], *headers[2], *headers[3], *headers[4], *headers[5], *headers[6]}; + case 8: + return header::Stack{*headers[0], *headers[1], *headers[2], *headers[3], *headers[4], *headers[5], *headers[6], *headers[7]}; + default: + throw std::runtime_error(fmt::format("Too many headers to copy {}", count)); + } +} + void Dispatcher::run(ProcessingContext& ctx) { // todo: consider matching (and deciding) in completion policy to save some time @@ -106,7 +143,7 @@ void Dispatcher::run(ProcessingContext& ctx) // so that custom data-dependent headers are passed forward, // and we add a DataSamplingHeader. header::Stack headerStack{ - std::move(extractAdditionalHeaders(part.header)), + extractAdditionalHeaders(part.header), dsheader}; const auto* partInputHeader = DataRefUtils::getHeader(part); @@ -156,21 +193,6 @@ DataSamplingHeader Dispatcher::prepareDataSamplingHeader(const DataSamplingPolic original}; } -header::Stack Dispatcher::extractAdditionalHeaders(const char* inputHeaderStack) const -{ - header::Stack headerStack; - - const auto* first = header::BaseHeader::get(reinterpret_cast(inputHeaderStack)); - for (const auto* current = first; current != nullptr; current = current->next()) { - if (current->description != header::DataHeader::sHeaderType && - current->description != DataProcessingHeader::sHeaderType) { - headerStack = std::move(header::Stack{std::move(headerStack), *current}); - } - } - - return headerStack; -} - void Dispatcher::send(DataAllocator& dataAllocator, const DataRef& inputData, const Output& output) const { const auto* inputHeader = DataRefUtils::getHeader(inputData);