std::transf...clusive_scan(3)

πŸ“¦ version 2024.07.05, in nixpkgs unstable, opensuse-leap 16.0

πŸŽ€ std::transform_inclusive_scan πŸŽ€

okay so bestie, welcome to the C++ Standard Library page for std::transform_inclusive_scan β€” the manpage header calls it std::transf...clusive_scan(3) and says C++ Standard Libary (their typo, not mine πŸ’…). This is the inclusive-scan-with-a-transform-glow-up situation, and we're gonna get through every single overload together. It lives in header <numeric>, arrived since C++17, and overloads (1) and (3) are constexpr since C++20. periodt. ✨


πŸ’– NAME πŸ’–

std::transform_inclusive_scan β€” std::transform_inclusive_scan. Yes, the NAME line is literally that, twice, and it ate. πŸ‘‘


✨ SYNOPSIS ✨

Defined in header <numeric>.

template< class InputIt, class OutputIt,
          class BinaryOp, class UnaryOp >                    (since C++17)
OutputIt transform_inclusive_scan                        (1)
(constexpr since C++20)
( InputIt first, InputIt last, OutputIt d_first,
  BinaryOp binary_op, UnaryOp unary_op );
template< class ExecutionPolicy,
          class ForwardIt1, class ForwardIt2,
          class BinaryOp, class UnaryOp >
ForwardIt2 transform_inclusive_scan                      (2) (since C++17)
( ExecutionPolicy&& policy,
  ForwardIt1 first, ForwardIt1 last, ForwardIt2 d_first,
  BinaryOp binary_op, UnaryOp unary_op );
template< class InputIt, class OutputIt,
          class BinaryOp, class UnaryOp, class T >           (since C++17)
OutputIt transform_inclusive_scan                        (3)
(constexpr since C++20)
( InputIt first, InputIt last, OutputIt d_first,
  BinaryOp binary_op, UnaryOp unary_op, T init );
template< class ExecutionPolicy,
          class ForwardIt1, class ForwardIt2,
          class BinaryOp, class UnaryOp, class T >
ForwardIt2 transform_inclusive_scan                      (4) (since C++17)
( ExecutionPolicy&& policy,
  ForwardIt1 first, ForwardIt1 last, ForwardIt2 d_first,
  BinaryOp binary_op, UnaryOp unary_op, T init );
  1. Computes the inclusive prefix sum using op. For each integer i in [0, std::distance(first, last)), performs the following operations in order:
  2. Creates a sequence which is formed by the values transformed from the elements of [first, iter] in order by unary_op, where iter is the next ith iterator of first.
  3. Computes the generalized noncommutative sum of the sequence over binary_op.
  4. Assigns the result to *dest, where dest is the next ith iterator of d_first.
  5. Same as (1), but each sequence created is formed by init followed by the elements of [first, iter] in order.

2,4) Same as (1,3), but executed according to policy.

These overloads participate in overload resolution only if:

  • until C++20: std::is_execution_policy_v<std::decay_t<ExecutionPolicy>> is true.
  • since C++20: std::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> is true.

The generalized noncommutative sum of a sequence of elements over a binary operation binary_op is defined as follows:

  • If the sequence only has one element, the sum is the value of the element.
  • Otherwise, performs the following operations in order:
  1. Selects any two adjacent elements elem1 and elem2 from the sequence.
  2. Calculates binary_op(elem1, elem2) and replaces the two elements in the sequence with the result.
  3. Repeats steps 1 and 2 until there is only one element in the sequence.
The result is non-deterministic if the binary_op is not associative (such as floating-point addition). 🫠

For overloads (1,2), if binary_op(unary_op(*first), unary_op(*first)) is not convertible to the value type of decltype(first), the program is ill-formed.

For overloads (3,4), if any of the following values is not convertible to T, the program is ill-formed:

  • binary_op(init, init)
  • binary_op(init, unary_op(*first))
  • binary_op(unary_op(*first), unary_op(*first))

If any of the following conditions is satisfied, the behavior is undefined:

  • For overloads (1,2), the value type of decltype(first) is not MoveConstructible.
  • For overloads (3,4), T is not MoveConstructible.
  • unary_op or binary_op modifies any element of [first, last).
  • unary_op or binary_op invalidates any iterator or subrange of [first, last).

🫢 PARAMETERS 🫢

  • first, last β€” the range of elements to sum.
  • d_first β€” the beginning of the destination range; may be equal to first.
  • policy β€” the execution policy to use. See execution policy for details.
  • init β€” the initial value.
  • unary_op β€” unary FunctionObject that will be applied to each element of the input range. The return type must be acceptable as input to binary_op.
  • binary_op β€” binary FunctionObject that will be applied to the result of unary_op, the results of other binary_op, and init if provided.

🌈 TYPE REQUIREMENTS 🌈

  • InputIt must meet the requirements of LegacyInputIterator.
  • OutputIt must meet the requirements of LegacyOutputIterator.
  • ForwardIt1, ForwardIt2 must meet the requirements of LegacyForwardIterator.

πŸ¦‹ RETURN VALUE πŸ¦‹

Iterator to the element past the last element written. slay. ✨


🌸 COMPLEXITY 🌸

Given N as std::distance(first, last):

  • 1-4) O(N) applications of unary_op and binary_op respectively.

πŸ’€ EXCEPTIONS πŸ’€

The overloads with a template parameter named ExecutionPolicy report errors as follows:

  • If execution of a function invoked as part of the algorithm throws an exception and ExecutionPolicy is one of the standard policies, std::terminate is called. For any other ExecutionPolicy, the behavior is implementation-defined.
  • If the algorithm fails to allocate memory, std::bad_alloc is thrown.

πŸ“ NOTES πŸ“

  • unary_op is never applied to init.
  • The parameter init appears last, differing from std::transform_exclusive_scan, because it is optional for this function.

🧚 EXAMPLE 🧚

// Run this code

#include <functional>
#include <iostream>
#include <iterator>
#include <numeric>
#include <vector>

int main()
{
    std::vector data{3, 1, 4, 1, 5, 9, 2, 6};

    auto times_10 = [](int x) { return x * 10; };

    std::cout << "10 times exclusive sum: ";
    std::transform_exclusive_scan(data.begin(), data.end(),
                                  std::ostream_iterator<int>(std::cout, " "),
                                  0, std::plus<int>{}, times_10);
    std::cout << "\n10 times inclusive sum: ";
    std::transform_inclusive_scan(data.begin(), data.end(),
                                  std::ostream_iterator<int>(std::cout, " "),
                                  std::plus<int>{}, times_10);
    std::cout << '\n';
}

Output:

10 times exclusive sum: 0 30 40 80 90 140 230 250
10 times inclusive sum: 30 40 80 90 140 230 250 310

πŸ‘‘ SEE ALSO πŸ‘‘

  • partial_sum β€” computes the partial sum of a range of elements (function template).
  • transform β€” applies a function to a range of elements, storing results in a destination range (function template).
  • inclusive_scan (C++17) β€” similar to std::partial_sum, includes the i^th input element in the i^th sum (function template).
  • transform_exclusive_scan (C++17) β€” applies an invocable, then calculates exclusive scan (function template).

okay bestie, that's the whole page πŸ’– source: http://cppreference.com Β· version/date: 2024.06.10 Β· page: std::transf...clusive_scan(3) Β· mwah πŸ’‹

πŸ“¦ where this page comes from