Init
This commit is contained in:
38
cppdraft/algorithms/general.md
Normal file
38
cppdraft/algorithms/general.md
Normal file
@@ -0,0 +1,38 @@
|
||||
[algorithms.general]
|
||||
|
||||
# 26 Algorithms library [[algorithms]](./#algorithms)
|
||||
|
||||
## 26.1 General [algorithms.general]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L6)
|
||||
|
||||
This Clause describes components that C++ programs may use to perform
|
||||
algorithmic operations on <containers> and other sequences[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L10)
|
||||
|
||||
The following subclauses describe components for
|
||||
non-modifying sequence operations,
|
||||
mutating sequence operations,
|
||||
sorting and related operations,
|
||||
and algorithms from the C library,
|
||||
as summarized in Table [85](#tab:algorithms.summary "Table 85: Algorithms library summary")[.](#2.sentence-1)
|
||||
|
||||
Table [85](#tab:algorithms.summary) — Algorithms library summary [[tab:algorithms.summary]](./tab:algorithms.summary)
|
||||
|
||||
| [ð](#tab:algorithms.summary-row-1) | **Subclause** | **Header** |
|
||||
| --- | --- | --- |
|
||||
| [ð](#tab:algorithms.summary-row-2)<br>[[algorithms.requirements]](algorithms.requirements "26.2 Algorithms requirements") | Algorithms requirements | |
|
||||
| [ð](#tab:algorithms.summary-row-3)<br>[[algorithms.parallel]](algorithms.parallel "26.3 Parallel algorithms") | Parallel algorithms | <execution> |
|
||||
| [ð](#tab:algorithms.summary-row-4)<br>[[algorithms.results]](algorithms.results "26.5 Algorithm result types") | Algorithm result types | <algorithm> |
|
||||
| [ð](#tab:algorithms.summary-row-5)<br>[[alg.nonmodifying]](alg.nonmodifying "26.6 Non-modifying sequence operations") | Non-modifying sequence operations | |
|
||||
| [ð](#tab:algorithms.summary-row-6)<br>[[alg.modifying.operations]](alg.modifying.operations "26.7 Mutating sequence operations") | Mutating sequence operations | |
|
||||
| [ð](#tab:algorithms.summary-row-7)<br>[[alg.sorting]](alg.sorting "26.8 Sorting and related operations") | Sorting and related operations | |
|
||||
| [ð](#tab:algorithms.summary-row-8)<br>[[numeric.ops]](numeric.ops "26.10 Generalized numeric operations") | Generalized numeric operations | <numeric> |
|
||||
| [ð](#tab:algorithms.summary-row-9)<br>[[specialized.algorithms]](specialized.algorithms "26.11 Specialized <memory> algorithms") | Specialized <memory> algorithms | <memory> |
|
||||
| [ð](#tab:algorithms.summary-row-10)<br>[[alg.rand]](alg.rand "26.12 Specialized <random> algorithms") | Specialized <random> algorithms | <random> |
|
||||
| [ð](#tab:algorithms.summary-row-11)<br>[[alg.c.library]](alg.c.library "26.13 C library algorithms") | C library algorithms | <cstdlib> |
|
||||
609
cppdraft/algorithms/parallel.md
Normal file
609
cppdraft/algorithms/parallel.md
Normal file
@@ -0,0 +1,609 @@
|
||||
[algorithms.parallel]
|
||||
|
||||
# 26 Algorithms library [[algorithms]](./#algorithms)
|
||||
|
||||
## 26.3 Parallel algorithms [algorithms.parallel]
|
||||
|
||||
### [26.3.1](#defns) Preamble [[algorithms.parallel.defns]](algorithms.parallel.defns)
|
||||
|
||||
[1](#defns-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L287)
|
||||
|
||||
Subclause [algorithms.parallel] describes components that C++ programs may use
|
||||
to perform operations on containers and other sequences in parallel[.](#defns-1.sentence-1)
|
||||
|
||||
[2](#defns-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L291)
|
||||
|
||||
A [*parallel algorithm*](#def:parallel_algorithm "26.3.1 Preamble [algorithms.parallel.defns]") is a function template listed in this document
|
||||
with a template parameter named ExecutionPolicy or constrained by the following exposition-only concept:template<class Ep>concept [*execution-policy*](#concept:execution-policy "26.3.1 Preamble [algorithms.parallel.defns]") = is_execution_policy_v<remove_cvref_t<Ep>>; // *exposition only*
|
||||
|
||||
Such a template parameter is termed an [*execution policy template parameter*](#def:template_parameter,execution_policy "26.3.1 Preamble [algorithms.parallel.defns]")[.](#defns-2.sentence-2)
|
||||
|
||||
[3](#defns-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L301)
|
||||
|
||||
A parallel algorithm accesses objects indirectly accessible via its arguments
|
||||
by invoking the following functions:
|
||||
|
||||
- [(3.1)](#defns-3.1)
|
||||
|
||||
All operations of the categories of the iterators, sentinels, or mdspan types
|
||||
that the algorithm is instantiated with[.](#defns-3.1.sentence-1)
|
||||
|
||||
- [(3.2)](#defns-3.2)
|
||||
|
||||
Operations on those sequence elements that are required by its specification[.](#defns-3.2.sentence-1)
|
||||
|
||||
- [(3.3)](#defns-3.3)
|
||||
|
||||
User-provided invocable objects
|
||||
to be applied during the execution of the algorithm,
|
||||
if required by the specification[.](#defns-3.3.sentence-1)
|
||||
|
||||
- [(3.4)](#defns-3.4)
|
||||
|
||||
Operations on those invocable objects required by the specification[.](#defns-3.4.sentence-1)
|
||||
[*Note [1](#defns-note-1)*:
|
||||
See [[algorithms.requirements]](algorithms.requirements "26.2 Algorithms requirements")[.](#defns-3.4.sentence-2)
|
||||
â *end note*]
|
||||
|
||||
These functions are herein called [*element access functions*](#def:element_access_functions "26.3.1 Preamble [algorithms.parallel.defns]")[.](#defns-3.sentence-2)
|
||||
|
||||
[4](#defns-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L322)
|
||||
|
||||
[*Example [1](#defns-example-1)*:
|
||||
|
||||
The sort function may invoke the following element access functions:
|
||||
|
||||
- [(4.1)](#defns-4.1)
|
||||
|
||||
Operations of the random-access iterator of the actual template argument
|
||||
(as per [[random.access.iterators]](random.access.iterators "24.3.5.7 Random access iterators")),
|
||||
as implied by the name of the template parameter RandomAccessIterator[.](#defns-4.1.sentence-1)
|
||||
|
||||
- [(4.2)](#defns-4.2)
|
||||
|
||||
The swap function on the elements of the sequence
|
||||
(as per the preconditions specified in [[sort]](sort "26.8.2.1 sort"))[.](#defns-4.2.sentence-1)
|
||||
|
||||
- [(4.3)](#defns-4.3)
|
||||
|
||||
The user-provided Compare function object[.](#defns-4.3.sentence-1)
|
||||
|
||||
â *end example*]
|
||||
|
||||
[5](#defns-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L338)
|
||||
|
||||
A standard library function is [*vectorization-unsafe*](#def:vectorization-unsafe "26.3.1 Preamble [algorithms.parallel.defns]") if it is specified to synchronize with another function invocation, or
|
||||
another function invocation is specified to synchronize with it,
|
||||
and if it is not a memory allocation or deallocation function
|
||||
or lock-free atomic modify-write operation ([[atomics.order]](atomics.order "32.5.4 Order and consistency"))[.](#defns-5.sentence-1)
|
||||
|
||||
[*Note [2](#defns-note-2)*:
|
||||
|
||||
Implementations must ensure that internal synchronization
|
||||
inside standard library functions does not prevent forward progress
|
||||
when those functions are executed by threads of execution
|
||||
with weakly parallel forward progress guarantees[.](#defns-5.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Example [2](#defns-example-2)*: int x = 0;
|
||||
std::mutex m;void f() {int a[] = {1,2};
|
||||
std::for_each(std::execution::par_unseq, std::begin(a), std::end(a), [&](int) { std::lock_guard<mutex> guard(m); // incorrect: lock_guard constructor calls m.lock()++x; });}
|
||||
|
||||
The above program may result in two consecutive calls to m.lock() on the same thread of execution (which may deadlock),
|
||||
because the applications of the function object are not guaranteed
|
||||
to run on different threads of execution[.](#defns-5.sentence-3)
|
||||
|
||||
â *end example*]
|
||||
|
||||
### [26.3.2](#user) Requirements on user-provided function objects [[algorithms.parallel.user]](algorithms.parallel.user)
|
||||
|
||||
[1](#user-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L370)
|
||||
|
||||
Unless otherwise specified,
|
||||
invocable objects passed into parallel algorithms as objects of a type
|
||||
denoted by a template parameter namedPredicate,BinaryPredicate,Compare,UnaryOperation,BinaryOperation,BinaryOperation1,BinaryOperation2,BinaryDivideOp, or
|
||||
constrained by a concept that subsumes [regular_invocable](concept.regularinvocable#concept:regular_invocable "18.7.3 Concept regular_invocable [concept.regularinvocable]") and the operators used by the analogous overloads to these parallel algorithms
|
||||
that are formed by an invocation
|
||||
with the specified default predicate or operation (where applicable)
|
||||
shall not directly or indirectly modify objects via their arguments,
|
||||
nor shall they rely on the identity of the provided objects[.](#user-1.sentence-1)
|
||||
|
||||
### [26.3.3](#exec) Effect of execution policies on algorithm execution [[algorithms.parallel.exec]](algorithms.parallel.exec)
|
||||
|
||||
[1](#exec-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L391)
|
||||
|
||||
An execution policy template parameter describes
|
||||
the manner in which the execution of a parallel algorithm may be
|
||||
parallelized and the manner in which it applies the element access functions[.](#exec-1.sentence-1)
|
||||
|
||||
[2](#exec-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L396)
|
||||
|
||||
If an object is modified by an element access function,
|
||||
the algorithm will perform no other unsynchronized accesses to that object[.](#exec-2.sentence-1)
|
||||
|
||||
The modifying element access functions are those
|
||||
which are specified as modifying the object[.](#exec-2.sentence-2)
|
||||
|
||||
[*Note [1](#exec-note-1)*:
|
||||
|
||||
For example,swap,++,--,@=, and
|
||||
assignments
|
||||
modify the object[.](#exec-2.sentence-3)
|
||||
|
||||
For the assignment and @= operators, only the left argument is modified[.](#exec-2.sentence-4)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[3](#exec-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L412)
|
||||
|
||||
Unless otherwise stated, implementations may make arbitrary copies of elements
|
||||
(with type T) from sequences
|
||||
where is_trivially_copy_constructible_v<T> and is_trivially_destructible_v<T> are true[.](#exec-3.sentence-1)
|
||||
|
||||
[*Note [2](#exec-note-2)*:
|
||||
|
||||
This implies that user-supplied function objects cannot rely on
|
||||
object identity of arguments for such input sequences[.](#exec-3.sentence-2)
|
||||
|
||||
If object identity of the arguments to these function objects
|
||||
is important, a wrapping iterator
|
||||
that returns a non-copied implementation object
|
||||
such as reference_wrapper<T> ([[refwrap]](refwrap "22.10.6 Class template reference_wrapper")),
|
||||
or some equivalent solution, can be used[.](#exec-3.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[4](#exec-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L427)
|
||||
|
||||
The invocations of element access functions in parallel algorithms invoked with
|
||||
an execution policy object of type execution::sequenced_policy all occur
|
||||
in the calling thread of execution[.](#exec-4.sentence-1)
|
||||
|
||||
[*Note [3](#exec-note-3)*:
|
||||
|
||||
The invocations are not interleaved; see [[intro.execution]](intro.execution "6.10.1 Sequential execution")[.](#exec-4.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[5](#exec-5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L435)
|
||||
|
||||
The invocations of element access functions in parallel algorithms invoked with
|
||||
an execution policy object of type execution::unsequenced_policy are permitted to execute in an unordered fashion
|
||||
in the calling thread of execution,
|
||||
unsequenced with respect to one another in the calling thread of execution[.](#exec-5.sentence-1)
|
||||
|
||||
[*Note [4](#exec-note-4)*:
|
||||
|
||||
This means that multiple function object invocations
|
||||
can be interleaved on a single thread of execution,
|
||||
which overrides the usual guarantee from [[intro.execution]](intro.execution "6.10.1 Sequential execution") that function executions do not overlap with one another[.](#exec-5.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
The behavior of a program is undefined if
|
||||
it invokes a vectorization-unsafe standard library function
|
||||
from user code
|
||||
called from an execution::unsequenced_policy algorithm[.](#exec-5.sentence-3)
|
||||
|
||||
[*Note [5](#exec-note-5)*:
|
||||
|
||||
Because execution::unsequenced_policy allows
|
||||
the execution of element access functions
|
||||
to be interleaved on a single thread of execution,
|
||||
blocking synchronization, including the use of mutexes, risks deadlock[.](#exec-5.sentence-4)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[6](#exec-6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L458)
|
||||
|
||||
The invocations of element access functions in parallel algorithms invoked with
|
||||
an execution policy object of type execution::parallel_policy are permitted to execute either
|
||||
in the invoking thread of execution or
|
||||
in a thread of execution implicitly created by the library
|
||||
to support parallel algorithm execution[.](#exec-6.sentence-1)
|
||||
|
||||
If the threads of execution created by thread ([[thread.thread.class]](thread.thread.class "32.4.3 Class thread"))
|
||||
or jthread ([[thread.jthread.class]](thread.jthread.class "32.4.4 Class jthread"))
|
||||
provide concurrent forward progress guarantees ([[intro.progress]](intro.progress "6.10.2.3 Forward progress")),
|
||||
then a thread of execution implicitly created by the library will provide
|
||||
parallel forward progress guarantees;
|
||||
otherwise, the provided forward progress guarantee isimplementation-defined[.](#exec-6.sentence-2)
|
||||
|
||||
Any such invocations executing in the same thread of execution
|
||||
are indeterminately sequenced with respect to each other[.](#exec-6.sentence-3)
|
||||
|
||||
[*Note [6](#exec-note-6)*:
|
||||
|
||||
It is the caller's responsibility to ensure
|
||||
that the invocation does not introduce data races or deadlocks[.](#exec-6.sentence-4)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Example [1](#exec-example-1)*: int a[] = {0,1};
|
||||
std::vector<int> v;
|
||||
std::for_each(std::execution::par, std::begin(a), std::end(a), [&](int i) { v.push_back(i*2+1); // incorrect: data race});
|
||||
|
||||
The program above has a data race because of the unsynchronized access to the
|
||||
container v[.](#exec-6.sentence-5)
|
||||
|
||||
â *end example*]
|
||||
|
||||
[*Example [2](#exec-example-2)*: std::atomic<int> x{0};int a[] = {1,2};
|
||||
std::for_each(std::execution::par, std::begin(a), std::end(a), [&](int) { x.fetch_add(1, std::memory_order::relaxed); // spin wait for another iteration to change the value of xwhile (x.load(std::memory_order::relaxed) == 1) { } // incorrect: assumes execution order});
|
||||
|
||||
The above example depends on the order of execution of the iterations, and
|
||||
will not terminate if both iterations are executed sequentially
|
||||
on the same thread of execution[.](#exec-6.sentence-6)
|
||||
|
||||
â *end example*]
|
||||
|
||||
[*Example [3](#exec-example-3)*: int x = 0;
|
||||
std::mutex m;int a[] = {1,2};
|
||||
std::for_each(std::execution::par, std::begin(a), std::end(a), [&](int) { std::lock_guard<mutex> guard(m); ++x;});
|
||||
|
||||
The above example synchronizes access to object x ensuring that it is incremented correctly[.](#exec-6.sentence-7)
|
||||
|
||||
â *end example*]
|
||||
|
||||
[7](#exec-7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L518)
|
||||
|
||||
The invocations of element access functions in parallel algorithms invoked with
|
||||
an execution policy object of type execution::parallel_unsequenced_policy are
|
||||
permitted to execute
|
||||
in an unordered fashion in unspecified threads of execution, and
|
||||
unsequenced with respect to one another within each thread of execution[.](#exec-7.sentence-1)
|
||||
|
||||
These threads of execution are
|
||||
either the invoking thread of execution
|
||||
or threads of execution implicitly created by the library;
|
||||
the latter will provide weakly parallel forward progress guarantees[.](#exec-7.sentence-2)
|
||||
|
||||
[*Note [7](#exec-note-7)*:
|
||||
|
||||
This means that multiple function object invocations can be interleaved
|
||||
on a single thread of execution,
|
||||
which overrides the usual guarantee from [[intro.execution]](intro.execution "6.10.1 Sequential execution") that function executions do not overlap with one another[.](#exec-7.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
The behavior of a program is undefined if
|
||||
it invokes a vectorization-unsafe standard library function
|
||||
from user code
|
||||
called from an execution::parallel_unsequenced_policy algorithm[.](#exec-7.sentence-4)
|
||||
|
||||
[*Note [8](#exec-note-8)*:
|
||||
|
||||
Because execution::parallel_unsequenced_policy allows
|
||||
the execution of element access functions
|
||||
to be interleaved on a single thread of execution,
|
||||
blocking synchronization, including the use of mutexes, risks deadlock[.](#exec-7.sentence-5)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[8](#exec-8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L545)
|
||||
|
||||
[*Note [9](#exec-note-9)*:
|
||||
|
||||
The semantics of invocation withexecution::unsequenced_policy,execution::parallel_policy, orexecution::parallel_unsequenced_policy allow the implementation to fall back to sequential execution
|
||||
if the system cannot parallelize an algorithm invocation,
|
||||
e.g., due to lack of resources[.](#exec-8.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[9](#exec-9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L556)
|
||||
|
||||
If an invocation of a parallel algorithm uses threads of execution
|
||||
implicitly created by the library,
|
||||
then the invoking thread of execution will either
|
||||
|
||||
- [(9.1)](#exec-9.1)
|
||||
|
||||
temporarily block
|
||||
with forward progress guarantee delegation ([[intro.progress]](intro.progress "6.10.2.3 Forward progress"))
|
||||
on the completion of these library-managed threads of execution, or
|
||||
|
||||
- [(9.2)](#exec-9.2)
|
||||
|
||||
eventually execute an element access function;
|
||||
|
||||
the thread of execution will continue to do so until the algorithm is finished[.](#exec-9.sentence-1)
|
||||
|
||||
[*Note [10](#exec-note-10)*:
|
||||
|
||||
In blocking with forward progress guarantee delegation in this context,
|
||||
a thread of execution created by the library
|
||||
is considered to have finished execution
|
||||
as soon as it has finished the execution
|
||||
of the particular element access function
|
||||
that the invoking thread of execution logically depends on[.](#exec-9.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[10](#exec-10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L578)
|
||||
|
||||
The semantics of parallel algorithms invoked with an execution policy object ofimplementation-defined type
|
||||
are implementation-defined[.](#exec-10.sentence-1)
|
||||
|
||||
### [26.3.4](#exceptions) Parallel algorithm exceptions [[algorithms.parallel.exceptions]](algorithms.parallel.exceptions)
|
||||
|
||||
[1](#exceptions-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L586)
|
||||
|
||||
During the execution of a parallel algorithm,
|
||||
if temporary memory resources are required for parallelization
|
||||
and none are available, the algorithm throws a bad_alloc exception[.](#exceptions-1.sentence-1)
|
||||
|
||||
[2](#exceptions-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L591)
|
||||
|
||||
During the execution of a parallel algorithm,
|
||||
if the invocation of an element access function exits via an uncaught exception,
|
||||
the behavior is determined by the execution policy[.](#exceptions-2.sentence-1)
|
||||
|
||||
### [26.3.5](#overloads) Parallel algorithm overloads [[algorithms.parallel.overloads]](algorithms.parallel.overloads)
|
||||
|
||||
[1](#overloads-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L598)
|
||||
|
||||
Parallel algorithms are algorithm overloads[.](#overloads-1.sentence-1)
|
||||
|
||||
Each parallel algorithm overload
|
||||
has an additional function parameter P of type T&& as the first function parameter,
|
||||
where T is the execution policy template parameter[.](#overloads-1.sentence-2)
|
||||
|
||||
[*Note [1](#overloads-note-1)*:
|
||||
|
||||
Not all algorithms have parallel algorithm overloads[.](#overloads-1.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[2](#overloads-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L608)
|
||||
|
||||
Unless otherwise specified,
|
||||
the semantics of calling a parallel algorithm overload are identical to
|
||||
calling the corresponding algorithm overload without the parameter P,
|
||||
using all but the first argument[.](#overloads-2.sentence-1)
|
||||
|
||||
[3](#overloads-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L614)
|
||||
|
||||
Unless otherwise specified,
|
||||
the complexity requirements of a parallel algorithm overload
|
||||
are relaxed from the complexity requirements of the corresponding overload
|
||||
without the parameter P as follows:
|
||||
when the guarantee says âat most *expr*â or
|
||||
âexactly *expr*â
|
||||
and does not specify the number of assignments or swaps, and*expr* is not already expressed with O() notation,
|
||||
the complexity of the algorithm shall be O(expr)[.](#overloads-3.sentence-1)
|
||||
|
||||
[4](#overloads-4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L626)
|
||||
|
||||
A parallel algorithm
|
||||
with a template parameter named ExecutionPolicy shall not participate in overload resolution unless
|
||||
that template parameter satisfies [*execution-policy*](#concept:execution-policy "26.3.1 Preamble [algorithms.parallel.defns]")[.](#overloads-4.sentence-1)
|
||||
|
||||
### [26.3.6](#execpol) Execution policies [[execpol]](execpol)
|
||||
|
||||
#### [26.3.6.1](#execpol.general) General [[execpol.general]](execpol.general)
|
||||
|
||||
[1](#execpol.general-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L636)
|
||||
|
||||
Subclause [[execpol]](#execpol "26.3.6 Execution policies") describes classes that are [*execution policy*](#def:execution_policy "26.3.6.1 General [execpol.general]") types[.](#execpol.general-1.sentence-1)
|
||||
|
||||
An
|
||||
object of an execution policy type indicates the kinds of parallelism allowed
|
||||
in the execution of an algorithm and expresses the consequent requirements on
|
||||
the element access functions[.](#execpol.general-1.sentence-2)
|
||||
|
||||
Execution policy types are declared in header [<execution>](execution.syn#header:%3cexecution%3e "33.4 Header <execution> synopsis [execution.syn]")[.](#execpol.general-1.sentence-3)
|
||||
|
||||
[*Example [1](#execpol.general-example-1)*: using namespace std;
|
||||
vector<int> v = /* ... */;
|
||||
|
||||
// standard sequential sort sort(v.begin(), v.end());
|
||||
|
||||
// explicitly sequential sort sort(execution::seq, v.begin(), v.end());
|
||||
|
||||
// permitting parallel execution sort(execution::par, v.begin(), v.end());
|
||||
|
||||
// permitting vectorization as well sort(execution::par_unseq, v.begin(), v.end()); â *end example*]
|
||||
|
||||
[*Note [1](#execpol.general-note-1)*:
|
||||
|
||||
Implementations can provide additional execution policies
|
||||
to those described in this document as extensions
|
||||
to address parallel architectures that require idiosyncratic
|
||||
parameters for efficient execution[.](#execpol.general-1.sentence-4)
|
||||
|
||||
â *end note*]
|
||||
|
||||
#### [26.3.6.2](#execpol.type) Execution policy type trait [[execpol.type]](execpol.type)
|
||||
|
||||
[ð](#lib:is_execution_policy)
|
||||
|
||||
`template<class T> struct is_execution_policy;
|
||||
`
|
||||
|
||||
[1](#execpol.type-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L675)
|
||||
|
||||
is_execution_policy can be used to detect execution policies for the
|
||||
purpose of excluding function signatures from otherwise ambiguous overload
|
||||
resolution participation[.](#execpol.type-1.sentence-1)
|
||||
|
||||
[2](#execpol.type-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L680)
|
||||
|
||||
is_execution_policy<T> is a *Cpp17UnaryTypeTrait* with a
|
||||
base characteristic of true_type if T is the type of a standard
|
||||
or implementation-defined
|
||||
execution policy, otherwise false_type[.](#execpol.type-2.sentence-1)
|
||||
|
||||
[*Note [1](#execpol.type-note-1)*:
|
||||
|
||||
This provision reserves the privilege of creating non-standard execution
|
||||
policies to the library implementation[.](#execpol.type-2.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[3](#execpol.type-3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L691)
|
||||
|
||||
The behavior of a program that adds specializations foris_execution_policy is undefined[.](#execpol.type-3.sentence-1)
|
||||
|
||||
#### [26.3.6.3](#execpol.seq) Sequenced execution policy [[execpol.seq]](execpol.seq)
|
||||
|
||||
[ð](#lib:execution::sequenced_policy)
|
||||
|
||||
`class execution::sequenced_policy { unspecified };
|
||||
`
|
||||
|
||||
[1](#execpol.seq-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L704)
|
||||
|
||||
The class execution::sequenced_policy is an execution policy type used
|
||||
as a unique type to disambiguate parallel algorithm overloading and require
|
||||
that a parallel algorithm's execution may not be parallelized[.](#execpol.seq-1.sentence-1)
|
||||
|
||||
[2](#execpol.seq-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L709)
|
||||
|
||||
During the execution of a parallel algorithm with
|
||||
the execution::sequenced_policy policy,
|
||||
if the invocation of an element access function exits via an exception,terminate is invoked ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#execpol.seq-2.sentence-1)
|
||||
|
||||
#### [26.3.6.4](#execpol.par) Parallel execution policy [[execpol.par]](execpol.par)
|
||||
|
||||
[ð](#lib:execution::parallel_policy)
|
||||
|
||||
`class execution::parallel_policy { unspecified };
|
||||
`
|
||||
|
||||
[1](#execpol.par-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L724)
|
||||
|
||||
The class execution::parallel_policy is an execution policy type used as
|
||||
a unique type to disambiguate parallel algorithm overloading and indicate that
|
||||
a parallel algorithm's execution may be parallelized[.](#execpol.par-1.sentence-1)
|
||||
|
||||
[2](#execpol.par-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L729)
|
||||
|
||||
During the execution of a parallel algorithm with
|
||||
the execution::parallel_policy policy,
|
||||
if the invocation of an element access function exits via an exception,terminate is invoked ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#execpol.par-2.sentence-1)
|
||||
|
||||
#### [26.3.6.5](#execpol.parunseq) Parallel and unsequenced execution policy [[execpol.parunseq]](execpol.parunseq)
|
||||
|
||||
[ð](#lib:execution::parallel_unsequenced_policy)
|
||||
|
||||
`class execution::parallel_unsequenced_policy { unspecified };
|
||||
`
|
||||
|
||||
[1](#execpol.parunseq-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L744)
|
||||
|
||||
The class execution::parallel_unsequenced_policy is an execution policy type
|
||||
used as a unique type to disambiguate parallel algorithm overloading and
|
||||
indicate that a parallel algorithm's execution may be parallelized and
|
||||
vectorized[.](#execpol.parunseq-1.sentence-1)
|
||||
|
||||
[2](#execpol.parunseq-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L750)
|
||||
|
||||
During the execution of a parallel algorithm with
|
||||
the execution::parallel_unsequenced_policy policy,
|
||||
if the invocation of an element access function exits via an exception,terminate is invoked ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#execpol.parunseq-2.sentence-1)
|
||||
|
||||
#### [26.3.6.6](#execpol.unseq) Unsequenced execution policy [[execpol.unseq]](execpol.unseq)
|
||||
|
||||
[ð](#lib:execution::unsequenced_policy)
|
||||
|
||||
`class execution::unsequenced_policy { unspecified };
|
||||
`
|
||||
|
||||
[1](#execpol.unseq-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L765)
|
||||
|
||||
The class unsequenced_policy is an execution policy type
|
||||
used as a unique type to disambiguate parallel algorithm overloading and
|
||||
indicate that a parallel algorithm's execution may be vectorized,
|
||||
e.g., executed on a single thread using instructions
|
||||
that operate on multiple data items[.](#execpol.unseq-1.sentence-1)
|
||||
|
||||
[2](#execpol.unseq-2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L772)
|
||||
|
||||
During the execution of a parallel algorithm with
|
||||
the execution::unsequenced_policy policy,
|
||||
if the invocation of an element access function exits via an exception,terminate is invoked ([[except.terminate]](except.terminate "14.6.2 The std::terminate function"))[.](#execpol.unseq-2.sentence-1)
|
||||
|
||||
#### [26.3.6.7](#execpol.objects) Execution policy objects [[execpol.objects]](execpol.objects)
|
||||
|
||||
[ð](#lib:seq)
|
||||
|
||||
`inline constexpr execution::sequenced_policy execution::seq{ unspecified };
|
||||
inline constexpr execution::parallel_policy execution::par{ unspecified };
|
||||
inline constexpr execution::parallel_unsequenced_policy execution::par_unseq{ unspecified };
|
||||
inline constexpr execution::unsequenced_policy execution::unseq{ unspecified };
|
||||
`
|
||||
|
||||
[1](#execpol.objects-1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L795)
|
||||
|
||||
The header [<execution>](execution.syn#header:%3cexecution%3e "33.4 Header <execution> synopsis [execution.syn]") declares global objects associated with each type of execution policy[.](#execpol.objects-1.sentence-1)
|
||||
107
cppdraft/algorithms/parallel/defns.md
Normal file
107
cppdraft/algorithms/parallel/defns.md
Normal file
@@ -0,0 +1,107 @@
|
||||
[algorithms.parallel.defns]
|
||||
|
||||
# 26 Algorithms library [[algorithms]](./#algorithms)
|
||||
|
||||
## 26.3 Parallel algorithms [[algorithms.parallel]](algorithms.parallel#defns)
|
||||
|
||||
### 26.3.1 Preamble [algorithms.parallel.defns]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L287)
|
||||
|
||||
Subclause [[algorithms.parallel]](algorithms.parallel "26.3 Parallel algorithms") describes components that C++ programs may use
|
||||
to perform operations on containers and other sequences in parallel[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L291)
|
||||
|
||||
A [*parallel algorithm*](#def:parallel_algorithm "26.3.1 Preamble [algorithms.parallel.defns]") is a function template listed in this document
|
||||
with a template parameter named ExecutionPolicy or constrained by the following exposition-only concept:template<class Ep>concept [*execution-policy*](#concept:execution-policy "26.3.1 Preamble [algorithms.parallel.defns]") = is_execution_policy_v<remove_cvref_t<Ep>>; // *exposition only*
|
||||
|
||||
Such a template parameter is termed an [*execution policy template parameter*](#def:template_parameter,execution_policy "26.3.1 Preamble [algorithms.parallel.defns]")[.](#2.sentence-2)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L301)
|
||||
|
||||
A parallel algorithm accesses objects indirectly accessible via its arguments
|
||||
by invoking the following functions:
|
||||
|
||||
- [(3.1)](#3.1)
|
||||
|
||||
All operations of the categories of the iterators, sentinels, or mdspan types
|
||||
that the algorithm is instantiated with[.](#3.1.sentence-1)
|
||||
|
||||
- [(3.2)](#3.2)
|
||||
|
||||
Operations on those sequence elements that are required by its specification[.](#3.2.sentence-1)
|
||||
|
||||
- [(3.3)](#3.3)
|
||||
|
||||
User-provided invocable objects
|
||||
to be applied during the execution of the algorithm,
|
||||
if required by the specification[.](#3.3.sentence-1)
|
||||
|
||||
- [(3.4)](#3.4)
|
||||
|
||||
Operations on those invocable objects required by the specification[.](#3.4.sentence-1)
|
||||
[*Note [1](#note-1)*:
|
||||
See [[algorithms.requirements]](algorithms.requirements "26.2 Algorithms requirements")[.](#3.4.sentence-2)
|
||||
â *end note*]
|
||||
|
||||
These functions are herein called [*element access functions*](#def:element_access_functions "26.3.1 Preamble [algorithms.parallel.defns]")[.](#3.sentence-2)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L322)
|
||||
|
||||
[*Example [1](#example-1)*:
|
||||
|
||||
The sort function may invoke the following element access functions:
|
||||
|
||||
- [(4.1)](#4.1)
|
||||
|
||||
Operations of the random-access iterator of the actual template argument
|
||||
(as per [[random.access.iterators]](random.access.iterators "24.3.5.7 Random access iterators")),
|
||||
as implied by the name of the template parameter RandomAccessIterator[.](#4.1.sentence-1)
|
||||
|
||||
- [(4.2)](#4.2)
|
||||
|
||||
The swap function on the elements of the sequence
|
||||
(as per the preconditions specified in [[sort]](sort "26.8.2.1 sort"))[.](#4.2.sentence-1)
|
||||
|
||||
- [(4.3)](#4.3)
|
||||
|
||||
The user-provided Compare function object[.](#4.3.sentence-1)
|
||||
|
||||
â *end example*]
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L338)
|
||||
|
||||
A standard library function is [*vectorization-unsafe*](#def:vectorization-unsafe "26.3.1 Preamble [algorithms.parallel.defns]") if it is specified to synchronize with another function invocation, or
|
||||
another function invocation is specified to synchronize with it,
|
||||
and if it is not a memory allocation or deallocation function
|
||||
or lock-free atomic modify-write operation ([[atomics.order]](atomics.order "32.5.4 Order and consistency"))[.](#5.sentence-1)
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
Implementations must ensure that internal synchronization
|
||||
inside standard library functions does not prevent forward progress
|
||||
when those functions are executed by threads of execution
|
||||
with weakly parallel forward progress guarantees[.](#5.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Example [2](#example-2)*: int x = 0;
|
||||
std::mutex m;void f() {int a[] = {1,2};
|
||||
std::for_each(std::execution::par_unseq, std::begin(a), std::end(a), [&](int) { std::lock_guard<mutex> guard(m); // incorrect: lock_guard constructor calls m.lock()++x; });}
|
||||
|
||||
The above program may result in two consecutive calls to m.lock() on the same thread of execution (which may deadlock),
|
||||
because the applications of the function object are not guaranteed
|
||||
to run on different threads of execution[.](#5.sentence-3)
|
||||
|
||||
â *end example*]
|
||||
23
cppdraft/algorithms/parallel/exceptions.md
Normal file
23
cppdraft/algorithms/parallel/exceptions.md
Normal file
@@ -0,0 +1,23 @@
|
||||
[algorithms.parallel.exceptions]
|
||||
|
||||
# 26 Algorithms library [[algorithms]](./#algorithms)
|
||||
|
||||
## 26.3 Parallel algorithms [[algorithms.parallel]](algorithms.parallel#exceptions)
|
||||
|
||||
### 26.3.4 Parallel algorithm exceptions [algorithms.parallel.exceptions]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L586)
|
||||
|
||||
During the execution of a parallel algorithm,
|
||||
if temporary memory resources are required for parallelization
|
||||
and none are available, the algorithm throws a bad_alloc exception[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L591)
|
||||
|
||||
During the execution of a parallel algorithm,
|
||||
if the invocation of an element access function exits via an uncaught exception,
|
||||
the behavior is determined by the execution policy[.](#2.sentence-1)
|
||||
241
cppdraft/algorithms/parallel/exec.md
Normal file
241
cppdraft/algorithms/parallel/exec.md
Normal file
@@ -0,0 +1,241 @@
|
||||
[algorithms.parallel.exec]
|
||||
|
||||
# 26 Algorithms library [[algorithms]](./#algorithms)
|
||||
|
||||
## 26.3 Parallel algorithms [[algorithms.parallel]](algorithms.parallel#exec)
|
||||
|
||||
### 26.3.3 Effect of execution policies on algorithm execution [algorithms.parallel.exec]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L391)
|
||||
|
||||
An execution policy template parameter describes
|
||||
the manner in which the execution of a parallel algorithm may be
|
||||
parallelized and the manner in which it applies the element access functions[.](#1.sentence-1)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L396)
|
||||
|
||||
If an object is modified by an element access function,
|
||||
the algorithm will perform no other unsynchronized accesses to that object[.](#2.sentence-1)
|
||||
|
||||
The modifying element access functions are those
|
||||
which are specified as modifying the object[.](#2.sentence-2)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
For example,swap,++,--,@=, and
|
||||
assignments
|
||||
modify the object[.](#2.sentence-3)
|
||||
|
||||
For the assignment and @= operators, only the left argument is modified[.](#2.sentence-4)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L412)
|
||||
|
||||
Unless otherwise stated, implementations may make arbitrary copies of elements
|
||||
(with type T) from sequences
|
||||
where is_trivially_copy_constructible_v<T> and is_trivially_destructible_v<T> are true[.](#3.sentence-1)
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
This implies that user-supplied function objects cannot rely on
|
||||
object identity of arguments for such input sequences[.](#3.sentence-2)
|
||||
|
||||
If object identity of the arguments to these function objects
|
||||
is important, a wrapping iterator
|
||||
that returns a non-copied implementation object
|
||||
such as reference_wrapper<T> ([[refwrap]](refwrap "22.10.6 Class template reference_wrapper")),
|
||||
or some equivalent solution, can be used[.](#3.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L427)
|
||||
|
||||
The invocations of element access functions in parallel algorithms invoked with
|
||||
an execution policy object of type execution::sequenced_policy all occur
|
||||
in the calling thread of execution[.](#4.sentence-1)
|
||||
|
||||
[*Note [3](#note-3)*:
|
||||
|
||||
The invocations are not interleaved; see [[intro.execution]](intro.execution "6.10.1 Sequential execution")[.](#4.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L435)
|
||||
|
||||
The invocations of element access functions in parallel algorithms invoked with
|
||||
an execution policy object of type execution::unsequenced_policy are permitted to execute in an unordered fashion
|
||||
in the calling thread of execution,
|
||||
unsequenced with respect to one another in the calling thread of execution[.](#5.sentence-1)
|
||||
|
||||
[*Note [4](#note-4)*:
|
||||
|
||||
This means that multiple function object invocations
|
||||
can be interleaved on a single thread of execution,
|
||||
which overrides the usual guarantee from [[intro.execution]](intro.execution "6.10.1 Sequential execution") that function executions do not overlap with one another[.](#5.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
The behavior of a program is undefined if
|
||||
it invokes a vectorization-unsafe standard library function
|
||||
from user code
|
||||
called from an execution::unsequenced_policy algorithm[.](#5.sentence-3)
|
||||
|
||||
[*Note [5](#note-5)*:
|
||||
|
||||
Because execution::unsequenced_policy allows
|
||||
the execution of element access functions
|
||||
to be interleaved on a single thread of execution,
|
||||
blocking synchronization, including the use of mutexes, risks deadlock[.](#5.sentence-4)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L458)
|
||||
|
||||
The invocations of element access functions in parallel algorithms invoked with
|
||||
an execution policy object of type execution::parallel_policy are permitted to execute either
|
||||
in the invoking thread of execution or
|
||||
in a thread of execution implicitly created by the library
|
||||
to support parallel algorithm execution[.](#6.sentence-1)
|
||||
|
||||
If the threads of execution created by thread ([[thread.thread.class]](thread.thread.class "32.4.3 Class thread"))
|
||||
or jthread ([[thread.jthread.class]](thread.jthread.class "32.4.4 Class jthread"))
|
||||
provide concurrent forward progress guarantees ([[intro.progress]](intro.progress "6.10.2.3 Forward progress")),
|
||||
then a thread of execution implicitly created by the library will provide
|
||||
parallel forward progress guarantees;
|
||||
otherwise, the provided forward progress guarantee isimplementation-defined[.](#6.sentence-2)
|
||||
|
||||
Any such invocations executing in the same thread of execution
|
||||
are indeterminately sequenced with respect to each other[.](#6.sentence-3)
|
||||
|
||||
[*Note [6](#note-6)*:
|
||||
|
||||
It is the caller's responsibility to ensure
|
||||
that the invocation does not introduce data races or deadlocks[.](#6.sentence-4)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[*Example [1](#example-1)*: int a[] = {0,1};
|
||||
std::vector<int> v;
|
||||
std::for_each(std::execution::par, std::begin(a), std::end(a), [&](int i) { v.push_back(i*2+1); // incorrect: data race});
|
||||
|
||||
The program above has a data race because of the unsynchronized access to the
|
||||
container v[.](#6.sentence-5)
|
||||
|
||||
â *end example*]
|
||||
|
||||
[*Example [2](#example-2)*: std::atomic<int> x{0};int a[] = {1,2};
|
||||
std::for_each(std::execution::par, std::begin(a), std::end(a), [&](int) { x.fetch_add(1, std::memory_order::relaxed); // spin wait for another iteration to change the value of xwhile (x.load(std::memory_order::relaxed) == 1) { } // incorrect: assumes execution order});
|
||||
|
||||
The above example depends on the order of execution of the iterations, and
|
||||
will not terminate if both iterations are executed sequentially
|
||||
on the same thread of execution[.](#6.sentence-6)
|
||||
|
||||
â *end example*]
|
||||
|
||||
[*Example [3](#example-3)*: int x = 0;
|
||||
std::mutex m;int a[] = {1,2};
|
||||
std::for_each(std::execution::par, std::begin(a), std::end(a), [&](int) { std::lock_guard<mutex> guard(m); ++x;});
|
||||
|
||||
The above example synchronizes access to object x ensuring that it is incremented correctly[.](#6.sentence-7)
|
||||
|
||||
â *end example*]
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L518)
|
||||
|
||||
The invocations of element access functions in parallel algorithms invoked with
|
||||
an execution policy object of type execution::parallel_unsequenced_policy are
|
||||
permitted to execute
|
||||
in an unordered fashion in unspecified threads of execution, and
|
||||
unsequenced with respect to one another within each thread of execution[.](#7.sentence-1)
|
||||
|
||||
These threads of execution are
|
||||
either the invoking thread of execution
|
||||
or threads of execution implicitly created by the library;
|
||||
the latter will provide weakly parallel forward progress guarantees[.](#7.sentence-2)
|
||||
|
||||
[*Note [7](#note-7)*:
|
||||
|
||||
This means that multiple function object invocations can be interleaved
|
||||
on a single thread of execution,
|
||||
which overrides the usual guarantee from [[intro.execution]](intro.execution "6.10.1 Sequential execution") that function executions do not overlap with one another[.](#7.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
The behavior of a program is undefined if
|
||||
it invokes a vectorization-unsafe standard library function
|
||||
from user code
|
||||
called from an execution::parallel_unsequenced_policy algorithm[.](#7.sentence-4)
|
||||
|
||||
[*Note [8](#note-8)*:
|
||||
|
||||
Because execution::parallel_unsequenced_policy allows
|
||||
the execution of element access functions
|
||||
to be interleaved on a single thread of execution,
|
||||
blocking synchronization, including the use of mutexes, risks deadlock[.](#7.sentence-5)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L545)
|
||||
|
||||
[*Note [9](#note-9)*:
|
||||
|
||||
The semantics of invocation withexecution::unsequenced_policy,execution::parallel_policy, orexecution::parallel_unsequenced_policy allow the implementation to fall back to sequential execution
|
||||
if the system cannot parallelize an algorithm invocation,
|
||||
e.g., due to lack of resources[.](#8.sentence-1)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L556)
|
||||
|
||||
If an invocation of a parallel algorithm uses threads of execution
|
||||
implicitly created by the library,
|
||||
then the invoking thread of execution will either
|
||||
|
||||
- [(9.1)](#9.1)
|
||||
|
||||
temporarily block
|
||||
with forward progress guarantee delegation ([[intro.progress]](intro.progress "6.10.2.3 Forward progress"))
|
||||
on the completion of these library-managed threads of execution, or
|
||||
|
||||
- [(9.2)](#9.2)
|
||||
|
||||
eventually execute an element access function;
|
||||
|
||||
the thread of execution will continue to do so until the algorithm is finished[.](#9.sentence-1)
|
||||
|
||||
[*Note [10](#note-10)*:
|
||||
|
||||
In blocking with forward progress guarantee delegation in this context,
|
||||
a thread of execution created by the library
|
||||
is considered to have finished execution
|
||||
as soon as it has finished the execution
|
||||
of the particular element access function
|
||||
that the invoking thread of execution logically depends on[.](#9.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[10](#10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L578)
|
||||
|
||||
The semantics of parallel algorithms invoked with an execution policy object ofimplementation-defined type
|
||||
are implementation-defined[.](#10.sentence-1)
|
||||
53
cppdraft/algorithms/parallel/overloads.md
Normal file
53
cppdraft/algorithms/parallel/overloads.md
Normal file
@@ -0,0 +1,53 @@
|
||||
[algorithms.parallel.overloads]
|
||||
|
||||
# 26 Algorithms library [[algorithms]](./#algorithms)
|
||||
|
||||
## 26.3 Parallel algorithms [[algorithms.parallel]](algorithms.parallel#overloads)
|
||||
|
||||
### 26.3.5 Parallel algorithm overloads [algorithms.parallel.overloads]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L598)
|
||||
|
||||
Parallel algorithms are algorithm overloads[.](#1.sentence-1)
|
||||
|
||||
Each parallel algorithm overload
|
||||
has an additional function parameter P of type T&& as the first function parameter,
|
||||
where T is the execution policy template parameter[.](#1.sentence-2)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
Not all algorithms have parallel algorithm overloads[.](#1.sentence-3)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L608)
|
||||
|
||||
Unless otherwise specified,
|
||||
the semantics of calling a parallel algorithm overload are identical to
|
||||
calling the corresponding algorithm overload without the parameter P,
|
||||
using all but the first argument[.](#2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L614)
|
||||
|
||||
Unless otherwise specified,
|
||||
the complexity requirements of a parallel algorithm overload
|
||||
are relaxed from the complexity requirements of the corresponding overload
|
||||
without the parameter P as follows:
|
||||
when the guarantee says âat most *expr*â or
|
||||
âexactly *expr*â
|
||||
and does not specify the number of assignments or swaps, and*expr* is not already expressed with O() notation,
|
||||
the complexity of the algorithm shall be O(expr)[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L626)
|
||||
|
||||
A parallel algorithm
|
||||
with a template parameter named ExecutionPolicy shall not participate in overload resolution unless
|
||||
that template parameter satisfies [*execution-policy*](algorithms.parallel.defns#concept:execution-policy "26.3.1 Preamble [algorithms.parallel.defns]")[.](#4.sentence-1)
|
||||
20
cppdraft/algorithms/parallel/user.md
Normal file
20
cppdraft/algorithms/parallel/user.md
Normal file
@@ -0,0 +1,20 @@
|
||||
[algorithms.parallel.user]
|
||||
|
||||
# 26 Algorithms library [[algorithms]](./#algorithms)
|
||||
|
||||
## 26.3 Parallel algorithms [[algorithms.parallel]](algorithms.parallel#user)
|
||||
|
||||
### 26.3.2 Requirements on user-provided function objects [algorithms.parallel.user]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L370)
|
||||
|
||||
Unless otherwise specified,
|
||||
invocable objects passed into parallel algorithms as objects of a type
|
||||
denoted by a template parameter namedPredicate,BinaryPredicate,Compare,UnaryOperation,BinaryOperation,BinaryOperation1,BinaryOperation2,BinaryDivideOp, or
|
||||
constrained by a concept that subsumes [regular_invocable](concept.regularinvocable#concept:regular_invocable "18.7.3 Concept regular_invocable [concept.regularinvocable]") and the operators used by the analogous overloads to these parallel algorithms
|
||||
that are formed by an invocation
|
||||
with the specified default predicate or operation (where applicable)
|
||||
shall not directly or indirectly modify objects via their arguments,
|
||||
nor shall they rely on the identity of the provided objects[.](#1.sentence-1)
|
||||
271
cppdraft/algorithms/requirements.md
Normal file
271
cppdraft/algorithms/requirements.md
Normal file
@@ -0,0 +1,271 @@
|
||||
[algorithms.requirements]
|
||||
|
||||
# 26 Algorithms library [[algorithms]](./#algorithms)
|
||||
|
||||
## 26.2 Algorithms requirements [algorithms.requirements]
|
||||
|
||||
[1](#1)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L32)
|
||||
|
||||
All of the algorithms
|
||||
are separated from the particular implementations of data structures and
|
||||
are parameterized by iterator types[.](#1.sentence-1)
|
||||
|
||||
Because of this, they can work with program-defined data structures,
|
||||
as long as these data structures have iterator types
|
||||
satisfying the assumptions on the algorithms[.](#1.sentence-2)
|
||||
|
||||
[2](#2)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L40)
|
||||
|
||||
The entities defined in the std::ranges namespace in this Clause and
|
||||
specified as function templates are
|
||||
algorithm function objects ([[alg.func.obj]](alg.func.obj "16.3.3.4 Algorithm function objects"))[.](#2.sentence-1)
|
||||
|
||||
[3](#3)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L45)
|
||||
|
||||
For purposes of determining the existence of data races,
|
||||
algorithms shall not modify objects referenced through an iterator argument
|
||||
unless the specification requires such modification[.](#3.sentence-1)
|
||||
|
||||
[4](#4)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L50)
|
||||
|
||||
Throughout this Clause, where the template parameters are not constrained,
|
||||
the names of template parameters are used to express type requirements[.](#4.sentence-1)
|
||||
|
||||
- [(4.1)](#4.1)
|
||||
|
||||
If an algorithm's *Effects* element specifies
|
||||
that a value pointed to by any iterator passed as an argument is modified,
|
||||
then the type of that argument shall meet
|
||||
the requirements of a mutable iterator ([[iterator.requirements]](iterator.requirements "24.3 Iterator requirements"))[.](#4.1.sentence-1)
|
||||
|
||||
- [(4.2)](#4.2)
|
||||
|
||||
If an algorithm's template parameter is named InputIterator, InputIterator1, or InputIterator2,
|
||||
the template argument shall meet the [*Cpp17InputIterator*](input.iterators#:Cpp17InputIterator "24.3.5.3 Input iterators [input.iterators]") requirements ([[input.iterators]](input.iterators "24.3.5.3 Input iterators"))[.](#4.2.sentence-1)
|
||||
|
||||
- [(4.3)](#4.3)
|
||||
|
||||
If an algorithm's template parameter is named OutputIterator, OutputIterator1, or OutputIterator2,
|
||||
the template argument shall meet the [*Cpp17OutputIterator*](output.iterators#:Cpp17OutputIterator "24.3.5.4 Output iterators [output.iterators]") requirements ([[output.iterators]](output.iterators "24.3.5.4 Output iterators"))[.](#4.3.sentence-1)
|
||||
|
||||
- [(4.4)](#4.4)
|
||||
|
||||
If an algorithm's template parameter is named ForwardIterator, ForwardIterator1, ForwardIterator2, or NoThrowForwardIterator,
|
||||
the template argument shall meet the [*Cpp17ForwardIterator*](forward.iterators#:Cpp17ForwardIterator "24.3.5.5 Forward iterators [forward.iterators]") requirements ([[forward.iterators]](forward.iterators "24.3.5.5 Forward iterators"))
|
||||
if it is required to be a mutable iterator, or
|
||||
model [forward_iterator](iterator.concept.forward#concept:forward_iterator "24.3.4.11 Concept forward_iterator [iterator.concept.forward]") ([[iterator.concept.forward]](iterator.concept.forward "24.3.4.11 Concept forward_iterator")) otherwise[.](#4.4.sentence-1)
|
||||
|
||||
- [(4.5)](#4.5)
|
||||
|
||||
If an algorithm's template parameter is named NoThrowForwardIterator,
|
||||
the template argument
|
||||
is also required to have the property that no exceptions are thrown
|
||||
from increment, assignment, or comparison of, or
|
||||
indirection through, valid iterators[.](#4.5.sentence-1)
|
||||
|
||||
- [(4.6)](#4.6)
|
||||
|
||||
If an algorithm's template parameter is named BidirectionalIterator, BidirectionalIterator1, or BidirectionalIterator2,
|
||||
the template argument shall meet the [*Cpp17BidirectionalIterator*](bidirectional.iterators#:Cpp17BidirectionalIterator "24.3.5.6 Bidirectional iterators [bidirectional.iterators]") requirements ([[bidirectional.iterators]](bidirectional.iterators "24.3.5.6 Bidirectional iterators"))
|
||||
if it is required to be a mutable iterator, or model [bidirectional_iterator](iterator.concept.bidir#concept:bidirectional_iterator "24.3.4.12 Concept bidirectional_iterator [iterator.concept.bidir]") ([[iterator.concept.bidir]](iterator.concept.bidir "24.3.4.12 Concept bidirectional_iterator")) otherwise[.](#4.6.sentence-1)
|
||||
|
||||
- [(4.7)](#4.7)
|
||||
|
||||
If an algorithm's template parameter is named RandomAccessIterator, RandomAccessIterator1, or RandomAccessIterator2,
|
||||
the template argument shall meet the [*Cpp17RandomAccessIterator*](random.access.iterators#:Cpp17RandomAccessIterator "24.3.5.7 Random access iterators [random.access.iterators]") requirements ([[random.access.iterators]](random.access.iterators "24.3.5.7 Random access iterators"))
|
||||
if it is required to be a mutable iterator, or model [random_access_iterator](iterator.concept.random.access#concept:random_access_iterator "24.3.4.13 Concept random_access_iterator [iterator.concept.random.access]") ([[iterator.concept.random.access]](iterator.concept.random.access "24.3.4.13 Concept random_access_iterator")) otherwise[.](#4.7.sentence-1)
|
||||
|
||||
[*Note [1](#note-1)*:
|
||||
|
||||
These requirements do not affect iterator arguments that are constrained,
|
||||
for which iterator category and mutability requirements
|
||||
are expressed explicitly[.](#4.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[5](#5)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L115)
|
||||
|
||||
Both in-place and copying versions are provided for certain algorithms[.](#5.sentence-1)[200](#footnote-200 "The decision whether to include a copying version was usually based on complexity considerations. When the cost of doing the operation dominates the cost of copy, the copying version is not included. For example, sort_copy is not included because the cost of sorting is much more significant, and users can invoke copy followed by sort.")
|
||||
|
||||
When such a version is provided for *algorithm* it is called*algorithm_copy*[.](#5.sentence-2)
|
||||
|
||||
Algorithms that take predicates end with the suffix _if (which follows the suffix _copy)[.](#5.sentence-3)
|
||||
|
||||
[6](#6)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L131)
|
||||
|
||||
When not otherwise constrained, the Predicate parameter is used
|
||||
whenever an algorithm expects a function object ([[function.objects]](function.objects "22.10 Function objects")) that,
|
||||
when applied to the result of dereferencing the corresponding iterator,
|
||||
returns a value testable as true[.](#6.sentence-1)
|
||||
|
||||
If an algorithm takes Predicate pred as its argument andfirst as its iterator argument with value type T,
|
||||
the expression pred(*first) shall be well-formed and
|
||||
the type decltype(pred(*first)) shall model[*boolean-testable*](concept.booleantestable#concept:boolean-testable "18.5.2 Boolean testability [concept.booleantestable]") ([[concept.booleantestable]](concept.booleantestable "18.5.2 Boolean testability"))[.](#6.sentence-2)
|
||||
|
||||
The function object pred shall not apply any non-constant function
|
||||
through its argument[.](#6.sentence-3)
|
||||
|
||||
Given a glvalue u of type (possibly const) T that designates the same object as *first,pred(u) shall be a valid expression
|
||||
that is equal to pred(*first)[.](#6.sentence-4)
|
||||
|
||||
[7](#7)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L148)
|
||||
|
||||
When not otherwise constrained, the BinaryPredicate parameter is used
|
||||
whenever an algorithm expects a function object that, when applied
|
||||
to the result of dereferencing two corresponding iterators or
|
||||
to dereferencing an iterator and type T when T is part of the signature,
|
||||
returns a value testable as true[.](#7.sentence-1)
|
||||
|
||||
If an algorithm takes BinaryPredicate binary_pred as its argument andfirst1 and first2 as its iterator arguments
|
||||
with respective value types T1 and T2,
|
||||
the expression binary_pred(*first1, *first2) shall be well-formed and
|
||||
the type decltype(binary_pred(*first1, *first2)) shall model[*boolean-testable*](concept.booleantestable#concept:boolean-testable "18.5.2 Boolean testability [concept.booleantestable]")[.](#7.sentence-2)
|
||||
|
||||
Unless otherwise specified,BinaryPredicate always takes the first iterator's value_type as its first argument, that is, in those cases when T value is part of the signature,
|
||||
the expression binary_pred(*first1, value) shall be well-formed and
|
||||
the type decltype(binary_pred(*first1, value)) shall model[*boolean-testable*](concept.booleantestable#concept:boolean-testable "18.5.2 Boolean testability [concept.booleantestable]")[.](#7.sentence-3)
|
||||
|
||||
binary_pred shall not apply any non-constant function
|
||||
through any of its arguments[.](#7.sentence-4)
|
||||
|
||||
Given a glvalue u of type (possibly const) T1 that designates the same object as *first1, and
|
||||
a glvalue v of type (possibly const) T2 that designates the same object as *first2,binary_pred(u, *first2),binary_pred(*first1, v), andbinary_pred(u, v) shall each be a valid expression that is equal tobinary_pred(*first1, *first2), andbinary_pred(u, value) shall be a valid expression that is equal tobinary_pred(*first1, value)[.](#7.sentence-5)
|
||||
|
||||
[8](#8)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L183)
|
||||
|
||||
The parametersUnaryOperation,BinaryOperation,BinaryOperation1,
|
||||
and BinaryOperation2 are used
|
||||
whenever an algorithm expects a function object ([[function.objects]](function.objects "22.10 Function objects"))[.](#8.sentence-1)
|
||||
|
||||
[9](#9)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L192)
|
||||
|
||||
[*Note [2](#note-2)*:
|
||||
|
||||
Unless otherwise specified, algorithms that take function objects as arguments
|
||||
can copy those function objects freely[.](#9.sentence-1)
|
||||
|
||||
If object identity is important,
|
||||
a wrapper class that points to a non-copied implementation object
|
||||
such as reference_wrapper<T> ([[refwrap]](refwrap "22.10.6 Class template reference_wrapper")), or some equivalent solution,
|
||||
can be used[.](#9.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[10](#10)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L202)
|
||||
|
||||
When the description of an algorithm gives an expression such as*first == value for a condition, the expression
|
||||
shall evaluate to either true or false in boolean contexts[.](#10.sentence-1)
|
||||
|
||||
[11](#11)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L207)
|
||||
|
||||
In the description of the algorithms, operator + is used for some of the iterator categories
|
||||
for which it does not have to be defined[.](#11.sentence-1)
|
||||
|
||||
In these cases the semantics of a + n are the same as those ofauto tmp = a;for (; n < 0; ++n) --tmp;for (; n > 0; --n) ++tmp;return tmp;
|
||||
|
||||
Similarly, operator - is used
|
||||
for some combinations of iterators and sentinel types
|
||||
for which it does not have to be defined[.](#11.sentence-3)
|
||||
|
||||
If [a, b) denotes a range,
|
||||
the semantics of b - a in these cases are the same as those ofiter_difference_t<decltype(a)> n = 0;for (auto tmp = a; tmp != b; ++tmp) ++n;return n; and if [b, a) denotes a range, the same as those ofiter_difference_t<decltype(b)> n = 0;for (auto tmp = b; tmp != a; ++tmp) --n;return n;
|
||||
|
||||
For each iterator i and sentinel s produced from a range r,
|
||||
the semantics of s - i has the same type, value, and value category
|
||||
as ranges::distance(i, s)[.](#11.sentence-5)
|
||||
|
||||
[*Note [3](#note-3)*:
|
||||
|
||||
The implementation can use ranges::distance(r) when that produces the same value as ranges::distance(i, s)[.](#11.sentence-6)
|
||||
|
||||
This can be more efficient for sized ranges[.](#11.sentence-7)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[12](#12)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L244)
|
||||
|
||||
In the description of the algorithms,
|
||||
given an iterator a whose difference type is D, and
|
||||
an expression n of integer-like type other than cv D,
|
||||
the semantics of a + n and a - n are, respectively,
|
||||
those of a + D(n) and a - D(n)[.](#12.sentence-1)
|
||||
|
||||
[13](#13)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L251)
|
||||
|
||||
In the description of algorithm return values,
|
||||
a sentinel value s denoting the end of a range [i, s)
|
||||
is sometimes returned where an iterator is expected[.](#13.sentence-1)
|
||||
|
||||
In these cases,
|
||||
the semantics are as if the sentinel is converted into an iterator usingranges::next(i, s)[.](#13.sentence-2)
|
||||
|
||||
[14](#14)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L259)
|
||||
|
||||
Overloads of algorithms that take [range](range.range#concept:range "25.4.2 Ranges [range.range]") arguments ([[range.range]](range.range "25.4.2 Ranges"))
|
||||
behave as if they are implemented by
|
||||
dispatching to the overload in namespace ranges that takes separate iterator and sentinel arguments,
|
||||
where for each range argument r
|
||||
|
||||
- [(14.1)](#14.1)
|
||||
|
||||
a corresponding iterator argument is initialized with ranges::begin(r) and
|
||||
|
||||
- [(14.2)](#14.2)
|
||||
|
||||
a corresponding sentinel argument is initialized with ranges::end(r),
|
||||
or ranges::next(ranges::begin(r), ranges::end(r)) if the type of r models [forward_range](range.refinements#concept:forward_range "25.4.6 Other range refinements [range.refinements]") and computing ranges::next meets the specified complexity requirements[.](#14.sentence-1)
|
||||
|
||||
[15](#15)
|
||||
|
||||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/algorithms.tex#L275)
|
||||
|
||||
The well-formedness and behavior of a call to an algorithm with
|
||||
an explicitly-specified template argument list
|
||||
is unspecified, except where explicitly stated otherwise[.](#15.sentence-1)
|
||||
|
||||
[*Note [4](#note-4)*:
|
||||
|
||||
Consequently, an implementation can declare an algorithm with
|
||||
different template parameters than those presented[.](#15.sentence-2)
|
||||
|
||||
â *end note*]
|
||||
|
||||
[200)](#footnote-200)[200)](#footnoteref-200)
|
||||
|
||||
The decision whether to include a copying version was
|
||||
usually based on complexity considerations[.](#footnote-200.sentence-1)
|
||||
|
||||
When the cost of doing the operation dominates the cost of copy,
|
||||
the copying version is not included[.](#footnote-200.sentence-2)
|
||||
|
||||
For example, sort_copy is not included
|
||||
because the cost of sorting is much more significant,
|
||||
and users can invoke copy followed by sort[.](#footnote-200.sentence-3)
|
||||
15
cppdraft/algorithms/results.md
Normal file
15
cppdraft/algorithms/results.md
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user