Views

All views live in kamping::v2::views and compose with |. Each one can be called with the buffer as the first argument or applied with |, like a std::ranges adaptor: views::with_counts(buf, counts) is the same as buf | views::with_counts(counts). Views without arguments, such as views::resize, are applied without parentheses. Buffers passed as lvalues are borrowed, rvalues are moved into the view.

Views are lazy: composing them allocates and computes nothing, and their metadata is computed on first access.

Getting the container back

Operations return the buffers they were given, so a buffer passed through views comes back as a view. Every view has underlying(), which returns the container at the bottom of the chain: moved out of an rvalue, by reference from an lvalue.

std::vector<int> data = v2::recv(std::vector<int>{} | views::resize, source, comm).underlying();

auto [_, recv] = v2::allgatherv(local, v2::auto_recv_v<int>(), comm);
std::vector<int>& all = recv.underlying();

Attaching metadata

auto with_type(MPI_Datatype type)
template<typename Buf>
auto with_type(Buf &&buf, MPI_Datatype type)

Overrides the MPI datatype: buf | views::with_type(dt).

Defined in header <kamping/v2/views/with_type_view.hpp>

auto with_count(std::ptrdiff_t count)
template<typename Buf>
auto with_count(Buf &&buf, std::ptrdiff_t count)

Overrides the element count: buf | views::with_count(n).

Useful for non-range objects that expose mpi_ptr() but no size — compose with with_type to build a complete data_buffer. For limiting the element count of a range, prefer std::views::take.

Defined in header <kamping/v2/views/with_count_view.hpp>

template<count_range Counts>
auto with_counts(Counts &&counts)
template<typename Buf, count_range Counts>
auto with_counts(Buf &&buf, Counts &&counts)

Attaches per-rank counts: buf | views::with_counts(counts). The counts are borrowed if passed as lvalue.

Defined in header <kamping/v2/views/with_counts_view.hpp>

Example:

std::vector<int> data = ..., counts = ...;
auto send = data | views::with_counts(counts) | views::auto_displs;
v2::alltoallv(send, v2::auto_recv_v<int>(), comm);
template<count_range Displs>
auto with_displs(Displs &&displs)
template<typename Buf, count_range Displs>
auto with_displs(Buf &&buf, Displs &&displs)
template<count_range Displs>
auto with_displs(monotonic_t, Displs &&displs)
template<typename Buf, count_range Displs>
auto with_displs(monotonic_t, Buf &&buf, Displs &&displs)

Attaches per-rank displacements: buf | views::with_displs(displs), or buf | views::with_displs(monotonic, displs) to declare them monotonically non-decreasing. The displacements are borrowed if passed as lvalue.

Monotonic displacements let views::resize_v size the receive buffer in O(1), from the last displacement and count, instead of scanning all of them.

Defined in header <kamping/v2/views/with_displs_view.hpp>

auto auto_displs()
template<count_range Displs>
auto auto_displs(Displs &&displs)
template<typename Buf, count_range Displs>
auto auto_displs(Buf &&buf, Displs &&displs)
template<count_range Displs>
auto auto_displs(resize_t, Displs &&displs)
template<typename Buf, count_range Displs>
auto auto_displs(resize_t, Buf &&buf, Displs &&displs)

Attaches displacements computed from the buffer’s counts (exclusive prefix sum), lazily on first access:

  • buf | auto_displs or buf | auto_displs(): stored in an owned std::vector<int>, resized as needed;

  • buf | auto_displs(displs) or auto_displs(buf, displs): in the caller-provided displs, which must already be large enough;

  • buf | auto_displs(resize, displs) or auto_displs(resize, buf, displs): in the caller-provided displs, resized as needed.

Defined in header <kamping/v2/views/auto_displs_view.hpp>

auto with_value_type(MPI_Datatype type)
template<typename Buf>
auto with_value_type(Buf &&buf, MPI_Datatype type)

Sets the MPI datatype of the payload of a structured buffer: buf | views::with_value_type(dt).

Defined in header <kamping/v2/views/with_value_type_view.hpp>

Receive buffers that size themselves

template<typename Buf>
auto resize(Buf &&buf)

Resizes the wrapped container to fit the incoming data before receiving: buf | views::resize.

