Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions HeterogeneousCore/SerialisationCore/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# `ngt::AnyBuffer`

`ngt::AnyBuffer` behaves like `std::any`, with two differences: it can only be
used with trivially copyable types, and provides access to the underlying memory
buffer to allow `memcpy`'ing its content.
74 changes: 74 additions & 0 deletions HeterogeneousCore/SerialisationCore/interface/AnyBuffer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#ifndef HeterogeneousCore_SerialisationCore_interface_AnyBuffer_h
#define HeterogeneousCore_SerialisationCore_interface_AnyBuffer_h

#include <type_traits>
#include <typeinfo>
#include <cstddef>

#include <boost/container/small_vector.hpp>

#include "FWCore/Utilities/interface/EDMException.h"
#include "FWCore/Utilities/interface/TypeDemangler.h"

namespace ngt {

class AnyBuffer {
public:
AnyBuffer() = default;

template <typename T>
AnyBuffer(T const& t)
requires(std::is_trivially_copyable_v<T>)
: storage_(reinterpret_cast<std::byte const*>(&t), reinterpret_cast<std::byte const*>(&t) + sizeof(T)),
typeid_(&typeid(std::remove_cv_t<T>)) {}

template <typename T>
T& cast_to()
requires(std::is_trivially_copyable_v<T>)
{
if (empty()) {
throw edm::Exception(edm::errors::LogicError)
<< "Attempt to read an object of type " << edm::typeDemangle(typeid(T).name())
<< " from an empty AnyBuffer";
}
if (typeid(std::remove_cv_t<T>) != *typeid_) {
throw edm::Exception(edm::errors::LogicError)
<< "Attempt to read an object of type " << edm::typeDemangle(typeid(T).name())
<< " from an AnyBuffer holding an object of type " << edm::typeDemangle(typeid_->name());
}
return *reinterpret_cast<T*>(storage_.data());
}

template <typename T>
T const& cast_to() const
requires(std::is_trivially_copyable_v<T>)
{
if (empty()) {
throw edm::Exception(edm::errors::LogicError)
<< "Attempt to read an object of type " << edm::typeDemangle(typeid(T).name())
<< " from an empty AnyBuffer";
}
if (typeid(std::remove_cv_t<T>) != *typeid_) {
throw edm::Exception(edm::errors::LogicError)
<< "Attempt to read an object of type " << edm::typeDemangle(typeid(T).name())
<< " from an AnyBuffer holding an object of type " << edm::typeDemangle(typeid_->name());
}
return *reinterpret_cast<T const*>(storage_.data());
}

bool empty() const { return typeid_ == nullptr; }

std::byte* data() { return storage_.data(); }

std::byte const* data() const { return storage_.data(); }

size_t size_bytes() const { return storage_.size(); }

private:
boost::container::small_vector<std::byte, 32> storage_; // small_vector size chosen to fit AnyBuffer in 64 bytes
std::type_info const* typeid_ = nullptr;
};

} // namespace ngt

#endif // HeterogeneousCore_SerialisationCore_interface_AnyBuffer_h