Skip to content

Commit

Permalink
Add RecordComponent::visit
Browse files Browse the repository at this point in the history
  • Loading branch information
franzpoeschel committed Oct 20, 2023
1 parent 1248a43 commit 42fd638
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 0 deletions.
65 changes: 65 additions & 0 deletions include/openPMD/RecordComponent.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <stdexcept>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>

// expose private and protected members for invasive testing
Expand Down Expand Up @@ -97,6 +98,29 @@ namespace internal
};
} // namespace internal

class RecordComponent;

namespace detail
{
template <typename Functor, typename Res>
struct VisitRecordComponent
{
template <typename T, typename... Args>
static Res call(RecordComponent &rc, Args &&...args)
{
return Functor::template call<T>(rc, std::forward<Args>(args)...);
}

template <int = 0, typename... Args>
static Res call(Args &&...)
{
throw std::runtime_error(
"[RecordComponent::visit()] Unknown datatype in "
"RecordComponent");
}
};
} // namespace detail

class RecordComponent : public BaseRecordComponent
{
template <typename T, typename T_key, typename T_container>
Expand Down Expand Up @@ -404,6 +428,47 @@ class RecordComponent : public BaseRecordComponent
template <typename T>
DynamicMemoryView<T> storeChunk(Offset, Extent);

/**
* @brief Run a template functor on the type of the record component,
* similar to std::visit().
*
* Note that unlike std::visit(), this template cannot "switch" over
* a single existing value, meaning that the interface needs to work
* a bit different.
* The functor is given as a struct/class with a call() operation.
*
* (Ideally, this can be harmonized by using template lambdas once we
* support C++20)
*
* @tparam Visitor A struct type that has a static template method:
* Visitor::template call<T>(RecordComponent &, ...)
* In here, T will be instantiated with this RecordComponent's type
* and a reference to this RecordComponent will be passed as first
* argument.
*
* @tparam Args Types of optional further arguments.
* @param args Optional further arguments that will be forwarded to
* Visitor::template call()
* @return Whatever Visitor::template call() returned.
* Take special note that the return types must match (i.e. cannot
* be different across instantiations
* of T for Visitor::template call<T>()).
* Formally, the return type is that of
* Visitor::template call<char>(RecordComponent &, Args&&...)
* and returned values from other template instantiations might then
* be implicitly converted.
*/
template <typename Visitor, typename... Args>
constexpr auto visit(Args &&...args)
-> decltype(Visitor::template call<char>(
std::declval<RecordComponent &>(), std::forward<Args>(args)...))
{
using Res = decltype(Visitor::template call<char>(
std::declval<RecordComponent &>(), std::forward<Args>(args)...));
return switchNonVectorType<detail::VisitRecordComponent<Visitor, Res>>(
getDatatype(), *this, std::forward<Args>(args)...);
}

static constexpr char const *const SCALAR = "\vScalar";

private:
Expand Down
15 changes: 15 additions & 0 deletions test/SerialIOTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1525,6 +1525,15 @@ TEST_CASE("dtype_test", "[serial]")
}
}

struct ReadFromAnyType
{
template <typename T>
static std::shared_ptr<void> call(RecordComponent &rc)
{
return std::static_pointer_cast<void>(rc.loadChunk<T>());
}
};

inline void write_test(const std::string &backend)
{
Series o = Series("../samples/serial_write." + backend, Access::CREATE);
Expand Down Expand Up @@ -1623,6 +1632,12 @@ inline void write_test(const std::string &backend)
}

o.flush();

o.close();

Series read("../samples/serial_write." + backend, Access::READ_ONLY);
auto rc = read.iterations[1].particles["e"]["position"]["x"];
auto opaqueTypeDataset = rc.visit<ReadFromAnyType>();
}

TEST_CASE("write_test", "[serial]")
Expand Down

0 comments on commit 42fd638

Please sign in to comment.