The operation determines the receive count (for point-to-point receives by probing the message) and passes it to set_recv_count(n); the container is resized on first access to its data. Existing elements are kept. Takes no arguments, so it is applied without parentheses. Place it last in a pipeline: buf | views::with_type(t) | views::resize.

Defined in header <kamping/v2/views/resize_view.hpp>

auto auto_counts()
template<count_range Counts>
auto auto_counts(Counts &&counts)
template<count_range Counts>
auto auto_counts(resize_t, Counts &&counts)

Attaches deferred per-rank counts, which the operation exchanges (see infer()):

  • buf | auto_counts or buf | auto_counts(): the counts are stored in an owned std::vector<int>, resized to the communicator size;

  • buf | auto_counts(counts): in the caller-provided counts, which must already have one entry per rank;

  • buf | auto_counts(resize, counts): in the caller-provided counts, resized to the communicator size.

Defined in header <kamping/v2/views/auto_counts_view.hpp>

template<typename Buf>
auto resize_v(Buf &&buf)

Resizes a variable-size receive buffer to fit its counts and displacements before receiving: buf | views::auto_counts | views::auto_displs | views::resize_v.

The buffer must already provide per-rank counts and displacements, e.g. via auto_counts | auto_displs or with_counts | with_displs. The container is resized on first access to its data, once the counts are known; with monotonic displacements in O(1). Takes no arguments, so it is applied without parentheses.

Defined in header <kamping/v2/views/resize_v_view.hpp>

template<typename Buf>
auto auto_recv_v(Buf &&buf)

Makes a variable-size receive buffer that sizes itself: buf | views::auto_recv_v is shorthand for buf | views::auto_counts | views::auto_displs | views::resize_v.

The operation exchanges the per-rank counts, the displacements are computed from them, and the container is resized to fit before receiving. For a fresh, owned buffer use the factory kamping::v2::auto_recv_v<T>().

Defined in header <kamping/v2/views/auto_recv_v.hpp>

template<typename T, typename Cont = std::vector<T>>
auto auto_recv_v()
(1)
template<typename T, typename Cont = std::vector<T>>
auto auto_recv_v(type_pool &pool)
(2)
template<typename T, typename Cont = std::vector<T>, typename Env>
requires has_pool<std::remove_cvref_t<Env>>
auto auto_recv_v(Env &&env)
(3)

(1) Convenience factory for a fully-managed variadic receive buffer.

Returns an owned Cont wrapped in views::auto_recv_v, which provides automatic per-rank count exchange, displacement computation, and buffer resizing.

v2::allgatherv(send_data, v2::auto_recv_v<int>(), comm); v2::alltoallv(sbuf, v2::auto_recv_v<float>(), comm);

The default container is std::vector<T>. Substitute a different container type as the second argument when needed.

(2) Convenience factory for a fully-managed variadic receive buffer with automatic type registration.

Like the zero-argument overload but additionally attaches the MPI datatype for T by calling pool.register_type<T>(), making it suitable for non-builtin types.

v2::allgatherv(send_data, v2::auto_recv_v<MyStruct>(pool), comm);

(3) Convenience factory accepting a comm_view_with_pool instead of a bare pool.

Equivalent to auto_recv_v<T>(env.pool()).

v2::alltoallv(sbuf, v2::auto_recv_v<MyStruct>(comm), comm);

Template parameters:
  • T – Element type satisfying has_static_type_v.

  • Cont – Container type (must support resize(n) and data()).

Parameters:
  • pool – Type pool used to commit and cache the MPI datatype for T.

  • env – Pooled communicator view; the pool is used to commit and cache the MPI datatype for T.

Defined in header <kamping/v2/views/auto_recv_v.hpp>

template<typename T, typename Cont = std::vector<T>>
auto auto_recv()
(1)
template<typename T, typename Cont = std::vector<T>>
auto auto_recv(type_pool &pool)
(2)
template<typename T, typename Cont = std::vector<T>, typename Env>
requires has_pool<std::remove_cvref_t<Env>>
auto auto_recv(Env &&env)
(3)

(1) Convenience factory for a fully-managed non-variadic receive buffer.

Returns an owned Cont wrapped in views::resize, which defers the actual resize until the collective has inferred the receive count via infer().

v2::recv(v2::auto_recv<int>(), 0, comm);

The default container is std::vector<T>. Pass a different container type as the second template argument when needed.

(2) Convenience factory for a fully-managed non-variadic receive buffer with automatic type registration.

