/******************************************************************************** * Copyright (C) 2018 CERN and copyright holders of ALICE O2 * * Copyright (C) 2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * * * * This software is distributed under the terms of the * * GNU Lesser General Public Licence (LGPL) version 3, * * copied verbatim in the file "LICENSE" * ********************************************************************************/ /// @brief Tools for interfacing containers to the transport via polymorphic /// allocators /// /// @author Mikolaj Krzewicki, mkrzewic@cern.ch #include #include namespace fair { namespace mq { using ByteSpectatorAllocator = SpectatorAllocator; using BytePmrAllocator = boost::container::pmr::polymorphic_allocator; //_________________________________________________________________________________________________ // return the message associated with the container or nullptr if it does not // make sense (e.g. when // we are just watching an existing message or when the container is not using // FairMQMemoryResource // as backend). template // typename std::enable_if< // std::is_base_of< // boost::container::pmr::polymorphic_allocator, // typename ContainerT::allocator_type>::value == true, // FairMQMessagePtr>::type FairMQMessagePtr getMessage(ContainerT &&container_, FairMQMemoryResource *targetResource = nullptr) { auto container = std::move(container_); auto alloc = container.get_allocator(); auto resource = dynamic_cast(alloc.resource()); if (!resource && !targetResource) { throw std::runtime_error("Neither the container or target resource specified"); } size_t containerSizeBytes = container.size() * sizeof(typename ContainerT::value_type); if ((!targetResource && resource) || (resource && targetResource && resource->is_equal(*targetResource))) { auto message = resource->getMessage(static_cast( const_cast::type *>( container.data()))); if (message) message->SetUsedSize(containerSizeBytes); return std::move(message); } else { auto message = targetResource->getTransportFactory()->CreateMessage(containerSizeBytes); std::memcpy(static_cast(message->GetData()), container.data(), containerSizeBytes); return std::move(message); } }; //_________________________________________________________________________________________________ /// Return a vector of const ElemT, no wonership transfer. /// Resource must be kept alive throughout the lifetime of the /// container and associated message. template std::vector> adoptVector( size_t nelem, SpectatorMessageResource *resource) { return std::vector>( nelem, SpectatorAllocator(resource)); }; //_________________________________________________________________________________________________ /// Return a vector of const ElemT, takes ownership of the message template std::vector> adoptVector(size_t nelem, FairMQMessagePtr message) { return std::vector>( nelem, OwningMessageSpectatorAllocator( MessageResource{std::move(message)})); }; //_________________________________________________________________________________________________ // TODO: this is C++14, converting it down to C++11 is too much work atm // This returns a unique_ptr of const vector, does not allow modifications at // the cost of pointer // semantics for access. // use auto or decltype to catch the return type. // template // auto adoptVector(size_t nelem, FairMQMessage* message) //{ // using DataType = std::vector; // // struct doubleDeleter // { // // kids: don't do this at home! (but here it's OK) // // this stateful deleter allows a single unique_ptr to manage 2 // resources at the same time. // std::unique_ptr extra; // void operator()(const DataType* ptr) { delete ptr; } // }; // // using OutputType = std::unique_ptr; // // auto resource = std::make_unique(message); // auto output = new DataType(nelem, ByteSpectatorAllocator{resource.get()}); // return OutputType(output, doubleDeleter{std::move(resource)}); //} } /* namespace mq */ } /* namespace fair */