forked from lwg/issues
-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
New issue from Oscar Slotosch: "Wrong range in [alg.search]"
- Loading branch information
Showing
1 changed file
with
167 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
<?xml version='1.0' encoding='utf-8' standalone='no'?> | ||
<!DOCTYPE issue SYSTEM "lwg-issue.dtd"> | ||
|
||
<issue num="4179" status="New"> | ||
<title>Wrong range in [alg.search]</title> | ||
<section><sref ref="[alg.search]"/></section> | ||
<submitter>Oscar Slotosch</submitter> | ||
<date>05 Dec 2024</date> | ||
<priority>99</priority> | ||
|
||
<discussion> | ||
<p> | ||
Originally reported as editorial request <a href="https://github.com/cplusplus/draft/issues/7474">#7474</a>: | ||
<p/> | ||
During the qualification of the C++ STL Validas has pointed me to the following issue: | ||
<p/> | ||
The specification of <sref ref="[alg.search]"/> has a wrong range. Currently the range is | ||
"<tt>[first1, last1 - (last2 - first2))</tt>" (exclusive) but should be | ||
"<tt>[first1, last1 - (last2 - first2)]</tt>" (inclusive). So please correct the closing ")" to "]". | ||
Otherwise the last occurrence will not be found. We observed the issue in C++14 and C++17 | ||
and cppreference.com. | ||
<p/> | ||
The implementations do the right thing and work correctly and find even the last occurrence. | ||
<p/> | ||
For example in the list `{1, 2, 3, 4, 5}` the pattern `{4, 5}` should be found (obviously). | ||
In the case the last element is not included it will not be found. | ||
<p/> | ||
<a href="https://godbolt.org/z/daMa5nTY9">Demonstration on godbolt</a> shows that the implementation | ||
is working and finds the pattern. | ||
</p> | ||
|
||
<note>2024-12-07; Daniel comments and provides wording</note> | ||
<p> | ||
The mentioned wording issue is present in all previous standard versions, including the | ||
<a href="https://sgistl.github.io/search.html">SGI STL</a>. It needs to be fixed in all search | ||
variants specified in <sref ref="[alg.search]"/> (except for the form using a `Searcher`). | ||
</p> | ||
</discussion> | ||
|
||
<resolution> | ||
<p> | ||
This wording is relative to <paper num="N4993"/>. | ||
</p> | ||
|
||
<ol> | ||
<li><p>Modify <sref ref="[alg.search]"/> as indicated:</p> | ||
|
||
<blockquote> | ||
<pre> | ||
template<class ForwardIterator1, class ForwardIterator2> | ||
constexpr ForwardIterator1 | ||
search(ForwardIterator1 first1, ForwardIterator1 last1, | ||
ForwardIterator2 first2, ForwardIterator2 last2); | ||
[…] | ||
template<class ExecutionPolicy, class ForwardIterator1, class ForwardIterator2, | ||
class BinaryPredicate> | ||
ForwardIterator1 | ||
search(ExecutionPolicy&& exec, | ||
ForwardIterator1 first1, ForwardIterator1 last1, | ||
ForwardIterator2 first2, ForwardIterator2 last2, | ||
BinaryPredicate pred); | ||
</pre> | ||
<blockquote> | ||
<p> | ||
-1- <i>Returns</i>: The first iterator `i` in the range <tt>[first1, last1 - (last2 - first2)<ins>]</ins><del>)</del></tt> | ||
such that for every nonnegative integer `n` less than `last2 - first2` the following | ||
corresponding conditions hold: `*(i + n) == *(first2 + n), pred(*(i + n)`, `*(first2 + n)) != false`. | ||
Returns `first1` if `[first2, last2)` is empty, otherwise returns `last1` if no such iterator is found. | ||
<p/> | ||
-2- […] | ||
</p> | ||
</blockquote> | ||
<pre> | ||
template<forward_iterator I1, sentinel_for<I1> S1, forward_iterator I2, | ||
sentinel_for<I2> S2, class Pred = ranges::equal_to, | ||
class Proj1 = identity, class Proj2 = identity> | ||
requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2> | ||
constexpr subrange<I1> | ||
ranges::search(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {}, | ||
Proj1 proj1 = {}, Proj2 proj2 = {}); | ||
template<forward_range R1, forward_range R2, class Pred = ranges::equal_to, | ||
class Proj1 = identity, class Proj2 = identity> | ||
requires indirectly_comparable<iterator_t<R1>, iterator_t<R2>, Pred, Proj1, Proj2> | ||
constexpr borrowed_subrange_t<R1> | ||
ranges::search(R1&& r1, R2&& r2, Pred pred = {}, | ||
Proj1 proj1 = {}, Proj2 proj2 = {}); | ||
</pre> | ||
<blockquote> | ||
<p> | ||
-3- <i>Returns</i>: | ||
</p> | ||
<ol style="list-style-type: none"> | ||
<li><p>(3.1) — `{i, i + (last2 - first2)}`, where `i` is the first iterator in the range | ||
<tt>[first1, last1 - (last2 - first2)<ins>]</ins><del>)</del></tt> such that for every non-negative integer `n` | ||
less than `last2 - first2` the condition</p> | ||
<blockquote><pre> | ||
bool(invoke(pred, invoke(proj1, *(i + n)), invoke(proj2, *(first2 + n)))) | ||
</pre></blockquote> | ||
<p>is `true`.</p> | ||
</li> | ||
<li><p>(3.2) — Returns `{last1, last1}` if no such iterator exists.</p></li> | ||
</ol> | ||
<p> | ||
-4- […] | ||
</p> | ||
</blockquote> | ||
<pre> | ||
template<class ForwardIterator, class Size, class T = iterator_traits<ForwardIterator>::value_type> | ||
constexpr ForwardIterator | ||
search_n(ForwardIterator first, ForwardIterator last, | ||
Size count, const T& value); | ||
[…] | ||
template<class ExecutionPolicy, class ForwardIterator, class Size, | ||
class T = iterator_traits<ForwardIterator>::value_type, | ||
class BinaryPredicate> | ||
ForwardIterator | ||
search_n(ExecutionPolicy&& exec, | ||
ForwardIterator first, ForwardIterator last, | ||
Size count, const T& value, | ||
BinaryPredicate pred); | ||
</pre> | ||
<blockquote> | ||
<p> | ||
-5- […] | ||
<p/> | ||
-6- […] | ||
<p/> | ||
-7- <i>Returns</i>: The first iterator `i` in the range <tt>[first, last-count<ins>]</ins><del>)</del></tt> | ||
such that for every non-negative integer `n` less than `count` the condition <tt><i>E</i></tt> is `true`. | ||
Returns `last` if no such iterator is found. | ||
<p/> | ||
-8- […] | ||
</p> | ||
</blockquote> | ||
<pre> | ||
template<forward_iterator I, sentinel_for<I> S, | ||
class Pred = ranges::equal_to, class Proj = identity, | ||
class T = projected_value_t<I, Proj>> | ||
requires indirectly_comparable<I, const T*, Pred, Proj> | ||
constexpr subrange<I> | ||
ranges::search_n(I first, S last, iter_difference_t<I> count, | ||
const T& value, Pred pred = {}, Proj proj = {}); | ||
template<forward_range R, class Pred = ranges::equal_to, | ||
class Proj = identity, class T = projected_value_t<iterator_t<R>, Proj>> | ||
requires indirectly_comparable<iterator_t<R>, const T*, Pred, Proj> | ||
constexpr borrowed_subrange_t<R> | ||
ranges::search_n(R&& r, range_difference_t<R> count, | ||
const T& value, Pred pred = {}, Proj proj = {}); | ||
</pre> | ||
<blockquote> | ||
<p> | ||
-9- <i>Returns</i>: `{i, i + count}` where `i` is the first iterator in the range | ||
<tt>[first, last - count<ins>]</ins><del>)</del></tt> such that for every non-negative integer | ||
`n` less than `count`, the following condition holds: `invoke(pred, invoke(proj, *(i + n)), value)`. | ||
Returns `{last, last}` if no such iterator is found. | ||
<p/> | ||
-10- […] | ||
</p> | ||
</blockquote> | ||
</blockquote> | ||
|
||
</li> | ||
|
||
</ol> | ||
</resolution> | ||
|
||
</issue> |