From 75880007b72a5d322fa10b4b23533c7f27815c7e Mon Sep 17 00:00:00 2001 From: Ashley Claymore Date: Thu, 17 Mar 2022 10:54:10 +0000 Subject: [PATCH] Update sorting methods to use abstract closures (#78) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * update sorting methods to use abstract closures Co-authored-by: NicolΓ² Ribaudo --- spec.html | 235 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 191 insertions(+), 44 deletions(-) diff --git a/spec.html b/spec.html index 544d62e..0638846 100644 --- a/spec.html +++ b/spec.html @@ -18,6 +18,112 @@

Array Objects

Properties of the Array Prototype Object

+ +

Array.prototype.sort ( _comparefn_ )

+ +

When the `sort` method is called, the following steps are taken:

+ + 1. [id="step-array-sort-comparefn"] If _comparefn_ is not *undefined* and IsCallable(_comparefn_) is *false*, throw a *TypeError* exception. + 1. Let _obj_ be ? ToObject(*this* value). + 1. [id="step-array-sort-len"] Let _len_ be ? LengthOfArrayLike(_obj_). + 1. Let _SortCompare_ be a new Abstract Closure with parameters (_x_, _y_) that captures _comparefn_ and performs the following steps when called: + 1. If _x_ and _y_ are both *undefined*, return *+0*𝔽. + 1. If _x_ is *undefined*, return *1*𝔽. + 1. If _y_ is *undefined*, return *-1*𝔽. + 1. If _comparefn_ is not *undefined*, then + 1. Let _v_ be ? ToNumber(? Call(_comparefn_, *undefined*, « _x_, _y_ »)). + 1. If _v_ is *NaN*, return *+0*𝔽. + 1. Return _v_. + 1. [id="step-sortcompare-tostring-x"] Let _xString_ be ? ToString(_x_). + 1. [id="step-sortcompare-tostring-y"] Let _yString_ be ? ToString(_y_). + 1. Let _xSmaller_ be ! IsLessThan(_xString_, _yString_, *true*). + 1. If _xSmaller_ is *true*, return *-1*𝔽. + 1. Let _ySmaller_ be ! IsLessThan(_yString_, _xString_, *true*). + 1. If _ySmaller_ is *true*, return *1*𝔽. + 1. Return *+0*𝔽. + 1. Return ? CompareArrayElements(_x_, _y_, _comparefn_). + 1. Return ? SortIndexedProperties(_obj_, _len_, _SortCompare_). + 1. [id="step-array-sortindexedproperties"] Let _sortedList_ be ? SortIndexedProperties(_obj_, _len_, _SortCompare_, *true*). + 1. Let _itemCount_ be the number of elements in _sortedList_. + 1. Let _j_ be 0. + 1. Repeat, while _j_ < _itemCount_, + 1. Perform ? CreateDataPropertyOrThrow(_obj_, ! ToString(𝔽(_j_)), _sortedList_[_j_]). + 1. Set _j_ to _j_ + 1. + 1. NOTE: The call to SortIndexedProperties in step has the *skipHoles* parameter set to *true*. The remaining indexes are deleted to preserve the number of holes that were detected and excluded from the sort. + 1. Repeat, while _j_ < _len_, + 1. Perform ? DeletePropertyOrThrow(_obj_, ! ToString(𝔽(_j_))). + 1. Set _j_ to _j_ + 1. + 1. Return _obj_. + +
+ + +

+ CompareArrayElements( + _x_: unknown, + _y_: unknown, + _comparefn_: a function object or *undefined* + ): either a normal completion containing a Number or an abrupt completion +

+
+
+ + 1. If _x_ and _y_ are both *undefined*, return *+0*𝔽. + 1. If _x_ is *undefined*, return *1*𝔽. + 1. If _y_ is *undefined*, return *-1*𝔽. + 1. If _comparefn_ is not *undefined*, then + 1. Let _v_ be ? ToNumber(? Call(_comparefn_, *undefined*, « _x_, _y_ »)). + 1. If _v_ is *NaN*, return *+0*𝔽. + 1. Return _v_. + 1. [id="step-sortcompare-tostring-x"] Let _xString_ be ? ToString(_x_). + 1. [id="step-sortcompare-tostring-y"] Let _yString_ be ? ToString(_y_). + 1. Let _xSmaller_ be ! IsLessThan(_xString_, _yString_, *true*). + 1. If _xSmaller_ is *true*, return *-1*𝔽. + 1. Let _ySmaller_ be ! IsLessThan(_yString_, _xString_, *true*). + 1. If _ySmaller_ is *true*, return *1*𝔽. + 1. Return *+0*𝔽. + +
+ + +

+ SortIndexedProperties ( + _obj_: an Object, + _len_: a non-negative integer, + _SortCompare_: an Abstract Closure with two parameters, + _skipHoles_: a Boolean + ): either a normal completion containing an Objecta List or an abrupt completion +

+
+
+ + 1. Let _items_ be a new empty List. + 1. Let _k_ be 0. + 1. Repeat, while _k_ < _len_, + 1. Let _Pk_ be ! ToString(𝔽(_k_)). + 1. Let _kPresent_ be ? HasProperty(_obj_, _Pk_). + 1. If _skipHoles_ is *true*, then + 1. Let _kRead_ be ? HasProperty(_obj_, _Pk_). + 1. Else, + 1. Let _kRead_ be *true*. + 1. If _kPresent__kRead_ is *true*, then + 1. Let _kValue_ be ? Get(_obj_, _Pk_). + 1. Append _kValue_ to _items_. + 1. Set _k_ to _k_ + 1. + 1. Let _itemCount_ be the number of elements in _items_. + 1. [id="step-array-sort"] Sort _items_ using an implementation-defined sequence of calls to _SortCompare_. If any such call returns an abrupt completion, stop before performing any further calls to _SortCompare_ or steps in this algorithm and return that Completion Record. + 1. Let _j_ be 0. + 1. Repeat, while _j_ < _itemCount_, + 1. Perform ? Set(_obj_, ! ToString(𝔽(_j_)), _items_[_j_], *true*). + 1. Set _j_ to _j_ + 1. + 1. Repeat, while _j_ < _len_, + 1. Perform ? DeletePropertyOrThrow(_obj_, ! ToString(𝔽(_j_))). + 1. Set _j_ to _j_ + 1. + 1. Return _obj_. + 1. Return _items_. + +
+

Array.prototype.toReversed ( )

@@ -39,7 +145,7 @@

Array.prototype.toReversed ( )

-

Array.prototype.toSorted ( _compareFn_ )

+

Array.prototype.toSorted ( _comparefn_ )

When the *toSorted* method is called, the following steps are taken:

@@ -48,19 +154,13 @@

Array.prototype.toSorted ( _compareFn_ )

1. Let _O_ be ? ToObject(*this* value). 1. Let _len_ be ? LengthOfArrayLike(_O_). 1. Let _A_ be ? ArrayCreate(𝔽(_len_)). - 1. Let _items_ be a new empty List. - 1. Let _k_ be 0. - 1. Repeat, while _k_ < _len_, - 1. Let _Pk_ be ! ToString(𝔽(_k_)). - 1. Let _kValue_ be ? Get(_O_, _Pk_). - 1. Append _kValue_ to _items_. - 1. Set _k_ to _k_ + 1. - 1. Sort _items_ using an implementation-defined sequence of calls to SortCompare. If any such call returns an abrupt completion, stop before performing any further calls to SortCompare or steps in this algorithm and return that completion. + 1. Let _SortCompare_ be a new Abstract Closure with parameters (_x_, _y_) that captures _comparefn_ and performs the following steps when called: + 1. Return ? CompareArrayElements(_x_, _y_, _comparefn_). + 1. Let _sortedList_ be ? SortIndexedProperties(_obj_, _len_, _SortCompare_, *false*). 1. Let _j_ be 0. - 1. For each element _E_ of _items_, do - 1. Let _Pj_ be ! ToString(𝔽(_j_)). - 1. Perform ! CreateDataPropertyOrThrow(_A_, _Pj_, _E_). - 1. Set _j_ to _j_ + 1. + 1. Repeat, while _j_ < _len_, + 1. Perform ! CreateDataPropertyOrThrow(_A_, ! ToString(𝔽(_j_)), _sortedList_[_j_]). + 1. Set _j_ to _j_ + 1. 1. Return _A_.
@@ -197,6 +297,75 @@

The %TypedArray% Intrinsic Object

Properties of the %TypedArray% Prototype Object

+ +

%TypedArray%.prototype.sort ( _comparefn_ )

+ +

The following steps are performed:

+ + 1. If _comparefn_ is not *undefined* and IsCallable(_comparefn_) is *false*, throw a *TypeError* exception. + 1. Let _obj_ be the *this* value. + 1. Perform ? ValidateTypedArray(_obj_). + 1. Let _buffer_ be _obj_.[[ViewedArrayBuffer]]. + 1. Let _len_ be _obj_.[[ArrayLength]]. + 1. NOTE: The following closure performs a numeric comparison rather than the string comparison used in . + 1. Let _SortCompare_ be a new Abstract Closure with parameters (_x_, _y_) that captures _comparefn_ and _buffer_ and performs the following steps when called: + 1. Assert: Both Type(_x_) and Type(_y_) are Number or both are BigInt. + 1. If _comparefn_ is not *undefined*, then + 1. Let _v_ be ? ToNumber(? Call(_comparefn_, *undefined*, « _x_, _y_ »)). + 1. If IsDetachedBuffer(_buffer_) is *true*, throw a *TypeError* exception. + 1. If _v_ is *NaN*, return *+0*𝔽. + 1. Return _v_. + 1. If _x_ and _y_ are both *NaN*, return *+0*𝔽. + 1. If _x_ is *NaN*, return *1*𝔽. + 1. If _y_ is *NaN*, return *-1*𝔽. + 1. If _x_ < _y_, return *-1*𝔽. + 1. If _x_ > _y_, return *1*𝔽. + 1. If _x_ is *-0*𝔽 and _y_ is *+0*𝔽, return *-1*𝔽. + 1. If _x_ is *+0*𝔽 and _y_ is *-0*𝔽, return *1*𝔽. + 1. Return *+0*𝔽. + 1. Return ? CompareTypedArrayElements(_x_, _y_, _comparefn_, _buffer_). + 1. Return ? SortIndexedProperties(_obj_, _len_, _SortCompare_). + 1. Let _sortedList_ be ? SortIndexedProperties(_obj_, _len_, _SortCompare_, *false*). + 1. Let _j_ be 0. + 1. Repeat, while _j_ < _len_, + 1. Perform ! Set(_obj_, ! ToString(𝔽(_j_)), _sortedList_[_j_], *true*). + 1. Set _j_ to _j_ + 1. + 1. Return _obj_. + +
+ + +

+ CompareTypedArrayElements( + _x_: unknown, + _y_: unknown, + _comparefn_: a function object or *undefined*, + _buffer_: An ArrayBuffer + ): either a normal completion containing a Number or an abrupt completion +

+
+
+ + 1. Assert: Both Type(_x_) and Type(_y_) are Number or both are BigInt. + 1. If _comparefn_ is not *undefined*, then + 1. Let _v_ be ? ToNumber(? Call(_comparefn_, *undefined*, « _x_, _y_ »)). + 1. If IsDetachedBuffer(_buffer_) is *true*, throw a *TypeError* exception. + 1. If _v_ is *NaN*, return *+0*𝔽. + 1. Return _v_. + 1. If _x_ and _y_ are both *NaN*, return *+0*𝔽. + 1. If _x_ is *NaN*, return *1*𝔽. + 1. If _y_ is *NaN*, return *-1*𝔽. + 1. If _x_ < _y_, return *-1*𝔽. + 1. If _x_ > _y_, return *1*𝔽. + 1. If _x_ is *-0*𝔽 and _y_ is *+0*𝔽, return *-1*𝔽. + 1. If _x_ is *+0*𝔽 and _y_ is *-0*𝔽, return *1*𝔽. + 1. Return *+0*𝔽. + + + This performs a numeric comparison rather than the string comparison used in . + +
+

%TypedArray%.prototype.toReversed ( )

@@ -219,7 +388,7 @@

%TypedArray%.prototype.toReversed ( )

-

%TypedArray%.prototype.toSorted ( _compareFn_ )

+

%TypedArray%.prototype.toSorted ( _comparefn_ )

When the *toSorted* method is called, the following steps are taken:

@@ -227,41 +396,19 @@

%TypedArray%.prototype.toSorted ( _compareFn_ )

1. If _comparefn_ is not *undefined* and IsCallable(_comparefn_) is *false*, throw a *TypeError* exception. 1. Let _O_ be the *this* value. 1. Perform ? ValidateTypedArray(_O_). + 1. Let _buffer_ be _obj_.[[ViewedArrayBuffer]]. 1. Let _len_ be _O_.[[ArrayLength]]. 1. Let _A_ be ? TypedArrayCreateSameType(_O_, « 𝔽(_len_) »). - 1. Let _items_ be a new empty List. - 1. Let _k_ be 0. - 1. Repeat, while _k_ < _len_, - 1. Let _Pk_ be ! ToString(𝔽(_k_)). - 1. Let _kValue_ be ! Get(_O_, _Pk_). - 1. Append _kValue_ to _items_. - 1. Set _k_ to _k_ + 1. - 1. Sort _items_ using an implementation-defined sequence of calls to SortCompare. If any such call returns an abrupt completion, stop before performing any further calls to SortCompare or steps in this algorithm and return that completion. + 1. NOTE: The following closure performs a numeric comparison rather than the string comparison used in . + 1. Let _SortCompare_ be a new Abstract Closure with parameters (_x_, _y_) that captures _comparefn_ and _buffer_ and performs the following steps when called: + 1. Return ? CompareTypedArrayElements(_x_, _y_, _comparefn_, _buffer_). + 1. Let _sortedList_ be ? SortIndexedProperties(_obj_, _len_, _SortCompare_, *false*). 1. Let _j_ be 0. - 1. For each element _E_ of _items_, do - 1. Let _Pj_ be ! ToString(𝔽(_j_)). - 1. Perform ! Set(_A_, _Pj_, _E_, *true*). - 1. Set _j_ to _j_ + 1. + 1. Repeat, while _j_ < _len_, + 1. Perform ! Set(_A_, ! ToString(𝔽(_j_)), _sortedList_[_j_], *true*). + 1. Set _j_ to _j_ + 1. 1. Return _A_. -

The following version of SortCompare is used by %TypedArray%`.prototype.toSorted`.

-

The abstract operation TypedArraySortCompare performs the following steps when called:

- - 1. Assert: Both Type(_x_) and Type(_y_) are Number or both are BigInt. - 1. If _comparefn_ is not *undefined*, then - 1. Let _v_ be ? ToNumber(? Call(_comparefn_, *undefined*, « _x_, _y_ »)). - 1. If IsDetachedBuffer(_buffer_) is *true*, throw a *TypeError* exception. - 1. If _v_ is *NaN*, return *+0*𝔽. - 1. Return _v_. - 1. If _x_ and _y_ are both *NaN*, return *+0*𝔽. - 1. If _x_ is *NaN*, return *1*𝔽. - 1. If _y_ is *NaN*, return *-1*𝔽. - 1. If _x_ < _y_, return *-1*𝔽. - 1. If _x_ > _y_, return *1*𝔽. - 1. If _x_ is *-0*𝔽 and _y_ is *+0*𝔽, return *-1*𝔽. - 1. If _x_ is *+0*𝔽 and _y_ is *-0*𝔽, return *1*𝔽. - 1. Return *+0*𝔽. -