Skip to content

Commit

Permalink
New issue from Oscar Slotosch: "Wrong range in [alg.search]"
Browse files Browse the repository at this point in the history
  • Loading branch information
Dani-Hub committed Dec 7, 2024
1 parent 362a2b1 commit 668ffec
Showing 1 changed file with 167 additions and 0 deletions.
167 changes: 167 additions & 0 deletions xml/issue4179.xml
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&lt;class ForwardIterator1, class ForwardIterator2&gt;
constexpr ForwardIterator1
search(ForwardIterator1 first1, ForwardIterator1 last1,
ForwardIterator2 first2, ForwardIterator2 last2);
[&hellip;]
template&lt;class ExecutionPolicy, class ForwardIterator1, class ForwardIterator2,
class BinaryPredicate&gt;
ForwardIterator1
search(ExecutionPolicy&amp;&amp; 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- [&hellip;]
</p>
</blockquote>
<pre>
template&lt;forward_iterator I1, sentinel_for&lt;I1&gt; S1, forward_iterator I2,
sentinel_for&lt;I2&gt; S2, class Pred = ranges::equal_to,
class Proj1 = identity, class Proj2 = identity&gt;
requires indirectly_comparable&lt;I1, I2, Pred, Proj1, Proj2&gt;
constexpr subrange&lt;I1&gt;
ranges::search(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = {},
Proj1 proj1 = {}, Proj2 proj2 = {});
template&lt;forward_range R1, forward_range R2, class Pred = ranges::equal_to,
class Proj1 = identity, class Proj2 = identity&gt;
requires indirectly_comparable&lt;iterator_t&lt;R1&gt;, iterator_t&lt;R2&gt;, Pred, Proj1, Proj2&gt;
constexpr borrowed_subrange_t&lt;R1&gt;
ranges::search(R1&amp;&amp; r1, R2&amp;&amp; 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) &mdash; `{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) &mdash; Returns `{last1, last1}` if no such iterator exists.</p></li>
</ol>
<p>
-4- [&hellip;]
</p>
</blockquote>
<pre>
template&lt;class ForwardIterator, class Size, class T = iterator_traits&lt;ForwardIterator&gt;::value_type&gt;
constexpr ForwardIterator
search_n(ForwardIterator first, ForwardIterator last,
Size count, const T&amp; value);
[&hellip;]
template&lt;class ExecutionPolicy, class ForwardIterator, class Size,
class T = iterator_traits&lt;ForwardIterator&gt;::value_type,
class BinaryPredicate&gt;
ForwardIterator
search_n(ExecutionPolicy&amp;&amp; exec,
ForwardIterator first, ForwardIterator last,
Size count, const T&amp; value,
BinaryPredicate pred);
</pre>
<blockquote>
<p>
-5- [&hellip;]
<p/>
-6- [&hellip;]
<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- [&hellip;]
</p>
</blockquote>
<pre>
template&lt;forward_iterator I, sentinel_for&lt;I&gt; S,
class Pred = ranges::equal_to, class Proj = identity,
class T = projected_value_t&lt;I, Proj&gt;&gt;
requires indirectly_comparable&lt;I, const T*, Pred, Proj&gt;
constexpr subrange&lt;I&gt;
ranges::search_n(I first, S last, iter_difference_t&lt;I&gt; count,
const T&amp; value, Pred pred = {}, Proj proj = {});
template&lt;forward_range R, class Pred = ranges::equal_to,
class Proj = identity, class T = projected_value_t&lt;iterator_t&lt;R&gt;, Proj&gt;&gt;
requires indirectly_comparable&lt;iterator_t&lt;R&gt;, const T*, Pred, Proj&gt;
constexpr borrowed_subrange_t&lt;R&gt;
ranges::search_n(R&amp;&amp; r, range_difference_t&lt;R&gt; count,
const T&amp; 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- [&hellip;]
</p>
</blockquote>
</blockquote>

</li>

</ol>
</resolution>

</issue>

0 comments on commit 668ffec

Please sign in to comment.