1 /*
2 * Copyright (c) 2022-2024 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/interpreter/interpreter.h"
20 #include "ecmascript/js_api/js_api_tree_map.h"
21 #include "ecmascript/js_api/js_api_tree_map_iterator.h"
22 #include "ecmascript/js_function.h"
23 #include "ecmascript/tagged_tree.h"
24
25 namespace panda::ecmascript::containers {
TreeMapConstructor(EcmaRuntimeCallInfo * argv)26 JSTaggedValue ContainersTreeMap::TreeMapConstructor(EcmaRuntimeCallInfo *argv)
27 {
28 ASSERT(argv);
29 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Constructor);
30 JSThread *thread = argv->GetThread();
31 [[maybe_unused]] EcmaHandleScope handleScope(thread);
32 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
33
34 JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
35 if (newTarget->IsUndefined()) {
36 JSTaggedValue error =
37 ContainerError::BusinessError(thread, ErrorFlag::IS_NULL_ERROR,
38 "The TreeMap's constructor cannot be directly invoked");
39 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
40 }
41
42 // new TreeMap
43 JSHandle<JSTaggedValue> constructor = GetConstructor(argv);
44 JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), newTarget);
45 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
46
47 // Set map’s internal slot with a new empty List.
48 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(obj);
49 JSTaggedValue internal = TaggedTreeMap::Create(thread);
50 map->SetTreeMap(thread, internal);
51
52 // If comparefn was supplied, let compare be comparefn; else let compare be hole.
53 JSHandle<JSTaggedValue> compareFn(GetCallArg(argv, 0));
54 if (compareFn->IsUndefined() || compareFn->IsNull()) {
55 return map.GetTaggedValue();
56 }
57 if (!compareFn->IsCallable()) {
58 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, compareFn.GetTaggedValue());
59 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
60 CString errorMsg =
61 "The type of \"comparefn\" must be callable. Received value is: " + ConvertToString(*result);
62 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
63 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
64 }
65
66 TaggedTreeMap::Cast(internal.GetTaggedObject())->SetCompare(thread, compareFn.GetTaggedValue());
67 return map.GetTaggedValue();
68 }
69
Set(EcmaRuntimeCallInfo * argv)70 JSTaggedValue ContainersTreeMap::Set(EcmaRuntimeCallInfo *argv)
71 {
72 ASSERT(argv);
73 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Set);
74 JSThread *thread = argv->GetThread();
75 [[maybe_unused]] EcmaHandleScope handleScope(thread);
76 JSHandle<JSTaggedValue> self = GetThis(argv);
77 // get and check this map
78 if (!self->IsJSAPITreeMap()) {
79 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
80 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
81 } else {
82 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
83 "The set method cannot be bound");
84 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
85 }
86 }
87
88 JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
89 JSHandle<JSTaggedValue> value = GetCallArg(argv, 1);
90
91 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
92 JSAPITreeMap::Set(thread, map, key, value);
93 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
94 return map.GetTaggedValue();
95 }
96
Get(EcmaRuntimeCallInfo * argv)97 JSTaggedValue ContainersTreeMap::Get(EcmaRuntimeCallInfo *argv)
98 {
99 ASSERT(argv);
100 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Get);
101 JSThread *thread = argv->GetThread();
102 [[maybe_unused]] EcmaHandleScope handleScope(thread);
103 // get and check this map
104 JSHandle<JSTaggedValue> self(GetThis(argv));
105 if (!self->IsJSAPITreeMap()) {
106 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
107 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
108 } else {
109 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
110 "The get method cannot be bound");
111 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
112 }
113 }
114
115 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
116 JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
117 return JSAPITreeMap::Get(thread, map, key);
118 }
119
Remove(EcmaRuntimeCallInfo * argv)120 JSTaggedValue ContainersTreeMap::Remove(EcmaRuntimeCallInfo *argv)
121 {
122 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Remove);
123 JSThread *thread = argv->GetThread();
124 [[maybe_unused]] EcmaHandleScope handleScope(thread);
125 JSHandle<JSTaggedValue> self = GetThis(argv);
126 // get and check this map
127 if (!self->IsJSAPITreeMap()) {
128 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
129 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
130 } else {
131 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
132 "The remove method cannot be bound");
133 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
134 }
135 }
136
137 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
138 JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
139 return JSAPITreeMap::Delete(thread, map, key);
140 }
141
HasKey(EcmaRuntimeCallInfo * argv)142 JSTaggedValue ContainersTreeMap::HasKey(EcmaRuntimeCallInfo *argv)
143 {
144 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, HasKey);
145 JSThread *thread = argv->GetThread();
146 [[maybe_unused]] EcmaHandleScope handleScope(thread);
147 // get and check this map
148 JSHandle<JSTaggedValue> self(GetThis(argv));
149 if (!self->IsJSAPITreeMap()) {
150 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
151 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
152 } else {
153 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
154 "The hasKey method cannot be bound");
155 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
156 }
157 }
158
159 JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
160 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
161
162 bool flag = JSAPITreeMap::HasKey(thread, JSHandle<JSAPITreeMap>::Cast(map), key);
163 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
164 return GetTaggedBoolean(flag);
165 }
166
HasValue(EcmaRuntimeCallInfo * argv)167 JSTaggedValue ContainersTreeMap::HasValue(EcmaRuntimeCallInfo *argv)
168 {
169 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, HasValue);
170 JSThread *thread = argv->GetThread();
171 [[maybe_unused]] EcmaHandleScope handleScope(thread);
172 // get and check this map
173 JSHandle<JSTaggedValue> self(GetThis(argv));
174 if (!self->IsJSAPITreeMap()) {
175 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
176 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
177 } else {
178 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
179 "The hasValue method cannot be bound");
180 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
181 }
182 }
183
184 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
185 bool flag = map->HasValue(thread, GetCallArg(argv, 0));
186 return GetTaggedBoolean(flag);
187 }
188
GetFirstKey(EcmaRuntimeCallInfo * argv)189 JSTaggedValue ContainersTreeMap::GetFirstKey(EcmaRuntimeCallInfo *argv)
190 {
191 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, GetFirstKey);
192 JSThread *thread = argv->GetThread();
193 [[maybe_unused]] EcmaHandleScope handleScope(thread);
194 // get and check this map
195 JSHandle<JSTaggedValue> self(GetThis(argv));
196 if (!self->IsJSAPITreeMap()) {
197 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
198 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
199 } else {
200 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
201 "The getFirstKey method cannot be bound");
202 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
203 }
204 }
205
206 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
207 return TaggedTreeMap::Cast(map->GetTreeMap().GetTaggedObject())->GetFirstKey();
208 }
209
GetLastKey(EcmaRuntimeCallInfo * argv)210 JSTaggedValue ContainersTreeMap::GetLastKey(EcmaRuntimeCallInfo *argv)
211 {
212 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, GetLastKey);
213 JSThread *thread = argv->GetThread();
214 [[maybe_unused]] EcmaHandleScope handleScope(thread);
215 // get and check this map
216 JSHandle<JSTaggedValue> self(GetThis(argv));
217 if (!self->IsJSAPITreeMap()) {
218 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
219 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
220 } else {
221 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
222 "The getLastKey method cannot be bound");
223 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
224 }
225 }
226
227 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
228 return TaggedTreeMap::Cast(map->GetTreeMap().GetTaggedObject())->GetLastKey();
229 }
230
SetAll(EcmaRuntimeCallInfo * argv)231 JSTaggedValue ContainersTreeMap::SetAll(EcmaRuntimeCallInfo *argv)
232 {
233 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, SetAll);
234 JSThread *thread = argv->GetThread();
235 [[maybe_unused]] EcmaHandleScope handleScope(thread);
236 // get and check this map
237 JSHandle<JSTaggedValue> self(GetThis(argv));
238 if (!self->IsJSAPITreeMap()) {
239 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
240 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
241 } else {
242 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
243 "The setAll method cannot be bound");
244 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
245 }
246 }
247
248 JSHandle<JSTaggedValue> obj = GetCallArg(argv, 0);
249 if (!obj->IsJSAPITreeMap()) {
250 if (obj->IsJSProxy() && JSHandle<JSProxy>::Cast(obj)->GetTarget().IsJSAPITreeMap()) {
251 obj = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(obj)->GetTarget());
252 } else {
253 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, obj.GetTaggedValue());
254 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
255 CString errorMsg =
256 "The type of \"map\" must be TreeMap. Received value is: " + ConvertToString(*result);
257 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
258 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
259 }
260 }
261
262 JSHandle<JSAPITreeMap> dst = JSHandle<JSAPITreeMap>::Cast(self);
263 JSHandle<TaggedTreeMap> dmap(thread, dst->GetTreeMap());
264 JSHandle<TaggedTreeMap> smap(thread, JSHandle<JSAPITreeMap>::Cast(obj)->GetTreeMap());
265
266 if (JSHandle<JSAPITreeMap>::Cast(obj)->GetSize() > 0) {
267 JSTaggedValue tmap = TaggedTreeMap::SetAll(thread, dmap, smap);
268 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
269 dst->SetTreeMap(thread, tmap);
270 }
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 forEach 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