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 CString errorMsg =
62 "The type of \"comparefn\" must be callable. Received value is: " + ConvertToString(*result);
63 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
64 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
65 }
66
67 TaggedTreeMap::Cast(internal.GetTaggedObject())->SetCompare(thread, compareFn.GetTaggedValue());
68 return map.GetTaggedValue();
69 }
70
Set(EcmaRuntimeCallInfo * argv)71 JSTaggedValue ContainersTreeMap::Set(EcmaRuntimeCallInfo *argv)
72 {
73 ASSERT(argv);
74 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Set);
75 JSThread *thread = argv->GetThread();
76 [[maybe_unused]] EcmaHandleScope handleScope(thread);
77 JSHandle<JSTaggedValue> self = GetThis(argv);
78 // get and check this map
79 if (!self->IsJSAPITreeMap()) {
80 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
81 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
82 } else {
83 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
84 "The set method cannot be bound");
85 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
86 }
87 }
88
89 JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
90 JSHandle<JSTaggedValue> value = GetCallArg(argv, 1);
91
92 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
93 JSAPITreeMap::Set(thread, map, key, value);
94 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
95 return map.GetTaggedValue();
96 }
97
Get(EcmaRuntimeCallInfo * argv)98 JSTaggedValue ContainersTreeMap::Get(EcmaRuntimeCallInfo *argv)
99 {
100 ASSERT(argv);
101 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Get);
102 JSThread *thread = argv->GetThread();
103 [[maybe_unused]] EcmaHandleScope handleScope(thread);
104 // get and check this map
105 JSHandle<JSTaggedValue> self(GetThis(argv));
106 if (!self->IsJSAPITreeMap()) {
107 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
108 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
109 } else {
110 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
111 "The get method cannot be bound");
112 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
113 }
114 }
115
116 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
117 JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
118 return JSAPITreeMap::Get(thread, map, key);
119 }
120
Remove(EcmaRuntimeCallInfo * argv)121 JSTaggedValue ContainersTreeMap::Remove(EcmaRuntimeCallInfo *argv)
122 {
123 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Remove);
124 JSThread *thread = argv->GetThread();
125 [[maybe_unused]] EcmaHandleScope handleScope(thread);
126 JSHandle<JSTaggedValue> self = GetThis(argv);
127 // get and check this map
128 if (!self->IsJSAPITreeMap()) {
129 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
130 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
131 } else {
132 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
133 "The remove method cannot be bound");
134 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
135 }
136 }
137
138 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
139 JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
140 return JSAPITreeMap::Delete(thread, map, key);
141 }
142
HasKey(EcmaRuntimeCallInfo * argv)143 JSTaggedValue ContainersTreeMap::HasKey(EcmaRuntimeCallInfo *argv)
144 {
145 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, HasKey);
146 JSThread *thread = argv->GetThread();
147 [[maybe_unused]] EcmaHandleScope handleScope(thread);
148 // get and check this map
149 JSHandle<JSTaggedValue> self(GetThis(argv));
150 if (!self->IsJSAPITreeMap()) {
151 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
152 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
153 } else {
154 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
155 "The hasKey method cannot be bound");
156 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
157 }
158 }
159
160 JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
161 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
162
163 bool flag = JSAPITreeMap::HasKey(thread, JSHandle<JSAPITreeMap>::Cast(map), key);
164 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
165 return GetTaggedBoolean(flag);
166 }
167
HasValue(EcmaRuntimeCallInfo * argv)168 JSTaggedValue ContainersTreeMap::HasValue(EcmaRuntimeCallInfo *argv)
169 {
170 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, HasValue);
171 JSThread *thread = argv->GetThread();
172 [[maybe_unused]] EcmaHandleScope handleScope(thread);
173 // get and check this map
174 JSHandle<JSTaggedValue> self(GetThis(argv));
175 if (!self->IsJSAPITreeMap()) {
176 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
177 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
178 } else {
179 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
180 "The hasValue method cannot be bound");
181 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
182 }
183 }
184
185 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
186 bool flag = map->HasValue(thread, GetCallArg(argv, 0));
187 return GetTaggedBoolean(flag);
188 }
189
GetFirstKey(EcmaRuntimeCallInfo * argv)190 JSTaggedValue ContainersTreeMap::GetFirstKey(EcmaRuntimeCallInfo *argv)
191 {
192 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, GetFirstKey);
193 JSThread *thread = argv->GetThread();
194 [[maybe_unused]] EcmaHandleScope handleScope(thread);
195 // get and check this map
196 JSHandle<JSTaggedValue> self(GetThis(argv));
197 if (!self->IsJSAPITreeMap()) {
198 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
199 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
200 } else {
201 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
202 "The getFirstKey method cannot be bound");
203 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
204 }
205 }
206
207 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
208 return TaggedTreeMap::Cast(map->GetTreeMap().GetTaggedObject())->GetFirstKey();
209 }
210
GetLastKey(EcmaRuntimeCallInfo * argv)211 JSTaggedValue ContainersTreeMap::GetLastKey(EcmaRuntimeCallInfo *argv)
212 {
213 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, GetLastKey);
214 JSThread *thread = argv->GetThread();
215 [[maybe_unused]] EcmaHandleScope handleScope(thread);
216 // get and check this map
217 JSHandle<JSTaggedValue> self(GetThis(argv));
218 if (!self->IsJSAPITreeMap()) {
219 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
220 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
221 } else {
222 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
223 "The getLastKey method cannot be bound");
224 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
225 }
226 }
227
228 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
229 return TaggedTreeMap::Cast(map->GetTreeMap().GetTaggedObject())->GetLastKey();
230 }
231
SetAll(EcmaRuntimeCallInfo * argv)232 JSTaggedValue ContainersTreeMap::SetAll(EcmaRuntimeCallInfo *argv)
233 {
234 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, SetAll);
235 JSThread *thread = argv->GetThread();
236 [[maybe_unused]] EcmaHandleScope handleScope(thread);
237 // get and check this map
238 JSHandle<JSTaggedValue> self(GetThis(argv));
239 if (!self->IsJSAPITreeMap()) {
240 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
241 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
242 } else {
243 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
244 "The setAll method cannot be bound");
245 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
246 }
247 }
248
249 JSHandle<JSTaggedValue> obj = GetCallArg(argv, 0);
250 if (!obj->IsJSAPITreeMap()) {
251 if (obj->IsJSProxy() && JSHandle<JSProxy>::Cast(obj)->GetTarget().IsJSAPITreeMap()) {
252 obj = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(obj)->GetTarget());
253 } else {
254 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, obj.GetTaggedValue());
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 JSTaggedValue tmap = TaggedTreeMap::SetAll(thread, dmap, smap);
267 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
268 dst->SetTreeMap(thread, tmap);
269 return JSTaggedValue::Undefined();
270 }
271
Clear(EcmaRuntimeCallInfo * argv)272 JSTaggedValue ContainersTreeMap::Clear(EcmaRuntimeCallInfo *argv)
273 {
274 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Clear);
275 JSThread *thread = argv->GetThread();
276 [[maybe_unused]] EcmaHandleScope handleScope(thread);
277 // get and check this map
278 JSHandle<JSTaggedValue> self(GetThis(argv));
279 if (!self->IsJSAPITreeMap()) {
280 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
281 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
282 } else {
283 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
284 "The clear method cannot be bound");
285 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
286 }
287 }
288
289 JSAPITreeMap::Clear(thread, JSHandle<JSAPITreeMap>::Cast(self));
290 return JSTaggedValue::Undefined();
291 }
292
GetLowerKey(EcmaRuntimeCallInfo * argv)293 JSTaggedValue ContainersTreeMap::GetLowerKey(EcmaRuntimeCallInfo *argv)
294 {
295 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, GetLowerKey);
296 JSThread *thread = argv->GetThread();
297 [[maybe_unused]] EcmaHandleScope handleScope(thread);
298 // get and check this map
299 JSHandle<JSTaggedValue> self(GetThis(argv));
300 if (!self->IsJSAPITreeMap()) {
301 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
302 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
303 } else {
304 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
305 "The getLowerKey method cannot be bound");
306 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
307 }
308 }
309
310 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
311 JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
312
313 JSHandle<TaggedTreeMap> tmap(thread, map->GetTreeMap());
314 return TaggedTreeMap::GetLowerKey(thread, tmap, key);
315 }
316
GetHigherKey(EcmaRuntimeCallInfo * argv)317 JSTaggedValue ContainersTreeMap::GetHigherKey(EcmaRuntimeCallInfo *argv)
318 {
319 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, GetHigherKey);
320 JSThread *thread = argv->GetThread();
321 [[maybe_unused]] EcmaHandleScope handleScope(thread);
322 // get and check this map
323 JSHandle<JSTaggedValue> self(GetThis(argv));
324 if (!self->IsJSAPITreeMap()) {
325 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
326 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
327 } else {
328 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
329 "The getHigherKey method cannot be bound");
330 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
331 }
332 }
333
334 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
335 JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
336
337 JSHandle<TaggedTreeMap> tmap(thread, map->GetTreeMap());
338 return TaggedTreeMap::GetHigherKey(thread, tmap, key);
339 }
340
Replace(EcmaRuntimeCallInfo * argv)341 JSTaggedValue ContainersTreeMap::Replace(EcmaRuntimeCallInfo *argv)
342 {
343 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Replace);
344 JSThread *thread = argv->GetThread();
345 [[maybe_unused]] EcmaHandleScope handleScope(thread);
346 // get and check this map
347 JSHandle<JSTaggedValue> self(GetThis(argv));
348 if (!self->IsJSAPITreeMap()) {
349 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
350 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
351 } else {
352 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
353 "The replace method cannot be bound");
354 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
355 }
356 }
357
358 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
359 JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
360 JSHandle<JSTaggedValue> value = GetCallArg(argv, 1);
361
362 bool success = JSAPITreeMap::Replace(thread, map, key, value);
363 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
364 return GetTaggedBoolean(success);
365 }
366
Keys(EcmaRuntimeCallInfo * argv)367 JSTaggedValue ContainersTreeMap::Keys(EcmaRuntimeCallInfo *argv)
368 {
369 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Keys);
370 JSThread *thread = argv->GetThread();
371 [[maybe_unused]] EcmaHandleScope handleScope(thread);
372 JSHandle<JSTaggedValue> self = GetThis(argv);
373 JSHandle<JSTaggedValue> iter = JSAPITreeMapIterator::CreateTreeMapIterator(thread, self, IterationKind::KEY);
374 return iter.GetTaggedValue();
375 }
376
Values(EcmaRuntimeCallInfo * argv)377 JSTaggedValue ContainersTreeMap::Values(EcmaRuntimeCallInfo *argv)
378 {
379 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Values);
380 JSThread *thread = argv->GetThread();
381 [[maybe_unused]] EcmaHandleScope handleScope(thread);
382 JSHandle<JSTaggedValue> self = GetThis(argv);
383 JSHandle<JSTaggedValue> iter = JSAPITreeMapIterator::CreateTreeMapIterator(thread, self, IterationKind::VALUE);
384 return iter.GetTaggedValue();
385 }
386
Entries(EcmaRuntimeCallInfo * argv)387 JSTaggedValue ContainersTreeMap::Entries(EcmaRuntimeCallInfo *argv)
388 {
389 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Entries);
390 JSThread *thread = argv->GetThread();
391 [[maybe_unused]] EcmaHandleScope handleScope(thread);
392 JSHandle<JSTaggedValue> self = GetThis(argv);
393 JSHandle<JSTaggedValue> iter =
394 JSAPITreeMapIterator::CreateTreeMapIterator(thread, self, IterationKind::KEY_AND_VALUE);
395 return iter.GetTaggedValue();
396 }
397
ForEach(EcmaRuntimeCallInfo * argv)398 JSTaggedValue ContainersTreeMap::ForEach(EcmaRuntimeCallInfo *argv)
399 {
400 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, ForEach);
401 JSThread *thread = argv->GetThread();
402 [[maybe_unused]] EcmaHandleScope handleScope(thread);
403 // get and check TreeMap object
404 JSHandle<JSTaggedValue> self = GetThis(argv);
405 if (!self->IsJSAPITreeMap()) {
406 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
407 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
408 } else {
409 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
410 "The rorEach method cannot be bound");
411 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
412 }
413 }
414 // get and check callback function
415 JSHandle<JSTaggedValue> func(GetCallArg(argv, 0));
416 if (!func->IsCallable()) {
417 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, func.GetTaggedValue());
418 CString errorMsg =
419 "The type of \"callbackfn\" must be callable. Received value is: " + ConvertToString(*result);
420 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
421 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
422 }
423 // If thisArg was supplied, let T be thisArg; else let T be undefined.
424 JSHandle<JSTaggedValue> thisArg = GetCallArg(argv, 1);
425 JSHandle<JSAPITreeMap> tmap = JSHandle<JSAPITreeMap>::Cast(self);
426 JSMutableHandle<TaggedTreeMap> iteratedMap(thread, tmap->GetTreeMap());
427 int elements = iteratedMap->NumberOfElements();
428 JSHandle<TaggedArray> entries = TaggedTreeMap::GetArrayFromMap(thread, iteratedMap);
429 int index = 0;
430 size_t length = entries->GetLength();
431 const int32_t argsLength = 3;
432 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
433 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
434 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined());
435 while (index < elements) {
436 int entriesIndex = entries->Get(index).GetInt();
437 key.Update(iteratedMap->GetKey(entriesIndex));
438 value.Update(iteratedMap->GetValue(entriesIndex));
439 // Let funcResult be Call(callbackfn, T, «e, e, S»).
440 EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, func, thisArg, undefined, argsLength);
441 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
442 info->SetCallArg(value.GetTaggedValue(), key.GetTaggedValue(), self.GetTaggedValue());
443 JSTaggedValue ret = JSFunction::Call(info);
444 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ret);
445 // check entries should be update, size will be update in tmap set or remove.
446 if (tmap->GetSize() != static_cast<int>(length)) {
447 iteratedMap.Update(tmap->GetTreeMap());
448 entries = TaggedTreeMap::GetArrayFromMap(thread, iteratedMap);
449 elements = iteratedMap->NumberOfElements();
450 length = entries->GetLength();
451 }
452 index++;
453 }
454 return JSTaggedValue::Undefined();
455 }
456
GetLength(EcmaRuntimeCallInfo * argv)457 JSTaggedValue ContainersTreeMap::GetLength(EcmaRuntimeCallInfo *argv)
458 {
459 ASSERT(argv);
460 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, GetLength);
461 JSThread *thread = argv->GetThread();
462 [[maybe_unused]] EcmaHandleScope handleScope(thread);
463 // get and check this map
464 JSHandle<JSTaggedValue> self(GetThis(argv));
465 if (!self->IsJSAPITreeMap()) {
466 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
467 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
468 } else {
469 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
470 "The getLength method cannot be bound");
471 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
472 }
473 }
474 int count = JSHandle<JSAPITreeMap>::Cast(self)->GetSize();
475 return JSTaggedValue(count);
476 }
477
IsEmpty(EcmaRuntimeCallInfo * argv)478 JSTaggedValue ContainersTreeMap::IsEmpty(EcmaRuntimeCallInfo *argv)
479 {
480 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, IsEmpty);
481 JSThread *thread = argv->GetThread();
482 [[maybe_unused]] EcmaHandleScope handleScope(thread);
483 // get and check this map
484 JSHandle<JSTaggedValue> self = GetThis(argv);
485 if (!self->IsJSAPITreeMap()) {
486 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) {
487 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
488 } else {
489 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
490 "The isEmpty method cannot be bound");
491 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
492 }
493 }
494 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self);
495 return GetTaggedBoolean(map->GetSize() == 0);
496 }
497 } // namespace panda::ecmascript::containers
498