TRIQS/mpi 1.3.0
C++ interface to MPI
|
Generic and specialized implementations for a subset of collective MPI communications (broadcast, reduce, gather, scatter).
The generic functions (mpi::broadcast, mpi::reduce, mpi::scatter, ...) call their more specialized counterparts (e.g. mpi::mpi_broadcast, mpi::mpi_reduce, mpi::mpi_scatter, ...).
mpi provides (some) implementations for
std::vector
and std::array
types with MPI compatible value types,std::string
andstd::pair
.Furthermore, there are several functions to simplify communicating generic, contiguous ranges: mpi::broadcast_range, mpi::gather_range, mpi::reduce_in_place_range, mpi::reduce_range and mpi::scatter_range.
Functions | |
template<typename T > | |
bool | mpi::all_equal (T const &x, communicator c={}) |
Checks if a given object is equal across all ranks in the given communicator. | |
template<typename T > | |
decltype(auto) | mpi::all_gather (T &&x, communicator c={}) |
Generic MPI all-gather. | |
template<typename T > | |
decltype(auto) | mpi::all_reduce (T &&x, communicator c={}, MPI_Op op=MPI_SUM) |
Generic MPI all-reduce. | |
template<typename T > | |
void | mpi::all_reduce_in_place (T &&x, communicator c={}, MPI_Op op=MPI_SUM) |
Generic MPI all-reduce in-place. | |
template<typename T > | |
void | mpi::broadcast (T &&x, communicator c={}, int root=0) |
Generic MPI broadcast. | |
template<contiguous_sized_range R> | |
void | mpi::broadcast_range (R &&rg, communicator c={}, int root=0) |
Implementation of an MPI broadcast for an mpi::contiguous_sized_range object. | |
template<typename T > | |
decltype(auto) | mpi::gather (T &&x, mpi::communicator c={}, int root=0, bool all=false) |
Generic MPI gather. | |
template<contiguous_sized_range R1, contiguous_sized_range R2> | |
void | mpi::gather_range (R1 &&in_rg, R2 &&out_rg, long out_size, communicator c={}, int root=0, bool all=false) |
Implementation of an MPI gather for an mpi::contiguous_sized_range. | |
template<typename T , std::size_t N> | |
void | mpi::mpi_broadcast (std::array< T, N > &arr, communicator c={}, int root=0) |
Implementation of an MPI broadcast for a std::arr. | |
template<typename T1 , typename T2 > | |
void | mpi::mpi_broadcast (std::pair< T1, T2 > &p, communicator c={}, int root=0) |
Implementation of an MPI broadcast for a std::pair. | |
void | mpi::mpi_broadcast (std::string &s, communicator c, int root) |
Implementation of an MPI broadcast for a std::string. | |
template<typename T > | |
void | mpi::mpi_broadcast (std::vector< T > &v, communicator c={}, int root=0) |
Implementation of an MPI broadcast for a std::vector. | |
template<typename T > requires (has_mpi_type<T>) | |
void | mpi::mpi_broadcast (T &x, communicator c={}, int root=0) |
Implementation of an MPI broadcast for types that have a corresponding MPI datatype, i.e. for which a specialization of mpi::mpi_type has been defined. | |
std::string | mpi::mpi_gather (std::string const &s, communicator c={}, int root=0, bool all=false) |
Implementation of an MPI gather for a std::string. | |
template<typename T > | |
auto | mpi::mpi_gather (std::vector< T > const &v, communicator c={}, int root=0, bool all=false) |
Implementation of an MPI gather for a std::vector. | |
template<typename T , std::size_t N> | |
auto | mpi::mpi_reduce (std::array< T, N > const &arr, communicator c={}, int root=0, bool all=false, MPI_Op op=MPI_SUM) |
Implementation of an MPI reduce for a std::array. | |
template<typename T1 , typename T2 > | |
auto | mpi::mpi_reduce (std::pair< T1, T2 > const &p, communicator c={}, int root=0, bool all=false, MPI_Op op=MPI_SUM) |
Implementation of an MPI reduce for a std::pair. | |
template<typename T > | |
auto | mpi::mpi_reduce (std::vector< T > const &v, communicator c={}, int root=0, bool all=false, MPI_Op op=MPI_SUM) |
Implementation of an MPI reduce for a std::vector. | |
template<typename T > requires (has_mpi_type<T>) | |
T | mpi::mpi_reduce (T const &x, communicator c={}, int root=0, bool all=false, MPI_Op op=MPI_SUM) |
Implementation of an MPI reduce for types that have a corresponding MPI datatype, i.e. for which a specialization of mpi::mpi_type has been defined. | |
template<typename T , std::size_t N> | |
void | mpi::mpi_reduce_in_place (std::array< T, N > &arr, communicator c={}, int root=0, bool all=false, MPI_Op op=MPI_SUM) |
Implementation of an in-place MPI reduce for a std::array. | |
template<typename T > | |
void | mpi::mpi_reduce_in_place (std::vector< T > &v, communicator c={}, int root=0, bool all=false, MPI_Op op=MPI_SUM) |
Implementation of an in-place MPI reduce for a std::vector. | |
template<typename T > requires (has_mpi_type<T>) | |
void | mpi::mpi_reduce_in_place (T &x, communicator c={}, int root=0, bool all=false, MPI_Op op=MPI_SUM) |
Implementation of an in-place MPI reduce for types that have a corresponding MPI datatype, i.e. for which a specialization of mpi::mpi_type has been defined. | |
template<typename T > | |
auto | mpi::mpi_scatter (std::vector< T > const &v, communicator c={}, int root=0) |
Implementation of an MPI scatter for a std::vector. | |
template<typename T > | |
decltype(auto) | mpi::reduce (T &&x, communicator c={}, int root=0, bool all=false, MPI_Op op=MPI_SUM) |
Generic MPI reduce. | |
template<typename T > | |
void | mpi::reduce_in_place (T &&x, communicator c={}, int root=0, bool all=false, MPI_Op op=MPI_SUM) |
Generic in-place MPI reduce. | |
template<contiguous_sized_range R> | |
void | mpi::reduce_in_place_range (R &&rg, communicator c={}, int root=0, bool all=false, MPI_Op op=MPI_SUM) |
Implementation of an in-place MPI reduce for an mpi::contiguous_sized_range object. | |
template<contiguous_sized_range R1, contiguous_sized_range R2> | |
void | mpi::reduce_range (R1 &&in_rg, R2 &&out_rg, communicator c={}, int root=0, bool all=false, MPI_Op op=MPI_SUM) |
Implementation of an MPI reduce for an mpi::contiguous_sized_range. | |
template<typename T > | |
decltype(auto) | mpi::scatter (T &&x, mpi::communicator c={}, int root=0) |
Generic MPI scatter. | |
template<contiguous_sized_range R1, contiguous_sized_range R2> requires (std::same_as<std::ranges::range_value_t<R1>, std::ranges::range_value_t<R2>>) | |
void | mpi::scatter_range (R1 &&in_rg, R2 &&out_rg, long in_size, communicator c={}, int root=0, long chunk_size=1) |
Implementation of an MPI scatter for an mpi::contiguous_sized_range. | |
bool mpi::all_equal | ( | T const & | x, |
communicator | c = {} ) |
#include <mpi/generic_communication.hpp>
Checks if a given object is equal across all ranks in the given communicator.
It requires that there is a specialized mpi_reduce
for the given type T
and that it is equality comparable as well as default constructible.
It makes two calls to mpi::all_reduce, one with MPI_MIN
and the other with MPI_MAX
, and compares their results.
MPI_MIN
and MPI_MAX
need to make sense for the given type T
.T | Type to be checked. |
x | Object to be equality compared. |
c | mpi::communicator. |
Definition at line 287 of file generic_communication.hpp.
|
inline |
#include <mpi/generic_communication.hpp>
Generic MPI all-gather.
It simply calls mpi::gather with all = true
.
Definition at line 202 of file generic_communication.hpp.
|
inline |
#include <mpi/generic_communication.hpp>
Generic MPI all-reduce.
It simply calls mpi::reduce with all = true
.
Definition at line 186 of file generic_communication.hpp.
|
inline |
#include <mpi/generic_communication.hpp>
Generic MPI all-reduce in-place.
It simply calls mpi::reduce_in_place with all = true
.
Definition at line 194 of file generic_communication.hpp.
void mpi::broadcast | ( | T && | x, |
communicator | c = {}, | ||
int | root = 0 ) |
#include <mpi/generic_communication.hpp>
Generic MPI broadcast.
If mpi::has_env is true, this function calls the specialized mpi_broadcast
function for the given object, otherwise it does nothing.
T | Type to be broadcasted. |
x | Object to be broadcasted. |
c | mpi::communicator. |
root | Rank of the root process. |
Definition at line 76 of file generic_communication.hpp.
void mpi::broadcast_range | ( | R && | rg, |
communicator | c = {}, | ||
int | root = 0 ) |
#include <mpi/ranges.hpp>
Implementation of an MPI broadcast for an mpi::contiguous_sized_range object.
If mpi::has_mpi_type is true for the value type of the range, then the range is broadcasted using a simple MPI_Bcast
. Otherwise, the generic mpi::broadcast is called for each element of the range.
It throws an exception in case a call to the MPI C library fails and it expects that the sizes of the ranges are equal across all processes.
If the ranges are empty or if mpi::has_env is false or if the communicator size is < 2, it does nothing.
std::vector
, std::array
or std::string
. It is the user's responsibility to ensure that ranges have the correct sizes.Output (with 4 processes):
R | mpi::contiguous_sized_range type. |
rg | Range to broadcast. |
c | mpi::communicator. |
root | Rank of the root process. |
Definition at line 93 of file ranges.hpp.
|
inline |
#include <mpi/generic_communication.hpp>
Generic MPI gather.
If mpi::has_env is true or if the return type of the specialized mpi_gather
is lazy, this function calls the specialized mpi_gather
function for the given object. Otherwise, it simply converts the input object to the output type mpi_gather
would return.
T | Type to be gathered. |
x | Object to be gathered. |
c | mpi::communicator. |
root | Rank of the root process. |
all | Should all processes receive the result of the gather. |
mpi_gather
call. Definition at line 169 of file generic_communication.hpp.
void mpi::gather_range | ( | R1 && | in_rg, |
R2 && | out_rg, | ||
long | out_size, | ||
communicator | c = {}, | ||
int | root = 0, | ||
bool | all = false ) |
#include <mpi/ranges.hpp>
Implementation of an MPI gather for an mpi::contiguous_sized_range.
If mpi::has_mpi_type is true for the value type of the input ranges, then the ranges are gathered using a simple MPI_Gatherv
or MPI_Allgatherv
. Otherwise, each process broadcasts its elements to all other processes which implies that all == true
is required in this case.
It throws an exception in case a call to the MPI C library fails and it expects that the sizes of the input ranges add up to the given size of the output range and that the output ranges have the correct size on receiving processes.
If the input ranges are all empty, it does nothing. If mpi::has_env is false or if the communicator size is < 2, it simply copies the input range to the output range.
std::vector
and std::string
. It is the user's responsibility to ensure that the ranges have the correct sizes.Output (with 2 processes):
R1 | mpi::contiguous_sized_range type. |
R2 | mpi::contiguous_sized_range type. |
in_rg | Range to gather. |
out_rg | Range to gather into. |
out_size | Size of the output range on receiving processes (must also be given on non-receiving ranks). |
c | mpi::communicator. |
root | Rank of the root process. |
all | Should all processes receive the result of the reduction. |
Definition at line 412 of file ranges.hpp.
void mpi::mpi_broadcast | ( | std::array< T, N > & | arr, |
communicator | c = {}, | ||
int | root = 0 ) |
#include <mpi/array.hpp>
Implementation of an MPI broadcast for a std::arr.
It simply calls mpi::broadcast_range with the input array.
T | Value type of the array. |
N | Size of the array. |
arr | std::array to broadcast. |
c | mpi::communicator. |
root | Rank of the root process. |
void mpi::mpi_broadcast | ( | std::pair< T1, T2 > & | p, |
communicator | c = {}, | ||
int | root = 0 ) |
#include <mpi/pair.hpp>
Implementation of an MPI broadcast for a std::pair.
Simply calls the generic mpi::broadcast for the first and second element of the pair.
T1 | Type of the first element of the pair. |
T2 | Type of the second element of the pair. |
p | std::pair to broadcast. |
c | mpi::communicator. |
root | Rank of the root process. |
|
inline |
#include <mpi/string.hpp>
Implementation of an MPI broadcast for a std::string.
It first broadcasts the size of the string from the root process to all other processes, then resizes the string on all non-root processes and calls mpi::broadcast_range with the (resized) input string.
s | std::string to broadcast. |
c | mpi::communicator. |
root | Rank of the root process. |
Definition at line 47 of file string.hpp.
void mpi::mpi_broadcast | ( | std::vector< T > & | v, |
communicator | c = {}, | ||
int | root = 0 ) |
#include <mpi/vector.hpp>
Implementation of an MPI broadcast for a std::vector.
It first broadcasts the size of the vector from the root process to all other processes, then resizes the vector on all non-root processes and calls mpi::broadcast_range with the (resized) input vector.
T | Value type of the vector. |
v | std::vector to broadcast. |
c | mpi::communicator. |
root | Rank of the root process. |
Definition at line 51 of file vector.hpp.
void mpi::mpi_broadcast | ( | T & | x, |
communicator | c = {}, | ||
int | root = 0 ) |
#include <mpi/generic_communication.hpp>
Implementation of an MPI broadcast for types that have a corresponding MPI datatype, i.e. for which a specialization of mpi::mpi_type has been defined.
It throws an exception in case a call to the MPI C library fails.
T | Type to be broadcasted. |
x | Object to be broadcasted. |
c | mpi::communicator. |
root | Rank of the root process. |
Definition at line 219 of file generic_communication.hpp.
|
inline |
#include <mpi/string.hpp>
Implementation of an MPI gather for a std::string.
It first all-reduces the sizes of the input string from all processes and then calls mpi::gather_range.
s | std::string to gather. |
c | mpi::communicator. |
root | Rank of the root process. |
all | Should all processes receive the result. |
Definition at line 65 of file string.hpp.
auto mpi::mpi_gather | ( | std::vector< T > const & | v, |
communicator | c = {}, | ||
int | root = 0, | ||
bool | all = false ) |
#include <mpi/vector.hpp>
Implementation of an MPI gather for a std::vector.
It first all-reduces the sizes of the input vectors from all processes and then calls mpi::gather_range.
T | Value type of the vector. |
v | std::vector to gather. |
c | mpi::communicator. |
root | Rank of the root process. |
all | Should all processes receive the result. |
Definition at line 126 of file vector.hpp.
auto mpi::mpi_reduce | ( | std::array< T, N > const & | arr, |
communicator | c = {}, | ||
int | root = 0, | ||
bool | all = false, | ||
MPI_Op | op = MPI_SUM ) |
#include <mpi/array.hpp>
Implementation of an MPI reduce for a std::array.
It simply calls mpi::reduce_range with the given input array and an empty array of the same size.
T | Value type of the array. |
N | Size of the array. |
arr | std::array to reduce. |
c | mpi::communicator. |
root | Rank of the root process. |
all | Should all processes receive the result of the reduction. |
op | MPI_Op used in the reduction. |
auto mpi::mpi_reduce | ( | std::pair< T1, T2 > const & | p, |
communicator | c = {}, | ||
int | root = 0, | ||
bool | all = false, | ||
MPI_Op | op = MPI_SUM ) |
#include <mpi/pair.hpp>
Implementation of an MPI reduce for a std::pair.
Simply calls the generic mpi::reduce for the first and second element of the pair.
T1 | Type of the first element of the pair. |
T2 | Type of the second element of the pair. |
p | std::pair to be reduced. |
c | mpi::communicator. |
root | Rank of the root process. |
all | Should all processes receive the result of the reduction. |
op | MPI_Op used in the reduction. |
auto mpi::mpi_reduce | ( | std::vector< T > const & | v, |
communicator | c = {}, | ||
int | root = 0, | ||
bool | all = false, | ||
MPI_Op | op = MPI_SUM ) |
#include <mpi/vector.hpp>
Implementation of an MPI reduce for a std::vector.
It simply calls mpi::reduce_range with the given input vector and an empty vector of the same size.
T | Value type of the vector. |
v | std::vector to reduce. |
c | mpi::communicator. |
root | Rank of the root process. |
all | Should all processes receive the result of the reduction. |
op | MPI_Op used in the reduction. |
Definition at line 88 of file vector.hpp.
T mpi::mpi_reduce | ( | T const & | x, |
communicator | c = {}, | ||
int | root = 0, | ||
bool | all = false, | ||
MPI_Op | op = MPI_SUM ) |
#include <mpi/generic_communication.hpp>
Implementation of an MPI reduce for types that have a corresponding MPI datatype, i.e. for which a specialization of mpi::mpi_type has been defined.
It throws an exception in case a call to the MPI C library fails.
T | Type to be reduced. |
x | Object to be reduced. |
c | mpi::communicator. |
root | Rank of the root process. |
all | Should all processes receive the result of the reduction. |
op | MPI_Op used in the reduction. |
Definition at line 239 of file generic_communication.hpp.
void mpi::mpi_reduce_in_place | ( | std::array< T, N > & | arr, |
communicator | c = {}, | ||
int | root = 0, | ||
bool | all = false, | ||
MPI_Op | op = MPI_SUM ) |
#include <mpi/array.hpp>
Implementation of an in-place MPI reduce for a std::array.
It simply calls mpi::reduce_in_place_range with the given input array.
T | Value type of the array. |
N | Size of the array. |
arr | std::array to reduce. |
c | mpi::communicator. |
root | Rank of the root process. |
all | Should all processes receive the result of the reduction. |
op | MPI_Op used in the reduction. |
void mpi::mpi_reduce_in_place | ( | std::vector< T > & | v, |
communicator | c = {}, | ||
int | root = 0, | ||
bool | all = false, | ||
MPI_Op | op = MPI_SUM ) |
#include <mpi/vector.hpp>
Implementation of an in-place MPI reduce for a std::vector.
It simply calls mpi::reduce_in_place_range with the given input vector.
T | Value type of the vector. |
v | std::vector to reduce. |
c | mpi::communicator. |
root | Rank of the root process. |
all | Should all processes receive the result of the reduction. |
op | MPI_Op used in the reduction. |
Definition at line 70 of file vector.hpp.
void mpi::mpi_reduce_in_place | ( | T & | x, |
communicator | c = {}, | ||
int | root = 0, | ||
bool | all = false, | ||
MPI_Op | op = MPI_SUM ) |
#include <mpi/generic_communication.hpp>
Implementation of an in-place MPI reduce for types that have a corresponding MPI datatype, i.e. for which a specialization of mpi::mpi_type has been defined.
It throws an exception in case a call to the MPI C library fails.
T | Type to be reduced. |
x | Object to be reduced. |
c | mpi::communicator. |
root | Rank of the root process. |
all | Should all processes receive the result of the reduction. |
op | MPI_Op used in the reduction. |
Definition at line 265 of file generic_communication.hpp.
auto mpi::mpi_scatter | ( | std::vector< T > const & | v, |
communicator | c = {}, | ||
int | root = 0 ) |
#include <mpi/vector.hpp>
Implementation of an MPI scatter for a std::vector.
It first broadcasts the size of the vector from the root process to all other processes and then calls mpi::scatter_range.
T | Value type of the vector. |
v | std::vector to scatter. |
c | mpi::communicator. |
root | Rank of the root process. |
Definition at line 106 of file vector.hpp.
|
inline |
#include <mpi/generic_communication.hpp>
Generic MPI reduce.
If mpi::has_env is true or if the return type of the specialized mpi_reduce
is lazy, this function calls the specialized mpi_reduce
function for the given object. Otherwise, it simply converts the input object to the output type mpi_reduce
would return.
T | Type to be reduced. |
x | Object to be reduced. |
c | mpi::communicator. |
root | Rank of the root process. |
all | Should all processes receive the result of the reduction. |
op | MPI_Op used in the reduction. |
mpi_reduce
call. Definition at line 97 of file generic_communication.hpp.
|
inline |
#include <mpi/generic_communication.hpp>
Generic in-place MPI reduce.
If mpi::has_env is true, this functions calls the specialized mpi_reduce_in_place
function for the given object. Otherwise, it does nothing.
T | Type to be reduced. |
x | Object to be reduced. |
c | mpi::communicator. |
root | Rank of the root process. |
all | Should all processes receive the result of the reduction. |
op | MPI_Op used in the reduction. |
Definition at line 124 of file generic_communication.hpp.
void mpi::reduce_in_place_range | ( | R && | rg, |
communicator | c = {}, | ||
int | root = 0, | ||
bool | all = false, | ||
MPI_Op | op = MPI_SUM ) |
#include <mpi/ranges.hpp>
Implementation of an in-place MPI reduce for an mpi::contiguous_sized_range object.
If mpi::has_mpi_type is true for the value type of the range, then the range is reduced using a simple MPI_Reduce
or MPI_Allreduce
with MPI_IN_PLACE
. Otherwise, the specialized mpi_reduce_in_place
is called for each element in the range.
It throws an exception in case a call to the MPI C library fails and it expects that the sizes of the ranges are equal across all processes.
If the ranges are empty or if mpi::has_env is false or if the communicator size is < 2, it does nothing.
std::vector
or std::array
. It is the user's responsibility to ensure that ranges have the correct sizes.Output (with 4 processes):
R | mpi::contiguous_sized_range type. |
rg | Range to reduce. |
c | mpi::communicator. |
root | Rank of the root process. |
all | Should all processes receive the result of the reduction. |
op | MPI_Op used in the reduction. |
Definition at line 155 of file ranges.hpp.
void mpi::reduce_range | ( | R1 && | in_rg, |
R2 && | out_rg, | ||
communicator | c = {}, | ||
int | root = 0, | ||
bool | all = false, | ||
MPI_Op | op = MPI_SUM ) |
#include <mpi/ranges.hpp>
Implementation of an MPI reduce for an mpi::contiguous_sized_range.
If mpi::has_mpi_type is true for the value type of the range, then the range is reduced using a simple MPI_Reduce
or MPI_Allreduce
. Otherwise, the specialized mpi_reduce
is called for each element in the range.
It throws an exception in case a call to the MPI C library fails and it expects that the sizes of the input ranges are equal across all processes and that they are equal to the size of the output range on receiving processes.
If the input ranges are empty, it does nothing. If mpi::has_env is false or if the communicator size is < 2, it simply copies the input range to the output range.
std::vector
or std::array
. It is the user's responsibility to ensure that ranges have the correct sizes.Output (with 4 processes):
R1 | mpi::contiguous_sized_range type. |
R2 | mpi::contiguous_sized_range type. |
in_rg | Range to reduce. |
out_rg | Range to reduce into. |
c | mpi::communicator. |
root | Rank of the root process. |
all | Should all processes receive the result of the reduction. |
op | MPI_Op used in the reduction. |
Definition at line 226 of file ranges.hpp.
|
inline |
#include <mpi/generic_communication.hpp>
Generic MPI scatter.
If mpi::has_env is true or if the return type of the specialized mpi_scatter
is lazy, this function calls the specialized mpi_scatter
function for the given object. Otherwise, it simply converts the input object to the output type mpi_scatter
would return.
T | Type to be scattered. |
x | Object to be scattered. |
c | mpi::communicator. |
root | Rank of the root process. |
mpi_scatter
call. Definition at line 142 of file generic_communication.hpp.
void mpi::scatter_range | ( | R1 && | in_rg, |
R2 && | out_rg, | ||
long | in_size, | ||
communicator | c = {}, | ||
int | root = 0, | ||
long | chunk_size = 1 ) |
#include <mpi/ranges.hpp>
Implementation of an MPI scatter for an mpi::contiguous_sized_range.
If mpi::has_mpi_type is true for the value type of the range, then the range is scattered as evenly as possible across the processes in the communicator using a simple MPI_Scatterv
. Otherwise an exception is thrown.
The user can specify a chunk size which is used to divide the input range into chunks of the specified size. The number of chunks are then distributed evenly across the processes in the communicator. The size of the input range is required to be a multiple of the given chunk size, otherwise an exception is thrown.
It throws an exception in case a call to the MPI C library fails and it expects that the output ranges have the correct size and that they add up to the size of the input range on the root process.
If the input range is empty on root, it does nothing. If mpi::has_env is false or if the communicator size is < 2, it simply copies the input range to the output range.
std::vector
. It is the user's responsibility to ensure that the ranges have the correct sizes (mpi::chunk_length can be useful to do that).Output (with 2 processes):
R1 | mpi::contiguous_sized_range type. |
R2 | mpi::contiguous_sized_range type. |
in_rg | Range to scatter. |
out_rg | Range to scatter into. |
in_size | Size of the input range on root (must also be given on non-root ranks). |
c | mpi::communicator. |
root | Rank of the root process. |
chunk_size | Size of the chunks to scatter. |
Definition at line 317 of file ranges.hpp.