Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,13 @@ Function template that processes work items in parallel.
Requirements:

* The ``Body`` type must meet the :doc:`ParallelForEachBody requirements <../../named_requirements/algorithms/par_for_each_body>`.
Since C++17, ``Body`` may also be a pointer to a member function in ``Index``.
Since C++17, ``Body`` may also be a pointer to a member function in ``std::iterator_traits<InputIterator>::value_type``.
* The ``InputIterator`` type must meet the `Input Iterator` requirements from the [input.iterators] section of the ISO C++ Standard.
* If ``InputIterator`` type does not meet the `Forward Iterator` requirements from the [forward.iterators] section of the ISO C++ Standard,
the ``std::iterator_traits<InputIterator>::value_type`` type must be constructible from ``std::iterator_traits<InputIterator>::reference``.
* The ``Container`` type must meet the :doc:`ContainerBasedSequence requirements <../../named_requirements/algorithms/container_based_sequence>`.
* The type returned by ``Container::begin()`` must meet the same requirements as the ``InputIterator`` type above.
* The type returned by ``std::begin`` and ``std::end`` applied to a ``Container`` object
must meet the same requirements as the ``InputIterator`` type above.

The ``parallel_for_each`` template has two forms.

Expand Down
67 changes: 53 additions & 14 deletions source/elements/oneTBB/source/named_requirements.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ Named Requirements
This section describes named requirements used in the oneTBB Specification.

A *named requirement* is a set of requirements on a type. The requirements may be syntactic or semantic.
The *named_requirement* term is similar to “Requirements on types and expressions” term which is defined
by the ISO C++ Standard (chapter “Library Introduction”) or `“Named Requirements” section <https://en.cppreference.com/w/cpp/named_req>`_
on the cppreference.com site.
The *named requirement* term is similar to “Requirements on types and expressions” term which is defined
by the ISO C++ Standard (chapter “Library Introduction”) or
`“Named Requirements” section <https://en.cppreference.com/w/cpp/named_req>`_ on the cppreference.com site.

For example, the named requirement of *sortable* could be defined as a set of requirements that enable
an array to be sorted. A type ``T`` would be *sortable* if:
Expand All @@ -22,11 +22,22 @@ an array to be sorted. A type ``T`` would be *sortable* if:

You can write a sorting template function in C++ that sorts an array of any type that is *sortable*.

.. _pseudo_signatures:

Pseudo-Signatures
-----------------

Two approaches for defining named requirements are *valid expressions* and *pseudo-signatures*.
The ISO C++ standard follows the valid *expressions* approach, which shows what the usage pattern looks like for a requirement.
It has the drawback of relegating important details to notational conventions. This document uses
The ISO C++ standard follows the *valid expressions* approach, which shows what the usage pattern looks like for a requirement.
It has the drawback of relegating important details to notational conventions. This document mostly uses
pseudo-signatures because they are concise and can be cut-and-pasted for an initial implementation.

A pseudo-signature describes how an implementation interacts with a type or a function.
A real function signature (after template instantiation, if applicable) may differ from the pseudo-signature
that it implements in ways where implicit conversions would deal with the difference,
transforming function parameter types from the ones in the pseudo-signature to the real signature,
and transforming the actual return value type to the one in the pseudo-signature.

For example, the table below shows pseudo-signatures for a *sortable* type ``T``:

---------------------------------------------------------------------------------------------
Expand All @@ -35,20 +46,49 @@ For example, the table below shows pseudo-signatures for a *sortable* type ``T``

.. cpp:function:: bool operator<(const T& x, const T& y)

Compare x and y.
Compare ``x`` and ``y``.

.. cpp:function:: void swap(T& x, T& y)

Swap x and y.
Swap ``x`` and ``y``.

---------------------------------------------------------------------------------------------

A real signature may differ from the pseudo-signature that it implements in ways where implicit
conversions would deal with the difference. For an example type ``U``, the real signature that
implements ``operator<`` in the table above can be expressed as ``int operator<( U x, U y )``,
because C++ permits implicit conversion from ``int`` to ``bool``, and implicit conversion from ``U``
to (``const U&``). Similarly, the real signature ``bool operator<( U& x, U& y )`` is acceptable
because C++ permits implicit addition of a const qualifier to a reference type.
For a given type ``U``, the real signature that implements ``operator<`` in the table above
can be expressed as ``int operator<( U x, U y )``, because C++ permits implicit conversion from
``int`` to ``bool``, and implicit conversion from ``const U&`` to ``U`` if the type is copy-constructible.
As a counter-example, the real signature ``bool operator<( U& x, U& y )`` is not acceptable
because C++ does not permit implicit removal of the ``const`` qualifier from a type, and so the code
would not compile if the implementation attempts to pass a constant object to the function.

