Adaptors#
adjacent
#
-
template<distance_t N>
requires (N > 0)
auto adjacent(multipass_sequence auto seq) -> multipass_sequence auto# Given a compile-time size
N
and a multipass sequenceseq
, returns a new sequence which yields sliding windows of sizeN
as anN
-tuple of elements ofseq
. If seq has fewer thanN
elements, the adapted sequence will be empty.- The returned sequence is always a
multipass_sequence
. It is also
The
slide()
adaptor is similar toadjacent()
, but takes its window size as a run-time rather than a compile-time parameter, and returns length-n
subsequences rather than tuples.Equivalent to:
zip(seq, drop(seq, 1), drop(seq, 2), ..., drop(seq, N-1));
- Template Parameters:
N – The size of the sliding window. Must be greater than zero.
- Parameters:
seq – A multipass sequence.
- Returns:
A sequence adaptor whose element type is a std::tuple of size
N
, or a std::pair if N == 2.- Example:
std::vector vec{1, 2, 3, 4, 5}; std::vector<int> sums; // adjacent<3> yields 3-tuples which we can destructure for (auto [a, b, c] : flux::adjacent<3>(std::move(vec))) { sums.push_back(a + b + c); } assert((sums == std::vector{1 + 2 + 3, 2 + 3 + 4, 3 + 4 + 5}));
- See also:
- The returned sequence is always a
adjacent_filter
#
-
template<multipass_sequence Seq, typename Pred>
requires std::predicate<Pred&, element_t<Seq>, element_t<Seq>>
auto adjacent_filter(Seq seq, Pred pred) -> multipass_sequence auto;# Applies the given binary predicate
pred
to each pair of adjacent elements ofseq
. If the predicate returnsfalse
, the second element of the pair does not appear in the resulting sequence. The first element ofseq
is always included in the output.The resulting sequence is always multipass; it is also a
bidirectional_sequence
ifSeq
is bidirectional, and abounded_sequence
ifSeq
is bounded.A common use for
adjacent_filter()
is to remove adjacent equal elements from a sequence, which can be achieved by passing std::not_equal_to{} as the predicate. Thededup()
function is a handy alias for adjacent_filter(not_equal_to{}).- Parameters:
seq – A multipass sequence
pred – A binary predicate to compare sequence elements
- Returns:
The filtered sequence
- Example:
std::array nums{1, 1, 2, 3, 3, 2, 2}; // The adjacent_filter adaptor applies the given predicate to each pair // of elements in the sequence, and if the predicate returns false then // the second element of the pair is discarded auto filtered1 = flux::adjacent_filter(nums, std::less{}); assert(flux::equal(filtered1, std::array{1, 2, 3})); // For the common case of removing adjacent equal elements, Flux provides // the dedup() function as shorthand for adjacent_filter(std::not_equal_to{}) auto filtered2 = flux::dedup(nums); assert(flux::equal(filtered2, std::array{1, 2, 3, 2})); // We can use adjacent_filter with a custom comparator as well auto compare = [](auto p1, auto p2) { return p1.first != p2.first; }; std::pair<int, int> pairs[] = {{1, 2}, {1, 3}, {1, 4}, {2, 5}, {2, 6}}; auto filtered3 = flux::adjacent_filter(flux::ref(pairs), compare); assert(flux::equal(filtered3, std::array{std::pair{1, 2}, std::pair{2, 5}}));
- See also:
adjacent_map
#
-
template<distance_t N>
auto adjacent_map(multipass_sequence auto seq, auto func) -> multipass_sequence auto;#
cache_last
#
cartesian_product
#
-
auto cartesian_product(sequence auto seq0, multipass_sequence auto... seqs) -> sequence auto;#
cartesian_product_map
#
chain
#
chunk
#
chunk_by
#
-
template<multipass_sequence Seq, typename Pred>
requires std::predicate<Pred, element_t<Seq>, element_t<Seq>>
auto chunk_by(Seq seq, Pred pred) -> multipass_sequence auto;#
cursors
#
-
auto cursors(multipass_sequence auto seq) -> multipass_sequence auto;#
Given a sequence
seq
, cursors(seq) returns a new sequence whose elements are the cursors of the original sequence. Thecursors()
sequence retains all the capabilities of the source sequence (bidirectional, random access, sized etc), up tocontiguous_sequence
.This is basically a passthrough adaptor, except that read_at(seq, cur) returns a copy of
cur
.- Parameters:
seq – A multipass sequence
- Returns:
A sequence whose elements are the cursors of
seq
- Example:
std::array const array{"alpha"sv, "bravo"sv, "charlie"sv, "delta"sv, "echo"sv}; auto long_words = flux::drop(array, 2); // We can use the cursors() adaptor to iterate over the cursors of the // sequence (in this case integer indices) and use those to read from the // original sequence for (auto idx : flux::cursors(long_words)) { std::cout << idx << ": " << long_words[idx] << '\n'; } // prints // 2: charlie // 3: delta // 4: echo
cycle
#
-
template<sequence Seq>
requires multipass_sequence<Seq> || infinite_sequence<Seq>
auto cycle(Seq seq) -> infinite_sequence auto;#
-
template<multipass_sequence Seq>
auto cycle(Seq seq, std::integral auto count) -> multipass_sequence auto;# Repeats the elements of
seq
endlessly (for the first overload) orcount
times (for the second overload).For the first overload, if
Seq
is already aninfinite_sequence
, it is passed through unchanged.Otherwise, both overloads require a
multipass_sequence
, and the output is always amultipass_sequence
. The adapted sequence is also abidirectional_sequence
whenSeq
is both bidirectional and bounded, and arandom_access_sequence
whenSeq
is random-access and bounded.For the second overload, the returned sequence is additionally always a
bounded_sequence
(even ifSeq
is not), and asized_sequence
when the source sequence is sized.To avoid “spooky action at a distance” (where mutating s[n] would change the value of some other s[m])
cycle()
provides only immutable access to the elements ofseq
: that is, it behaves as ifseq
were first passed throughread_only()
.Caution
In order to provide random-access functionality, cursors for cycled sequences keep a
size_t
count of how many times they have looped round. For very long-running programs using the infinite version ofcycle()
it may be possible to overflow this counter. (Assuming 1000 iterations per second, this would take approximately 49 days on a machine with a 32-bitsize_t
, or around 500 million years on a 64-bit machine.)While this won’t cause undefined behaviour, it’s possible to encounter incorrect results or runtime errors when using the random-access functions on cursors which have overflowed.
- Parameters:
seq – A sequence to cycle through
count – The number of times to loop through the sequence before terminating. If not supplied, the sequence will be repeated endlessly.
- Returns:
An adapted sequence which repeatedly loops through the elements of
seq
.- Example:
std::array arr{1, 2, 3}; // cycle(seq) returns an infinite sequence. It's common to use this in // combination with take() to turn it back into a finite sequence: auto cycled1 = flux::take(flux::cycle(arr), 5); assert(flux::equal(cycled1, std::array{1, 2, 3, 1, 2})); // We can also use a cycled sequence as an argument to zip(): std::string_view letters = "ABCDE"; auto zipped = flux::zip(letters, flux::cycle(arr)); using P = std::pair<char const&, int const&>; assert(flux::equal(zipped, std::array{ P{'A', 1}, P{'B', 2}, P{'C', 3}, P{'D', 1}, P{'E', 2} })); // Alternatively, we can provide a second argument to cycle(seq, n) to // get a finite sequence which repeats the source n times: auto cycled2 = flux::cycle(arr, 3); assert(flux::equal(cycled2, std::array{1, 2, 3, 1, 2, 3, 1, 2, 3})); assert(flux::sum(cycled2) == 18); // Note that both versions of cycle() only provide immutable access to their // elements. The following would be a compile error: // flux::fill(cycled2, 99); // ERROR: cannot assign to const reference
- See also:
dedup
#
-
template<multipass_sequence Seq>
requires std::equality_comparable<element_t<Seq>>
auto dedup(Seq seq) -> multipass_sequence auto;# An alias for adjacent_filter(seq, std::ranges::not_equal_to{}). This can be used to remove adjacent elements from a sequence.
- See also:
drop
#
-
auto drop(sequence auto seq, std::integral auto count) -> sequence auto;#
Given a sequence
seq
and a non-negative integral valuecount
, returns a new sequence which skips the firstcount
elements ofseq
.The returned sequence has the same capabilities as :var:seq. If
seq
has fewer thancount
elements, the returned sequence is empty.- Parameters:
seq – A sequence.
count – A non-negative integral value indicating the number of elements to be skipped.
- Returns:
A sequence adaptor that yields the remaining elements of
seq
, with the firstcount
elements skipped.- Example:
std::vector vec{1, 2, 3, 4, 5}; auto dropped = flux::drop(std::move(vec), 3); assert(flux::size(dropped) == 2); assert(flux::equal(dropped, std::vector{4, 5}));
- See also:
std::views::drop (C++20)
drop_while
#
filter
#
flatten
#
map
#
mask
#
-
template<sequence Seq, sequence Mask>
requires boolean_testable<element_t<Mask>>
auto mask(Seq seq, Mask where) -> sequence auto;# Given a sequence of values and a sequence of booleans,
mask()
yields those elements ofseq
for which the corresponding element ofwhere
evaluates to true. Iteration is complete when either of the two input sequences is exhausted.The returned sequence models the lowest common category of the two input sequences, up to
bidirectional_sequence
. It is also abounded_sequence
and asized_sequence
when both inputs model these concepts.- Parameters:
seq – A sequence of values
where – A sequence whose element type is convertible to bool
- Returns:
An adapted sequence whose elements are the elements of
seq
, filtered by the corresponding elements ofwhere
- Example:
std::array values{"one"sv, "two"sv, "three"sv, "four"sv, "five"sv}; std::array selectors{true, false, true, false, true}; // flux::mask() selects those elements of values for which the corresponding // element of selectors is true auto masked = flux::mask(values, selectors); assert(flux::equal(masked, std::array{"one"sv, "three"sv, "five"sv})); // Note that the selectors sequence can have any element type which is // explicitly convertible to bool std::array int_selectors{0, 0, 0, 1, 1}; auto masked2 = flux::mask(values, int_selectors); assert(flux::equal(masked2, std::array{"four"sv, "five"sv}));
- See also:
pairwise
#
-
auto pairwise(multipass_sequence auto seq) -> multipass_sequence auto;#
Returns an adaptor which yields pairs of elements of
seq
. It is an alias foradjacent<2>()
.- Parameters:
seq – A multipass sequence.
- Returns:
A multipass sequence yielding pairs of elements of
seq
.
pairwise_map
#
prescan
#
-
template<sequence Seq, typename Func, std::movable Init>
requires foldable<Seq, Func, Init>
auto prescan(Seq seq, Func func, Init init) -> sequence auto;# Returns a stateful sequence adaptor which yields “partial folds” using the binary function
func
.First, this adaptor initialises an internal variable
state
toinit
and yields a read-only reference to this state. Then, for each successive elementelem
of the underlying sequence, it sets:state = func(std::move(state), std::forward(elem));
and yields a read-only reference to the new state.
The final value yielded by this adaptor is the same as fold(seq, func, init).
Because this adaptor needs to maintain internal state, it is only ever single-pass. However it is a
bounded_sequence
when the underlying sequence is bounded and asized_sequence
when the underlying sequence is sized.Unlike
scan()
, this function performs an exclusive scan, that is, the Nth element of the adapted sequence does not include the Nth element of the underlying sequence. The adaptor returned byprescan()
always yields at least one element – the initial value – followed by the elements that would be yielded by thescan()
adaptor.- Parameters:
- Returns:
A sequence adaptor which performs an exclusive scan of the elements of
seq
usingfunc
.- Example:
// We can compute the triangular numbers using prescan() std::array const ints{1, 2, 3, 4, 5}; // Note that unlike scan(), the initial value for prescan() is required, and // is the first element of the resulting sequence, which has one more element // than the input auto tri_nums = flux::prescan(ints, std::plus{}, 0); assert(flux::equal(tri_nums, std::array{0, 1, 3, 6, 10, 15}));
- See also:
read_only
#
-
template<sequence Seq>
auto read_only(Seq seq) -> read_only_sequence auto;# Returns an adapted sequence which prevents direct modification of the elements of
seq
. The returned sequence retains the capabilities of the source sequence, all the way up tocontiguous_sequence
.If
Seq
is already aread_only_sequence
, then it is returned unchanged. Otherwise,read_only()
is equivalent to:map(seq, [](auto&& elem) -> const_element_t<Seq> { return static_cast<const_element_t<Seq>>(std::forward(elem)); });
except that the returned sequence will be a
contiguous_sequence
if the source sequence models that concept. In this case, the pointer returned fromdata()
will have type value_t<Seq> const*.- Parameters:
seq – A sequence
- Returns:
An adapted sequence which provides read-only access to the elements of
seq
- Example:
// We can use the read_only_sequence concept to statically require a sequence // whose elements are immutable bool contains_a_two(flux::read_only_sequence auto&& seq) { for (auto&& elem : seq) { if (elem == 2) { // What if we wrote `elem = 2` (assignment) by mistake? return true; } } return false; } int main() { auto seq = flux::filter(std::vector{1, 2, 3, 4, 5}, flux::pred::even); // We cannot pass seq directly, as it yields mutable int& elements // contains_a_two(seq); // COMPILE ERROR // ...but we can use read_only() so that the sequence yields immutable // elements of type int const&. assert(contains_a_two(flux::read_only(std::move(seq)))); }
- See also:
std::views::as_const() (C++23)
reverse
#
-
template<bidirectional_sequence Seq>
requires bounded_sequence<Seq>
auto reverse(Seq seq) -> bidirectional_sequence auto;#
scan
#
-
template<sequence Seq, typename Func, std::movable Init = value_t<Seq>>
requires foldable<Seq, Func, Init>
auto scan(Seq seq, Func func, Init init = {}) -> sequence auto;# Returns a stateful sequence adaptor which yields “partial folds” using the binary function
func
.First, this adaptor initialises an internal variable
state
toinit
. Then, for each successive elementelem
of the underlying sequence, it sets:state = func(std::move(state), std::forward(elem));
and yields a read-only reference to the new state.
The final value yielded by this adaptor is the same as fold(seq, func, init).
Because this adaptor needs to maintain internal state, it is only ever single-pass. However it is a
bounded_sequence
when the underlying sequence is bounded and asized_sequence
when the underlying sequence is sized.Unlike
prescan()
, this function performs an inclusive scan, that is, the Nth element of the adapted sequence includes the Nth element of the underlying sequence. The adapted sequence always yields the same number of elements as the underlying sequence.- Parameters:
seq – A sequence to adapt
func – A binary callable of the form R(R, element_t<Seq>), where
R
is constructible fromInit
init – The initial value for the scan. If not supplied, a default constructed object of type
value_t<Seq>
is used.
- Returns:
A sequence adaptor which performs an inclusive scan of the elements of
seq
usingfunc
.- Example:
// We can compute the triangular numbers using scan() std::array const ints{1, 2, 3, 4, 5}; // Note that unlike prescan(), the initial value for scan() may be omitted // (here defaulting to int{}), and the resulting sequence has the same number // of elements as the original auto tri_nums = flux::scan(ints, std::plus{}); assert(flux::equal(tri_nums, std::array{1, 3, 6, 10, 15}));
scan_first
#
-
template<sequence Seq, typename Func>
requires foldable<Seq, Func, element_t<Seq>>
auto scan_first(Seq seq, Func func) -> sequence auto;# Returns a stateful sequence adaptor which yields “partial folds” using the binary function
func
.When iterated over, the returned sequence first initialises an internal variable
state
with the first element of the underlying sequence, and yields a read-only reference to this state. For each subsequent elementelem
, it sets:state = func(std::move(state), std::forward(elem));
and yields a read-only reference to the internal state. If
seq
is empty, the internal state is never initialised and the resulting sequence is also empty. For a non-empty sequence, the final value yielded byscan_first()
is the same as would be obtained from fold_first(seq, func).Because this adaptor needs to maintain internal state, it is only ever single-pass. However it is a
bounded_sequence
when the underlying sequence is bounded and asized_sequence
when the underlying sequence is sized.Like
scan()
, this function performs an inclusive scan, that is, the Nth element of the adapted sequence includes the Nth element of the underlying sequence. The adapted sequence always yields the same number of elements as the underlying sequence. Unlikescan()
, the first element ofscan_first()
is simply the first element of the underlying sequence, and the suppliedfunc
is only applied to subsequent elements (this is equivalent to the differing behaviours offold()
andfold_first()
respectively).- Parameters:
- Returns:
A sequence adaptor which performs an inclusive scan of the elements of
seq
usingfunc
.- Example:
// We can compute the triangular numbers using scan_first() std::array const ints{1, 2, 3, 4, 5}; // Note that unlike scan(), scan_first() never takes an initial value, // and instead the first element of the resulting sequence is the same as // the first element of the underlying sequence: the fold operation is only // applied to subsequent elements. auto tri_nums = flux::scan_first(ints, std::plus{}); assert(flux::equal(tri_nums, std::array{1, 3, 6, 10, 15}));
set_difference
#
-
template<sequence Seq1, sequence Seq2, typename Cmp = std::ranges::less>
requires strict_weak_order_for<Cmp, Seq1> && strict_weak_order_for<Cmp, Seq2>
auto set_difference(Seq1 seq1, Seq2 seq2, Cmp cmp = {}) -> sequence auto;# Returns a sequence adaptor which yields the set difference of the two input sequences
seq1
andseq2
, ordered by the given comparison functioncmp
.This function assumes that both
seq1
andseq2
are sorted with respect to the comparison functioncmp
. If the input sequences are not sorted, the contents of the resulting sequence is unspecified.When the resulting sequence is iterated, it will output the elements from
seq1
which are not found in theseq2
according tocmp
. If some element is foundm
times inseq1
andn
times inseq2
, then the resulting sequence yields exactlystd::max(m - n, 0)
elements.- Parameters:
seq1 – The first sorted sequence.
seq2 – The second sorted sequence.
cmp – A binary predicate that takes two elements as arguments and returns true if the first element is less than the second.
- Returns:
A sequence adaptor that yields those elements of seq1 which do not also appear in seq2.
- Example:
std::array arr1{0, 1, 2, 3, 4, 5}; std::array arr2{ 1, 3, 5}; auto merged = flux::set_difference(flux::ref(arr1), flux::ref(arr2)); assert(flux::equal(merged, std::array{0, 2, 4}));
set_intersection
#
-
template<sequence Seq1, sequence Seq2, typename Cmp = std::ranges::less>
requires strict_weak_order_for<Cmp, Seq1> && strict_weak_order_for<Cmp, Seq2>
auto set_intersection(Seq1 seq1, Seq2 seq2, Cmp cmp = {}) -> sequence auto;# Returns a sequence adaptor which yields the set intersection of the two input sequences
seq1
andseq2
, ordered by the given comparison functioncmp
.This function assumes that both
seq1
andseq2
are sorted with respect to the comparison functioncmp
. If the input sequences are not sorted, the contents of the resulting sequence is unspecified.When the resulting sequence is iterated, it will output the elements from
seq1
that are found in both sorted sequences according tocmp
. If some element is foundm
times inseq1
andn
times inseq2
, then the resulting sequence yields exactlystd::min(n, m)
elements.- Parameters:
seq1 – The first sorted sequence.
seq2 – The second sorted sequence.
cmp – A binary predicate that takes two elements as arguments and returns true if the first element is less than the second.
- Returns:
A sequence adaptor that represents the set intersection of the two input sequences.
- Example:
std::array arr1{0, 1, 2, 3, 4, 5}; std::array arr2{ 1, 3, 5}; auto merged = flux::set_intersection(flux::ref(arr1), flux::ref(arr2)); assert(flux::equal(merged, std::array{1, 3, 5}));
set_symmetric_difference
#
-
template<sequence Seq1, sequence Seq2, typename Cmp = std::ranges::less>
requires see_below
auto set_symmetric_difference(Seq1 seq1, Seq2 seq2, Cmp cmp = {}) -> sequence auto;# Returns a sequence adaptor which yields the set symmetric difference of the two input sequences
seq1
andseq2
, ordered by the given comparison functioncmp
.This function assumes that both
seq1
andseq2
are sorted with respect to the comparison functioncmp
. If the input sequences are not sorted, the contents of the resulting sequence is unspecified.When the resulting sequence is iterated, it will output the elements that are found in either of the sequence, but not in both of them according to
cmp
. If some element is foundm
times inseq1
andn
times inseq2
, then the resulting sequence yields exactlystd::abs(m - n)
elements, preserving order:if m > n, the final m - n of these elements from
seq1
if m < n, the final n - m of these elements from
seq2
- Requires:
The expression in the
requires
clause is equivalent to:std::common_reference_with<element_t<Seq1>, element_t<Seq2>> && std::common_reference_with<rvalue_element_t<Seq1>, rvalue_element_t<Seq2>> && requires { typename std::common_type_t<value_t<Seq1>, value_t<Seq2>>; } && strict_weak_order_for<Cmp, Seq1> && strict_weak_order_for<Cmp, Seq2>
- Parameters:
seq1 – The first sequence to merge.
seq2 – The second sequence to merge.
- Returns:
A sequence adaptor that yields elements of seq1 and seq2 which do not appear in both sequences.
- Example:
std::array arr1{0, 1, 2, 3, 4, 5}; std::array arr2{ 1, 3, 5, 6, 7}; auto merged = flux::set_symmetric_difference(flux::ref(arr1), flux::ref(arr2)); assert(flux::equal(merged, std::array{0, 2, 4, 6, 7}));
set_union
#
-
template<sequence Seq1, sequence Seq2, typename Cmp = std::ranges::less>
requires see_below
auto set_union(Seq1 seq1, Seq2 seq2, Cmp cmp = {}) -> sequence auto;# Returns a sequence adaptor which yields the set union of the two input sequences
seq1
andseq2
, ordered by the given comparison functioncmp
.This function assumes that both
seq1
andseq2
are sorted with respect to the comparison functioncmp
. If the input sequences are not sorted, the contents of the resulting sequence is unspecified.When the resulting sequence is iterated, it will output the elements from the two input sequences in order according to
cmp
. If some element is foundm
times inseq1
andn
times inseq2
, then the resulting sequence yields exactlystd::max(n, m)
elements.- Requires:
The expression in the
requires
clause is equivalent to:std::common_reference_with<element_t<Seq1>, element_t<Seq2>> && std::common_reference_with<rvalue_element_t<Seq1>, rvalue_element_t<Seq2>> && requires { typename std::common_type_t<value_t<Seq1>, value_t<Seq2>>; } && strict_weak_order_for<Cmp, Seq1> && strict_weak_order_for<Cmp, Seq2>
- Parameters:
seq1 – The first sorted sequence to merge.
seq2 – The second sorted sequence to merge.
cmp – A binary predicate that takes two elements as arguments and returns true if the first element is less than the second.
- Returns:
A sequence adaptor that represents the set union of the two input sequences.
- Example:
std::array arr1{1, 3, 5}; std::array arr2{1, 2, 4, 6}; auto merged = flux::set_union(flux::ref(arr1), flux::ref(arr2)); assert(flux::equal(merged, std::array{1, 2, 3, 4, 5, 6}));
slide
#
-
auto slide(multipass_sequence auto seq, std::integral auto win_sz) -> multipass_sequence auto;#
stride
#
split
#
-
template<multipass_sequence Seq, multipass_sequence Pattern>
requires std::equality_comparable_with<element_t<Seq>, element_t<Pattern>>
auto split(Seq seq, Pattern pattern) -> sequence auto;#