Skip to content

Commit

Permalink
Editorial: Factor out FindViaPredicate (#2898)
Browse files Browse the repository at this point in the history
... from:
- Array.prototype.find
- Array.prototype.findIndex
- Array.prototype.findLast
- Array.prototype.findLastIndex
- %TypedArray%.prototype.find
- %TypedArray%.prototype.findIndex
- %TypedArray%.prototype.findLast
- %TypedArray%.prototype.findLastIndex
  • Loading branch information
jmdyck authored and ljharb committed Feb 23, 2023
1 parent d00fc6a commit a623bfb
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 92 deletions.
1 change: 1 addition & 0 deletions esmeta-ignore.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"CreateIterResultObject",
"ECMAScriptFunctionObject.Call",
"ECMAScriptFunctionObject.Construct",
"FindViaPredicate",
"FlattenIntoArray",
"ForIn/OfBodyEvaluation",
"FunctionBody[0,0].EvaluateFunctionBody",
Expand Down
152 changes: 60 additions & 92 deletions spec.html
Original file line number Diff line number Diff line change
Expand Up @@ -37542,25 +37542,15 @@ <h1>Array.prototype.filter ( _callbackfn_ [ , _thisArg_ ] )</h1>
<emu-clause id="sec-array.prototype.find">
<h1>Array.prototype.find ( _predicate_ [ , _thisArg_ ] )</h1>
<emu-note>
<p>_predicate_ should be a function that accepts three arguments and returns a value that is coercible to a Boolean value. `find` calls _predicate_ once for each element of the array, in ascending order, until it finds one where _predicate_ returns *true*. If such an element is found, `find` immediately returns that element value. Otherwise, `find` returns *undefined*.</p>
<p>If a _thisArg_ parameter is provided, it will be used as the *this* value for each invocation of _predicate_. If it is not provided, *undefined* is used instead.</p>
<p>_predicate_ is called with three arguments: the value of the element, the index of the element, and the object being traversed.</p>
<p>`find` does not directly mutate the object on which it is called but the object may be mutated by the calls to _predicate_.</p>
<p>The range of elements processed by `find` is set before the first call to _predicate_. Elements that are appended to the array after the call to `find` begins will not be visited by _predicate_. If existing elements of the array are changed, their value as passed to _predicate_ will be the value at the time that `find` visits them; elements that are deleted after the call to `find` begins and before being visited are still visited and are either looked up from the prototype or are *undefined*.</p>
<p>This method calls _predicate_ once for each element of the array, in ascending index order, until it finds one where _predicate_ returns a value that coerces to *true*. If such an element is found, `find` immediately returns that element value. Otherwise, `find` returns *undefined*.</p>
<p>See FindViaPredicate for additional information.</p>
</emu-note>
<p>This method performs the following steps when called:</p>
<emu-alg>
1. Let _O_ be ? ToObject(*this* value).
1. Let _len_ be ? LengthOfArrayLike(_O_).
1. If IsCallable(_predicate_) is *false*, throw a *TypeError* exception.
1. Let _k_ be 0.
1. Repeat, while _k_ &lt; _len_,
1. Let _Pk_ be ! ToString(𝔽(_k_)).
1. Let _kValue_ be ? Get(_O_, _Pk_).
1. Let _testResult_ be ToBoolean(? Call(_predicate_, _thisArg_, « _kValue_, 𝔽(_k_), _O_ »)).
1. If _testResult_ is *true*, return _kValue_.
1. Set _k_ to _k_ + 1.
1. Return *undefined*.
1. Let _findRec_ be ? FindViaPredicate(_O_, _len_, ~ascending~, _predicate_, _thisArg_).
1. Return _findRec_.[[Value]].
</emu-alg>
<emu-note>
<p>This method is intentionally generic; it does not require that its *this* value be an Array. Therefore it can be transferred to other kinds of objects for use as a method.</p>
Expand All @@ -37570,25 +37560,15 @@ <h1>Array.prototype.find ( _predicate_ [ , _thisArg_ ] )</h1>
<emu-clause id="sec-array.prototype.findindex">
<h1>Array.prototype.findIndex ( _predicate_ [ , _thisArg_ ] )</h1>
<emu-note>
<p>_predicate_ should be a function that accepts three arguments and returns a value that is coercible to a Boolean value. `findIndex` calls _predicate_ once for each element of the array, in ascending order, until it finds one where _predicate_ returns *true*. If such an element is found, `findIndex` immediately returns the index of that element value. Otherwise, `findIndex` returns -1.</p>
<p>If a _thisArg_ parameter is provided, it will be used as the *this* value for each invocation of _predicate_. If it is not provided, *undefined* is used instead.</p>
<p>_predicate_ is called with three arguments: the value of the element, the index of the element, and the object being traversed.</p>
<p>`findIndex` does not directly mutate the object on which it is called but the object may be mutated by the calls to _predicate_.</p>
<p>The range of elements processed by `findIndex` is set before the first call to _predicate_. Elements that are appended to the array after the call to `findIndex` begins will not be visited by _predicate_. If existing elements of the array are changed, their value as passed to _predicate_ will be the value at the time that `findIndex` visits them; elements that are deleted after the call to `findIndex` begins and before being visited are still visited and are either looked up from the prototype or are *undefined*.</p>
<p>This method calls _predicate_ once for each element of the array, in ascending index order, until it finds one where _predicate_ returns a value that coerces to *true*. If such an element is found, `findIndex` immediately returns the index of that element value. Otherwise, `findIndex` returns -1.</p>
<p>See FindViaPredicate for additional information.</p>
</emu-note>
<p>This method performs the following steps when called:</p>
<emu-alg>
1. Let _O_ be ? ToObject(*this* value).
1. Let _len_ be ? LengthOfArrayLike(_O_).
1. If IsCallable(_predicate_) is *false*, throw a *TypeError* exception.
1. Let _k_ be 0.
1. Repeat, while _k_ &lt; _len_,
1. Let _Pk_ be ! ToString(𝔽(_k_)).
1. Let _kValue_ be ? Get(_O_, _Pk_).
1. Let _testResult_ be ToBoolean(? Call(_predicate_, _thisArg_, « _kValue_, 𝔽(_k_), _O_ »)).
1. If _testResult_ is *true*, return 𝔽(_k_).
1. Set _k_ to _k_ + 1.
1. Return *-1*<sub>𝔽</sub>.
1. Let _findRec_ be ? FindViaPredicate(_O_, _len_, ~ascending~, _predicate_, _thisArg_).
1. Return _findRec_.[[Index]].
</emu-alg>
<emu-note>
<p>This method is intentionally generic; it does not require that its *this* value be an Array. Therefore it can be transferred to other kinds of objects for use as a method.</p>
Expand All @@ -37598,25 +37578,15 @@ <h1>Array.prototype.findIndex ( _predicate_ [ , _thisArg_ ] )</h1>
<emu-clause id="sec-array.prototype.findlast">
<h1>Array.prototype.findLast ( _predicate_ [ , _thisArg_ ] )</h1>
<emu-note>
<p>_predicate_ should be a function that accepts three arguments and returns a value that is coercible to a Boolean value. `findLast` calls _predicate_ once for each element of the array, in descending index order, until it finds one where _predicate_ returns *true*. If such an element is found, `findLast` immediately returns that element value. Otherwise, `findLast` returns *undefined*.</p>
<p>If a _thisArg_ parameter is provided, it will be used as the *this* value for each invocation of _predicate_. If it is not provided, *undefined* is used instead.</p>
<p>_predicate_ is called with three arguments: the element, the index of the element in the array, and the object being traversed.</p>
<p>`findLast` does not directly mutate the object on which it is called but the object may be mutated by the calls to _predicate_.</p>
<p>The range of elements processed by `findLast` is set before the first call to _predicate_. Elements that are appended to the array after the call to `findLast` begins will not be visited by _predicate_. If existing elements of the array are changed, their value as passed to _predicate_ will be the value at the time that `findLast` visits them.</p>
<p>This method calls _predicate_ once for each element of the array, in descending index order, until it finds one where _predicate_ returns a value that coerces to *true*. If such an element is found, `findLast` immediately returns that element value. Otherwise, `findLast` returns *undefined*.</p>
<p>See FindViaPredicate for additional information.</p>
</emu-note>
<p>This method performs the following steps when called:</p>
<emu-alg>
1. Let _O_ be ? ToObject(*this* value).
1. Let _len_ be ? LengthOfArrayLike(_O_).
1. If IsCallable(_predicate_) is *false*, throw a *TypeError* exception.
1. Let _k_ be _len_ - 1.
1. Repeat, while _k_ ≥ 0,
1. Let _Pk_ be ! ToString(𝔽(_k_)).
1. Let _kValue_ be ? Get(_O_, _Pk_).
1. Let _testResult_ be ToBoolean(? Call(_predicate_, _thisArg_, « _kValue_, 𝔽(_k_), _O_ »)).
1. If _testResult_ is *true*, return _kValue_.
1. Set _k_ to _k_ - 1.
1. Return *undefined*.
1. Let _findRec_ be ? FindViaPredicate(_O_, _len_, ~descending~, _predicate_, _thisArg_).
1. Return _findRec_.[[Value]].
</emu-alg>
<emu-note>
<p>This method is intentionally generic; it does not require that its *this* value be an Array object. Therefore it can be transferred to other kinds of objects for use as a method.</p>
Expand All @@ -37626,29 +37596,55 @@ <h1>Array.prototype.findLast ( _predicate_ [ , _thisArg_ ] )</h1>
<emu-clause id="sec-array.prototype.findlastindex">
<h1>Array.prototype.findLastIndex ( _predicate_ [ , _thisArg_ ] )</h1>
<emu-note>
<p>_predicate_ should be a function that accepts three arguments and returns a value that is coercible to a Boolean value. `findLastIndex` calls _predicate_ once for each element of the array, in descending index order, until it finds one where _predicate_ returns *true*. If such an element is found, `findLastIndex` immediately returns the index of that element value. Otherwise, `findLastIndex` returns -1.</p>
<p>If a _thisArg_ parameter is provided, it will be used as the *this* value for each invocation of _predicate_. If it is not provided, *undefined* is used instead.</p>
<p>_predicate_ is called with three arguments: the element, the index of the element in the array, and the object being traversed.</p>
<p>`findLastIndex` does not directly mutate the object on which it is called but the object may be mutated by the calls to _predicate_.</p>
<p>The range of elements processed by `findLastIndex` is set before the first call to _predicate_. Elements that are appended to the array after the call to `findLastIndex` begins will not be visited by _predicate_. If existing elements of the array are changed, their value as passed to _predicate_ will be the value at the time that `findLastIndex` visits them.</p>
<p>This method calls _predicate_ once for each element of the array, in descending index order, until it finds one where _predicate_ returns a value that coerces to *true*. If such an element is found, `findLastIndex` immediately returns the index of that element value. Otherwise, `findLastIndex` returns -1.</p>
<p>See FindViaPredicate for additional information.</p>
</emu-note>
<p>This method performs the following steps when called:</p>
<emu-alg>
1. Let _O_ be ? ToObject(*this* value).
1. Let _len_ be ? LengthOfArrayLike(_O_).
1. If IsCallable(_predicate_) is *false*, throw a *TypeError* exception.
1. Let _k_ be _len_ - 1.
1. Repeat, while _k_ ≥ 0,
1. Let _Pk_ be ! ToString(𝔽(_k_)).
1. Let _kValue_ be ? Get(_O_, _Pk_).
1. Let _testResult_ be ToBoolean(? Call(_predicate_, _thisArg_, « _kValue_, 𝔽(_k_), _O_ »)).
1. If _testResult_ is *true*, return 𝔽(_k_).
1. Set _k_ to _k_ - 1.
1. Return *-1*<sub>𝔽</sub>.
1. Let _findRec_ be ? FindViaPredicate(_O_, _len_, ~descending~, _predicate_, _thisArg_).
1. Return _findRec_.[[Index]].
</emu-alg>
<emu-note>
<p>This method is intentionally generic; it does not require that its *this* value be an Array object. Therefore it can be transferred to other kinds of objects for use as a method.</p>
</emu-note>

<emu-clause id="sec-findviapredicate" type="abstract operation">
<h1>
FindViaPredicate (
_O_: an Object,
_len_: a non-negative integer,
_direction_: ~ascending~ or ~descending~,
_predicate_: an ECMAScript language value,
_thisArg_: an ECMAScript language value,
): either a normal completion containing a Record with fields [[Index]] (an integral Number) and [[Value]] (an ECMAScript language value) or a throw completion
</h1>
<dl class="header">
<dt>description</dt>
<dd>
<p>_O_ should be an array-like object or a TypedArray. This operation calls _predicate_ once for each element of _O_, in either ascending index order or descending index order (as indicated by _direction_), until it finds one where _predicate_ returns a value that coerces to *true*. At that point, this operation returns a Record that gives the index and value of the element found. If no such element is found, this operation returns a Record that specifies *-1*<sub>𝔽</sub> for the index and *undefined* for the value.</p>
<p>_predicate_ should be a function. When called for an element of the array, it is passed three arguments: the value of the element, the index of the element, and the object being traversed. Its return value will be coerced to a Boolean value.</p>
<p>_thisArg_ will be used as the *this* value for each invocation of _predicate_.</p>
<p>This operation does not directly mutate the object on which it is called, but the object may be mutated by the calls to _predicate_.</p>
<p>The range of elements processed is set before the first call to _predicate_, just before the traversal begins. Elements that are appended to the array after this will not be visited by _predicate_. If existing elements of the array are changed, their value as passed to _predicate_ will be the value at the time that this operation visits them. Elements that are deleted after traversal begins and before being visited are still visited and are either looked up from the prototype or are *undefined*.</p>
</dd>
</dl>
<emu-alg>
1. If IsCallable(_predicate_) is *false*, throw a *TypeError* exception.
1. If _direction_ is ~ascending~, then
1. Let _indices_ be a List of the integers in the interval from 0 (inclusive) to _len_ (exclusive), in ascending order.
1. Else,
1. Let _indices_ be a List of the integers in the interval from 0 (inclusive) to _len_ (exclusive), in descending order.
1. For each integer _k_ of _indices_, do
1. Let _Pk_ be ! ToString(𝔽(_k_)).
1. NOTE: If _O_ is a TypedArray, the following invocation of Get will return a normal completion.
1. Let _kValue_ be ? Get(_O_, _Pk_).
1. Let _testResult_ be ? Call(_predicate_, _thisArg_, « _kValue_, 𝔽(_k_), _O_ »).
1. If ToBoolean(_testResult_) is *true*, return the Record { [[Index]]: 𝔽(_k_), [[Value]]: _kValue_ }.
1. Return the Record { [[Index]]: *-1*<sub>𝔽</sub>, [[Value]]: *undefined* }.
</emu-alg>
</emu-clause>
</emu-clause>

<emu-clause id="sec-array.prototype.flat">
Expand Down Expand Up @@ -39110,15 +39106,8 @@ <h1>%TypedArray%.prototype.find ( _predicate_ [ , _thisArg_ ] )</h1>
1. Let _O_ be the *this* value.
1. Perform ? ValidateTypedArray(_O_).
1. Let _len_ be _O_.[[ArrayLength]].
1. If IsCallable(_predicate_) is *false*, throw a *TypeError* exception.
1. Let _k_ be 0.
1. Repeat, while _k_ &lt; _len_,
1. Let _Pk_ be ! ToString(𝔽(_k_)).
1. Let _kValue_ be ! Get(_O_, _Pk_).
1. Let _testResult_ be ToBoolean(? Call(_predicate_, _thisArg_, « _kValue_, 𝔽(_k_), _O_ »)).
1. If _testResult_ is *true*, return _kValue_.
1. Set _k_ to _k_ + 1.
1. Return *undefined*.
1. Let _findRec_ be ? FindViaPredicate(_O_, _len_, ~ascending~, _predicate_, _thisArg_).
1. Return _findRec_.[[Value]].
</emu-alg>
<p>This method is not generic. The *this* value must be an object with a [[TypedArrayName]] internal slot.</p>
</emu-clause>
Expand All @@ -39131,15 +39120,8 @@ <h1>%TypedArray%.prototype.findIndex ( _predicate_ [ , _thisArg_ ] )</h1>
1. Let _O_ be the *this* value.
1. Perform ? ValidateTypedArray(_O_).
1. Let _len_ be _O_.[[ArrayLength]].
1. If IsCallable(_predicate_) is *false*, throw a *TypeError* exception.
1. Let _k_ be 0.
1. Repeat, while _k_ &lt; _len_,
1. Let _Pk_ be ! ToString(𝔽(_k_)).
1. Let _kValue_ be ! Get(_O_, _Pk_).
1. Let _testResult_ be ToBoolean(? Call(_predicate_, _thisArg_, « _kValue_, 𝔽(_k_), _O_ »)).
1. If _testResult_ is *true*, return 𝔽(_k_).
1. Set _k_ to _k_ + 1.
1. Return *-1*<sub>𝔽</sub>.
1. Let _findRec_ be ? FindViaPredicate(_O_, _len_, ~ascending~, _predicate_, _thisArg_).
1. Return _findRec_.[[Index]].
</emu-alg>
<p>This method is not generic. The *this* value must be an object with a [[TypedArrayName]] internal slot.</p>
</emu-clause>
Expand All @@ -39152,15 +39134,8 @@ <h1>%TypedArray%.prototype.findLast ( _predicate_ [ , _thisArg_ ] )</h1>
1. Let _O_ be the *this* value.
1. Perform ? ValidateTypedArray(_O_).
1. Let _len_ be _O_.[[ArrayLength]].
1. If IsCallable(_predicate_) is *false*, throw a *TypeError* exception.
1. Let _k_ be _len_ - 1.
1. Repeat, while _k_ ≥ 0,
1. Let _Pk_ be ! ToString(𝔽(_k_)).
1. Let _kValue_ be ! Get(_O_, _Pk_).
1. Let _testResult_ be ToBoolean(? Call(_predicate_, _thisArg_, « _kValue_, 𝔽(_k_), _O_ »)).
1. If _testResult_ is *true*, return _kValue_.
1. Set _k_ to _k_ - 1.
1. Return *undefined*.
1. Let _findRec_ be ? FindViaPredicate(_O_, _len_, ~descending~, _predicate_, _thisArg_).
1. Return _findRec_.[[Value]].
</emu-alg>
<p>This method is not generic. The *this* value must be an object with a [[TypedArrayName]] internal slot.</p>
</emu-clause>
Expand All @@ -39173,15 +39148,8 @@ <h1>%TypedArray%.prototype.findLastIndex ( _predicate_ [ , _thisArg_ ] )</h1>
1. Let _O_ be the *this* value.
1. Perform ? ValidateTypedArray(_O_).
1. Let _len_ be _O_.[[ArrayLength]].
1. If IsCallable(_predicate_) is *false*, throw a *TypeError* exception.
1. Let _k_ be _len_ - 1.
1. Repeat, while _k_ ≥ 0,
1. Let _Pk_ be ! ToString(𝔽(_k_)).
1. Let _kValue_ be ! Get(_O_, _Pk_).
1. Let _testResult_ be ToBoolean(? Call(_predicate_, _thisArg_, « _kValue_, 𝔽(_k_), _O_ »)).
1. If _testResult_ is *true*, return 𝔽(_k_).
1. Set _k_ to _k_ - 1.
1. Return *-1*<sub>𝔽</sub>.
1. Let _findRec_ be ? FindViaPredicate(_O_, _len_, ~descending~, _predicate_, _thisArg_).
1. Return _findRec_.[[Index]].
</emu-alg>
<p>This method is not generic. The *this* value must be an object with a [[TypedArrayName]] internal slot.</p>
</emu-clause>
Expand Down

0 comments on commit a623bfb

Please sign in to comment.