Besides pseudo-signatures, semantic requirements also need to be met by real types and functions.
For example, while ``std::pair<U, U> swap(U x, U y)`` fits the pseudo-signature for *Sortable*
via implicit conversion of references to values and implicit drop of the returned value
(ignored by a library implementation), it is unable to swap the actual variables passed to the function
and therefore does not meet the semantic requirements of *Sortable*.

The following table provides guidance for the types of parameters used in pseudo-signatures
and potential alternatives in real signatures. In practice, suitable alternatives might depend
on the semantic requirements as well as type properties, such as availability of copy- or move-constructors.

========================== ================================ =============================
Pseudo-signature parameter General semantics Alternative real parameters
========================== ================================ =============================
``const T& a`` The function is not supposed - ``T a``
to modify the argument. - ``X& a``, ``auto& a``
- ``X&& a``, ``auto&& a``

Here and below ``X`` is a template type parameter.

``T& a`` The argument is an lvalue. - ``const T& a``
The function can or is - ``T a``
supposed to modify the argument. - ``X& a``, ``auto& a``
- ``X&& a``, ``auto&& a``

``T&& a`` The argument is an rvalue. The - ``const T& a``
function can use the argument - ``T a``
as a source in move operations. - ``X&& a``, ``auto&& a``
========================== ================================ =============================

Algorithms
----------
Expand Down Expand Up @@ -81,7 +121,6 @@ Mutexes

Containers
----------

.. toctree::
:titlesonly:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,27 @@ ContainerBasedSequence
======================
**[req.container_based_sequence]**

A type `C` satisfies `ContainerBasedSequence` if it meets the following requirements:
A type `C` satisfies `ContainerBasedSequence` if the following expressions are valid
for a (possibly const) object ``c`` of the type `C`:

----------------------------------------------------------------

**ContainerBasedSequence Requirements: Pseudo-Signature, Semantics**
**ContainerBasedSequence Requirements: Expression, Semantics**

.. note::
.. cpp:function:: std::begin(c)

In this page ``c`` is an object of type (possibly ``const``) ``C``.
Returns an iterator to the beginning of the sequence represented by ``c``.

Templates that use the named requirement can impose stricter requirements on the iterator concept.
.. cpp:function:: std::end(c)

.. cpp:function:: std::begin(c)
Returns an iterator one past the end of the sequence represented by ``c``.

Returns an input iterator to the beginning of the sequence represented by ``c``.
----------------------------------------------------------------

.. cpp:function:: std::end(c)
.. note::

Returns an input iterator one past the end of the sequence represented by ``c``.
The category of an iterator returned by ``std::begin``/``std::end`` is determined by
a template that uses `ContainerBasedSequence`.

See also:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,54 +7,44 @@ ParallelForEachBody
===================
**[req.parallel_for_each_body]**

A type `Body` satisfies `ParallelForBody` if it meets the `Function Objects`
requirements described in the [function.objects] section of the ISO C++ standard.
It should also meet one of the following requirements:
A type `Body` satisfies `ParallelForEachBody` if it meets the `Function Objects`
requirements described in the [function.objects] section of the ISO C++ standard,
as well as meets exactly one of the following two alternative requirements for ``operator()``:

----------------------------------------------------------------

**ParallelForEachBody Requirements: Pseudo-Signature, Semantics**

.. cpp:function:: Body::operator()( ItemType item ) const
Alternative 1:

Process the received item.

.. cpp:function:: Body::operator()( ItemType item, oneapi::tbb::feeder<ItemType>& feeder ) const

Process the received item. May invoke the ``feeder.add(T)`` function to spawn additional items.

-----------------------------------------------------------------
.. cpp:function:: void Body::operator()( ReferenceType item ) const

.. note::
Process the received item.

``ItemType`` may be optionally passed to ``Body::operator()`` by reference.
``const`` and ``volatile`` type qualifiers are also applicable.
----------------------------------------------------------------

Terms
-----
Alternative 2:

* ``iterator`` determines the type of the iterator passed into the ``parallel_for_each`` algorithm,
which is ``decltype(std::begin(c))`` for the overloads that accept the ``Container`` template argument or ``InputIterator``.
* ``value_type`` - the type ``std::iterator_traits<iterator>::value_type``.
* ``reference`` - the type ``std::iterator_traits<iterator>::reference``.
.. cpp:function:: void Body::operator()( ReferenceType item, oneapi::tbb::feeder<ItemType>& feeder ) const
void Body::operator()( ItemType&& item, oneapi::tbb::feeder<ItemType>& feeder ) const