Like the zero-argument overload but additionally attaches the MPI datatype for T by calling pool.register_type<T>(), making it suitable for non-builtin types.

v2::recv(v2::auto_recv<MyStruct>(pool), 0, comm);

(3) Convenience factory accepting a comm_view_with_pool instead of a bare pool.

Equivalent to auto_recv<T>(env.pool()).

v2::recv(v2::auto_recv<MyStruct>(comm), 0, comm);

Template parameters:
  • T – Element type.

  • Cont – Container type (must support resize(n) and data()).

Parameters:
  • pool – Type pool used to commit and cache the MPI datatype for T.

  • env – Pooled communicator view; the pool is used to commit and cache the MPI datatype for T.

Defined in header <kamping/v2/views/auto_recv.hpp>

Datatypes from a type pool

See Derived datatypes.

auto with_pool(type_pool const &pool)
template<typename Buf>
auto with_pool(Buf &&buf, type_pool const &pool)
template<has_pool Env>
auto with_pool(Env &&env)
template<typename Buf, has_pool Env>
auto with_pool(Buf &&buf, Env &&env)

Attaches the MPI datatype of the buffer’s element type from a type_pool: buf | views::with_pool(pool).

The element type is the range’s value type, or the value_type member of a buffer that is not a range (e.g. a Kokkos view). It must have been registered with pool.register_type<T>() before; an assertion fires otherwise. Use with_auto_pool to register it on first use instead. Instead of a pool, a communicator that carries one (comm_view_with_pool) can be passed.

pool.register_type<MyStruct>();
kamping::v2::bcast(v | kamping::v2::views::with_pool(pool), 0, comm);
kamping::v2::send(kokkos_buf | kamping::v2::views::with_pool(pool), 1, comm);

Defined in header <kamping/v2/type_pool.hpp>

auto with_auto_pool(type_pool &pool)
template<typename Buf>
auto with_auto_pool(Buf &&buf, type_pool &pool)
template<has_pool Env>
auto with_auto_pool(Env &&env)
template<typename Buf, has_pool Env>
auto with_auto_pool(Buf &&buf, Env &&env)

Attaches the MPI datatype of the buffer’s element type from a type_pool, registering it on first use: buf | views::with_auto_pool(pool).

Like with_pool, but the type need not be registered in advance: the pool commits its datatype the first time it is needed. This requires a kamping::types::mpi_type_traits<T> specialization describing the type.

kamping::v2::bcast(v | kamping::v2::views::with_auto_pool(pool), 0, comm);
kamping::v2::send(kokkos_buf | kamping::v2::views::with_auto_pool(pool), 1, comm);

Defined in header <kamping/v2/type_pool.hpp>

auto with_value_pool(type_pool const &pool)
template<typename Buf>
auto with_value_pool(Buf &&buf, type_pool const &pool)
template<has_pool Env>
auto with_value_pool(Env &&env)
template<typename Buf, has_pool Env>
auto with_value_pool(Buf &&buf, Env &&env)

Attaches the MPI datatype of the payload of a structured buffer from a type_pool: per_rank | views::with_value_pool(pool).

Structured send buffers, such as a range of per-rank ranges or of (value, rank) pairs, are consumed by views::flatten_v and the dstl algorithms; their payload is the type of the values sent, not the range’s own element type. The payload type must have been registered with pool.register_type<T>() or pool.register_type<T>(dt) before; use with_auto_value_pool to register it on first use instead.

pool.register_type<MyStruct>();
kamping::v2::alltoallv(per_rank | views::with_value_pool(pool) | views::flatten_v(), rbuf, comm);

Defined in header <kamping/v2/type_pool.hpp>

auto with_auto_value_pool(type_pool &pool)
template<typename Buf>
auto with_auto_value_pool(Buf &&buf, type_pool &pool)
template<has_pool Env>
auto with_auto_value_pool(Env &&env)
template<typename Buf, has_pool Env>
auto with_auto_value_pool(Buf &&buf, Env &&env)

Attaches the MPI datatype of the payload of a structured buffer from a type_pool, registering it on first use: per_rank | views::with_auto_value_pool(pool).

Like with_value_pool, but the payload type need not be registered in advance. This requires a kamping::types::mpi_type_traits<T> specialization describing the type.

kamping::v2::alltoallv(per_rank | views::with_auto_value_pool(pool) | views::flatten_v(), rbuf, comm);

