diff --git a/include/mpi_support.h b/include/mpi_support.h index fedb1b453..a1d900581 100644 --- a/include/mpi_support.h +++ b/include/mpi_support.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -104,15 +105,40 @@ class unique_payload_ptr : private std::unique_ptr - explicit unique_payload_ptr(allocate_uninitialized_tag, size_t count) : impl(operator new(count * sizeof(T)), [](void* p) { operator delete(p); }) {} + explicit unique_payload_ptr(allocate_uninitialized_tag, size_t count) : impl(allocate_uninitialized_payload(count)) {} template - explicit unique_payload_ptr(unique_frame_ptr frame) : impl(frame.release() + 1, [](void* p) { delete(static_cast(p) - 1); }) {} + explicit unique_payload_ptr(unique_frame_ptr frame) : impl(unique_frame_to_payload(std::move(frame))) {} void* get_pointer() { return impl::get(); } const void* get_pointer() const { return impl::get(); } using impl::operator bool; + + private: + template + static void delete_frame_from_payload(void* const type_erased_payload) { + const auto payload = static_cast(type_erased_payload); + const auto frame = reinterpret_cast(payload) - 1; // frame header is located at -sizeof(Frame) bytes (-1 Frame object) + delete frame; + } + + template + static impl unique_frame_to_payload(unique_frame_ptr unique_frame) { + deleter_type deleter{delete_frame_from_payload}; // allocate deleter (aka std::function) first so `impl` construction is noexcept + const auto frame = unique_frame.release(); + const auto payload = reinterpret_cast(frame + 1); // payload is located at +sizeof(Frame) bytes (+1 Frame object) + return impl{payload, std::move(deleter)}; + } + + static void delete_uninitialized_payload(void* const p) { operator delete(p); } + + template + static impl allocate_uninitialized_payload(size_t count) { + deleter_type deleter{delete_uninitialized_payload}; // allocate deleter (aka std::function) first so `impl` construction is noexcept + const auto payload = operator new(count * sizeof(T)); + return impl{payload, std::move(deleter)}; + } }; } // namespace celerity::detail