Skip to content

Commit

Permalink
implement TypedArray.prototype.toSorted
Browse files Browse the repository at this point in the history
  • Loading branch information
robik committed Jun 28, 2024
1 parent 70df046 commit ea1e6ac
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 0 deletions.
1 change: 1 addition & 0 deletions include/hermes/VM/NativeFunctions.def
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,7 @@ NATIVE_FUNCTION(typedArrayPrototypeSort)
NATIVE_FUNCTION(typedArrayPrototypeSubarray)
NATIVE_FUNCTION(typedArrayPrototypeSymbolToStringTag)
NATIVE_FUNCTION(typedArrayPrototypeToLocaleString)
NATIVE_FUNCTION(typedArrayPrototypeToSorted)
NATIVE_FUNCTION(unescape)
NATIVE_FUNCTION(weakMapConstructor)
NATIVE_FUNCTION(weakMapPrototypeDelete)
Expand Down
1 change: 1 addition & 0 deletions include/hermes/VM/PredefinedStrings.def
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ STR(flat, "flat")
STR(flatMap, "flatMap")
STR(toReversed, "toReversed")
STR(toSpliced, "toSpliced")
STR(toSorted, "toSorted")
STR(with, "with")

STR(ArrayBuffer, "ArrayBuffer")
Expand Down
62 changes: 62 additions & 0 deletions lib/VM/JSLib/TypedArray.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1746,6 +1746,60 @@ typedArrayPrototypeToLocaleString(void *, Runtime &runtime, NativeArgs args) {
return HermesValue::encodeStringValue(*builder->getStringPrimitive());
}

/// ES14.0 23.2.3.33
CallResult<HermesValue>
typedArrayPrototypeToSorted(void *, Runtime &runtime, NativeArgs args) {
GCScope gcScope{runtime};

// 1. If comparefn is not undefined and IsCallable(comparefn) is false, throw
// a TypeError exception.
auto compareFn = Handle<Callable>::dyn_vmcast(args.getArgHandle(0));
if (!args.getArg(0).isUndefined() && !compareFn) {
return runtime.raiseTypeError(
"TypedArray toSorted argument must be callable");
}

// 3. Perform ? ValidateTypedArray(O).
if (JSTypedArrayBase::validateTypedArray(runtime, args.getThisHandle()) ==
ExecutionStatus::EXCEPTION) {
return ExecutionStatus::EXCEPTION;
}

// 2. Let O be this value
auto self = args.vmcastThis<JSTypedArrayBase>();

// 4. Let len be O.[[ArrayLength]].
double len = self->getLength();

// 5. Let A be ? TypedArrayCreateSameType(O, « 𝔽(len) »).
auto aRes = JSTypedArrayBase::allocateSpecies(runtime, self, len);
if (LLVM_UNLIKELY(aRes == ExecutionStatus::EXCEPTION)) {
return ExecutionStatus::EXCEPTION;
}
auto A = aRes.getValue();

if (LLVM_UNLIKELY(
JSTypedArrayBase::setToCopyOfTypedArray(
runtime, A, 0, self, 0, len) == ExecutionStatus::EXCEPTION)) {
return ExecutionStatus::EXCEPTION;
}

// Use our custom sort routine. We can't use std::sort because it performs
// optimizations that allow it to bypass calls to std::swap, but our swap
// function is special, since it needs to use the internal Object functions.
if (compareFn) {
TypedArraySortModel<true> sm(runtime, A, compareFn);
if (LLVM_UNLIKELY(quickSort(&sm, 0, len) == ExecutionStatus::EXCEPTION))
return ExecutionStatus::EXCEPTION;
} else {
TypedArraySortModel<false> sm(runtime, A, compareFn);
if (LLVM_UNLIKELY(quickSort(&sm, 0, len) == ExecutionStatus::EXCEPTION))
return ExecutionStatus::EXCEPTION;
}

return A.getHermesValue();
}

Handle<JSObject> createTypedArrayBaseConstructor(Runtime &runtime) {
auto proto = Handle<JSObject>::vmcast(&runtime.typedArrayBasePrototype);

Expand Down Expand Up @@ -2044,6 +2098,14 @@ Handle<JSObject> createTypedArrayBaseConstructor(Runtime &runtime) {
typedArrayPrototypeToLocaleString,
0);

defineMethod(
runtime,
proto,
Predefined::getSymbolID(Predefined::toSorted),
nullptr,
typedArrayPrototypeToSorted,
0);

// TypedArrayBase.xxx
defineMethod(
runtime,
Expand Down
28 changes: 28 additions & 0 deletions test/hermes/TypedArray.js
Original file line number Diff line number Diff line change
Expand Up @@ -1438,6 +1438,34 @@ cons.forEach(function(TypedArray) {
});
/// @}

/// @name TypedArray.prototype.toSorted
/// @{
cons.forEach(function(TypedArray) {
var arr = new TypedArray([ 5, 1, 2, 4, 0, 3 ]);

assert.arrayEqual(arr.toSorted(), [ 0, 1, 2, 3, 4, 5 ]);
assert.arrayEqual(
arr.toSorted(
(a, b) => a < b ? -1
: a > b ? 1
: 0),
[ 0, 1, 2, 3, 4, 5 ]);
assert.arrayEqual(
arr.toSorted(
(a, b) => a < b ? 1
: a > b ? -1
: 0),
[ 5, 4, 3, 2, 1, 0 ]);

assert.throws(function() {
arr.toSorted(1);
}, TypeError);
assert.throws(function() {
arr.toSorted("test");
}, TypeError);
});
/// @}

/// @name Exception cases
/// @{

Expand Down

0 comments on commit ea1e6ac

Please sign in to comment.