Defined in header <kamping/v2/type_pool.hpp>

Building and splitting variable-size buffers

template<template<typename...> typename FlatTemplate = std::vector, typename CountsContainer = std::vector<int>, typename DisplsContainer = std::vector<int>>
auto flatten_v()
(1)
template<typename CountsContainer = std::vector<int>, typename DisplsContainer = std::vector<int>, typename Fb>
requires (!std::same_as<std::remove_cvref_t<Fb>, resize_t>)
auto flatten_v(Fb &&flat_buf)
(2)
template<typename DisplsContainer = std::vector<int>, typename Fb, typename Ct>
requires (!std::same_as<std::remove_cvref_t<Fb>, resize_t>)
auto flatten_v(Fb &&flat_buf, Ct &&counts)
(3)
template<typename Fb, typename Ct, typename Dt>
requires (!std::same_as<std::remove_cvref_t<Fb>, resize_t>)
auto flatten_v(Fb &&flat_buf, Ct &&counts, Dt &&displs)
(4)
template<typename CountsContainer = std::vector<int>, typename DisplsContainer = std::vector<int>, typename Fb>
auto flatten_v(resize_t, Fb &&flat_buf)
(5)
template<typename DisplsContainer = std::vector<int>, typename Fb, typename Ct>
auto flatten_v(resize_t, Fb &&flat_buf, Ct &&counts)
(6)
template<typename Fb, typename Ct, typename Dt>
auto flatten_v(resize_t, Fb &&flat_buf, Ct &&counts, Dt &&displs)
(7)

(1) Flattens a structured send buffer into a variable-size send buffer: per_rank | views::flatten_v().

A structured send buffer is a range of per-rank ranges (entry i is sent to rank i), a range of (rank, message) pairs, or a range of (value, rank) pairs. The result holds all elements contiguously, ordered by destination rank, with the matching counts and displacements, e.g. for alltoallv:

std::vector<std::vector<int>> per_rank = ...;  // per_rank[i] is sent to rank i
auto [_, recv] = kamping::v2::alltoallv(per_rank | views::flatten_v(), kamping::v2::auto_recv_v<int>(), comm);

The flat buffer, counts and displacements are allocated internally. The template arguments select their container types, e.g. flatten_v<std::deque>() for the flat buffer or flatten_v<std::vector, std::deque<int>>() for the counts. The overloads below flatten into storage you provide instead.

(2) Flattens into the caller-provided flat_buf, which must already be large enough; counts and displacements are allocated internally.

(3) Flattens into the caller-provided flat_buf and counts, which must already be large enough; displacements are allocated internally.

(4) Flattens into the caller-provided flat_buf, counts and displs, which must already be large enough.

(5) Flattens into the caller-provided flat_buf, resizing it as needed; counts and displacements are allocated internally.

(6) Flattens into the caller-provided flat_buf and counts, resizing them as needed; displacements are allocated internally.

(7) Flattens into the caller-provided flat_buf, counts and displs, resizing them as needed.

Defined in header <kamping/v2/views/flatten_v_view.hpp>

template<typename Buf>
auto chunked(Buf &&buf)

Splits a variadic buffer into its per-rank chunks: buf | views::chunked is a range of std::spans, chunk i holding the elements for rank i. The inverse of views::flatten_v.

Defined in header <kamping/v2/views/chunked_view.hpp>

Single values

template<typename T>
auto ref_single(T &val) noexcept

Makes a single value a buffer of one element, referring to it: views::ref_single(value).

int sum = local;
kamping::v2::allreduce(kamping::v2::inplace, views::ref_single(sum), comm);  // received into sum
kamping::v2::send(views::ref_single(std::as_const(sum)), 0, comm);         // send-only buffer

Defined in header <kamping/v2/views/ref_single_view.hpp>

Tags

resize_t resize

Selects the resizing variant of a view factory: views::auto_counts(resize, counts) resizes the caller-provided counts, instead of requiring them to be large enough.

Defined in header <kamping/v2/views/view_interface.hpp>

monotonic_t monotonic

Declares caller-provided displacements as monotonically non-decreasing, e.g. computed by a prefix sum: views::with_displs(monotonic, displs). Then views::resize_v sizes the receive buffer from the last displacement and count, in O(1), instead of scanning all of them.

Defined in header <kamping/v2/views/view_interface.hpp>