diff --git a/HeterogeneousCore/SerialisationCore/README.md b/HeterogeneousCore/SerialisationCore/README.md new file mode 100644 index 0000000000000..dacbe8e565b20 --- /dev/null +++ b/HeterogeneousCore/SerialisationCore/README.md @@ -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. diff --git a/HeterogeneousCore/SerialisationCore/interface/AnyBuffer.h b/HeterogeneousCore/SerialisationCore/interface/AnyBuffer.h new file mode 100644 index 0000000000000..6bf17fac22203 --- /dev/null +++ b/HeterogeneousCore/SerialisationCore/interface/AnyBuffer.h @@ -0,0 +1,74 @@ +#ifndef HeterogeneousCore_SerialisationCore_interface_AnyBuffer_h +#define HeterogeneousCore_SerialisationCore_interface_AnyBuffer_h + +#include +#include +#include + +#include + +#include "FWCore/Utilities/interface/EDMException.h" +#include "FWCore/Utilities/interface/TypeDemangler.h" + +namespace ngt { + + class AnyBuffer { + public: + AnyBuffer() = default; + + template + AnyBuffer(T const& t) + requires(std::is_trivially_copyable_v) + : storage_(reinterpret_cast(&t), reinterpret_cast(&t) + sizeof(T)), + typeid_(&typeid(std::remove_cv_t)) {} + + template + T& cast_to() + requires(std::is_trivially_copyable_v) + { + 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) != *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(storage_.data()); + } + + template + T const& cast_to() const + requires(std::is_trivially_copyable_v) + { + 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) != *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(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 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