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_lightweightset.h"
17
18#include "ecmascript/containers/containers_errors.h"
19#include "ecmascript/js_api/js_api_lightweightset.h"
20#include "ecmascript/js_api/js_api_lightweightset_iterator.h"
21#include "ecmascript/js_array.h"
22
23namespace panda::ecmascript::containers {
24JSTaggedValue ContainersLightWeightSet::LightWeightSetConstructor(EcmaRuntimeCallInfo *argv)
25{
26    ASSERT(argv != nullptr);
27    JSThread *thread = argv->GetThread();
28    BUILTINS_API_TRACE(thread, LightWeightSet, Constructor);
29    [[maybe_unused]] EcmaHandleScope handleScope(thread);
30    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
31    JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
32    if (newTarget->IsUndefined()) {
33        JSTaggedValue error =
34            ContainerError::BusinessError(thread, ErrorFlag::IS_NULL_ERROR,
35                                          "The LightWeightSet's constructor cannot be directly invoked");
36        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
37    }
38    JSHandle<JSTaggedValue> constructor = GetConstructor(argv);
39    JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), newTarget);
40    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
41    JSHandle<JSAPILightWeightSet> lightweightSet = JSHandle<JSAPILightWeightSet>::Cast(obj);
42
43    JSHandle<TaggedArray> hashes =
44        JSAPILightWeightSet::CreateSlot(thread, JSAPILightWeightSet::DEFAULT_CAPACITY_LENGTH);
45    JSHandle<TaggedArray> values =
46        JSAPILightWeightSet::CreateSlot(thread, JSAPILightWeightSet::DEFAULT_CAPACITY_LENGTH);
47    lightweightSet->SetHashes(thread, hashes);
48    lightweightSet->SetValues(thread, values);
49    return obj.GetTaggedValue();
50}
51
52JSTaggedValue ContainersLightWeightSet::Add(EcmaRuntimeCallInfo *argv)
53{
54    ASSERT(argv != nullptr);
55    JSThread *thread = argv->GetThread();
56    BUILTINS_API_TRACE(thread, LightWeightSet, Add);
57    [[maybe_unused]] EcmaHandleScope handleScope(thread);
58    JSHandle<JSTaggedValue> self = GetThis(argv);
59    if (!self->IsJSAPILightWeightSet()) {
60        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightSet()) {
61            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
62        } else {
63            JSTaggedValue error = ContainerError::BusinessError(thread, BIND_ERROR,
64                                                                "The add method cannot be bound");
65            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
66        }
67    }
68    JSHandle<JSTaggedValue> value(GetCallArg(argv, 0));
69    bool flag = JSAPILightWeightSet::Add(thread, JSHandle<JSAPILightWeightSet>::Cast(self), value);
70    return JSTaggedValue(flag);
71}
72
73JSTaggedValue ContainersLightWeightSet::AddAll(EcmaRuntimeCallInfo *argv)
74{
75    ASSERT(argv != nullptr);
76    JSThread *thread = argv->GetThread();
77    BUILTINS_API_TRACE(thread, LightWeightSet, AddAll);
78    [[maybe_unused]] EcmaHandleScope handleScope(thread);
79    JSHandle<JSTaggedValue> self = GetThis(argv);
80    if (!self->IsJSAPILightWeightSet()) {
81        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightSet()) {
82            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
83        } else {
84            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
85                                                                "The addAll method cannot be bound");
86            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
87        }
88    }
89
90    JSHandle<JSTaggedValue> value(GetCallArg(argv, 0));
91    if (!value->IsJSAPILightWeightSet()) {
92        if (value->IsJSProxy() && JSHandle<JSProxy>::Cast(value)->GetTarget().IsJSAPILightWeightSet()) {
93            value = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(value)->GetTarget());
94        } else {
95            JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, value.GetTaggedValue());
96            RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
97            CString errorMsg =
98                "The type of \"set\" must be LightWeightSet. Received value is: " + ConvertToString(*result);
99            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
100            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
101        }
102    }
103
104    return JSTaggedValue(JSAPILightWeightSet::AddAll(thread, JSHandle<JSAPILightWeightSet>::Cast(self), value));
105}
106
107JSTaggedValue ContainersLightWeightSet::IsEmpty(EcmaRuntimeCallInfo *argv)
108{
109    ASSERT(argv != nullptr);
110    JSThread *thread = argv->GetThread();
111    BUILTINS_API_TRACE(thread, LightWeightSet, IsEmpty);
112    [[maybe_unused]] EcmaHandleScope handleScope(thread);
113    JSHandle<JSTaggedValue> self = GetThis(argv);
114    if (!self->IsJSAPILightWeightSet()) {
115        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightSet()) {
116            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
117        } else {
118            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
119                                                                "The isEmpty method cannot be bound");
120            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
121        }
122    }
123    JSAPILightWeightSet *set = JSAPILightWeightSet::Cast(self->GetTaggedObject());
124    return JSTaggedValue(set->IsEmpty());
125}
126
127JSTaggedValue ContainersLightWeightSet::GetValueAt(EcmaRuntimeCallInfo *argv)
128{
129    ASSERT(argv != nullptr);
130    JSThread *thread = argv->GetThread();
131    BUILTINS_API_TRACE(thread, LightWeightSet, GetValueAt);
132    [[maybe_unused]] EcmaHandleScope handleScope(thread);
133    JSHandle<JSTaggedValue> self = GetThis(argv);
134    if (!self->IsJSAPILightWeightSet()) {
135        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightSet()) {
136            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
137        } else {
138            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
139                                                                "The getValueAt method cannot be bound");
140            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
141        }
142    }
143    JSHandle<JSTaggedValue> value(GetCallArg(argv, 0));
144    if (value->IsDouble()) {
145        value = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(value->GetDouble()));
146    }
147    if (!value->IsInt()) {
148        JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, value.GetTaggedValue());
149        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
150        CString errorMsg =
151            "The type of \"index\" must be small integer. Received value is: " + ConvertToString(*result);
152        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
153        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
154    }
155    JSAPILightWeightSet *set = JSAPILightWeightSet::Cast(self->GetTaggedObject());
156    return set->GetValueAt(value->GetInt());
157}
158
159JSTaggedValue ContainersLightWeightSet::HasAll(EcmaRuntimeCallInfo *argv)
160{
161    ASSERT(argv != nullptr);
162    JSThread *thread = argv->GetThread();
163    BUILTINS_API_TRACE(thread, LightWeightSet, HasAll);
164    [[maybe_unused]] EcmaHandleScope handleScope(thread);
165    JSHandle<JSTaggedValue> self = GetThis(argv);
166    if (!self->IsJSAPILightWeightSet()) {
167        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightSet()) {
168            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
169        } else {
170            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
171                                                                "The hasAll method cannot be bound");
172            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
173        }
174    }
175    JSHandle<JSTaggedValue> value(GetCallArg(argv, 0));
176    if (!value->IsJSAPILightWeightSet()) {
177        if (value->IsJSProxy() && JSHandle<JSProxy>::Cast(value)->GetTarget().IsJSAPILightWeightSet()) {
178            value = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(value)->GetTarget());
179        } else {
180            JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, value.GetTaggedValue());
181            RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
182            CString errorMsg =
183                "The type of \"set\" must be LightWeightSet. Received value is: " + ConvertToString(*result);
184            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
185            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
186        }
187    }
188    JSAPILightWeightSet *set = JSAPILightWeightSet::Cast(self->GetTaggedObject());
189    return JSTaggedValue(set->HasAll(value));
190}
191
192JSTaggedValue ContainersLightWeightSet::Has(EcmaRuntimeCallInfo *argv)
193{
194    ASSERT(argv != nullptr);
195    JSThread *thread = argv->GetThread();
196    BUILTINS_API_TRACE(thread, LightWeightSet, Has);
197    [[maybe_unused]] EcmaHandleScope handleScope(thread);
198    JSHandle<JSTaggedValue> self = GetThis(argv);
199    if (!self->IsJSAPILightWeightSet()) {
200        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightSet()) {
201            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
202        } else {
203            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
204                                                                "The has method cannot be bound");
205            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
206        }
207    }
208    JSHandle<JSTaggedValue> value(GetCallArg(argv, 0));
209    JSAPILightWeightSet *set = JSAPILightWeightSet::Cast(self->GetTaggedObject());
210    return JSTaggedValue(set->Has(thread, value));
211}
212
213JSTaggedValue ContainersLightWeightSet::HasHash(EcmaRuntimeCallInfo *argv)
214{
215    ASSERT(argv != nullptr);
216    JSThread *thread = argv->GetThread();
217    BUILTINS_API_TRACE(thread, LightWeightSet, HasHash);
218    [[maybe_unused]] EcmaHandleScope handleScope(thread);
219    JSHandle<JSTaggedValue> self = GetThis(argv);
220    if (!self->IsJSAPILightWeightSet()) {
221        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightSet()) {
222            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
223        } else {
224            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
225                                                                "The hasHash method cannot be bound");
226            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
227        }
228    }
229    JSHandle<JSTaggedValue> value(GetCallArg(argv, 0));
230    JSAPILightWeightSet *set = JSAPILightWeightSet::Cast(self->GetTaggedObject());
231    return JSTaggedValue(set->HasHash(value));
232}
233
234JSTaggedValue ContainersLightWeightSet::Equal(EcmaRuntimeCallInfo *argv)
235{
236    ASSERT(argv != nullptr);
237    JSThread *thread = argv->GetThread();
238    BUILTINS_API_TRACE(thread, LightWeightSet, Equal);
239    [[maybe_unused]] EcmaHandleScope handleScope(thread);
240    JSHandle<JSTaggedValue> self = GetThis(argv);
241    if (!self->IsJSAPILightWeightSet()) {
242        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightSet()) {
243            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
244        } else {
245            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
246                                                                "The equal method cannot be bound");
247            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
248        }
249    }
250    JSHandle<JSTaggedValue> value(GetCallArg(argv, 0));
251    return JSTaggedValue(JSAPILightWeightSet::Equal(thread, JSHandle<JSAPILightWeightSet>::Cast(self), value));
252}
253
254JSTaggedValue ContainersLightWeightSet::IncreaseCapacityTo(EcmaRuntimeCallInfo *argv)
255{
256    ASSERT(argv != nullptr);
257    JSThread *thread = argv->GetThread();
258    BUILTINS_API_TRACE(thread, LightWeightSet, IncreaseCapacityTo);
259    [[maybe_unused]] EcmaHandleScope handleScope(thread);
260    JSHandle<JSTaggedValue> self = GetThis(argv);
261    if (!self->IsJSAPILightWeightSet()) {
262        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightSet()) {
263            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
264        } else {
265            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
266                                                                "The increaseCapacityTo method cannot be bound");
267            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
268        }
269    }
270    JSHandle<JSTaggedValue> value(GetCallArg(argv, 0));
271
272    // for case like Math.foor(1.3), it gives double 1.0;
273    if (value->IsDouble()) {
274        value = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(value->GetDouble()));
275    }
276
277    if (!value->IsInt()) {
278        JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, value.GetTaggedValue());
279        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
280        CString errorMsg =
281            "The type of \"minimumCapacity\" must be small integer. Received value is: " + ConvertToString(*result);
282        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
283        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
284    }
285    int32_t minCapacity = value->GetInt();
286    JSAPILightWeightSet::IncreaseCapacityTo(thread, JSHandle<JSAPILightWeightSet>::Cast(self), minCapacity);
287    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::False());
288    return JSTaggedValue::Undefined();
289}
290
291JSTaggedValue ContainersLightWeightSet::GetIteratorObj(EcmaRuntimeCallInfo *argv)
292{
293    ASSERT(argv != nullptr);
294    JSThread *thread = argv->GetThread();
295    BUILTINS_API_TRACE(thread, LightWeightSet, GetIteratorObj);
296    [[maybe_unused]] EcmaHandleScope handleScope(thread);
297    JSHandle<JSTaggedValue> self = GetThis(argv);
298    if (!self->IsJSAPILightWeightSet()) {
299        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightSet()) {
300            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
301        } else {
302            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
303                                                                "The Symbol.iterator method cannot be bound");
304            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
305        }
306    }
307    JSHandle<JSTaggedValue> iter =
308        JSAPILightWeightSet::GetIteratorObj(thread, JSHandle<JSAPILightWeightSet>::Cast(self), IterationKind::VALUE);
309    return iter.GetTaggedValue();
310}
311
312JSTaggedValue ContainersLightWeightSet::Values(EcmaRuntimeCallInfo *argv)
313{
314    ASSERT(argv != nullptr);
315    JSThread *thread = argv->GetThread();
316    BUILTINS_API_TRACE(thread, LightWeightSet, Values);
317    [[maybe_unused]] EcmaHandleScope handleScope(thread);
318    JSHandle<JSTaggedValue> self = GetThis(argv);
319    if (!self->IsJSAPILightWeightSet()) {
320        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightSet()) {
321            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
322        } else {
323            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
324                                                                "The values method cannot be bound");
325            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
326        }
327    }
328    JSHandle<JSTaggedValue> iter =
329        JSAPILightWeightSet::GetIteratorObj(thread, JSHandle<JSAPILightWeightSet>::Cast(self), IterationKind::VALUE);
330    return iter.GetTaggedValue();
331}
332
333JSTaggedValue ContainersLightWeightSet::Entries(EcmaRuntimeCallInfo *argv)
334{
335    ASSERT(argv != nullptr);
336    JSThread *thread = argv->GetThread();
337    BUILTINS_API_TRACE(thread, LightWeightSet, Entries);
338    [[maybe_unused]] EcmaHandleScope handleScope(thread);
339    JSHandle<JSTaggedValue> self = GetThis(argv);
340    if (!self->IsJSAPILightWeightSet()) {
341        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightSet()) {
342            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
343        } else {
344            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
345                                                                "The entries method cannot be bound");
346            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
347        }
348    }
349    JSHandle<JSTaggedValue> iter =
350        JSAPILightWeightSet::GetIteratorObj(thread, JSHandle<JSAPILightWeightSet>::Cast(self),
351                                            IterationKind::KEY_AND_VALUE);
352    return iter.GetTaggedValue();
353}
354
355JSTaggedValue ContainersLightWeightSet::ForEach(EcmaRuntimeCallInfo *argv)
356{
357    ASSERT(argv != nullptr);
358    JSThread *thread = argv->GetThread();
359    BUILTINS_API_TRACE(thread, LightWeightSet, ForEach);
360    [[maybe_unused]] EcmaHandleScope handleScope(thread);
361    JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
362    JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
363
364    if (!thisHandle->IsJSAPILightWeightSet()) {
365        if (thisHandle->IsJSProxy() && JSHandle<JSProxy>::Cast(thisHandle)->GetTarget().IsJSAPILightWeightSet()) {
366            thisHandle = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(thisHandle)->GetTarget());
367        } else {
368            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
369                                                                "The forEach method cannot be bound");
370            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
371        }
372    }
373
374    if (!callbackFnHandle->IsCallable()) {
375        JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, callbackFnHandle.GetTaggedValue());
376        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
377        CString errorMsg =
378            "The type of \"callbackfn\" must be callable. Received value is: " + ConvertToString(*result);
379        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
380        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
381    }
382    JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
383    return JSAPILightWeightSet::ForEach(thread, thisHandle, callbackFnHandle, thisArgHandle);
384}
385
386JSTaggedValue ContainersLightWeightSet::GetIndexOf(EcmaRuntimeCallInfo *argv)
387{
388    ASSERT(argv != nullptr);
389    JSThread *thread = argv->GetThread();
390    BUILTINS_API_TRACE(thread, LightWeightSet, GetIndexOf);
391    [[maybe_unused]] EcmaHandleScope handleScope(thread);
392    JSHandle<JSTaggedValue> self = GetThis(argv);
393    if (!self->IsJSAPILightWeightSet()) {
394        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightSet()) {
395            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
396        } else {
397            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
398                                                                "The getIndexOf method cannot be bound");
399            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
400        }
401    }
402    JSHandle<JSTaggedValue> value(GetCallArg(argv, 0));
403    JSAPILightWeightSet *set = JSAPILightWeightSet::Cast(self->GetTaggedObject());
404    int32_t result = set->GetIndexOf(thread, value);
405    return JSTaggedValue(result);
406}
407
408JSTaggedValue ContainersLightWeightSet::Remove(EcmaRuntimeCallInfo *argv)
409{
410    ASSERT(argv != nullptr);
411    JSThread *thread = argv->GetThread();
412    BUILTINS_API_TRACE(thread, LightWeightSet, Remove);
413    [[maybe_unused]] EcmaHandleScope handleScope(thread);
414    JSHandle<JSTaggedValue> self = GetThis(argv);
415    if (!self->IsJSAPILightWeightSet()) {
416        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightSet()) {
417            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
418        } else {
419            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
420                                                                "The remove method cannot be bound");
421            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
422        }
423    }
424    JSHandle<JSTaggedValue> key(GetCallArg(argv, 0));
425    JSHandle<JSAPILightWeightSet> lightweightset(self);
426    JSAPILightWeightSet::CheckAndCopyValues(thread, lightweightset);
427    JSAPILightWeightSet *set = JSAPILightWeightSet::Cast(lightweightset.GetTaggedValue().GetTaggedObject());
428    return set->Remove(thread, key);
429}
430
431JSTaggedValue ContainersLightWeightSet::RemoveAt(EcmaRuntimeCallInfo *argv)
432{
433    ASSERT(argv != nullptr);
434    JSThread *thread = argv->GetThread();
435    BUILTINS_API_TRACE(thread, LightWeightSet, RemoveAt);
436    [[maybe_unused]] EcmaHandleScope handleScope(thread);
437    JSHandle<JSTaggedValue> self = GetThis(argv);
438    if (!self->IsJSAPILightWeightSet()) {
439        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightSet()) {
440            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
441        } else {
442            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
443                                                                "The removeAt method cannot be bound");
444            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
445        }
446    }
447    JSHandle<JSTaggedValue> value(GetCallArg(argv, 0));
448    if (value->IsDouble()) {
449        value = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(value->GetDouble()));
450    }
451    if (!value->IsInt()) {
452        JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, value.GetTaggedValue());
453        RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
454        CString errorMsg =
455            "The type of \"index\" must be small integer. Received value is: " + ConvertToString(*result);
456        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
457        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
458    }
459    JSHandle<JSAPILightWeightSet> lightweightset(self);
460    JSAPILightWeightSet::CheckAndCopyValues(thread, lightweightset);
461    JSAPILightWeightSet *set = JSAPILightWeightSet::Cast(lightweightset.GetTaggedValue().GetTaggedObject());
462    return JSTaggedValue(set->RemoveAt(thread, value->GetInt()));
463}
464
465JSTaggedValue ContainersLightWeightSet::Clear(EcmaRuntimeCallInfo *argv)
466{
467    ASSERT(argv != nullptr);
468    JSThread *thread = argv->GetThread();
469    BUILTINS_API_TRACE(thread, LightWeightSet, Clear);
470    [[maybe_unused]] EcmaHandleScope handleScope(thread);
471    JSHandle<JSTaggedValue> self = GetThis(argv);
472    if (!self->IsJSAPILightWeightSet()) {
473        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightSet()) {
474            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
475        } else {
476            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
477                                                                "The clear method cannot be bound");
478            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
479        }
480    }
481    JSAPILightWeightSet *set = JSAPILightWeightSet::Cast(self->GetTaggedObject());
482    set->Clear(thread);
483    return JSTaggedValue::Undefined();
484}
485
486JSTaggedValue ContainersLightWeightSet::ToString(EcmaRuntimeCallInfo *argv)
487{
488    ASSERT(argv != nullptr);
489    JSThread *thread = argv->GetThread();
490    BUILTINS_API_TRACE(thread, LightWeightSet, ToString);
491    [[maybe_unused]] EcmaHandleScope handleScope(thread);
492    JSHandle<JSTaggedValue> self = GetThis(argv);
493    if (!self->IsJSAPILightWeightSet()) {
494        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightSet()) {
495            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
496        } else {
497            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
498                                                                "The toString method cannot be bound");
499            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
500        }
501    }
502    JSTaggedValue value = JSAPILightWeightSet::ToString(thread, JSHandle<JSAPILightWeightSet>::Cast(self));
503    RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
504    return value;
505}
506
507JSTaggedValue ContainersLightWeightSet::ToArray(EcmaRuntimeCallInfo *argv)
508{
509    ASSERT(argv != nullptr);
510    JSThread *thread = argv->GetThread();
511    BUILTINS_API_TRACE(thread, LightWeightSet, ToArray);
512    [[maybe_unused]] EcmaHandleScope handleScope(thread);
513    JSHandle<JSTaggedValue> self = GetThis(argv);
514    if (!self->IsJSAPILightWeightSet()) {
515        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightSet()) {
516            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
517        } else {
518            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
519                                                                "The toArray method cannot be bound");
520            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
521        }
522    }
523    JSHandle<JSAPILightWeightSet> lightweightset = JSHandle<JSAPILightWeightSet>::Cast(self);
524    auto factory = thread->GetEcmaVM()->GetFactory();
525    JSHandle<JSArray> array = factory->NewJSArray();
526
527    uint32_t length = lightweightset->GetLength();
528    array->SetArrayLength(thread, length);
529
530    JSHandle<TaggedArray> srcArray(thread, lightweightset->GetValues());
531
532    if (srcArray.GetTaggedValue().IsCOWArray()) {
533        array->SetElements(thread, srcArray.GetTaggedValue());
534        return array.GetTaggedValue();
535    }
536
537    auto newElements = factory->CopyArray(srcArray, srcArray->GetLength(), srcArray->GetLength(),
538                                          JSTaggedValue::Hole(), MemSpaceType::NON_MOVABLE);
539    lightweightset->SetValues(thread, newElements.GetTaggedValue());
540    array->SetElements(thread, newElements);
541    return array.GetTaggedValue();
542}
543
544JSTaggedValue ContainersLightWeightSet::GetSize(EcmaRuntimeCallInfo *argv)
545{
546    ASSERT(argv != nullptr);
547    JSThread *thread = argv->GetThread();
548    BUILTINS_API_TRACE(thread, LightWeightSet, GetSize);
549    [[maybe_unused]] EcmaHandleScope handleScope(thread);
550    JSHandle<JSTaggedValue> self = GetThis(argv);
551    if (!self->IsJSAPILightWeightSet()) {
552        if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPILightWeightSet()) {
553            self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
554        } else {
555            JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
556                                                                "The getLength method cannot be bound");
557            THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
558        }
559    }
560    return JSTaggedValue(JSHandle<JSAPILightWeightSet>::Cast(self)->GetSize());
561}
562} // namespace panda::ecmascript::containers
563