mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-11-27 12:10:47 +00:00
!4923 Fix Array.prototype.sort part1
Merge pull request !4923 from xliu/fix_sort
This commit is contained in:
commit
c7dbfbdf8d
@ -366,9 +366,9 @@ JSTaggedValue ArrayHelper::FlattenIntoArray(JSThread *thread, const JSHandle<JSO
|
||||
return BuiltinsBase::GetTaggedDouble(tempArgs.start);
|
||||
}
|
||||
|
||||
JSTaggedValue ArrayHelper::SortIndexedProperties(JSThread *thread, const JSHandle<JSObject> &thisObj,
|
||||
int64_t len, const JSHandle<JSTaggedValue> &callbackFnHandle,
|
||||
HolesType holes)
|
||||
JSHandle<TaggedArray> ArrayHelper::SortIndexedProperties(JSThread *thread, const JSHandle<JSTaggedValue> &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));
|
||||
@ -386,33 +386,34 @@ JSTaggedValue ArrayHelper::SortIndexedProperties(JSThread *thread, const JSHandl
|
||||
// ii. Append kValue to items.
|
||||
// e. Set k to k + 1.
|
||||
bool kRead = false;
|
||||
JSHandle<JSTaggedValue> thisObjVal(thisObj);
|
||||
JSMutableHandle<JSTaggedValue> pk(thread, JSTaggedValue::Undefined());
|
||||
|
||||
int64_t index = 0;
|
||||
while (k < len) {
|
||||
if (holes == HolesType::SKIP_HOLES) {
|
||||
pk.Update(JSTaggedValue(k));
|
||||
kRead = JSTaggedValue::HasProperty(thread, thisObjVal, pk);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
pk.Update(JSTaggedValue(k));
|
||||
kRead = JSTaggedValue::HasProperty(thread, thisObj, pk);
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, items);
|
||||
} 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());
|
||||
JSHandle<JSTaggedValue> kValue = JSArray::FastGetPropertyByValue(thread, thisObj, k);
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, items);
|
||||
items->Set(thread, index++, kValue.GetTaggedValue());
|
||||
}
|
||||
++k;
|
||||
}
|
||||
JSHandle<JSArray> array(JSArray::CreateArrayFromList(thread, items));
|
||||
JSHandle<JSObject> arrayObj = JSHandle<JSObject>::Cast(array);
|
||||
if (index < k) {
|
||||
items->Trim(thread, index);
|
||||
}
|
||||
// 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);
|
||||
JSArray::SortElements(thread, items, callbackFnHandle);
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, items);
|
||||
// 5. Return items.
|
||||
return arrayObj.GetTaggedValue();
|
||||
return items;
|
||||
}
|
||||
} // namespace panda::ecmascript::base
|
||||
|
@ -70,9 +70,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);
|
||||
static JSHandle<TaggedArray> SortIndexedProperties(JSThread *thread, const JSHandle<JSTaggedValue> &thisObj,
|
||||
int64_t len, const JSHandle<JSTaggedValue> &callbackFnHandle,
|
||||
HolesType holes);
|
||||
};
|
||||
} // namespace panda::ecmascript::base
|
||||
|
||||
|
@ -2206,62 +2206,23 @@ JSTaggedValue BuiltinsArray::Some(EcmaRuntimeCallInfo *argv)
|
||||
JSTaggedValue BuiltinsArray::Sort(EcmaRuntimeCallInfo *argv)
|
||||
{
|
||||
ASSERT(argv);
|
||||
BUILTINS_API_TRACE(argv->GetThread(), Array, Sort);
|
||||
JSThread *thread = argv->GetThread();
|
||||
BUILTINS_API_TRACE(thread, Array, Sort);
|
||||
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
||||
|
||||
// 1. Let obj be ToObject(this value).
|
||||
JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
|
||||
JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(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 len be ToLength(Get(obj, "length")).
|
||||
int64_t len = ArrayHelper::GetArrayLength(thread, JSHandle<JSTaggedValue>(thisObjHandle));
|
||||
// 3. ReturnIfAbrupt(len).
|
||||
// 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);
|
||||
|
||||
JSMutableHandle<JSTaggedValue> presentValue(thread, JSTaggedValue::Undefined());
|
||||
JSMutableHandle<JSTaggedValue> middleValue(thread, JSTaggedValue::Undefined());
|
||||
JSMutableHandle<JSTaggedValue> previousValue(thread, JSTaggedValue::Undefined());
|
||||
for (int i = 1; i < len; i++) {
|
||||
int beginIndex = 0;
|
||||
int endIndex = i;
|
||||
presentValue.Update(ObjectFastOperator::FastGetPropertyByIndex<true>(thread, thisObjHandle.GetTaggedValue(), i));
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
while (beginIndex < endIndex) {
|
||||
int middleIndex = (beginIndex + endIndex) / 2; // 2 : half
|
||||
middleValue.Update(
|
||||
ObjectFastOperator::FastGetPropertyByIndex<true>(thread, thisObjHandle.GetTaggedValue(), middleIndex));
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
double compareResult = ArrayHelper::SortCompare(thread, callbackFnHandle, middleValue, presentValue);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
if (compareResult > 0) {
|
||||
endIndex = middleIndex;
|
||||
} else {
|
||||
beginIndex = middleIndex + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (endIndex >= 0 && endIndex < i) {
|
||||
for (int j = i; j > endIndex; j--) {
|
||||
previousValue.Update(
|
||||
ObjectFastOperator::FastGetPropertyByIndex<true>(thread, thisObjHandle.GetTaggedValue(), j - 1));
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
ObjectFastOperator::FastSetPropertyByIndex(thread, thisObjHandle.GetTaggedValue(), j,
|
||||
previousValue.GetTaggedValue());
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
}
|
||||
ObjectFastOperator::FastSetPropertyByIndex(thread, thisObjHandle.GetTaggedValue(), endIndex,
|
||||
presentValue.GetTaggedValue());
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
}
|
||||
}
|
||||
|
||||
// Array sort
|
||||
JSArray::Sort(thread, JSHandle<JSTaggedValue>::Cast(thisObjHandle), callbackFnHandle);
|
||||
return thisObjHandle.GetTaggedValue();
|
||||
}
|
||||
|
||||
@ -3064,20 +3025,20 @@ JSTaggedValue BuiltinsArray::ToSorted(EcmaRuntimeCallInfo *argv)
|
||||
// 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);
|
||||
JSHandle<TaggedArray> sortedList =
|
||||
ArrayHelper::SortIndexedProperties(thread, JSHandle<JSTaggedValue>::Cast(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.
|
||||
JSMutableHandle<JSTaggedValue> itemValue(thread, JSTaggedValue::Undefined());
|
||||
while (j < len) {
|
||||
JSHandle<JSTaggedValue> item = JSArray::FastGetPropertyByValue(thread, sortedArray, j);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, j, item);
|
||||
itemValue.Update(sortedList->Get(j));
|
||||
JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, j, itemValue);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
++j;
|
||||
}
|
||||
|
@ -24,6 +24,8 @@
|
||||
#include "ecmascript/object_fast_operator-inl.h"
|
||||
|
||||
namespace panda::ecmascript {
|
||||
using base::ArrayHelper;
|
||||
|
||||
JSTaggedValue JSArray::LengthGetter([[maybe_unused]] JSThread *thread, const JSHandle<JSObject> &self)
|
||||
{
|
||||
return JSTaggedValue(JSArray::Cast(*self)->GetLength());
|
||||
@ -387,30 +389,67 @@ bool JSArray::FastSetPropertyByValue(JSThread *thread, const JSHandle<JSTaggedVa
|
||||
value.GetTaggedValue());
|
||||
}
|
||||
|
||||
void JSArray::Sort(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &fn)
|
||||
// ecma2024 23.1.3.20 Array.prototype.sort(comparefn)
|
||||
JSTaggedValue JSArray::Sort(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &fn)
|
||||
{
|
||||
if (!fn->IsUndefined() && !fn->IsCallable()) {
|
||||
THROW_TYPE_ERROR(thread, "Callable is false");
|
||||
ASSERT(fn->IsUndefined() || fn->IsCallable());
|
||||
// 3. Let len be ?LengthOfArrayLike(obj).
|
||||
int64_t len = ArrayHelper::GetArrayLength(thread, obj);
|
||||
// ReturnIfAbrupt(len).
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
|
||||
// 4. 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).
|
||||
// 5. Let sortedList be ? SortIndexedProperties(O, len, SortCompare, SKIP-HOLES).
|
||||
JSHandle<TaggedArray> sortedList =
|
||||
ArrayHelper::SortIndexedProperties(thread, obj, len, fn, base::HolesType::SKIP_HOLES);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
// 6. Let itemCount be the number of elements in sortedList.
|
||||
uint32_t itemCount = sortedList->GetLength();
|
||||
|
||||
// 7. Let j be 0.
|
||||
uint32_t j = 0;
|
||||
// 8. Repeat, while j < itemCount,
|
||||
// a. Perform ! Set(obj, ! ToString((j)), sortedList[j], true).
|
||||
// b. Set j to j + 1.
|
||||
JSMutableHandle<JSTaggedValue> item(thread, JSTaggedValue::Undefined());
|
||||
while (j < itemCount) {
|
||||
item.Update(sortedList->Get(j));
|
||||
JSArray::FastSetPropertyByValue(thread, obj, j, item);
|
||||
ASSERT_NO_ABRUPT_COMPLETION(thread);
|
||||
++j;
|
||||
}
|
||||
// 9. NOTE: The call to SortIndexedProperties in step 5 uses SKIP-HOLES.The remaining indices are deleted to
|
||||
// preserve the number of holes that were detected and excluded from the sort.
|
||||
// 10. Repeat, while j < len,
|
||||
// a. Perform ? DeletePropertyOrThrow(obj, ! ToString((j))).
|
||||
// b. Set j to j + 1.
|
||||
while (j < len) {
|
||||
item.Update(JSTaggedValue(j));
|
||||
JSTaggedValue::DeletePropertyOrThrow(thread, obj, item);
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
++j;
|
||||
}
|
||||
|
||||
// 2. Let len be ToLength(Get(obj, "length")).
|
||||
int64_t len = base::ArrayHelper::GetArrayLength(thread, JSHandle<JSTaggedValue>(obj));
|
||||
// 3. ReturnIfAbrupt(len).
|
||||
RETURN_IF_ABRUPT_COMPLETION(thread);
|
||||
return obj.GetTaggedValue();
|
||||
}
|
||||
|
||||
void JSArray::SortElements(JSThread *thread, const JSHandle<TaggedArray> &elements, const JSHandle<JSTaggedValue> &fn)
|
||||
{
|
||||
ASSERT(fn->IsUndefined() || fn->IsCallable());
|
||||
|
||||
JSMutableHandle<JSTaggedValue> presentValue(thread, JSTaggedValue::Undefined());
|
||||
JSMutableHandle<JSTaggedValue> middleValue(thread, JSTaggedValue::Undefined());
|
||||
JSMutableHandle<JSTaggedValue> previousValue(thread, JSTaggedValue::Undefined());
|
||||
for (int64_t i = 1; i < len; i++) {
|
||||
int64_t beginIndex = 0;
|
||||
int64_t endIndex = i;
|
||||
presentValue.Update(ObjectFastOperator::FastGetPropertyByIndex<true>(thread, obj.GetTaggedValue(), i));
|
||||
RETURN_IF_ABRUPT_COMPLETION(thread);
|
||||
uint32_t len = elements->GetLength();
|
||||
for (uint32_t i = 1; i < len; i++) {
|
||||
uint32_t beginIndex = 0;
|
||||
uint32_t endIndex = i;
|
||||
presentValue.Update(elements->Get(i));
|
||||
while (beginIndex < endIndex) {
|
||||
int64_t middleIndex = (beginIndex + endIndex) / 2; // 2 : half
|
||||
middleValue.Update(
|
||||
ObjectFastOperator::FastGetPropertyByIndex<true>(thread, obj.GetTaggedValue(), middleIndex));
|
||||
RETURN_IF_ABRUPT_COMPLETION(thread);
|
||||
uint32_t middleIndex = (beginIndex + endIndex) / 2; // 2 : half
|
||||
middleValue.Update(elements->Get(middleIndex));
|
||||
int32_t compareResult = base::ArrayHelper::SortCompare(thread, fn, middleValue, presentValue);
|
||||
RETURN_IF_ABRUPT_COMPLETION(thread);
|
||||
if (compareResult > 0) {
|
||||
@ -421,17 +460,11 @@ void JSArray::Sort(JSThread *thread, const JSHandle<JSObject> &obj, const JSHand
|
||||
}
|
||||
|
||||
if (endIndex >= 0 && endIndex < i) {
|
||||
for (int64_t j = i; j > endIndex; j--) {
|
||||
previousValue.Update(
|
||||
ObjectFastOperator::FastGetPropertyByIndex<true>(thread, obj.GetTaggedValue(), j - 1));
|
||||
RETURN_IF_ABRUPT_COMPLETION(thread);
|
||||
ObjectFastOperator::FastSetPropertyByIndex(thread, obj.GetTaggedValue(), j,
|
||||
previousValue.GetTaggedValue());
|
||||
RETURN_IF_ABRUPT_COMPLETION(thread);
|
||||
for (uint32_t j = i; j > endIndex; j--) {
|
||||
previousValue.Update(elements->Get(j - 1));
|
||||
elements->Set(thread, j, previousValue);
|
||||
}
|
||||
ObjectFastOperator::FastSetPropertyByIndex(thread, obj.GetTaggedValue(), endIndex,
|
||||
presentValue.GetTaggedValue());
|
||||
RETURN_IF_ABRUPT_COMPLETION(thread);
|
||||
elements->Set(thread, endIndex, presentValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -91,13 +91,15 @@ public:
|
||||
static bool FastSetPropertyByValue(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
|
||||
const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value);
|
||||
|
||||
static void Sort(JSThread *thread, const JSHandle<JSObject> &obj, const JSHandle<JSTaggedValue> &fn);
|
||||
static JSTaggedValue Sort(JSThread *thread, const JSHandle<JSTaggedValue> &obj, const JSHandle<JSTaggedValue> &fn);
|
||||
static bool IncludeInSortedValue(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
|
||||
const JSHandle<JSTaggedValue> &value);
|
||||
static JSHandle<TaggedArray> ToTaggedArray(JSThread *thread, const JSHandle<JSTaggedValue> &obj);
|
||||
static void CheckAndCopyArray(const JSThread *thread, JSHandle<JSArray> obj);
|
||||
static void SetCapacity(JSThread *thread, const JSHandle<JSObject> &array, uint32_t oldLen, uint32_t newLen,
|
||||
bool isNew = false);
|
||||
static void SortElements(JSThread *thread, const JSHandle<TaggedArray> &elements,
|
||||
const JSHandle<JSTaggedValue> &fn);
|
||||
};
|
||||
|
||||
class TrackInfo : public TaggedObject {
|
||||
|
@ -45,7 +45,7 @@ JSHandle<ModuleNamespace> ModuleNamespace::ModuleNamespaceCreate(JSThread *threa
|
||||
// are ordered as if an Array of the same values had been sorted using
|
||||
// Array.prototype.sort using undefined as comparefn.
|
||||
JSHandle<JSArray> exportsArray = JSArray::CreateArrayFromList(thread, exports);
|
||||
JSHandle<JSObject> sortedExports = JSHandle<JSObject>::Cast(exportsArray);
|
||||
JSHandle<JSTaggedValue> sortedExports = JSHandle<JSTaggedValue>::Cast(exportsArray);
|
||||
JSHandle<JSTaggedValue> fn = globalConst->GetHandledUndefined();
|
||||
JSArray::Sort(thread, sortedExports, fn);
|
||||
// 8. Set M.[[Exports]] to sortedExports.
|
||||
|
@ -479,12 +479,11 @@ JSTaggedValue ObjectFastOperator::FastGetPropertyByValue(JSThread *thread, JSTag
|
||||
return result;
|
||||
}
|
||||
|
||||
template<bool UseHole> // UseHole is only for Array::Sort() which requires Hole order
|
||||
JSTaggedValue ObjectFastOperator::FastGetPropertyByIndex(JSThread *thread, JSTaggedValue receiver, uint32_t index)
|
||||
{
|
||||
INTERPRETER_TRACE(thread, FastGetPropertyByIndex);
|
||||
JSTaggedValue result = ObjectFastOperator::GetPropertyByIndex(thread, receiver, index);
|
||||
if (result.IsHole() && !UseHole) {
|
||||
if (result.IsHole()) {
|
||||
return JSTaggedValue::GetProperty(thread,
|
||||
JSHandle<JSTaggedValue>(thread, receiver), index).GetValue().GetTaggedValue();
|
||||
}
|
||||
|
@ -55,7 +55,6 @@ public:
|
||||
|
||||
static inline JSTaggedValue FastGetPropertyByValue(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key);
|
||||
|
||||
template<bool UseHole = false>
|
||||
static inline JSTaggedValue FastGetPropertyByIndex(JSThread *thread, JSTaggedValue receiver, uint32_t index);
|
||||
|
||||
static inline JSTaggedValue FastParseDate(const EcmaString *str);
|
||||
@ -105,4 +104,4 @@ private:
|
||||
friend class FastRuntimeStub;
|
||||
};
|
||||
} // namespace panda::ecmascript
|
||||
#endif // ECMASCRIPT_OBJECT_FAST_OPERATOR_H
|
||||
#endif // ECMASCRIPT_OBJECT_FAST_OPERATOR_H
|
||||
|
@ -2579,45 +2579,8 @@ JSTaggedValue RuntimeStubs::RuntimeArraySort(JSThread *thread, JSHandle<JSTagged
|
||||
}
|
||||
}
|
||||
|
||||
JSMutableHandle<JSTaggedValue> presentValue(thread, JSTaggedValue::Undefined());
|
||||
JSMutableHandle<JSTaggedValue> middleValue(thread, JSTaggedValue::Undefined());
|
||||
JSMutableHandle<JSTaggedValue> previousValue(thread, JSTaggedValue::Undefined());
|
||||
JSHandle<JSTaggedValue> callbackFnHandle(thread, JSTaggedValue::Undefined());
|
||||
for (int i = 1; i < len; i++) {
|
||||
int beginIndex = 0;
|
||||
int endIndex = i;
|
||||
presentValue.Update(
|
||||
ObjectFastOperator::FastGetPropertyByIndex<true>(thread, thisObjHandle.GetTaggedValue(), i));
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
|
||||
while (beginIndex < endIndex) {
|
||||
int middleIndex = beginIndex + (endIndex - beginIndex) / 2; // 2 : half
|
||||
middleValue.Update(
|
||||
ObjectFastOperator::FastGetPropertyByIndex<true>(thread, thisObjHandle.GetTaggedValue(), middleIndex));
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
|
||||
double compareResult = ArrayHelper::SortCompare(thread, callbackFnHandle, middleValue, presentValue);
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
|
||||
if (compareResult > 0) {
|
||||
endIndex = middleIndex;
|
||||
} else {
|
||||
beginIndex = middleIndex + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (endIndex >= 0 && endIndex < i) {
|
||||
for (int j = i; j > endIndex; j--) {
|
||||
previousValue.Update(
|
||||
ObjectFastOperator::FastGetPropertyByIndex<true>(thread, thisObjHandle.GetTaggedValue(), j - 1));
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
|
||||
ObjectFastOperator::FastSetPropertyByIndex(thread, thisObjHandle.GetTaggedValue(), j,
|
||||
previousValue.GetTaggedValue());
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
|
||||
}
|
||||
ObjectFastOperator::FastSetPropertyByIndex(thread, thisObjHandle.GetTaggedValue(), endIndex,
|
||||
presentValue.GetTaggedValue());
|
||||
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
|
||||
}
|
||||
}
|
||||
|
||||
JSArray::Sort(thread, JSHandle<JSTaggedValue>::Cast(thisObjHandle), callbackFnHandle);
|
||||
return thisObjHandle.GetTaggedValue();
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@ group("ark_js_moduletest") {
|
||||
"arraytoreversed",
|
||||
"arraytospliced",
|
||||
"arraywith",
|
||||
"arraysort",
|
||||
"arrayprotochange",
|
||||
"assignproxy",
|
||||
"async",
|
||||
@ -152,6 +153,7 @@ group("ark_asm_test") {
|
||||
"arrayfindlast",
|
||||
"arrayforeach",
|
||||
"arrayjoin",
|
||||
"arraysort",
|
||||
"arrayprotochange",
|
||||
"asmstackoverflow",
|
||||
"assignproxy",
|
||||
|
18
test/moduletest/arraysort/BUILD.gn
Normal file
18
test/moduletest/arraysort/BUILD.gn
Normal file
@ -0,0 +1,18 @@
|
||||
# Copyright (c) 2023 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import("//arkcompiler/ets_runtime/test/test_helper.gni")
|
||||
|
||||
host_moduletest_action("arraysort") {
|
||||
deps = []
|
||||
}
|
178
test/moduletest/arraysort/arraysort.js
Normal file
178
test/moduletest/arraysort/arraysort.js
Normal file
@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class DeepProxy {
|
||||
constructor(obj, handler) {
|
||||
return new Proxy(obj, handler);
|
||||
}
|
||||
}
|
||||
class ClassB {
|
||||
constructor(n) {
|
||||
this.n = 0;
|
||||
this.n = n;
|
||||
}
|
||||
}
|
||||
|
||||
let nextFreeId = 0;
|
||||
class ClassA {
|
||||
constructor(a, b) {
|
||||
this.a = a;
|
||||
this.b = new ClassB(b);
|
||||
this.id = nextFreeId++;
|
||||
}
|
||||
}
|
||||
|
||||
// Testing the proxy situation.
|
||||
let data1 = [new ClassA(1, 10), new ClassA(3, 30), new ClassA(4, 40), new ClassA(2, 20), new ClassA(11, 250)];
|
||||
let objHandler1 = new DeepProxy(data1, {});
|
||||
print(JSON.stringify(objHandler1));
|
||||
objHandler1.sort((a, b) => {
|
||||
return a.b.n - b.b.n;
|
||||
})
|
||||
print(JSON.stringify(objHandler1));
|
||||
|
||||
// Testing cases with both proxy and hole.
|
||||
let data2 = [new ClassA(1, 10), , new ClassA(3, 30), , new ClassA(4, 40), new ClassA(2, 20), new ClassA(11, 250)];
|
||||
let objHandler2 = new DeepProxy(data2, {
|
||||
deleteProperty(target, prop) {
|
||||
print(`delete ${prop.toString()}`);
|
||||
return Reflect.deleteProperty(target, prop);
|
||||
}
|
||||
});
|
||||
objHandler2.sort((a, b) => {
|
||||
return a.b.n - b.b.n;
|
||||
})
|
||||
print(JSON.stringify(objHandler2));
|
||||
|
||||
/*
|
||||
* Test Case Description:
|
||||
* 1. This use case is used to verify the logical processing order of the binary insertion sorting algorithm.
|
||||
* 2. If there are any changes to the use case, please confirm if the use case needs to be modified.
|
||||
*/
|
||||
let arr1 = [1, 3, 2];
|
||||
arr1.sort((a, b) => {
|
||||
print(`comparing a = ${a}, b = ${b}`);
|
||||
return a - b;
|
||||
});
|
||||
print(JSON.stringify(arr1));
|
||||
|
||||
// Modification of objects during the comparison process.
|
||||
let arr2 = [1, 3, 2];
|
||||
arr2.sort((a, b) => {
|
||||
if (a == 1 || b == 1) {
|
||||
arr2[0] == 2;
|
||||
}
|
||||
return a - b;
|
||||
});
|
||||
print(JSON.stringify(arr2));
|
||||
|
||||
let arr3 = [1, 3, 2];
|
||||
arr3.sort((a, b) => {
|
||||
if (a == 1 || b == 1) {
|
||||
arr3[4] == 2;
|
||||
}
|
||||
return a - b;
|
||||
});
|
||||
print(JSON.stringify(arr3));
|
||||
|
||||
// Testing the situation where this is an Object
|
||||
let obj1 = {0: 1, 1: 3, a: 6, 2: 2, length: 3};
|
||||
Array.prototype.sort.call(obj1, (a, b) => {
|
||||
return a - b;
|
||||
});
|
||||
print(JSON.stringify(obj1));
|
||||
|
||||
let obj2 = {0: 1, 1: 3, a: 6, 2: 2, length: 3};
|
||||
Array.prototype.sort.call(obj2, (a, b) => {
|
||||
if (a == 1 || b == 1) {
|
||||
obj2.a = 60;
|
||||
}
|
||||
return a - b;
|
||||
});
|
||||
print(obj2.a == 60);
|
||||
print(JSON.stringify(obj2));
|
||||
|
||||
let obj3 = {0: 1, 1: 3, a: 6, 2: 2, length: 2};
|
||||
Array.prototype.sort.call(obj3, (a, b) => {
|
||||
return a - b;
|
||||
});
|
||||
print(obj3[1] == 3)
|
||||
print(JSON.stringify(obj3));
|
||||
|
||||
let obj4 = {0: 1, 1: 3, a: 6, 3: 2, length: 4};
|
||||
Array.prototype.sort.call(obj4, (a, b) => {
|
||||
return a - b;
|
||||
});
|
||||
print(obj4[2] == 3)
|
||||
print(JSON.stringify(obj4));
|
||||
|
||||
// Test if this is a Map type;
|
||||
let map1 = new Map();
|
||||
map1.set(0, 1);
|
||||
map1.set(1, 3);
|
||||
map1.set(2, 2);
|
||||
map1.set("a", 6);
|
||||
map1.set("length", 3);
|
||||
Array.prototype.sort.call(map1, (a, b) => {
|
||||
return a - b;
|
||||
});
|
||||
print(JSON.stringify(map1));
|
||||
|
||||
let map2 = new Map();
|
||||
map2.set(0, 1);
|
||||
map2.set(1, 3);
|
||||
map2.set(2, 2);
|
||||
map2.set("a", 6);
|
||||
map2.set("length", 3);
|
||||
Array.prototype.sort.call(map2, (a, b) => {
|
||||
if (a == 1 || b == 1) {
|
||||
map2.set("a", 60);
|
||||
}
|
||||
return a - b;
|
||||
});
|
||||
print(JSON.stringify(map2));
|
||||
|
||||
// Test prototype
|
||||
let child1 = [1, 3, 2];
|
||||
let proto1 = [4, 7, 5];
|
||||
child1.__proto__ = proto1;
|
||||
child1.sort((a, b) => {
|
||||
return a - b;
|
||||
});
|
||||
print(JSON.stringify(child1));
|
||||
|
||||
let child2 = [1, , 2];
|
||||
child2.__proto__ = proto1;
|
||||
child2.sort((a, b) => {
|
||||
return a - b;
|
||||
});
|
||||
print(child2.hasOwnProperty('1'));
|
||||
print(JSON.stringify(child2));
|
||||
|
||||
let child3 = [1, 3, 2];
|
||||
let proto2 = [4, , 5];
|
||||
child3.__proto__ = proto2;
|
||||
child3.sort((a, b) => {
|
||||
return a - b;
|
||||
});
|
||||
print(JSON.stringify(child3));
|
||||
|
||||
let child4 = [1, , 2];
|
||||
child4.__proto__ = proto2;
|
||||
child4.sort((a, b) => {
|
||||
return a - b;
|
||||
});
|
||||
print(child4.hasOwnProperty('2'));
|
||||
print(JSON.stringify(child4));
|
39
test/moduletest/arraysort/expect_output.txt
Normal file
39
test/moduletest/arraysort/expect_output.txt
Normal file
@ -0,0 +1,39 @@
|
||||
# Copyright (c) 2023 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
[{"a":1,"b":{"n":10},"id":0},{"a":3,"b":{"n":30},"id":1},{"a":4,"b":{"n":40},"id":2},{"a":2,"b":{"n":20},"id":3},{"a":11,"b":{"n":250},"id":4}]
|
||||
[{"a":1,"b":{"n":10},"id":0},{"a":2,"b":{"n":20},"id":3},{"a":3,"b":{"n":30},"id":1},{"a":4,"b":{"n":40},"id":2},{"a":11,"b":{"n":250},"id":4}]
|
||||
delete 5
|
||||
delete 6
|
||||
[{"a":1,"b":{"n":10},"id":5},{"a":2,"b":{"n":20},"id":8},{"a":3,"b":{"n":30},"id":6},{"a":4,"b":{"n":40},"id":7},{"a":11,"b":{"n":250},"id":9},null,null]
|
||||
comparing a = 1, b = 3
|
||||
comparing a = 3, b = 2
|
||||
comparing a = 1, b = 2
|
||||
[1,2,3]
|
||||
[1,2,3]
|
||||
[1,2,3]
|
||||
{"0":1,"1":2,"2":3,"a":6,"length":3}
|
||||
true
|
||||
{"0":1,"1":2,"2":3,"a":60,"length":3}
|
||||
true
|
||||
{"0":1,"1":3,"2":2,"a":6,"length":2}
|
||||
true
|
||||
{"0":1,"1":2,"2":3,"a":6,"length":4}
|
||||
{}
|
||||
{}
|
||||
[1,2,3]
|
||||
true
|
||||
[1,2,7]
|
||||
[1,2,3]
|
||||
false
|
||||
[1,2,5]
|
Loading…
Reference in New Issue
Block a user