Customization points¶
KaMPIng-v2 finds the MPI properties of a buffer, and the native handle of an MPI object, through a small set of accessor functions. Each one is looked up in three steps: a traits specialization, for types you don’t own; a member function, for types you control; and a fallback for standard ranges and native MPI handles. See Data buffers and MPI objects.
The traits and concepts are defined in mpi-core, in mpi::experimental, and re-exported in kamping::v2.
Specialize the traits in mpi::experimental.
Buffers¶
-
template<typename T>
struct buffer_traits¶ Trait class for non-intrusive MPI buffer customization (see the file documentation for an example). Only implement the members you need (
count,ptr,type,counts,displs); the remaining accessors fall back to thempi_count()/mpi_ptr()/mpi_type()/mpi_counts()/mpi_displs()member functions.Defined in header
<mpi/buffer.hpp>
-
template<typename T>
requires detail::traits_has_count<std::remove_cvref_t<T>>
auto count(T &&t)¶
(1) -
template<typename T>
requires (!detail::traits_has_count<std::remove_cvref_t<T>>) && detail::has_count_member<T>
auto count(T &&t)¶
(2) -
template<typename T>
requires (!detail::traits_has_count<std::remove_cvref_t<T>>) && (!detail::has_count_member<T>) && std::ranges::sized_range<T>
auto count(T &&t)¶
(3) - Returns:
(1) The number of elements of the buffer
t, obtained viabuffer_traits<T>::count(t).(2) The number of elements of the buffer
t, obtained viat.mpi_count().(3) The number of elements of the sized range
t,std::ranges::size(t).
Defined in header
<kamping/v2/buffer.hpp>
-
template<typename T>
requires (detail::traits_has_const_ptr<std::remove_cvref_t<T>> || detail::traits_has_ptr<std::remove_cvref_t<T>>)
auto ptr(T &&t)¶
(1) -
template<typename T>
requires (!detail::traits_has_const_ptr<std::remove_cvref_t<T>>) && (!detail::traits_has_ptr<std::remove_cvref_t<T>>) && detail::has_ptr_member<T>
auto ptr(T &&t)¶
(2) -
template<typename T>
requires (!detail::traits_has_const_ptr<std::remove_cvref_t<T>>) && (!detail::traits_has_ptr<std::remove_cvref_t<T>>) && (!detail::has_ptr_member<T>) && std::ranges::contiguous_range<T>
auto ptr(T &&t)¶
(3) - Returns:
(1) The data pointer of the buffer
t, obtained viabuffer_traits<T>::ptr(t); points to const for a buffer only usable for sending.(2) The data pointer of the buffer
t, obtained viat.mpi_ptr().(3) The data pointer of the contiguous range
t,std::ranges::data(t).
Defined in header
<kamping/v2/buffer.hpp>
-
template<typename T>
requires detail::traits_has_type<std::remove_cvref_t<T>>
auto type(T &&t)¶
(1) -
template<typename T>
requires (!detail::traits_has_type<std::remove_cvref_t<T>>) && detail::has_type_member<T>
auto type(T &&t)¶
(2) -
template<typename T>
requires (!detail::traits_has_type<std::remove_cvref_t<T>>) && (!detail::has_type_member<T>) && detail::range_of_builtin_mpi_type<T>
auto type(T&&)¶
(3) - Returns:
(1) The MPI datatype of the elements of the buffer
t, obtained viabuffer_traits<T>::type(t).(2) The MPI datatype of the elements of the buffer
t, obtained viat.mpi_type().(3) The builtin MPI datatype of the element type of the range
t, e.g.MPI_INTforint.
Defined in header
<kamping/v2/buffer.hpp>
-
template<typename T>
requires detail::traits_has_counts<std::remove_cvref_t<T>>
decltype(auto) counts(T &&t)¶
(1) -
template<typename T>
requires (!detail::traits_has_counts<std::remove_cvref_t<T>>) && detail::has_counts_member<T>
decltype(auto) counts(T &&t)¶
(2) - Returns:
(1) The per-rank counts of the variadic buffer
t, obtained viabuffer_traits<T>::counts(t).(2) The per-rank counts of the variadic buffer
t, obtained viat.mpi_counts().
Defined in header
<kamping/v2/buffer.hpp>
-
template<typename T>
requires detail::traits_has_displs<std::remove_cvref_t<T>>
decltype(auto) displs(T &&t)¶
(1) -
template<typename T>
requires (!detail::traits_has_displs<std::remove_cvref_t<T>>) && detail::has_displs_member<T>
decltype(auto) displs(T &&t)¶
(2) - Returns:
(1) The per-rank displacements of the variadic buffer
t, obtained viabuffer_traits<T>::displs(t).(2) The per-rank displacements of the variadic buffer
t, obtained viat.mpi_displs().
Defined in header
<kamping/v2/buffer.hpp>
-
template<has_mpi_resize_for_receive T>
void resize_for_receive(T &t, std::ptrdiff_t n)¶
(1) -
template<typename T>
requires (!has_mpi_resize_for_receive<T>) && has_resize<T>
void resize_for_receive(T &t, std::ptrdiff_t n)¶
(2) (1) Resize t to hold n MPI elements before a receive. Dispatches to:
t.mpi_resize_for_receive(n) — custom protocol (e.g. resize_and_overwrite, NUMA alloc)
t.resize(n) — standard containers
Contract. The elements [0, min(old size, n)) keep their values; new elements are unspecified (they may be left uninitialized, which is what custom protocols are for). Like a receive, which only writes the range it has data for, a resize only touches what it has to. This allows growing a buffer that already holds received data, e.g. to receive further messages behind it. std::vector::resize, std::string::resize_and_overwrite and Kokkos::resize all behave this way.
(2) Resizes the standard container
ttonelements before a receive; see the overload above for the contract.Defined in header
<kamping/v2/views/view_interface.hpp>
-
bool enable_borrowed_buffer¶
Opt-in trait for non-owning buffer types, mirroring std::ranges::enable_borrowed_range.
A “borrowed” buffer does not own its data: the underlying memory is managed externally and outlives the buffer object. Non-blocking operations use this to decide whether the buffer has to be handed back on completion (see iresult). The default covers any std::ranges::borrowed_range (e.g. std::span); kamping views propagate borrowedness from their base.
template <> inline constexpr bool kamping::v2::enable_borrowed_buffer<MyView> = true;
Defined in header
<kamping/v2/views/concepts.hpp>
-
template<typename T>
concept borrowed_buffer¶ template<typename T> concept borrowed_buffer = enable_borrowed_buffer<std::remove_cvref_t<T>>
A buffer that does not own its data; see
enable_borrowed_buffer.Defined in header
<kamping/v2/views/concepts.hpp>
MPI objects¶
-
template<typename T>
struct handle_traits¶ Trait class for non-intrusive MPI handle customization of types you don’t own.
Only implement the members you need; unimplemented members fall back to the
mpi_handle()/mpi_handle_ptr()member functions.template <> struct mpi::experimental::handle_traits<MyComm> { static MPI_Comm handle(MyComm const& c) { return c.get_comm(); } static MPI_Comm* handle_ptr(MyComm& c) { return c.get_comm_ptr(); } };
Defined in header
<mpi/handle.hpp>
-
template<typename T>
requires detail::handle_traits_has_handle<std::remove_cvref_t<T>>
auto handle(T const &t)¶
(1) -
template<typename T>
requires (!detail::handle_traits_has_handle<std::remove_cvref_t<T>>) && detail::has_mpi_handle_member<T>
auto handle(T const &t)¶
(2) -
template<builtin_handle T>
T handle(T t) noexcept¶
(3) - Returns:
(1) The MPI handle of
t, obtained viahandle_traits<T>::handle(t).(2) The MPI handle of
t, obtained viat.mpi_handle().(3)
titself, for a raw MPI handle.
Defined in header
<kamping/v2/handle.hpp>
-
template<typename T>
requires detail::handle_traits_has_handle_ptr<std::remove_cvref_t<T>>
auto handle_ptr(T &t)¶
(1) -
template<typename T>
requires (!detail::handle_traits_has_handle_ptr<std::remove_cvref_t<T>>) && detail::has_mpi_handle_ptr_member<T>
auto handle_ptr(T &t)¶
(2) -
template<builtin_handle T>
T *handle_ptr(T &t) noexcept¶
(3) -
template<builtin_handle T>
T *handle_ptr(T *t) noexcept¶
(4) - Returns:
(1) A pointer to the MPI handle of
tthat MPI can write into, obtained viahandle_traits<T>::handle_ptr(t).(2) A pointer to the MPI handle of
tthat MPI can write into, obtained viat.mpi_handle_ptr().(3) The address of the raw MPI handle
t.(4)
titself, for a pointer to a raw MPI handle (e.g.MPI_STATUS_IGNORE).
Defined in header
<kamping/v2/handle.hpp>
-
template<typename T, typename HandleType>
concept convertible_to_mpi_handle¶ template<typename T, typename HandleType> concept convertible_to_mpi_handle = builtin_handle<HandleType> && requires(T const& t) { { handle(t) } -> std::same_as<HandleType>; }
A type from which
handle()extracts an MPI handle of typeHandleType.Defined in header
<kamping/v2/handle.hpp>
-
template<typename T, typename HandleType>
concept convertible_to_mpi_handle_ptr¶ template<typename T, typename HandleType> concept convertible_to_mpi_handle_ptr = builtin_handle<HandleType> && requires(T& t) { { handle_ptr(t) } -> std::same_as<HandleType*>; }
A type from which
handle_ptr()extracts a writable pointer to an MPI handle of typeHandleType.Defined in header
<kamping/v2/handle.hpp>
Arrays of handles¶
-
template<typename T>
struct handle_range_traits¶ Trait class for non-intrusively exposing the contiguous handle storage of a type you don’t own. Specialize with
static <contiguous_handle_range> handle_range(T& t); return a reference or a borrowed view (e.g. std::span) intot, never a copy.Defined in header
<mpi/handle.hpp>
-
template<typename T>
requires detail::handle_range_traits_has_handle_range<std::remove_cvref_t<T>>
decltype(auto) handle_range(T &&t)¶
(1) -
template<typename T>
requires (!detail::handle_range_traits_has_handle_range<std::remove_cvref_t<T>>) && detail::has_mpi_handle_range_member<T>
decltype(auto) handle_range(T &&t)¶
(2) -
template<typename T>
requires (!detail::handle_range_traits_has_handle_range<std::remove_cvref_t<T>>) && (!detail::has_mpi_handle_range_member<T>) && contiguous_handle_range<T>
T &handle_range(T &t) noexcept¶
(3) - Returns:
(1) The contiguous handle storage of
t, obtained viahandle_range_traits<T>::handle_range(t).(2) The contiguous handle storage of
t, obtained viat.mpi_handle_range().(3)
titself, for an lvalue contiguous range of raw MPI handles.
Defined in header
<kamping/v2/handle.hpp>
-
template<typename T, typename HandleType>
concept convertible_to_mpi_handle_range¶ template<typename T, typename HandleType> concept convertible_to_mpi_handle_range = builtin_handle<HandleType> && requires(T& t) { { handle_range(t) } -> contiguous_handle_range_of<HandleType>; }
A type whose handle_range() is a writable, contiguous range of
HandleTypethat refers to the caller’s storage: either an lvalue reference or a borrowed view (never a container returned by value, since MPI writes into it).Defined in header
<kamping/v2/handle.hpp>
Writing your own views¶
A view wraps a buffer, forwards the accessors it does not override and overrides the others as members. Derive from
view_interface to get the forwarding, and use adaptor or adaptor_closure to make it pipeable.
-
template<typename Derived>
struct view_interface¶ CRTP base of all kamping views.
Derivedimplementsbase(), returning the wrapped buffer.view_interfaceforwards the range interface and every member of the buffer protocol (mpi_ptr(),mpi_count(),mpi_type(),mpi_counts(), …) and of the deferred buffer protocols (set_recv_count(),set_comm_size(),commit_counts(),materialize()) to it, so a view only implements the members it changes. A forwarder only exists if the wrapped buffer provides the member.Defined in header
<kamping/v2/views/view_interface.hpp>-
template<typename Self = Derived>
requires has_materialize<decltype(std::declval<Self&>().base())>
void materialize()¶ Forwards eager realization to the wrapped base, so a deferred resizing view (
resize_view/resize_v_view) can still be materialized when nested inside other view layers. Use the free functionkamping::v2::materialize()rather than calling this directly.
-
template<typename Self = Derived>
requires deferred_recv_buf<std::remove_cvref_t<decltype(std::declval<Self&>().base())>>
void set_recv_count(std::ptrdiff_t n)¶ Forwards the single-count deferred protocol (set_recv_count) so a
resize_viewnested inside other view layers stays adeferred_recv_buf.
-
auto &underlying() &¶
(1) -
auto const &underlying() const &¶
(2) -
auto underlying() &&¶
(3) (1) Returns the container (or other buffer) at the bottom of a chain of views, e.g. the
std::vectorinstd::vector<int>{} | views::resize.Use it to get your container back from the result of an operation. On an rvalue, the container is moved out; on an lvalue, a reference to it is returned:
std::vector<int> data = kamping::v2::recv(std::vector<int>{} | views::resize, source, comm).underlying(); auto [_, recv] = kamping::v2::allgatherv(local, kamping::v2::auto_recv_v<int>(), comm); std::vector<int>& all = recv.underlying();
(2) Like the overload above, for a
constview.(3) Like the overload above, for an rvalue view: moves the container out, without copying it.
-
template<typename Self = Derived>
-
template<typename T>
concept view¶ template<typename T> concept view = std::ranges::view<T> || std::derived_from<T, view_interface_base>
A type that is a “view” in the kamping sense: either a std::ranges::view (lightweight, copyable, e.g. std::span) or a kamping view (derived from view_interface_base — may be owning and non-copyable like owning_view). Mirrors the role of the std::ranges::view concept but extended for kamping.
Defined in header
<kamping/v2/views/view_interface.hpp>
-
template<typename R>
auto all(R &&r)¶ Wraps a value in the appropriate view, mirroring std::views::all extended for kamping:
std::ranges::view (span, string_view, …) → copy/move through; no extra wrapping to avoid libc++ constraint circularity bugs with these types.
kamping view (derived from
view_interface_base, may be owning/non-copyable): lvalue →ref_view(borrow), rvalue → move through (no wrapping needed).any other lvalue →
ref_viewany other rvalue →
owning_view
Defined in header
<kamping/v2/views/all.hpp>
-
template<typename T>
class ref_view¶ Non-owning view over an lvalue. T is unconstrained — supports both ranges and non-range buffer types (e.g. a struct with mpi_ptr()/mpi_count() but no begin()/end()). All MPI protocol methods (mpi_ptr, mpi_count, mpi_type, mpi_resize_for_receive, …) are forwarded automatically via
view_interface.Defined in header
<kamping/v2/views/all.hpp>
-
template<std::movable T>
class owning_view¶ Owning view over an rvalue. Moves the object in and owns it. Same protocol forwarding as
ref_viewviaview_interface.Defined in header
<kamping/v2/views/all.hpp>
-
template<std::size_t ExtraArgs, typename Fn>
struct adaptor¶ Generic range adaptor factory, parameterized by the number of extra arguments (beyond the value). Arity-based disambiguation (like libstdc++ internally):
ExtraArgs arguments → partial application, returns a pipeable
partial_adaptorExtraArgs + 1 arguments → full call, first argument is the value
Usage: inline constexpr adaptor<1, decltype([](auto&& r, MPI_Datatype t) { … })> with_type{}; vec | with_type(MPI_INT) // partial →
partial_adaptor→ pipe applies it with_type(vec, MPI_INT) // full callDefined in header
<kamping/v2/views/adaptor.hpp>
-
template<typename Derived>
struct adaptor_closure¶ CRTP base that makes Derived pipe-able. Provides two operator| overloads found via ADL:
val | closure → closure(val) when val is NOT itself a closure
closure1 | closure2 →
composed_closure{…} when both sides are closures The !is_adaptor_closure constraint on the left side is intentionally the only constraint, so any value type (range, MPI buffer, scalar, …) can appear on the left side of |.
Defined in header
<kamping/v2/views/adaptor.hpp>
-
template<typename Derived>
struct adaptor_factory¶ CRTP base of an adaptor that takes optional arguments, such as
views::auto_counts: calling it returns a closure (auto_counts(),auto_counts(counts)), and the factory itself stands for its argument-less closure in a pipe, sobuf | auto_countsisbuf | auto_counts().Derivedmust be callable without arguments.A factory cannot simply be a closure applying itself to a buffer, since a one-argument call already means something else (e.g.
auto_counts(counts)passes the counts storage).Defined in header
<kamping/v2/views/adaptor.hpp>