1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ecmascript/containers/containers_treemap.h"
17
18 #include "ecmascript/containers/containers_errors.h"
19 #include "ecmascript/ecma_vm.h"
20 #include "ecmascript/interpreter/interpreter.h"
21 #include "ecmascript/js_api/js_api_tree_map.h"
22 #include "ecmascript/js_api/js_api_tree_map_iterator.h"
23 #include "ecmascript/object_factory.h"
24 #include "ecmascript/tagged_array-inl.h"
25 #include "ecmascript/tagged_tree.h"
26
27 namespace panda::ecmascript::containers {
TreeMapConstructor(EcmaRuntimeCallInfo * argv)28 JSTaggedValue ContainersTreeMap::TreeMapConstructor(EcmaRuntimeCallInfo *argv)
29 {
30 ASSERT(argv);
31 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Constructor);
32 JSThread *thread = argv->GetThread();
33 [[maybe_unused]] EcmaHandleScope handleScope(thread);
34 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
35
36 JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
37 if (newTarget->IsUndefined()) {
38 JSTaggedValue error =
39 ContainerError::BusinessError(thread, ErrorFlag::IS_NULL_ERROR,
40 "The TreeMap's constructor cannot be directly invoked");
41 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
42 }
43
44 // new TreeMap
45 JSHandle<JSTaggedValue> constructor = GetConstructor(argv);
46 JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), newTarget);
47 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
48
49 // Set map’s internal slot with a new empty List.
50 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(obj);
51 JSTaggedValue internal = TaggedTreeMap::Create(thread);
52 map->SetTreeMap(thread, internal);
53
54 // If comparefn was supplied, let compare be comparefn; else let compare be hole.
55 JSHandle<JSTaggedValue> compareFn(GetCallArg(argv, 0));
56 if (compareFn->IsUndefined() || compareFn->IsNull()) {
57 return map.GetTaggedValue();
58 }
59 if (!compareFn->IsCallable()) {
60 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, compareFn.GetTaggedValue());
61 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
62 CString errorMsg =
63 "The type of \"comparefn\" must be callable. Received value is: " + ConvertToString(*result);
64 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
65 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
66 }
67
68 TaggedTreeMap::Cast(internal.GetTaggedObject())->SetCompare(thread, compareFn.GetTaggedValue());
69 return map.GetTaggedValue();
70 }
71
Set(EcmaRuntimeCallInfo * argv)72 JSTaggedValue ContainersTreeMap::Set(EcmaRuntimeCallInfo *argv)
73 {
74 ASSERT(argv);
75 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Set);
76 JSThread *thread = argv->GetThread();
77 [[maybe_unused]] EcmaHandleScope handleScope(thread);
78 JSHandle<JSTaggedValue> self = GetThis(argv);
79 // get and check this map
80 if (!self->IsJSAPITreeMap()) {
81 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
82 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
83 } else {
84 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
85 "The set method cannot be bound");
86 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
87 }
88 }
89
90 JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
91 JSHandle<JSTaggedValue> value = GetCallArg(argv, 1);
92
93 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
94 JSAPITreeMap::Set(thread, map, key, value);
95 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
96 return map.GetTaggedValue();
97 }
98
Get(EcmaRuntimeCallInfo * argv)99 JSTaggedValue ContainersTreeMap::Get(EcmaRuntimeCallInfo *argv)
100 {
101 ASSERT(argv);
102 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Get);
103 JSThread *thread = argv->GetThread();
104 [[maybe_unused]] EcmaHandleScope handleScope(thread);
105 // get and check this map
106 JSHandle<JSTaggedValue> self(GetThis(argv));
107 if (!self->IsJSAPITreeMap()) {
108 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
109 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
110 } else {
111 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
112 "The get method cannot be bound");
113 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
114 }
115 }
116
117 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
118 JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
119 return JSAPITreeMap::Get(thread, map, key);
120 }
121
Remove(EcmaRuntimeCallInfo * argv)122 JSTaggedValue ContainersTreeMap::Remove(EcmaRuntimeCallInfo *argv)
123 {
124 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Remove);
125 JSThread *thread = argv->GetThread();
126 [[maybe_unused]] EcmaHandleScope handleScope(thread);
127 JSHandle<JSTaggedValue> self = GetThis(argv);
128 // get and check this map
129 if (!self->IsJSAPITreeMap()) {
130 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
131 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
132 } else {
133 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
134 "The remove method cannot be bound");
135 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
136 }
137 }
138
139 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
140 JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
141 return JSAPITreeMap::Delete(thread, map, key);
142 }
143
HasKey(EcmaRuntimeCallInfo * argv)144 JSTaggedValue ContainersTreeMap::HasKey(EcmaRuntimeCallInfo *argv)
145 {
146 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, HasKey);
147 JSThread *thread = argv->GetThread();
148 [[maybe_unused]] EcmaHandleScope handleScope(thread);
149 // get and check this map
150 JSHandle<JSTaggedValue> self(GetThis(argv));
151 if (!self->IsJSAPITreeMap()) {
152 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
153 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
154 } else {
155 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
156 "The hasKey method cannot be bound");
157 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
158 }
159 }
160
161 JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
162 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
163
164 bool flag = JSAPITreeMap::HasKey(thread, JSHandle<JSAPITreeMap>::Cast(map), key);
165 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
166 return GetTaggedBoolean(flag);
167 }
168
HasValue(EcmaRuntimeCallInfo * argv)169 JSTaggedValue ContainersTreeMap::HasValue(EcmaRuntimeCallInfo *argv)
170 {
171 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, HasValue);
172 JSThread *thread = argv->GetThread();
173 [[maybe_unused]] EcmaHandleScope handleScope(thread);
174 // get and check this map
175 JSHandle<JSTaggedValue> self(GetThis(argv));
176 if (!self->IsJSAPITreeMap()) {
177 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
178 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
179 } else {
180 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
181 "The hasValue method cannot be bound");
182 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
183 }
184 }
185
186 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
187 bool flag = map->HasValue(thread, GetCallArg(argv, 0));
188 return GetTaggedBoolean(flag);
189 }
190
GetFirstKey(EcmaRuntimeCallInfo * argv)191 JSTaggedValue ContainersTreeMap::GetFirstKey(EcmaRuntimeCallInfo *argv)
192 {
193 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, GetFirstKey);
194 JSThread *thread = argv->GetThread();
195 [[maybe_unused]] EcmaHandleScope handleScope(thread);
196 // get and check this map
197 JSHandle<JSTaggedValue> self(GetThis(argv));
198 if (!self->IsJSAPITreeMap()) {
199 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
200 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
201 } else {
202 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
203 "The getFirstKey method cannot be bound");
204 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
205 }
206 }
207
208 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
209 return TaggedTreeMap::Cast(map->GetTreeMap().GetTaggedObject())->GetFirstKey();
210 }
211
GetLastKey(EcmaRuntimeCallInfo * argv)212 JSTaggedValue ContainersTreeMap::GetLastKey(EcmaRuntimeCallInfo *argv)
213 {
214 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, GetLastKey);
215 JSThread *thread = argv->GetThread();
216 [[maybe_unused]] EcmaHandleScope handleScope(thread);
217 // get and check this map
218 JSHandle<JSTaggedValue> self(GetThis(argv));
219 if (!self->IsJSAPITreeMap()) {
220 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
221 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
222 } else {
223 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
224 "The getLastKey method cannot be bound");
225 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
226 }
227 }
228
229 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
230 return TaggedTreeMap::Cast(map->GetTreeMap().GetTaggedObject())->GetLastKey();
231 }
232
SetAll(EcmaRuntimeCallInfo * argv)233 JSTaggedValue ContainersTreeMap::SetAll(EcmaRuntimeCallInfo *argv)
234 {
235 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, SetAll);
236 JSThread *thread = argv->GetThread();
237 [[maybe_unused]] EcmaHandleScope handleScope(thread);
238 // get and check this map
239 JSHandle<JSTaggedValue> self(GetThis(argv));
240 if (!self->IsJSAPITreeMap()) {
241 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
242 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
243 } else {
244 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
245 "The setAll method cannot be bound");
246 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
247 }
248 }
249
250 JSHandle<JSTaggedValue> obj = GetCallArg(argv, 0);
251 if (!obj->IsJSAPITreeMap()) {
252 if (obj->IsJSProxy() && JSHandle<JSProxy>::Cast(obj)->GetTarget().IsJSAPITreeMap()) {
253 obj = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(obj)->GetTarget());
254 } else {
255 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, obj.GetTaggedValue());
256 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
257 CString errorMsg =
258 "The type of \"map\" must be TreeMap. Received value is: " + ConvertToString(*result);
259 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
260 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
261 }
262 }
263
264 JSHandle<JSAPITreeMap> dst = JSHandle<JSAPITreeMap>::Cast(self);
265 JSHandle<TaggedTreeMap> dmap(thread, dst->GetTreeMap());
266 JSHandle<TaggedTreeMap> smap(thread, JSHandle<JSAPITreeMap>::Cast(obj)->GetTreeMap());
267
268 JSTaggedValue tmap = TaggedTreeMap::SetAll(thread, dmap, smap);
269 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
270 dst->SetTreeMap(thread, tmap);
271 return JSTaggedValue::Undefined();
272 }
273
Clear(EcmaRuntimeCallInfo * argv)274 JSTaggedValue ContainersTreeMap::Clear(EcmaRuntimeCallInfo *argv)
275 {
276 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Clear);
277 JSThread *thread = argv->GetThread();
278 [[maybe_unused]] EcmaHandleScope handleScope(thread);
279 // get and check this map
280 JSHandle<JSTaggedValue> self(GetThis(argv));
281 if (!self->IsJSAPITreeMap()) {
282 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
283 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
284 } else {
285 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
286 "The clear method cannot be bound");
287 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
288 }
289 }
290
291 JSAPITreeMap::Clear(thread, JSHandle<JSAPITreeMap>::Cast(self));
292 return JSTaggedValue::Undefined();
293 }
294
GetLowerKey(EcmaRuntimeCallInfo * argv)295 JSTaggedValue ContainersTreeMap::GetLowerKey(EcmaRuntimeCallInfo *argv)
296 {
297 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, GetLowerKey);
298 JSThread *thread = argv->GetThread();
299 [[maybe_unused]] EcmaHandleScope handleScope(thread);
300 // get and check this map
301 JSHandle<JSTaggedValue> self(GetThis(argv));
302 if (!self->IsJSAPITreeMap()) {
303 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
304 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
305 } else {
306 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
307 "The getLowerKey method cannot be bound");
308 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
309 }
310 }
311
312 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
313 JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
314
315 JSHandle<TaggedTreeMap> tmap(thread, map->GetTreeMap());
316 return TaggedTreeMap::GetLowerKey(thread, tmap, key);
317 }
318
GetHigherKey(EcmaRuntimeCallInfo * argv)319 JSTaggedValue ContainersTreeMap::GetHigherKey(EcmaRuntimeCallInfo *argv)
320 {
321 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, GetHigherKey);
322 JSThread *thread = argv->GetThread();
323 [[maybe_unused]] EcmaHandleScope handleScope(thread);
324 // get and check this map
325 JSHandle<JSTaggedValue> self(GetThis(argv));
326 if (!self->IsJSAPITreeMap()) {
327 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
328 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
329 } else {
330 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
331 "The getHigherKey method cannot be bound");
332 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
333 }
334 }
335
336 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
337 JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
338
339 JSHandle<TaggedTreeMap> tmap(thread, map->GetTreeMap());
340 return TaggedTreeMap::GetHigherKey(thread, tmap, key);
341 }
342
Replace(EcmaRuntimeCallInfo * argv)343 JSTaggedValue ContainersTreeMap::Replace(EcmaRuntimeCallInfo *argv)
344 {
345 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Replace);
346 JSThread *thread = argv->GetThread();
347 [[maybe_unused]] EcmaHandleScope handleScope(thread);
348 // get and check this map
349 JSHandle<JSTaggedValue> self(GetThis(argv));
350 if (!self->IsJSAPITreeMap()) {
351 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
352 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
353 } else {
354 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
355 "The replace method cannot be bound");
356 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
357 }
358 }
359
360 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
361 JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
362 JSHandle<JSTaggedValue> value = GetCallArg(argv, 1);
363
364 bool success = JSAPITreeMap::Replace(thread, map, key, value);
365 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
366 return GetTaggedBoolean(success);
367 }
368
Keys(EcmaRuntimeCallInfo * argv)369 JSTaggedValue ContainersTreeMap::Keys(EcmaRuntimeCallInfo *argv)
370 {
371 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Keys);
372 JSThread *thread = argv->GetThread();
373 [[maybe_unused]] EcmaHandleScope handleScope(thread);
374 JSHandle<JSTaggedValue> self = GetThis(argv);
375 JSHandle<JSTaggedValue> iter = JSAPITreeMapIterator::CreateTreeMapIterator(thread, self, IterationKind::KEY);
376 return iter.GetTaggedValue();
377 }
378
Values(EcmaRuntimeCallInfo * argv)379 JSTaggedValue ContainersTreeMap::Values(EcmaRuntimeCallInfo *argv)
380 {
381 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Values);
382 JSThread *thread = argv->GetThread();
383 [[maybe_unused]] EcmaHandleScope handleScope(thread);
384 JSHandle<JSTaggedValue> self = GetThis(argv);
385 JSHandle<JSTaggedValue> iter = JSAPITreeMapIterator::CreateTreeMapIterator(thread, self, IterationKind::VALUE);
386 return iter.GetTaggedValue();
387 }
388
Entries(EcmaRuntimeCallInfo * argv)389 JSTaggedValue ContainersTreeMap::Entries(EcmaRuntimeCallInfo *argv)
390 {
391 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Entries);
392 JSThread *thread = argv->GetThread();
393 [[maybe_unused]] EcmaHandleScope handleScope(thread);
394 JSHandle<JSTaggedValue> self = GetThis(argv);
395 JSHandle<JSTaggedValue> iter =
396 JSAPITreeMapIterator::CreateTreeMapIterator(thread, self, IterationKind::KEY_AND_VALUE);
397 return iter.GetTaggedValue();
398 }
399
ForEach(EcmaRuntimeCallInfo * argv)400 JSTaggedValue ContainersTreeMap::ForEach(EcmaRuntimeCallInfo *argv)
401 {
402 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, ForEach);
403 JSThread *thread = argv->GetThread();
404 [[maybe_unused]] EcmaHandleScope handleScope(thread);
405 // get and check TreeMap object
406 JSHandle<JSTaggedValue> self = GetThis(argv);
407 if (!self->IsJSAPITreeMap()) {
408 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
409 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
410 } else {
411 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
412 "The rorEach method cannot be bound");
413 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
414 }
415 }
416 // get and check callback function
417 JSHandle<JSTaggedValue> func(GetCallArg(argv, 0));
418 if (!func->IsCallable()) {
419 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, func.GetTaggedValue());
420 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
421 CString errorMsg =
422 "The type of \"callbackfn\" must be callable. Received value is: " + ConvertToString(*result);
423 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
424 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
425 }
426 // If thisArg was supplied, let T be thisArg; else let T be undefined.
427 JSHandle<JSTaggedValue> thisArg = GetCallArg(argv, 1);
428 JSHandle<JSAPITreeMap> tmap = JSHandle<JSAPITreeMap>::Cast(self);
429 JSMutableHandle<TaggedTreeMap> iteratedMap(thread, tmap->GetTreeMap());
430 uint32_t elements = iteratedMap->NumberOfElements();
431 JSHandle<TaggedArray> entries = TaggedTreeMap::GetArrayFromMap(thread, iteratedMap);
432 uint32_t index = 0;
433 size_t length = entries->GetLength();
434 const uint32_t argsLength = 3;
435 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
436 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
437 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
438 while (index < elements) {
439 int entriesIndex = entries->Get(index).GetInt();
440 key.Update(iteratedMap->GetKey(entriesIndex));
441 value.Update(iteratedMap->GetValue(entriesIndex));
442 // Let funcResult be Call(callbackfn, T, «e, e, S»).
443 EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, func, thisArg, undefined, argsLength);
444 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
445 info->SetCallArg(value.GetTaggedValue(), key.GetTaggedValue(), self.GetTaggedValue());
446 JSTaggedValue ret = JSFunction::Call(info);
447 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ret);
448 // check entries should be update, size will be update in tmap set or remove.
449 if (tmap->GetSize() != static_cast<int>(length)) {
450 iteratedMap.Update(tmap->GetTreeMap());
451 entries = TaggedTreeMap::GetArrayFromMap(thread, iteratedMap);
452 elements = iteratedMap->NumberOfElements();
453 length = entries->GetLength();
454 }
455 index++;
456 }
457 return JSTaggedValue::Undefined();
458 }
459
GetLength(EcmaRuntimeCallInfo * argv)460 JSTaggedValue ContainersTreeMap::GetLength(EcmaRuntimeCallInfo *argv)
461 {
462 ASSERT(argv);
463 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, GetLength);
464 JSThread *thread = argv->GetThread();
465 [[maybe_unused]] EcmaHandleScope handleScope(thread);
466 // get and check this map
467 JSHandle<JSTaggedValue> self(GetThis(argv));
468 if (!self->IsJSAPITreeMap()) {
469 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
470 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
471 } else {
472 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
473 "The getLength method cannot be bound");
474 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
475 }
476 }
477 int count = JSHandle<JSAPITreeMap>::Cast(self)->GetSize();
478 return JSTaggedValue(count);
479 }
480
IsEmpty(EcmaRuntimeCallInfo * argv)481 JSTaggedValue ContainersTreeMap::IsEmpty(EcmaRuntimeCallInfo *argv)
482 {
483 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, IsEmpty);
484 JSThread *thread = argv->GetThread();
485 [[maybe_unused]] EcmaHandleScope handleScope(thread);
486 // get and check this map
487 JSHandle<JSTaggedValue> self = GetThis(argv);
488 if (!self->IsJSAPITreeMap()) {
489 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
490 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
491 } else {
492 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
493 "The isEmpty method cannot be bound");
494 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
495 }
496 }
497 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
498 return GetTaggedBoolean(map->GetSize() == 0);
499 }
500 } // namespace panda::ecmascript::containers
501