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_lightweightmap.h"
17
18#include "ecmascript/containers/containers_errors.h"
19#include "ecmascript/interpreter/interpreter.h"
20#include "ecmascript/js_api/js_api_lightweightmap.h"
21#include "ecmascript/js_api/js_api_lightweightmap_iterator.h"
22#include "ecmascript/js_function.h"
23
24namespace panda::ecmascript::containers {
25JSTaggedValue ContainersLightWeightMap::LightWeightMapConstructor(EcmaRuntimeCallInfo *argv)
26{
27    ASSERT(argv != nullptr);
28    JSThread *thread = argv->GetThread();
29    BUILTINS_API_TRACE(thread, LightWeightMap, Constructor);
30    [[maybe_unused]] EcmaHandleScope handleScope(thread);
31    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
32    JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
33    if (newTarget->IsUndefined()) {
34        JSTaggedValue error =
35            ContainerError::BusinessError(thread, ErrorFlag::IS_NULL_ERROR,
36                                          "The LightWeightMap's constructor cannot be directly invoked");
37        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
38    }
39    JSHandle<JSTaggedValue> constructor = GetConstructor(argv);
40    JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), newTarget);
41    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
42    JSHandle<JSAPILightWeightMap> lwMap = JSHandle<JSAPILightWeightMap>::Cast(obj);
43    JSHandle<TaggedArray> hashArray = factory->NewTaggedArray(JSAPILightWeightMap::DEFAULT_CAPACITY_LENGTH);
44    JSHandle<TaggedArray> keyArray = factory->NewTaggedArray(JSAPILightWeightMap::DEFAULT_CAPACITY_LENGTH);
45    JSHandle<TaggedArray> valueArray = factory->NewTaggedArray(JSAPILightWeightMap::DEFAULT_CAPACITY_LENGTH);
46    lwMap->SetHashes(thread, hashArray.GetTaggedValue());
47    lwMap->SetKeys(thread, keyArray.GetTaggedValue());
48    lwMap->SetValues(thread, valueArray.GetTaggedValue());
49
50    return lwMap.GetTaggedValue();
51}
52
53JSTaggedValue ContainersLightWeightMap::Length(EcmaRuntimeCallInfo *argv)
54{
55    ASSERT(argv != nullptr);
56    JSThread *thread = argv->GetThread();
57    BUILTINS_API_TRACE(thread, LightWeightMap, Length);
58    [[maybe_unused]] EcmaHandleScope handleScope(thread);
59    JSHandle<JSTaggedValue> self = GetThis(argv);
60
61    if (!self->IsJSAPILightWeightMap()) {
62        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
63            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
64        } else {
65            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
66                                                                "The getLength method cannot be bound");
67            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
68        }
69    }
70
71    return JSTaggedValue(JSHandle<JSAPILightWeightMap>::Cast(self)->GetLength());
72}
73
74JSTaggedValue ContainersLightWeightMap::HasAll(EcmaRuntimeCallInfo *argv)
75{
76    ASSERT(argv != nullptr);
77    JSThread *thread = argv->GetThread();
78    BUILTINS_API_TRACE(thread, LightWeightMap, HasAll);
79    [[maybe_unused]] EcmaHandleScope handleScope(thread);
80    JSHandle<JSTaggedValue> self = GetThis(argv);
81
82    if (!self->IsJSAPILightWeightMap()) {
83        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
84            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
85        } else {
86            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
87                                                                "The hasAll method cannot be bound");
88            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
89        }
90    }
91
92    JSHandle<JSTaggedValue> lightWeightMap(GetCallArg(argv, 0));
93    if (!lightWeightMap->IsJSAPILightWeightMap()) {
94        if (lightWeightMap->IsJSProxy() &&
95            JSHandle<JSProxy>::Cast(lightWeightMap)->GetTarget().IsJSAPILightWeightMap()) {
96            lightWeightMap = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(lightWeightMap)->GetTarget());
97        } else {
98            JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, lightWeightMap.GetTaggedValue());
99            RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
100            CString errorMsg =
101                "The type of \"map\" must be LightWeightMap. Received value is: " + ConvertToString(*result);
102            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
103            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
104        }
105    }
106
107    return JSAPILightWeightMap::HasAll(thread, JSHandle<JSAPILightWeightMap>::Cast(self),
108                                       JSHandle<JSAPILightWeightMap>::Cast(lightWeightMap));
109}
110
111JSTaggedValue ContainersLightWeightMap::HasKey(EcmaRuntimeCallInfo *argv)
112{
113    ASSERT(argv != nullptr);
114    JSThread *thread = argv->GetThread();
115    BUILTINS_API_TRACE(thread, LightWeightMap, HasKey);
116    [[maybe_unused]] EcmaHandleScope handleScope(thread);
117    JSHandle<JSTaggedValue> self = GetThis(argv);
118
119    if (!self->IsJSAPILightWeightMap()) {
120        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
121            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
122        } else {
123            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
124                                                                "The hasKey method cannot be bound");
125            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
126        }
127    }
128    JSHandle<JSTaggedValue> key(GetCallArg(argv, 0));
129
130    return JSAPILightWeightMap::HasKey(thread, JSHandle<JSAPILightWeightMap>::Cast(self), key);
131}
132
133JSTaggedValue ContainersLightWeightMap::HasValue(EcmaRuntimeCallInfo *argv)
134{
135    ASSERT(argv != nullptr);
136    JSThread *thread = argv->GetThread();
137    BUILTINS_API_TRACE(thread, LightWeightMap, HasValue);
138    [[maybe_unused]] EcmaHandleScope handleScope(thread);
139    JSHandle<JSTaggedValue> self = GetThis(argv);
140
141    if (!self->IsJSAPILightWeightMap()) {
142        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
143            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
144        } else {
145            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
146                                                                "The hasValue method cannot be bound");
147            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
148        }
149    }
150
151    JSHandle<JSTaggedValue> value(GetCallArg(argv, 0));
152    return JSAPILightWeightMap::HasValue(thread, JSHandle<JSAPILightWeightMap>::Cast(self), value);
153}
154
155JSTaggedValue ContainersLightWeightMap::IncreaseCapacityTo(EcmaRuntimeCallInfo *argv)
156{
157    ASSERT(argv != nullptr);
158    JSThread *thread = argv->GetThread();
159    BUILTINS_API_TRACE(thread, LightWeightMap, IncreaseCapacityTo);
160    [[maybe_unused]] EcmaHandleScope handleScope(thread);
161    JSHandle<JSTaggedValue> self = GetThis(argv);
162
163    if (!self->IsJSAPILightWeightMap()) {
164        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
165            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
166        } else {
167            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
168                                                                "The increaseCapacityTo method cannot be bound");
169            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
170        }
171    }
172
173    JSHandle<JSTaggedValue> index(GetCallArg(argv, 0));
174
175    // for case like Math.foor(1.3), it gives double 1.0;
176    if (index->IsDouble()) {
177        index = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(index->GetDouble()));
178    }
179
180    if (!index->IsInt()) {
181        JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index);
182        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
183        CString errorMsg =
184            "The type of \"minimumCapacity\" must be small integer. Received value is: " + ConvertToString(*result);
185        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
186        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
187    }
188    JSAPILightWeightMap::IncreaseCapacityTo(thread, JSHandle<JSAPILightWeightMap>::Cast(self),
189                                            index->GetInt());
190
191    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
192    return JSTaggedValue::Undefined();
193}
194
195JSTaggedValue ContainersLightWeightMap::Entries(EcmaRuntimeCallInfo *argv)
196{
197    ASSERT(argv != nullptr);
198    JSThread *thread = argv->GetThread();
199    BUILTINS_API_TRACE(thread, LightWeightMap, Entries);
200    [[maybe_unused]] EcmaHandleScope handleScope(thread);
201    JSHandle<JSTaggedValue> self = GetThis(argv);
202    JSHandle<JSTaggedValue> iter =
203        JSAPILightWeightMapIterator::CreateLightWeightMapIterator(thread, self, IterationKind::KEY_AND_VALUE);
204    return iter.GetTaggedValue();
205}
206
207JSTaggedValue ContainersLightWeightMap::Get(EcmaRuntimeCallInfo *argv)
208{
209    ASSERT(argv != nullptr);
210    JSThread *thread = argv->GetThread();
211    BUILTINS_API_TRACE(thread, LightWeightMap, Get);
212    [[maybe_unused]] EcmaHandleScope handleScope(thread);
213    JSHandle<JSTaggedValue> self = GetThis(argv);
214
215    if (!self->IsJSAPILightWeightMap()) {
216        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
217            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
218        } else {
219            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
220                                                                "The get method cannot be bound");
221            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
222        }
223    }
224
225    JSHandle<JSTaggedValue> key(GetCallArg(argv, 0));
226
227    return JSAPILightWeightMap::Get(thread, JSHandle<JSAPILightWeightMap>::Cast(self), key);
228}
229
230JSTaggedValue ContainersLightWeightMap::GetIndexOfKey(EcmaRuntimeCallInfo *argv)
231{
232    ASSERT(argv != nullptr);
233    JSThread *thread = argv->GetThread();
234    BUILTINS_API_TRACE(thread, LightWeightMap, GetIndexOfKey);
235    [[maybe_unused]] EcmaHandleScope handleScope(thread);
236    JSHandle<JSTaggedValue> self = GetThis(argv);
237
238    if (!self->IsJSAPILightWeightMap()) {
239        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
240            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
241        } else {
242            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
243                                                                "The getIndexOfKey method cannot be bound");
244            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
245        }
246    }
247
248    JSHandle<JSTaggedValue> key(GetCallArg(argv, 0));
249
250    int32_t index = JSAPILightWeightMap::GetIndexOfKey(thread, JSHandle<JSAPILightWeightMap>::Cast(self), key);
251    return JSTaggedValue(index);
252}
253
254JSTaggedValue ContainersLightWeightMap::GetIndexOfValue(EcmaRuntimeCallInfo *argv)
255{
256    ASSERT(argv != nullptr);
257    JSThread *thread = argv->GetThread();
258    BUILTINS_API_TRACE(thread, LightWeightMap, GetIndexOfValue);
259    [[maybe_unused]] EcmaHandleScope handleScope(thread);
260    JSHandle<JSTaggedValue> self = GetThis(argv);
261
262    if (!self->IsJSAPILightWeightMap()) {
263        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
264            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
265        } else {
266            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
267                                                                "The getIndexOfValue method cannot be bound");
268            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
269        }
270    }
271
272    JSHandle<JSTaggedValue> value(GetCallArg(argv, 0));
273
274    int32_t index = JSAPILightWeightMap::GetIndexOfValue(thread, JSHandle<JSAPILightWeightMap>::Cast(self), value);
275    return JSTaggedValue(index);
276}
277
278JSTaggedValue ContainersLightWeightMap::IsEmpty(EcmaRuntimeCallInfo *argv)
279{
280    ASSERT(argv != nullptr);
281    JSThread *thread = argv->GetThread();
282    BUILTINS_API_TRACE(thread, LightWeightMap, IsEmpty);
283    [[maybe_unused]] EcmaHandleScope handleScope(thread);
284    JSHandle<JSTaggedValue> self = GetThis(argv);
285
286    if (!self->IsJSAPILightWeightMap()) {
287        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
288            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
289        } else {
290            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
291                                                                "The isEmpty method cannot be bound");
292            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
293        }
294    }
295    return JSHandle<JSAPILightWeightMap>::Cast(self)->IsEmpty();
296}
297
298JSTaggedValue ContainersLightWeightMap::GetKeyAt(EcmaRuntimeCallInfo *argv)
299{
300    ASSERT(argv != nullptr);
301    JSThread *thread = argv->GetThread();
302    BUILTINS_API_TRACE(thread, LightWeightMap, GetKeyAt);
303    [[maybe_unused]] EcmaHandleScope handleScope(thread);
304    JSHandle<JSTaggedValue> self = GetThis(argv);
305
306    if (!self->IsJSAPILightWeightMap()) {
307        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
308            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
309        } else {
310            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
311                                                                "The getKeyAt method cannot be bound");
312            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
313        }
314    }
315
316    JSHandle<JSTaggedValue> index(GetCallArg(argv, 0));
317
318    if (index->IsDouble()) {
319        index = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(index->GetDouble()));
320    }
321    if (!index->IsInt()) {
322        JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index);
323        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
324        CString errorMsg =
325            "The type of \"index\" must be small integer. Received value is: " + ConvertToString(*result);
326        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
327        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
328    }
329
330    return JSAPILightWeightMap::GetKeyAt(thread, JSHandle<JSAPILightWeightMap>::Cast(self),
331                                         index->GetInt());
332}
333
334JSTaggedValue ContainersLightWeightMap::Keys(EcmaRuntimeCallInfo *argv)
335{
336    ASSERT(argv != nullptr);
337    JSThread *thread = argv->GetThread();
338    BUILTINS_API_TRACE(thread, LightWeightMap, Keys);
339    [[maybe_unused]] EcmaHandleScope handleScope(thread);
340    JSHandle<JSTaggedValue> self = GetThis(argv);
341    JSHandle<JSTaggedValue> iter =
342        JSAPILightWeightMapIterator::CreateLightWeightMapIterator(thread, self, IterationKind::KEY);
343    return iter.GetTaggedValue();
344}
345
346JSTaggedValue ContainersLightWeightMap::SetAll(EcmaRuntimeCallInfo *argv)
347{
348    ASSERT(argv != nullptr);
349    JSThread *thread = argv->GetThread();
350    BUILTINS_API_TRACE(thread, LightWeightMap, SetAll);
351    [[maybe_unused]] EcmaHandleScope handleScope(thread);
352    JSHandle<JSTaggedValue> self = GetThis(argv);
353
354    if (!self->IsJSAPILightWeightMap()) {
355        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
356            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
357        } else {
358            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
359                                                                "The setAll method cannot be bound");
360            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
361        }
362    }
363
364    JSHandle<JSTaggedValue> lightWeightMap(GetCallArg(argv, 0));
365
366    if (!lightWeightMap->IsJSAPILightWeightMap()) {
367        if (lightWeightMap->IsJSProxy() &&
368            JSHandle<JSProxy>::Cast(lightWeightMap)->GetTarget().IsJSAPILightWeightMap()) {
369            lightWeightMap = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(lightWeightMap)->GetTarget());
370        } else {
371            JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, lightWeightMap.GetTaggedValue());
372            RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
373            CString errorMsg =
374                "The type of \"map\" must be LightWeightMap. Received value is: " + ConvertToString(*result);
375            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
376            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
377        }
378    }
379
380    JSAPILightWeightMap::SetAll(thread, JSHandle<JSAPILightWeightMap>::Cast(self),
381                                JSHandle<JSAPILightWeightMap>::Cast(lightWeightMap));
382    return JSTaggedValue::True();
383}
384
385JSTaggedValue ContainersLightWeightMap::Set(EcmaRuntimeCallInfo *argv)
386{
387    ASSERT(argv != nullptr);
388    JSThread *thread = argv->GetThread();
389    BUILTINS_API_TRACE(thread, LightWeightMap, Set);
390    [[maybe_unused]] EcmaHandleScope handleScope(thread);
391    JSHandle<JSTaggedValue> self = GetThis(argv);
392
393    if (!self->IsJSAPILightWeightMap()) {
394        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
395            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
396        } else {
397            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
398                                                                "The set method cannot be bound");
399            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
400        }
401    }
402
403    JSHandle<JSTaggedValue> key(GetCallArg(argv, 0));
404    JSHandle<JSTaggedValue> value(GetCallArg(argv, 1));
405    JSHandle<JSAPILightWeightMap> lightWeightMap = JSHandle<JSAPILightWeightMap>::Cast(self);
406    JSAPILightWeightMap::Set(thread, lightWeightMap, key, value);
407
408    return lightWeightMap.GetTaggedValue();
409}
410
411JSTaggedValue ContainersLightWeightMap::Remove(EcmaRuntimeCallInfo *argv)
412{
413    ASSERT(argv != nullptr);
414    JSThread *thread = argv->GetThread();
415    BUILTINS_API_TRACE(thread, LightWeightMap, Remove);
416    [[maybe_unused]] EcmaHandleScope handleScope(thread);
417    JSHandle<JSTaggedValue> self = GetThis(argv);
418
419    if (!self->IsJSAPILightWeightMap()) {
420        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
421            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
422        } else {
423            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
424                                                                "The remove method cannot be bound");
425            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
426        }
427    }
428    JSHandle<JSTaggedValue> key(GetCallArg(argv, 0));
429
430    return JSAPILightWeightMap::Remove(thread, JSHandle<JSAPILightWeightMap>::Cast(self), key);
431}
432
433JSTaggedValue ContainersLightWeightMap::RemoveAt(EcmaRuntimeCallInfo *argv)
434{
435    ASSERT(argv != nullptr);
436    JSThread *thread = argv->GetThread();
437    BUILTINS_API_TRACE(thread, LightWeightMap, RemoveAt);
438    [[maybe_unused]] EcmaHandleScope handleScope(thread);
439    JSHandle<JSTaggedValue> self = GetThis(argv);
440
441    if (!self->IsJSAPILightWeightMap()) {
442        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
443            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
444        } else {
445            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
446                                                                "The removeAt method cannot be bound");
447            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
448        }
449    }
450
451    JSHandle<JSTaggedValue> index(GetCallArg(argv, 0));
452
453    if (index->IsDouble()) {
454        index = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(index->GetDouble()));
455    }
456    if (!index->IsInt()) {
457        JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index);
458        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
459        CString errorMsg =
460            "The type of \"index\" must be small integer. Received value is: " + ConvertToString(*result);
461        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
462        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
463    }
464
465    return JSAPILightWeightMap::RemoveAt(thread, JSHandle<JSAPILightWeightMap>::Cast(self),
466                                         index->GetInt());
467}
468
469JSTaggedValue ContainersLightWeightMap::Clear(EcmaRuntimeCallInfo *argv)
470{
471    ASSERT(argv != nullptr);
472    JSThread *thread = argv->GetThread();
473    BUILTINS_API_TRACE(thread, LightWeightMap, Clear);
474    [[maybe_unused]] EcmaHandleScope handleScope(thread);
475    JSHandle<JSTaggedValue> self = GetThis(argv);
476
477    if (!self->IsJSAPILightWeightMap()) {
478        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
479            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
480        } else {
481            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
482                                                                "The clear method cannot be bound");
483            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
484        }
485    }
486
487    JSAPILightWeightMap::Clear(thread, JSHandle<JSAPILightWeightMap>::Cast(self));
488    return JSTaggedValue::Undefined();
489}
490
491JSTaggedValue ContainersLightWeightMap::SetValueAt(EcmaRuntimeCallInfo *argv)
492{
493    ASSERT(argv != nullptr);
494    JSThread *thread = argv->GetThread();
495    BUILTINS_API_TRACE(thread, LightWeightMap, SetValueAt);
496    [[maybe_unused]] EcmaHandleScope handleScope(thread);
497    JSHandle<JSTaggedValue> self = GetThis(argv);
498
499    if (!self->IsJSAPILightWeightMap()) {
500        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
501            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
502        } else {
503            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
504                                                                "The setValueAt method cannot be bound");
505            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
506        }
507    }
508
509    JSHandle<JSTaggedValue> index(GetCallArg(argv, 0));
510    JSHandle<JSTaggedValue> value(GetCallArg(argv, 1));
511    if (index->IsDouble()) {
512        index = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(index->GetDouble()));
513    }
514    if (!index->IsInt()) {
515        JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index);
516        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
517        CString errorMsg =
518            "The type of \"index\" must be small integer. Received value is: " + ConvertToString(*result);
519        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
520        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
521    }
522
523    return JSAPILightWeightMap::SetValueAt(thread, JSHandle<JSAPILightWeightMap>::Cast(self),
524                                           index->GetInt(), value);
525}
526
527JSTaggedValue ContainersLightWeightMap::ForEach(EcmaRuntimeCallInfo *argv)
528{
529    ASSERT(argv != nullptr);
530    JSThread *thread = argv->GetThread();
531    BUILTINS_API_TRACE(thread, LightWeightMap, ForEach);
532    [[maybe_unused]] EcmaHandleScope handleScope(thread);
533    // get and check lightweightmap object
534    JSHandle<JSTaggedValue> self = GetThis(argv);
535    if (!self->IsJSAPILightWeightMap()) {
536        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
537            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
538        } else {
539            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
540                                                                "The forEach method cannot be bound");
541            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
542        }
543    }
544    // get and check callback function
545    JSHandle<JSTaggedValue> func(GetCallArg(argv, 0));
546    if (!func->IsCallable()) {
547        JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, func.GetTaggedValue());
548        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
549        CString errorMsg =
550            "The type of \"callbackfn\" must be callable. Received value is: " + ConvertToString(*result);
551        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
552        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
553    }
554    // If thisArg was supplied, let T be thisArg; else let T be undefined.
555    JSHandle<JSTaggedValue> thisArg = GetCallArg(argv, 1);
556    JSHandle<JSAPILightWeightMap> tmap = JSHandle<JSAPILightWeightMap>::Cast(self);
557    JSMutableHandle<TaggedArray> keys(thread, tmap->GetKeys());
558    JSMutableHandle<TaggedArray> values(thread, tmap->GetValues());
559
560    uint32_t index = 0;
561    uint32_t length = tmap->GetSize();
562    const uint32_t argsLength = 3;
563    JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
564    while (index < length) {
565        // ignore the hash value is required to determine the true index
566        // Let funcResult be Call(callbackfn, T, «e, e, S»).
567        EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, func, thisArg, undefined, argsLength);
568        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
569        info->SetCallArg(values->Get(index), keys->Get(index), self.GetTaggedValue());
570        JSTaggedValue ret = JSFunction::Call(info);
571        RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ret);
572
573        // check entries should be update, size will be update in tmap set or remove.
574        if (tmap->GetSize() != length) {
575            keys.Update(tmap->GetKeys());
576            values.Update(tmap->GetValues());
577            length = tmap->GetSize();
578        }
579        index++;
580    }
581    return JSTaggedValue::Undefined();
582}
583
584JSTaggedValue ContainersLightWeightMap::ToString(EcmaRuntimeCallInfo *argv)
585{
586    ASSERT(argv != nullptr);
587    JSThread *thread = argv->GetThread();
588    BUILTINS_API_TRACE(thread, LightWeightMap, ToString);
589    [[maybe_unused]] EcmaHandleScope handleScope(thread);
590    JSHandle<JSTaggedValue> self = GetThis(argv);
591
592    if (!self->IsJSAPILightWeightMap()) {
593        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
594            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
595        } else {
596            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
597                                                                "The toString method cannot be bound");
598            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
599        }
600    }
601
602    return JSAPILightWeightMap::ToString(thread, JSHandle<JSAPILightWeightMap>::Cast(self));
603}
604
605JSTaggedValue ContainersLightWeightMap::GetValueAt(EcmaRuntimeCallInfo *argv)
606{
607    ASSERT(argv != nullptr);
608    JSThread *thread = argv->GetThread();
609    BUILTINS_API_TRACE(thread, LightWeightMap, GetValueAt);
610    [[maybe_unused]] EcmaHandleScope handleScope(thread);
611    JSHandle<JSTaggedValue> self = GetThis(argv);
612
613    if (!self->IsJSAPILightWeightMap()) {
614        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightMap()) {
615            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
616        } else {
617            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
618                                                                "The getValueAt method cannot be bound");
619            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
620        }
621    }
622    JSHandle<JSTaggedValue> index(GetCallArg(argv, 0));
623    if (index->IsDouble()) {
624        index = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(index->GetDouble()));
625    }
626    if (!index->IsInt()) {
627        JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index);
628        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
629        CString errorMsg =
630            "The type of \"index\" must be small integer. Received value is: " + ConvertToString(*result);
631        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
632        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
633    }
634
635    if (index->IsDouble()) {
636        index = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(index->GetDouble()));
637    }
638    return JSAPILightWeightMap::GetValueAt(thread, JSHandle<JSAPILightWeightMap>::Cast(self),
639                                           index->GetInt());
640}
641
642JSTaggedValue ContainersLightWeightMap::Values(EcmaRuntimeCallInfo *argv)
643{
644    ASSERT(argv != nullptr);
645    JSThread *thread = argv->GetThread();
646    BUILTINS_API_TRACE(thread, LightWeightMap, Keys);
647    [[maybe_unused]] EcmaHandleScope handleScope(thread);
648    JSHandle<JSTaggedValue> self = GetThis(argv);
649    JSHandle<JSTaggedValue> iter =
650        JSAPILightWeightMapIterator::CreateLightWeightMapIterator(thread, self, IterationKind::VALUE);
651    return iter.GetTaggedValue();
652}
653}  // namespace panda::ecmascript::containers
654