From 162fed2a4d0c6bcdb00526143d041ad58e5753cd Mon Sep 17 00:00:00 2001 From: Alexey Kukanov Date: Fri, 19 Sep 2025 15:24:37 +0200 Subject: [PATCH 1/4] Clarify the use of pseudo-signatures --- .../oneTBB/source/named_requirements.rst | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/source/elements/oneTBB/source/named_requirements.rst b/source/elements/oneTBB/source/named_requirements.rst index e134f6fd19..b3e62c16fa 100644 --- a/source/elements/oneTBB/source/named_requirements.rst +++ b/source/elements/oneTBB/source/named_requirements.rst @@ -22,9 +22,14 @@ 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 +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. For example, the table below shows pseudo-signatures for a *sortable* type ``T``: @@ -43,12 +48,18 @@ For example, the table below shows pseudo-signatures for a *sortable* type ``T`` --------------------------------------------------------------------------------------------- +A pseudo-signature describes how an implementation interacts with a type or a function. 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. +conversions would deal with the difference: function parameters need to implicitly convert +from the ones in the pseudo-signature, and return value needs to implicitly convert to the one +in the pseudo-signature. + +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 ``const U&`` to ``U`` if the type is copyable. +For a counter-example, the real signature ``bool operator<( U& x, U& y )`` is not acceptable +because C++ does not permit implicit removal of a const qualifier from a type, and so the code +would not compile if the implementation attempts to pass a const object to the function. Algorithms ---------- @@ -81,7 +92,6 @@ Mutexes Containers ---------- - .. toctree:: :titlesonly: From b2431ceb335c8f68f87edeab92064048997d85be Mon Sep 17 00:00:00 2001 From: Alexey Kukanov Date: Fri, 19 Sep 2025 15:27:09 +0200 Subject: [PATCH 2/4] Simplify the definition of ParallelForEachBody requirements --- .../algorithms/par_for_each_body.rst | 42 ++++++------------- 1 file changed, 12 insertions(+), 30 deletions(-) diff --git a/source/elements/oneTBB/source/named_requirements/algorithms/par_for_each_body.rst b/source/elements/oneTBB/source/named_requirements/algorithms/par_for_each_body.rst index 8abfcbb498..10fe95dc20 100644 --- a/source/elements/oneTBB/source/named_requirements/algorithms/par_for_each_body.rst +++ b/source/elements/oneTBB/source/named_requirements/algorithms/par_for_each_body.rst @@ -15,46 +15,28 @@ It should also meet one of the following requirements: **ParallelForEachBody Requirements: Pseudo-Signature, Semantics** -.. cpp:function:: Body::operator()( ItemType item ) const +.. cpp:function:: void Body::operator()( ReferenceType item ) const Process the received item. -.. cpp:function:: Body::operator()( ItemType item, oneapi::tbb::feeder& feeder ) const +.. cpp:function:: void Body::operator()( ItemType&& item, oneapi::tbb::feeder& feeder ) const - Process the received item. May invoke the ``feeder.add(T)`` function to spawn additional items. + Process the received item. May invoke the ``feeder.add`` function to spawn additional items. ----------------------------------------------------------------- -.. note:: - - ``ItemType`` may be optionally passed to ``Body::operator()`` by reference. - ``const`` and ``volatile`` type qualifiers are also applicable. - -Terms ------ - -* ``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::value_type``. -* ``reference`` - the type ``std::iterator_traits::reference``. +where ``ItemType`` is ``std::iterator_traits::value_type`` for the type of the iterator +the ``parallel_for_each`` algorithm operates with, and ``ReferenceType`` is -``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. +* ``std::iterator_traits::reference`` if the iterator type is a forward iterator + as described in the [forward.iterators] section of the ISO C++ Standard; +* otherwise, ``ItemType&&``. -`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 - -.. caution:: - - 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 ` apply. + Therefore, ``Body::operator()`` may optionally take ``ItemType`` by value. + ``const`` and ``volatile`` type qualifiers are also applicable. See also: From 2c5ebc0a19e2200d02a414c4cbcef6a046a88a8f Mon Sep 17 00:00:00 2001 From: Alexey Kukanov Date: Fri, 19 Sep 2025 15:32:41 +0200 Subject: [PATCH 3/4] Improve the definition of ContainerBasedSequence --- .../functions/parallel_for_each_func.rst | 3 ++- .../algorithms/container_based_sequence.rst | 18 ++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/source/elements/oneTBB/source/algorithms/functions/parallel_for_each_func.rst b/source/elements/oneTBB/source/algorithms/functions/parallel_for_each_func.rst index 0469c277b5..534aae0733 100644 --- a/source/elements/oneTBB/source/algorithms/functions/parallel_for_each_func.rst +++ b/source/elements/oneTBB/source/algorithms/functions/parallel_for_each_func.rst @@ -42,7 +42,8 @@ Requirements: * If ``InputIterator`` type does not meet the `Forward Iterator` requirements from the [forward.iterators] section of the ISO C++ Standard, the ``std::iterator_traits::value_type`` type must be constructible from ``std::iterator_traits::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. diff --git a/source/elements/oneTBB/source/named_requirements/algorithms/container_based_sequence.rst b/source/elements/oneTBB/source/named_requirements/algorithms/container_based_sequence.rst index e46490e274..b68c36fda0 100644 --- a/source/elements/oneTBB/source/named_requirements/algorithms/container_based_sequence.rst +++ b/source/elements/oneTBB/source/named_requirements/algorithms/container_based_sequence.rst @@ -7,17 +7,12 @@ 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 an object ``c`` of type (possibly ``const``) ``C``: ---------------------------------------------------------------- -**ContainerBasedSequence Requirements: Pseudo-Signature, Semantics** - - .. note:: - - In this page ``c`` is an object of type (possibly ``const``) ``C``. - - Templates that use the named requirement can impose stricter requirements on the iterator concept. +**ContainerBasedSequence Requirements: Expression, Semantics** .. cpp:function:: std::begin(c) @@ -27,6 +22,13 @@ A type `C` satisfies `ContainerBasedSequence` if it meets the following requirem Returns an input iterator one past the end of the sequence represented by ``c``. +---------------------------------------------------------------- + +.. note:: + + Templates that use ``ContainerBasedSequence`` may impose stricter requirements on the iterator type + returned by ``std::begin``/``std::end``. + See also: * :doc:`parallel_for_each algorithm <../../algorithms/functions/parallel_for_each_func>` From f0cc3091de16d6c84fe6e73094f754c303200ef4 Mon Sep 17 00:00:00 2001 From: Alexey Kukanov Date: Mon, 6 Oct 2025 16:08:06 +0200 Subject: [PATCH 4/4] Address the review feedback Co-authored-by: Ruslan Arutyunyan --- .../oneTBB/source/named_requirements.rst | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/source/elements/oneTBB/source/named_requirements.rst b/source/elements/oneTBB/source/named_requirements.rst index b3e62c16fa..b0d8af7765 100644 --- a/source/elements/oneTBB/source/named_requirements.rst +++ b/source/elements/oneTBB/source/named_requirements.rst @@ -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 `_ -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 `_ 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: @@ -49,16 +49,17 @@ For example, the table below shows pseudo-signatures for a *sortable* type ``T`` --------------------------------------------------------------------------------------------- A pseudo-signature describes how an implementation interacts with a type or a function. -A real signature may differ from the pseudo-signature that it implements in ways where implicit -conversions would deal with the difference: function parameters need to implicitly convert -from the ones in the pseudo-signature, and return value needs to implicitly convert to the one +A real 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: its function parameter types need to implicitly convert +from the ones in the pseudo-signature, and the return value type needs to implicitly convert to the one in the pseudo-signature. 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 ``const U&`` to ``U`` if the type is copyable. +``int`` to ``bool``, and implicit conversion from ``const U&`` to ``U`` if the type is copy-constructible. For a counter-example, the real signature ``bool operator<( U& x, U& y )`` is not acceptable -because C++ does not permit implicit removal of a const qualifier from a type, and so the code +because C++ does not permit implicit removal of a ``const`` qualifier from a type, and so the code would not compile if the implementation attempts to pass a const object to the function. Algorithms