mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-10-07 16:13:49 +00:00
!4493 ECMA Script 2023-支持Array.prototype.toSorted方法
Merge pull request !4493 from 查维/master
This commit is contained in:
commit
f27f8bceae
@ -24,6 +24,7 @@
|
||||
#include "ecmascript/js_hclass.h"
|
||||
#include "ecmascript/js_tagged_number.h"
|
||||
#include "ecmascript/js_tagged_value-inl.h"
|
||||
#include "ecmascript/object_fast_operator-inl.h"
|
||||
|
||||
namespace panda::ecmascript::base {
|
||||
bool ArrayHelper::IsConcatSpreadable(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
|
||||
@ -248,4 +249,54 @@ JSTaggedValue ArrayHelper::FlattenIntoArray(JSThread *thread, const JSHandle<JSO
|
||||
// 7. Return targetIndex.
|
||||
return BuiltinsBase::GetTaggedDouble(tempArgs.start);
|
||||
}
|
||||
|
||||
JSTaggedValue ArrayHelper::SortIndexedProperties(JSThread *thread, const JSHandle<JSObject> &thisObj,
|
||||
int64_t len, const JSHandle<JSTaggedValue> &callbackFnHandle,
|
||||
HolesType holes)
|
||||
{
|
||||
// 1. Let items be a new empty List.
|
||||
JSHandle<TaggedArray> items(thread->GetEcmaVM()->GetFactory()->NewTaggedArray(len));
|
||||
// 2. Let k be 0.
|
||||
int64_t k = 0;
|
||||
// 3. Repeat, while k < len,
|
||||
// a. Let Pk be ! ToString(𝔽(k)).
|
||||
// b. If holes is skip-holes, then
|
||||
// i. Let kRead be ? HasProperty(obj, Pk).
|
||||
// c. Else,
|
||||
// i. Assert: holes is read-through-holes.
|
||||
// ii. Let kRead be true.
|
||||
// d. If kRead is true, then
|
||||
// i. Let kValue be ? Get(obj, Pk).
|
||||
// ii. Append kValue to items.
|
||||
// e. Set k to k + 1.
|
||||
bool kRead = false;
|
||||
JSHandle<JSTaggedValue> thisObjVal(thisObj);
|
||||
JSMutableHandle<JSTaggedValue> pk(thread, JSTaggedValue::Undefined());
|
||||
|
||||
while(k < len) {
|
||||
if (holes == HolesType::SKIP_HOLES) {
|
||||
pk.Update(JSTaggedValue(k));
|
||||
kRead = JSTaggedValue::HasProperty(thread, thisObjVal, pk);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
} else {
|
||||
ASSERT(holes == HolesType::READ_THROUGH_HOLES);
|
||||
kRead = true;
|
||||
}
|
||||
if (kRead) {
|
||||
JSHandle<JSTaggedValue> kValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, k);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
items->Set(thread, k, kValue.GetTaggedValue());
|
||||
}
|
||||
++k;
|
||||
}
|
||||
JSHandle<JSArray> array(JSArray::CreateArrayFromList(thread, items));
|
||||
JSHandle<JSObject> arrayObj = JSHandle<JSObject>::Cast(array);
|
||||
// 4. 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 and return that Completion Record.
|
||||
JSArray::Sort(thread, arrayObj, callbackFnHandle);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
// 5. Return items.
|
||||
return arrayObj.GetTaggedValue();
|
||||
}
|
||||
} // namespace panda::ecmascript::base
|
||||
|
@ -26,6 +26,11 @@ struct FlattenArgs {
|
||||
int64_t start = 0;
|
||||
double depth = 0;
|
||||
};
|
||||
|
||||
enum class HolesType {
|
||||
SKIP_HOLES,
|
||||
READ_THROUGH_HOLES,
|
||||
};
|
||||
class ArrayHelper {
|
||||
public:
|
||||
static bool IsConcatSpreadable(JSThread *thread, const JSHandle<JSTaggedValue> &obj);
|
||||
@ -37,6 +42,9 @@ public:
|
||||
const JSHandle<JSTaggedValue> &thisObjVal, const FlattenArgs &args,
|
||||
const JSHandle<JSTaggedValue> &mapperFunctionHandle,
|
||||
const JSHandle<JSTaggedValue> &thisArg);
|
||||
static JSTaggedValue SortIndexedProperties(JSThread *thread, const JSHandle<JSObject> &thisObj,
|
||||
int64_t len, const JSHandle<JSTaggedValue> &callbackFnHandle,
|
||||
HolesType holes);
|
||||
};
|
||||
} // namespace panda::ecmascript::base
|
||||
|
||||
|
@ -2129,6 +2129,7 @@ void Builtins::InitializeArray(const JSHandle<GlobalEnv> &env, const JSHandle<JS
|
||||
SetFunction(env, arrFuncPrototype, "flat", BuiltinsArray::Flat, FunctionLength::ZERO);
|
||||
SetFunction(env, arrFuncPrototype, "flatMap", BuiltinsArray::FlatMap, FunctionLength::ONE);
|
||||
SetFunction(env, arrFuncPrototype, "at", BuiltinsArray::At, FunctionLength::ONE);
|
||||
SetFunction(env, arrFuncPrototype, "toSorted", BuiltinsArray::ToSorted, FunctionLength::ONE);
|
||||
SetFunction(env, arrFuncPrototype, "toSpliced", BuiltinsArray::ToSpliced, FunctionLength::TWO);
|
||||
|
||||
// %ArrayPrototype% [ @@iterator ]
|
||||
|
@ -2980,6 +2980,60 @@ JSTaggedValue BuiltinsArray::At(EcmaRuntimeCallInfo *argv)
|
||||
return element.GetTaggedValue();
|
||||
}
|
||||
|
||||
// 23.1.3.34 Array.prototype.toSorted ( comparefn )
|
||||
JSTaggedValue BuiltinsArray::ToSorted(EcmaRuntimeCallInfo *argv)
|
||||
{
|
||||
ASSERT(argv);
|
||||
JSThread *thread = argv->GetThread();
|
||||
BUILTINS_API_TRACE(thread, Array, ToSorted);
|
||||
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
||||
|
||||
// 1. If comparefn is not undefined and IsCallable(comparefn) is false, throw a TypeError exception.
|
||||
JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
|
||||
if (!callbackFnHandle->IsUndefined() && !callbackFnHandle->IsCallable()) {
|
||||
THROW_TYPE_ERROR_AND_RETURN(thread, "Callable is false", JSTaggedValue::Exception());
|
||||
}
|
||||
|
||||
// 2. Let obj be ToObject(this value).
|
||||
JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
|
||||
JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
|
||||
// 3. Let len be ToLength(Get(obj, "length")).
|
||||
int64_t len = ArrayHelper::GetArrayLength(thread, JSHandle<JSTaggedValue>(thisObjHandle));
|
||||
// ReturnIfAbrupt(len).
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
|
||||
// 4. Let A be ? ArrayCreate(len).
|
||||
JSTaggedValue newArray = JSArray::ArrayCreate(thread, JSTaggedNumber(static_cast<double>(len))).GetTaggedValue();
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
JSHandle<JSObject> newArrayHandle(thread, newArray);
|
||||
|
||||
// 5. Let SortCompare be a new Abstract Closure with parameters (x, y) that captures comparefn and performs
|
||||
// the following steps when called:
|
||||
// a. Return ? CompareArrayElements(x, y, comparefn).
|
||||
// 6. Let sortedList be ? SortIndexedProperties(O, len, SortCompare, read-through-holes).
|
||||
JSTaggedValue sortedList = ArrayHelper::SortIndexedProperties(thread, thisObjHandle, len, callbackFnHandle,
|
||||
base::HolesType::READ_THROUGH_HOLES);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
JSHandle<JSTaggedValue> sortedArray(thread, sortedList);
|
||||
|
||||
//7. Let j be 0.
|
||||
int64_t j = 0;
|
||||
// 8. Repeat, while j < len,
|
||||
// a. Perform ! CreateDataPropertyOrThrow(A, ! ToString(𝔽(j)), sortedList[j]).
|
||||
// b. Set j to j + 1.
|
||||
while (j < len) {
|
||||
JSHandle<JSTaggedValue> item = JSArray::FastGetPropertyByValue(thread, sortedArray, j);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, j, item);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
++j;
|
||||
}
|
||||
// 9. Return A.
|
||||
return newArrayHandle.GetTaggedValue();
|
||||
}
|
||||
|
||||
// 23.1.3.35 Array.prototype.toSpliced ( start, skipCount, ...items )
|
||||
JSTaggedValue BuiltinsArray::ToSpliced(EcmaRuntimeCallInfo *argv)
|
||||
{
|
||||
|
@ -103,6 +103,8 @@ public:
|
||||
static JSTaggedValue FlatMap(EcmaRuntimeCallInfo *argv);
|
||||
// 23.1.3.1 Array.prototype.at ( index )
|
||||
static JSTaggedValue At(EcmaRuntimeCallInfo *argv);
|
||||
// 23.1.3.34 Array.prototype.toSorted ( comparefn )
|
||||
static JSTaggedValue ToSorted(EcmaRuntimeCallInfo *argv);
|
||||
// 23.1.3.11
|
||||
static JSTaggedValue FindLast(EcmaRuntimeCallInfo *argv);
|
||||
// 23.1.3.12
|
||||
@ -112,4 +114,4 @@ public:
|
||||
};
|
||||
} // namespace panda::ecmascript::builtins
|
||||
|
||||
#endif // ECMASCRIPT_BUILTINS_BUILTINS_ARRAY_H
|
||||
#endif // ECMASCRIPT_BUILTINS_BUILTINS_ARRAY_H
|
||||
|
@ -38,6 +38,8 @@ using namespace panda::ecmascript::base;
|
||||
constexpr int32_t INT_VALUE_0 = 0;
|
||||
constexpr int32_t INT_VALUE_1 = 1;
|
||||
constexpr int32_t INT_VALUE_2 = 2;
|
||||
constexpr int32_t INT_VALUE_3 = 3;
|
||||
constexpr uint32_t RUNTIME_CALL_INFO_PARA_NUM_4 = 4;
|
||||
constexpr int32_t INT_VALUE_666 = 666;
|
||||
constexpr uint32_t RUNTIME_CALL_INFO_PARA_NUM_10 = 10;
|
||||
|
||||
@ -1736,6 +1738,42 @@ HWTEST_F_L0(BuiltinsArrayTest, At)
|
||||
ASSERT_EQ(result, JSTaggedValue::Undefined());
|
||||
}
|
||||
|
||||
HWTEST_F_L0(BuiltinsArrayTest, ToSorted)
|
||||
{
|
||||
JSHandle<JSTaggedValue> lengthKeyHandle = thread->GlobalConstants()->GetHandledLengthString();
|
||||
JSArray *arr =
|
||||
JSArray::Cast(JSArray::ArrayCreate(thread, JSTaggedNumber(INT_VALUE_0)).GetTaggedValue().GetTaggedObject());
|
||||
EXPECT_TRUE(arr != nullptr);
|
||||
JSHandle<JSObject> obj(thread, arr);
|
||||
EXPECT_EQ(JSArray::GetProperty(thread, JSHandle<JSTaggedValue>(obj),
|
||||
lengthKeyHandle).GetValue()->GetInt(), INT_VALUE_0);
|
||||
JSHandle<JSTaggedValue> key0(thread, JSTaggedValue(INT_VALUE_0));
|
||||
PropertyDescriptor desc0(thread, JSHandle<JSTaggedValue>(thread, JSTaggedValue(INT_VALUE_3)), true, true, true);
|
||||
JSArray::DefineOwnProperty(thread, obj, key0, desc0);
|
||||
JSHandle<JSTaggedValue> key1(thread, JSTaggedValue(INT_VALUE_1));
|
||||
PropertyDescriptor desc1(thread, JSHandle<JSTaggedValue>(thread, JSTaggedValue(INT_VALUE_2)), true, true, true);
|
||||
JSArray::DefineOwnProperty(thread, obj, key1, desc1);
|
||||
JSHandle<JSTaggedValue> key2(thread, JSTaggedValue(INT_VALUE_2));
|
||||
PropertyDescriptor desc2(thread, JSHandle<JSTaggedValue>(thread, JSTaggedValue(INT_VALUE_1)), true, true, true);
|
||||
JSArray::DefineOwnProperty(thread, obj, key2, desc2);
|
||||
|
||||
auto ecmaRuntimeCallInfo1 =
|
||||
TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), RUNTIME_CALL_INFO_PARA_NUM_4);
|
||||
ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue::Undefined());
|
||||
ecmaRuntimeCallInfo1->SetThis(obj.GetTaggedValue());
|
||||
|
||||
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1);
|
||||
JSTaggedValue result2 = Array::ToSorted(ecmaRuntimeCallInfo1);
|
||||
TestHelper::TearDownFrame(thread, prev);
|
||||
|
||||
EXPECT_TRUE(result2.IsECMAObject());
|
||||
JSHandle<JSTaggedValue> resultArr =
|
||||
JSHandle<JSTaggedValue>(thread, JSTaggedValue(static_cast<JSTaggedType>(result2.GetRawData())));
|
||||
EXPECT_EQ(JSArray::GetProperty(thread, resultArr, key0).GetValue()->GetInt(), INT_VALUE_1);
|
||||
EXPECT_EQ(JSArray::GetProperty(thread, resultArr, key1).GetValue()->GetInt(), INT_VALUE_2);
|
||||
EXPECT_EQ(JSArray::GetProperty(thread, resultArr, key2).GetValue()->GetInt(), INT_VALUE_3);
|
||||
}
|
||||
|
||||
HWTEST_F_L0(BuiltinsArrayTest, ToSpliced)
|
||||
{
|
||||
JSHandle<JSTaggedValue> lengthKeyHandle = thread->GlobalConstants()->GetHandledLengthString();
|
||||
|
@ -272,6 +272,7 @@ namespace panda::ecmascript {
|
||||
V(Array, Flat) \
|
||||
V(Array, FlatMap) \
|
||||
V(Array, At) \
|
||||
V(Array, ToSorted) \
|
||||
V(Array, ToSpliced) \
|
||||
V(ArrayBuffer, Constructor) \
|
||||
V(ArrayBuffer, Slice) \
|
||||
|
@ -420,6 +420,7 @@ static uintptr_t g_nativeTable[] = {
|
||||
reinterpret_cast<uintptr_t>(BuiltinsArray::Flat),
|
||||
reinterpret_cast<uintptr_t>(BuiltinsArray::FlatMap),
|
||||
reinterpret_cast<uintptr_t>(BuiltinsArray::At),
|
||||
reinterpret_cast<uintptr_t>(BuiltinsArray::ToSorted),
|
||||
reinterpret_cast<uintptr_t>(BuiltinsArray::ToSpliced),
|
||||
reinterpret_cast<uintptr_t>(BuiltinsTypedArray::TypedArrayBaseConstructor),
|
||||
reinterpret_cast<uintptr_t>(BuiltinsTypedArray::CopyWithin),
|
||||
|
@ -142,4 +142,14 @@ print(arr21.at(5));
|
||||
print(arr21.at(-1));
|
||||
print(arr21.at(6));
|
||||
print(arr21.at('1.9'));
|
||||
print(arr21.at(true));
|
||||
print(arr21.at(true));
|
||||
|
||||
const months = ["Mar", "Jan", "Feb", "Dec"];
|
||||
const sortedMonths = months.toSorted();
|
||||
print(sortedMonths); // ['Dec', 'Feb', 'Jan', 'Mar']
|
||||
print(months); // ['Mar', 'Jan', 'Feb', 'Dec']
|
||||
|
||||
const values = [1, 10, 21, 2];
|
||||
const sortedValues = values.toSorted((a, b) => {return a- b});
|
||||
print(sortedValues); // [1, 2, 10, 21]
|
||||
print(values); // [1, 10, 21, 2]
|
@ -75,3 +75,7 @@ undefined
|
||||
undefined
|
||||
2
|
||||
2
|
||||
Dec,Feb,Jan,Mar
|
||||
Mar,Jan,Feb,Dec
|
||||
1,2,10,21
|
||||
1,10,21,2
|
||||
|
Loading…
Reference in New Issue
Block a user