``oneapi::tbb::parallel_for_each`` requires the ``Body::operator()`` call with an object of the ``reference`` type to be well-formed if
the ``iterator`` meets the `Forward iterator` requirements described in the [forward.iterators] section of the
ISO C++ Standard.
Process the received item. May invoke the ``feeder.add`` function to spawn additional items.
The ``Body::operator()`` must accept both ``ReferenceType`` and ``ItemType&&`` values as the first argument.

`oneapi::tbb::parallel_for_each algorithm <../../algorithms/functions/parallel_for_each_func>`_
requires the ``Body::operator()`` call with an object of type ``const value_type&`` or ``value_type&&`` to be well-formed if following requirements are met:
-----------------------------------------------------------------

* the iterator meets the `Input iterator` requirements described in the [input.iterators] section of the ISO C++ Standard
* the iterator does not meet the `Forward iterator` requirements described in the [forward.iterators] section of the ISO C++ Standard
where

.. caution::
* ``ItemType`` is ``std::iterator_traits<Iterator>::value_type`` for the type of the iterator
the ``parallel_for_each`` algorithm operates with, and
* ``ReferenceType`` is ``std::iterator_traits<Iterator>::reference`` if the iterator type is
a `forward iterator` as described in the [forward.iterators] section of the ISO C++ Standard,
* otherwise, ``ReferenceType`` is ``ItemType&&``.

If the ``Body`` only takes non-const lvalue reference to the ``value_type``, the requirements described above
are violated, and the program can be ill-formed.
.. note::

Additional elements submitted into ``oneapi::tbb::parallel_for_each`` through the ``feeder::add`` are passed to the ``Body`` as rvalues. In this case, the corresponding
execution of the ``Body`` is required to be well-formed.
The usual rules for :ref:`pseudo-signatures <pseudo_signatures>` apply.
Therefore, ``Body::operator()`` may optionally take items by value or by ``const`` reference.

See also:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ A type `Body` satisfies `ParallelReduceBody` if it meets the following requireme
See also:

* :doc:`parallel_reduce algorithm <../../algorithms/functions/parallel_reduce_func>`
* :doc:`parallel_determinstic_reduce algorithm <../../algorithms/functions/parallel_deterministic_reduce_func>`
* :doc:`parallel_deterministic_reduce algorithm <../../algorithms/functions/parallel_deterministic_reduce_func>`
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,22 @@
==================
ParallelReduceFunc
==================
**[req.parallel_reduce_body]**
**[req.parallel_reduce_func]**

A type `Func` satisfies `ParallelReduceFunc` if it meets the following requirements:

-----------------------------------------------------------------------------------------------------

**ParallelReduceFunc Requirements: Pseudo-Signature, Semantics**

.. cpp:function:: Value Func::operator()(const Range& range, const Value& x) const
.. cpp:function:: Value Func::operator()(const Range& range, Value&& x) const

Accumulates result for a subrange, starting with initial value ``x``.
``Range`` type must meet the :doc:`Range requirements <range>`.
``Value`` type must be the same as a corresponding template parameter for the
:doc:`parallel_reduce algorithm <../../algorithms/functions/parallel_reduce_func>` algorithm.
Accumulates values over ``range``, starting with the initial value ``x``.
The ``Range`` type must meet the :doc:`Range requirements <range>`.
The ``Value`` type must be the same as the corresponding template parameter for the
:doc:`parallel_reduce algorithm <../../algorithms/functions/parallel_reduce_func>`.

See also:

* :doc:`parallel_reduce algorithm <../../algorithms/functions/parallel_reduce_func>`
* :doc:`parallel_determinstic_reduce algorithm <../../algorithms/functions/parallel_deterministic_reduce_func>`
* :doc:`parallel_deterministic_reduce algorithm <../../algorithms/functions/parallel_deterministic_reduce_func>`
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ A type `Reduction` satisfies `ParallelReduceReduction` if it meets the following

**ParallelReduceReduction Requirements: Pseudo-Signature, Semantics**

.. cpp:function:: Value Reduction::operator()(const Value& x, const Value& y) const
.. cpp:function:: Value Reduction::operator()(Value&& x, Value&& y) const

Combines results ``x`` and ``y``.
``Value`` type must be the same as a corresponding template parameter for the
:doc:`parallel_reduce algorithm <../../algorithms/functions/parallel_reduce_func>` algorithm.
Combines the results ``x`` and ``y``.
The ``Value`` type must be the same as the corresponding template parameter for the
:doc:`parallel_reduce algorithm <../../algorithms/functions/parallel_reduce_func>`.

See also:

* :doc:`parallel_reduce algorithm <../../algorithms/functions/parallel_reduce_func>`
* :doc:`parallel_determinstic_reduce algorithm <../../algorithms/functions/parallel_deterministic_reduce_func>`
* :doc:`parallel_deterministic_reduce algorithm <../../algorithms/functions/parallel_deterministic_reduce_func>`
Loading