2021-09-04 08:06:49 +00:00
|
|
|
/*
|
2022-03-14 09:42:27 +00:00
|
|
|
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
2021-09-04 08:06:49 +00:00
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2022-07-23 10:33:33 +00:00
|
|
|
#include "ecmascript/js_map_iterator.h"
|
|
|
|
|
|
|
|
#include "ecmascript/builtins/builtins_errors.h"
|
2023-12-18 07:57:47 +00:00
|
|
|
#include "ecmascript/element_accessor-inl.h"
|
2022-07-23 10:33:33 +00:00
|
|
|
#include "ecmascript/js_array.h"
|
|
|
|
#include "ecmascript/linked_hash_table.h"
|
2021-09-04 08:06:49 +00:00
|
|
|
|
|
|
|
namespace panda::ecmascript {
|
|
|
|
using BuiltinsBase = base::BuiltinsBase;
|
|
|
|
JSTaggedValue JSMapIterator::Next(EcmaRuntimeCallInfo *argv)
|
|
|
|
{
|
|
|
|
ASSERT(argv);
|
|
|
|
JSThread *thread = argv->GetThread();
|
|
|
|
[[maybe_unused]] EcmaHandleScope handleScope(thread);
|
|
|
|
// 1.Let O be the this value
|
2023-10-21 08:42:54 +00:00
|
|
|
JSHandle<JSTaggedValue> thisObj(BuiltinsBase::GetThis(argv));
|
|
|
|
return NextInternal(thread, thisObj);
|
|
|
|
}
|
2021-09-04 08:06:49 +00:00
|
|
|
|
2023-10-21 08:42:54 +00:00
|
|
|
JSTaggedValue JSMapIterator::NextInternal(JSThread *thread, JSHandle<JSTaggedValue> thisObj)
|
|
|
|
{
|
2021-09-04 08:06:49 +00:00
|
|
|
// 3.If O does not have all of the internal slots of a Map Iterator Instance (23.1.5.3), throw a TypeError
|
|
|
|
// exception.
|
2023-10-21 08:42:54 +00:00
|
|
|
if (!thisObj->IsJSMapIterator()) {
|
2021-09-04 08:06:49 +00:00
|
|
|
THROW_TYPE_ERROR_AND_RETURN(thread, "this value is not a map iterator", JSTaggedValue::Exception());
|
|
|
|
}
|
2023-10-21 08:42:54 +00:00
|
|
|
JSHandle<JSMapIterator> iter(thisObj);
|
2021-09-04 08:06:49 +00:00
|
|
|
iter->Update(thread);
|
|
|
|
JSHandle<JSTaggedValue> undefinedHandle(thread, JSTaggedValue::Undefined());
|
|
|
|
// 4.Let m be O.[[IteratedMap]].
|
|
|
|
JSHandle<JSTaggedValue> iteratedMap(thread, iter->GetIteratedMap());
|
|
|
|
|
|
|
|
// 5.Let index be O.[[MapNextIndex]].
|
2022-04-12 08:49:37 +00:00
|
|
|
int index = static_cast<int>(iter->GetNextIndex());
|
2022-01-25 10:05:12 +00:00
|
|
|
IterationKind itemKind = iter->GetIterationKind();
|
2021-09-04 08:06:49 +00:00
|
|
|
// 7.If m is undefined, return CreateIterResultObject(undefined, true).
|
|
|
|
if (iteratedMap->IsUndefined()) {
|
|
|
|
return JSIterator::CreateIterResultObject(thread, undefinedHandle, true).GetTaggedValue();
|
|
|
|
};
|
|
|
|
JSHandle<LinkedHashMap> map(iteratedMap);
|
|
|
|
int totalElements = map->NumberOfElements() + map->NumberOfDeletedElements();
|
|
|
|
|
|
|
|
JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined());
|
|
|
|
while (index < totalElements) {
|
|
|
|
JSTaggedValue key = map->GetKey(index);
|
|
|
|
if (!key.IsHole()) {
|
2022-01-25 10:05:12 +00:00
|
|
|
iter->SetNextIndex(index + 1);
|
2021-09-04 08:06:49 +00:00
|
|
|
keyHandle.Update(key);
|
|
|
|
// If itemKind is key, let result be e.[[Key]]
|
|
|
|
if (itemKind == IterationKind::KEY) {
|
|
|
|
return JSIterator::CreateIterResultObject(thread, keyHandle, false).GetTaggedValue();
|
|
|
|
}
|
|
|
|
JSHandle<JSTaggedValue> value(thread, map->GetValue(index));
|
|
|
|
// Else if itemKind is value, let result be e.[[Value]].
|
|
|
|
if (itemKind == IterationKind::VALUE) {
|
|
|
|
return JSIterator::CreateIterResultObject(thread, value, false).GetTaggedValue();
|
|
|
|
}
|
|
|
|
// Else
|
|
|
|
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
|
|
|
JSHandle<TaggedArray> array(factory->NewTaggedArray(2)); // 2 means the length of array
|
|
|
|
array->Set(thread, 0, keyHandle);
|
|
|
|
array->Set(thread, 1, value);
|
|
|
|
JSHandle<JSTaggedValue> keyAndValue(JSArray::CreateArrayFromList(thread, array));
|
|
|
|
return JSIterator::CreateIterResultObject(thread, keyAndValue, false).GetTaggedValue();
|
|
|
|
}
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
// 13.Set O.[[IteratedMap]] to undefined.
|
|
|
|
iter->SetIteratedMap(thread, JSTaggedValue::Undefined());
|
|
|
|
return JSIterator::CreateIterResultObject(thread, undefinedHandle, true).GetTaggedValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
void JSMapIterator::Update(const JSThread *thread)
|
|
|
|
{
|
2024-11-12 13:46:57 +00:00
|
|
|
DISALLOW_GARBAGE_COLLECTION;
|
2021-09-04 08:06:49 +00:00
|
|
|
JSTaggedValue iteratedMap = GetIteratedMap();
|
|
|
|
if (iteratedMap.IsUndefined()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
LinkedHashMap *map = LinkedHashMap::Cast(iteratedMap.GetTaggedObject());
|
|
|
|
if (map->GetNextTable().IsHole()) {
|
|
|
|
return;
|
|
|
|
}
|
2022-04-12 08:49:37 +00:00
|
|
|
int index = static_cast<int>(GetNextIndex());
|
2021-09-04 08:06:49 +00:00
|
|
|
JSTaggedValue nextTable = map->GetNextTable();
|
|
|
|
while (!nextTable.IsHole()) {
|
|
|
|
index -= map->GetDeletedElementsAt(index);
|
|
|
|
map = LinkedHashMap::Cast(nextTable.GetTaggedObject());
|
|
|
|
nextTable = map->GetNextTable();
|
|
|
|
}
|
|
|
|
SetIteratedMap(thread, JSTaggedValue(map));
|
2022-01-25 10:05:12 +00:00
|
|
|
SetNextIndex(index);
|
2021-09-04 08:06:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
JSHandle<JSTaggedValue> JSMapIterator::CreateMapIterator(JSThread *thread, const JSHandle<JSTaggedValue> &obj,
|
|
|
|
IterationKind kind)
|
|
|
|
{
|
|
|
|
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
|
|
|
if (!obj->IsJSMap()) {
|
|
|
|
JSHandle<JSTaggedValue> undefinedHandle(thread, JSTaggedValue::Undefined());
|
|
|
|
THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSMap", undefinedHandle);
|
|
|
|
}
|
|
|
|
JSHandle<JSTaggedValue> iter(factory->NewJSMapIterator(JSHandle<JSMap>(obj), kind));
|
|
|
|
return iter;
|
|
|
|
}
|
2023-07-24 02:11:27 +00:00
|
|
|
|
2024-07-14 12:30:57 +00:00
|
|
|
JSTaggedValue JSMapIterator::MapIteratorToList(JSThread *thread, JSHandle<JSTaggedValue> iterator)
|
2023-07-24 02:11:27 +00:00
|
|
|
{
|
|
|
|
JSTaggedValue newArray = JSArray::ArrayCreate(thread, JSTaggedNumber(0)).GetTaggedValue();
|
|
|
|
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
|
|
|
JSHandle<JSObject> newArrayHandle(thread, newArray);
|
|
|
|
JSHandle<JSMapIterator> iter(iterator);
|
|
|
|
JSHandle<JSTaggedValue> iteratedMap(thread, iter->GetIteratedMap());
|
|
|
|
if (iteratedMap->IsUndefined()) {
|
|
|
|
return newArrayHandle.GetTaggedValue();
|
|
|
|
}
|
|
|
|
IterationKind itemKind = iter->GetIterationKind();
|
|
|
|
JSHandle<LinkedHashMap> map(iteratedMap);
|
|
|
|
int totalElements = map->NumberOfElements() + map->NumberOfDeletedElements();
|
|
|
|
int index = static_cast<int>(iter->GetNextIndex());
|
|
|
|
int k = 0;
|
|
|
|
|
|
|
|
JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined());
|
|
|
|
JSMutableHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue::Undefined());
|
|
|
|
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
2023-09-19 13:17:01 +00:00
|
|
|
JSHandle<TaggedArray> oldElements(thread, newArrayHandle->GetElements());
|
|
|
|
JSHandle<TaggedArray> elements = factory->ExtendArray(oldElements, totalElements);
|
2023-12-18 07:57:47 +00:00
|
|
|
newArrayHandle->SetElements(thread, elements);
|
2023-07-24 02:11:27 +00:00
|
|
|
while (index < totalElements) {
|
|
|
|
JSTaggedValue key = map->GetKey(index);
|
|
|
|
if (!key.IsHole()) {
|
|
|
|
keyHandle.Update(key);
|
|
|
|
valueHandle.Update(map->GetValue(index));
|
|
|
|
if (itemKind == IterationKind::KEY) {
|
2023-12-18 07:57:47 +00:00
|
|
|
ElementAccessor::Set(thread, newArrayHandle, k, keyHandle, true);
|
2023-07-24 02:11:27 +00:00
|
|
|
} else if (itemKind == IterationKind::VALUE) {
|
2023-12-18 07:57:47 +00:00
|
|
|
ElementAccessor::Set(thread, newArrayHandle, k, valueHandle, true);
|
2023-07-24 02:11:27 +00:00
|
|
|
} else {
|
2023-07-28 09:16:53 +00:00
|
|
|
JSHandle<TaggedArray> array(factory->NewTaggedArray(2)); // 2 means the length of array
|
2023-07-24 02:11:27 +00:00
|
|
|
array->Set(thread, 0, keyHandle);
|
|
|
|
array->Set(thread, 1, valueHandle);
|
|
|
|
JSHandle<JSTaggedValue> keyAndValue(JSArray::CreateArrayFromList(thread, array));
|
2023-12-18 07:57:47 +00:00
|
|
|
ElementAccessor::Set(thread, newArrayHandle, k, keyAndValue, true);
|
2023-07-24 02:11:27 +00:00
|
|
|
}
|
|
|
|
k++;
|
|
|
|
}
|
|
|
|
index++;
|
|
|
|
}
|
2023-09-19 13:17:01 +00:00
|
|
|
JSHandle<JSArray>(newArrayHandle)->SetArrayLength(thread, k);
|
2023-07-24 02:11:27 +00:00
|
|
|
return newArrayHandle.GetTaggedValue();
|
|
|
|
}
|
2021-09-04 08:06:49 +00:00
|
|
|
} // namespace panda::ecmascript
|