Skip to content
Merged
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
64 changes: 45 additions & 19 deletions include/openPMD/auxiliary/Memory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,13 @@

#include "openPMD/Dataset.hpp"
#include "openPMD/Datatype.hpp"
#include "openPMD/Error.hpp"
#include "openPMD/auxiliary/UniquePtr.hpp"

#include <complex>
#include <any>
#include <functional>
#include <iostream>
#include <memory>
#include <type_traits>
#include <utility>
#include <variant>

namespace openPMD
{
Expand All @@ -48,30 +46,58 @@ namespace auxiliary
*/
struct WriteBuffer
{
using EligibleTypes = std::
variant<std::shared_ptr<void const>, UniquePtrWithLambda<void>>;
EligibleTypes m_buffer;
/*
* Sic. Have to put the unique_ptr behind a shared_ptr because
* std::variant does not want non-copyable types.
* Use a separate class to avoid mistakes in double dereference.
*/
struct CopyableUniquePtr
: private std::shared_ptr<UniquePtrWithLambda<void>>
{
private:
using parent_t = std::shared_ptr<UniquePtrWithLambda<void>>;

WriteBuffer();
public:
CopyableUniquePtr();
CopyableUniquePtr(UniquePtrWithLambda<void> ptr_in);
auto get() -> void *;
[[nodiscard]] auto get() const -> void const *;
[[nodiscard]] auto release() -> UniquePtrWithLambda<void>;
};
using SharedPtr = std::shared_ptr<void const>;
/*
* Use std::any publically since some compilers have trouble with
* certain uses of std::variant, so hide it from them.
* Look into Memory_internal.hpp for the variant type.
* https://github.com/openPMD/openPMD-api/issues/1720
*/
std::any m_buffer;

template <typename... Args>
explicit WriteBuffer(Args &&...args)
: m_buffer(std::forward<Args>(args)...)
{}
WriteBuffer();
WriteBuffer(std::shared_ptr<void const> ptr);
WriteBuffer(UniquePtrWithLambda<void> ptr);

WriteBuffer(WriteBuffer &&) noexcept(
noexcept(EligibleTypes(std::declval<EligibleTypes &&>())));
WriteBuffer(WriteBuffer &&) noexcept;
WriteBuffer(WriteBuffer const &) = delete;
WriteBuffer &operator=(WriteBuffer &&) noexcept(noexcept(
std::declval<EligibleTypes &>() =
std::declval<EligibleTypes &&>()));
WriteBuffer &operator=(WriteBuffer &&) noexcept;
WriteBuffer &operator=(WriteBuffer const &) = delete;

WriteBuffer const &operator=(std::shared_ptr<void const> ptr);

WriteBuffer const &operator=(UniquePtrWithLambda<void const> ptr);
WriteBuffer const &operator=(UniquePtrWithLambda<void> ptr);

void const *get() const;

template <typename variant_t>
auto as_variant() -> variant_t &
{
return *std::any_cast<variant_t>(&m_buffer);
}

template <typename variant_t>
auto as_variant() const -> variant_t const &
{
return *std::any_cast<variant_t>(&m_buffer);
}
};
} // namespace auxiliary
} // namespace openPMD
30 changes: 30 additions & 0 deletions include/openPMD/auxiliary/Memory_internal.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/* Copyright 2025 Franz Poeschel
*
* This file is part of openPMD-api.
*
* openPMD-api is free software: you can redistribute it and/or modify
* it under the terms of of either the GNU General Public License or
* the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* openPMD-api is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License and the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* and the GNU Lesser General Public License along with openPMD-api.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once

#include "openPMD/auxiliary/Memory.hpp"

namespace openPMD::auxiliary
{
// cannot use a unique_ptr inside a std::variant, so we represent it with this
using WriteBufferTypes =
std::variant<WriteBuffer::CopyableUniquePtr, WriteBuffer::SharedPtr>;
} // namespace openPMD::auxiliary
15 changes: 0 additions & 15 deletions include/openPMD/openPMD.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,6 @@
namespace openPMD
{}

#if defined(CUDA_VERSION) && !defined(OPENPMD_SKIP_CHECK_ISSUE_1720)
static_assert(__cplusplus < 202002L || CUDA_VERSION >= 12040, R"(
Cannot use the openPMD-api in C++20 projects under a Cuda version lower
than 12.4.0 due to a bug in the implementation of std::variant.
Further information at:
https://github.com/openPMD/openPMD-api/issues/1720
https://forums.developer.nvidia.com/t/nvcc-c-20-std-variant-complie-failed/270162/5
This cannot be fixed on our side, please either upgrade to CUDA >= 12.4.0
or use C++17.
If you think that this assertion is shown wrongly, please apply
'#define OPENPMD_SKIP_CHECK_ISSUE_1720' before including
'<openPMD/openPMD.hpp>'.
)");
#endif

// IWYU pragma: begin_exports
#include "openPMD/Dataset.hpp"
#include "openPMD/Datatype.hpp"
Expand Down
17 changes: 5 additions & 12 deletions src/IO/ADIOS/ADIOS2File.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
#include "openPMD/IO/AbstractIOHandler.hpp"
#include "openPMD/IterationEncoding.hpp"
#include "openPMD/auxiliary/Environment.hpp"
#include "openPMD/auxiliary/Memory.hpp"
#include "openPMD/auxiliary/Memory_internal.hpp"
#include "openPMD/auxiliary/StringManip.hpp"

#include <cstdint>
Expand Down Expand Up @@ -114,22 +116,13 @@ void WriteDataset::call(ADIOS2File &ba, detail::BufferedPut &bp)
}
else if constexpr (std::is_same_v<
ptr_type,
UniquePtrWithLambda<void>>)
auxiliary::WriteBuffer::CopyableUniquePtr>)
{
BufferedUniquePtrPut bput;
bput.name = std::move(bp.name);
bput.offset = std::move(bp.param.offset);
bput.extent = std::move(bp.param.extent);
/*
* Note: Moving is required here since it's a unique_ptr.
* std::forward<>() would theoretically work, but it
* requires the type parameter and we don't have that
* inside the lambda.
* (ptr_type does not work for this case).
*/
// clang-format off
bput.data = std::move(arg); // NOLINT(bugprone-move-forwarding-reference)
// clang-format on
bput.data = arg.release();
bput.dtype = bp.param.dtype;
ba.m_uniquePtrPuts.push_back(std::move(bput));
}
Expand All @@ -139,7 +132,7 @@ void WriteDataset::call(ADIOS2File &ba, detail::BufferedPut &bp)
always_false_v<ptr_type>, "Unhandled std::variant branch");
}
},
bp.param.data.m_buffer);
bp.param.data.as_variant<auxiliary::WriteBufferTypes>());
}

template <int n, typename... Params>
Expand Down
60 changes: 49 additions & 11 deletions src/auxiliary/Memory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@
*/

#include "openPMD/auxiliary/Memory.hpp"
#include "openPMD/ChunkInfo.hpp"
#include "openPMD/auxiliary/Memory_internal.hpp"
#include "openPMD/auxiliary/UniquePtr.hpp"

#include <any>
#include <complex>
#include <functional>
#include <iostream>
Expand Down Expand Up @@ -157,24 +161,58 @@ allocatePtr(Datatype dtype, Extent const &e)
return allocatePtr(dtype, numPoints);
}

WriteBuffer::WriteBuffer() : m_buffer(UniquePtrWithLambda<void>())
WriteBuffer::CopyableUniquePtr::CopyableUniquePtr() = default;

WriteBuffer::CopyableUniquePtr::CopyableUniquePtr(
UniquePtrWithLambda<void> ptr_in)
: parent_t{std::make_shared<UniquePtrWithLambda<void>>(std::move(ptr_in))}
{}

WriteBuffer::WriteBuffer(WriteBuffer &&) noexcept(
noexcept(EligibleTypes(std::declval<EligibleTypes &&>()))) = default;
WriteBuffer &WriteBuffer::operator=(WriteBuffer &&) noexcept(noexcept(
std::declval<EligibleTypes &>() = std::declval<EligibleTypes &&>())) =
default;
auto WriteBuffer::CopyableUniquePtr::get() -> void *
{
return (**this).get();
}

auto WriteBuffer::CopyableUniquePtr::get() const -> void const *
{
return (**this).get();
}

auto WriteBuffer::CopyableUniquePtr::release() -> UniquePtrWithLambda<void>
{
if (parent_t::use_count() > 1)
{
throw error::Internal(
"Control flow error: UniquePtr variant of WriteBuffer "
"has been copied.");
}
UniquePtrWithLambda<void> res = std::move(**this);
this->reset();
return res;
}

WriteBuffer::WriteBuffer() : m_buffer(std::make_any<CopyableUniquePtr>())
{}
WriteBuffer::WriteBuffer(std::shared_ptr<void const> ptr)
: m_buffer(std::make_any<WriteBufferTypes>(std::move(ptr)))
{}
WriteBuffer::WriteBuffer(UniquePtrWithLambda<void> ptr)
: m_buffer(
std::make_any<WriteBufferTypes>(CopyableUniquePtr(std::move(ptr))))
{}

WriteBuffer::WriteBuffer(WriteBuffer &&) noexcept = default;
WriteBuffer &WriteBuffer::operator=(WriteBuffer &&) noexcept = default;

WriteBuffer const &WriteBuffer::operator=(std::shared_ptr<void const> ptr)
{
m_buffer = std::move(ptr);
m_buffer = std::make_any<WriteBufferTypes>(std::move(ptr));
return *this;
}

WriteBuffer const &WriteBuffer::operator=(UniquePtrWithLambda<void const> ptr)
WriteBuffer const &WriteBuffer::operator=(UniquePtrWithLambda<void> ptr)
{
m_buffer = std::move(ptr);
m_buffer =
std::make_any<WriteBufferTypes>(CopyableUniquePtr(std::move(ptr)));
return *this;
}

Expand All @@ -186,6 +224,6 @@ void const *WriteBuffer::get() const
// we're being sneaky and don't distinguish the types here
return static_cast<void const *>(arg.get());
},
m_buffer);
as_variant<WriteBufferTypes>());
}
} // namespace openPMD::auxiliary
4 changes: 2 additions & 2 deletions test/CoreTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

#include "openPMD/IO/ADIOS/macros.hpp"
#include "openPMD/auxiliary/Filesystem.hpp"
#include "openPMD/auxiliary/JSON.hpp"
#include "openPMD/auxiliary/Memory_internal.hpp"
#include "openPMD/auxiliary/UniquePtr.hpp"

#include <catch2/catch.hpp>
Expand Down Expand Up @@ -1252,7 +1252,7 @@ TEST_CASE("use_count_test", "[core]")
std::get<std::shared_ptr<void const>>(
static_cast<Parameter<Operation::WRITE_DATASET> *>(
pprc.get().m_chunks.front().parameter.get())
->data.m_buffer)
->data.as_variant<auxiliary::WriteBufferTypes>())
.use_count() == 1);
#endif
}
Expand Down
Loading