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_arraylist.h"
17
18 #include "ecmascript/containers/containers_errors.h"
19 #include "ecmascript/base/array_helper.h"
20 #include "ecmascript/base/number_helper.h"
21 #include "ecmascript/ecma_vm.h"
22 #include "ecmascript/js_api/js_api_arraylist.h"
23 #include "ecmascript/js_api/js_api_arraylist_iterator.h"
24 #include "ecmascript/js_array.h"
25 #include "ecmascript/js_function.h"
26 #include "ecmascript/js_iterator.h"
27 #include "ecmascript/object_factory.h"
28 #include "ecmascript/tagged_array-inl.h"
29
30 namespace panda::ecmascript::containers {
ArrayListConstructor(EcmaRuntimeCallInfo * argv)31 JSTaggedValue ContainersArrayList::ArrayListConstructor(EcmaRuntimeCallInfo *argv)
32 {
33 ASSERT(argv);
34 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Constructor);
35 JSThread *thread = argv->GetThread();
36 [[maybe_unused]] EcmaHandleScope handleScope(thread);
37 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
38 JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
39 if (newTarget->IsUndefined()) {
40 JSTaggedValue error =
41 ContainerError::BusinessError(thread, ErrorFlag::IS_NULL_ERROR,
42 "The ArrayList's constructor cannot be directly invoked.");
43 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
44 }
45 JSHandle<JSTaggedValue> constructor = GetConstructor(argv);
46 JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), newTarget);
47 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
48 JSHandle<TaggedArray> newTaggedArray = factory->NewTaggedArray(JSAPIArrayList::DEFAULT_CAPACITY_LENGTH);
49 obj->SetElements(thread, newTaggedArray);
50 return obj.GetTaggedValue();
51 }
52
Add(EcmaRuntimeCallInfo * argv)53 JSTaggedValue ContainersArrayList::Add(EcmaRuntimeCallInfo *argv)
54 {
55 ASSERT(argv);
56 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Add);
57 JSThread *thread = argv->GetThread();
58 [[maybe_unused]] EcmaHandleScope handleScope(thread);
59 JSHandle<JSTaggedValue> self = GetThis(argv);
60
61 if (!self->IsJSAPIArrayList()) {
62 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
63 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
64 } else {
65 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
66 "The add method cannot be bound");
67 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
68 }
69 }
70
71 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
72 return GetTaggedBoolean(JSAPIArrayList::Add(thread, JSHandle<JSAPIArrayList>::Cast(self), value));
73 }
74
Insert(EcmaRuntimeCallInfo * argv)75 JSTaggedValue ContainersArrayList::Insert(EcmaRuntimeCallInfo *argv)
76 {
77 ASSERT(argv);
78 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Insert);
79 JSThread *thread = argv->GetThread();
80 [[maybe_unused]] EcmaHandleScope handleScope(thread);
81 JSHandle<JSTaggedValue> self = GetThis(argv);
82
83 if (!self->IsJSAPIArrayList()) {
84 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
85 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
86 } else {
87 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
88 "The insert method cannot be bound");
89 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
90 }
91 }
92
93 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
94 JSHandle<JSTaggedValue> index = GetCallArg(argv, 1);
95 if (!index->IsInteger()) {
96 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, index);
97 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
98 CString errorMsg = "The type of \"index\" must be number. 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 JSAPIArrayList::Insert(thread, JSHandle<JSAPIArrayList>::Cast(self), value, JSTaggedValue::ToUint32(thread, index));
103 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
104
105 return JSTaggedValue::Undefined();
106 }
107
Clear(EcmaRuntimeCallInfo * argv)108 JSTaggedValue ContainersArrayList::Clear(EcmaRuntimeCallInfo *argv)
109 {
110 ASSERT(argv);
111 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Clear);
112 JSThread *thread = argv->GetThread();
113 [[maybe_unused]] EcmaHandleScope handleScope(thread);
114 JSHandle<JSTaggedValue> self = GetThis(argv);
115
116 if (!self->IsJSAPIArrayList()) {
117 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
118 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
119 } else {
120 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
121 "The clear method cannot be bound");
122 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
123 }
124 }
125
126 JSAPIArrayList::Clear(thread, JSHandle<JSAPIArrayList>::Cast(self));
127
128 return JSTaggedValue::True();
129 }
130
Clone(EcmaRuntimeCallInfo * argv)131 JSTaggedValue ContainersArrayList::Clone(EcmaRuntimeCallInfo *argv)
132 {
133 ASSERT(argv);
134 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Clone);
135 JSThread *thread = argv->GetThread();
136 [[maybe_unused]] EcmaHandleScope handleScope(thread);
137 JSHandle<JSTaggedValue> self = GetThis(argv);
138
139 if (!self->IsJSAPIArrayList()) {
140 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
141 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
142 } else {
143 JSTaggedValue error = ContainerError::BusinessError(thread, BIND_ERROR,
144 "The clone method cannot be bound");
145 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
146 }
147 }
148
149 JSHandle<JSAPIArrayList> newArrayList = JSAPIArrayList::Clone(thread, JSHandle<JSAPIArrayList>::Cast(self));
150
151 return newArrayList.GetTaggedValue();
152 }
153
Has(EcmaRuntimeCallInfo * argv)154 JSTaggedValue ContainersArrayList::Has(EcmaRuntimeCallInfo *argv)
155 {
156 ASSERT(argv);
157 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Has);
158 JSThread *thread = argv->GetThread();
159 [[maybe_unused]] EcmaHandleScope handleScope(thread);
160 JSHandle<JSTaggedValue> self = GetThis(argv);
161
162 if (!self->IsJSAPIArrayList()) {
163 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
164 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
165 } else {
166 JSTaggedValue error = ContainerError::BusinessError(thread, BIND_ERROR,
167 "The has method cannot be bound");
168 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
169 }
170 }
171
172 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
173 bool isHas = JSHandle<JSAPIArrayList>::Cast(self)->Has(value.GetTaggedValue());
174
175 return GetTaggedBoolean(isHas);
176 }
177
GetCapacity(EcmaRuntimeCallInfo * argv)178 JSTaggedValue ContainersArrayList::GetCapacity(EcmaRuntimeCallInfo *argv)
179 {
180 ASSERT(argv);
181
182 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, GetCapacity);
183 JSThread *thread = argv->GetThread();
184
185 JSHandle<JSTaggedValue> self = GetThis(argv);
186 if (!self->IsJSAPIArrayList()) {
187 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
188 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
189 } else {
190 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
191 "The getCapacity method cannot be bound");
192 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
193 }
194 }
195
196 uint32_t capacity = JSAPIArrayList::GetCapacity(thread, JSHandle<JSAPIArrayList>::Cast(self));
197
198 return JSTaggedValue(capacity);
199 }
200
IncreaseCapacityTo(EcmaRuntimeCallInfo * argv)201 JSTaggedValue ContainersArrayList::IncreaseCapacityTo(EcmaRuntimeCallInfo *argv)
202 {
203 ASSERT(argv);
204 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, IncreaseCapacityTo);
205 JSThread *thread = argv->GetThread();
206 [[maybe_unused]] EcmaHandleScope handleScope(thread);
207 JSHandle<JSTaggedValue> self = GetThis(argv);
208
209 if (!self->IsJSAPIArrayList()) {
210 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
211 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
212 } else {
213 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
214 "The increaseCapacityTo method cannot be bound");
215 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
216 }
217 }
218
219 JSHandle<JSTaggedValue> newCapacity = GetCallArg(argv, 0);
220 if (!newCapacity->IsInteger()) {
221 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, newCapacity);
222 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
223 CString errorMsg =
224 "The type of \"newCapacity\" must be number. Received value is: " + ConvertToString(*result);
225 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
226 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
227 }
228
229 JSAPIArrayList::IncreaseCapacityTo(thread, JSHandle<JSAPIArrayList>::Cast(self),
230 JSTaggedValue::ToUint32(thread, newCapacity));
231
232 return JSTaggedValue::True();
233 }
234
TrimToCurrentLength(EcmaRuntimeCallInfo * argv)235 JSTaggedValue ContainersArrayList::TrimToCurrentLength(EcmaRuntimeCallInfo *argv)
236 {
237 ASSERT(argv);
238 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, TrimToCurrentLength);
239 JSThread *thread = argv->GetThread();
240 [[maybe_unused]] EcmaHandleScope handleScope(thread);
241 JSHandle<JSTaggedValue> self = GetThis(argv);
242
243 if (!self->IsJSAPIArrayList()) {
244 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
245 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
246 } else {
247 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
248 "The trimToCurrentLength method cannot be bound");
249 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
250 }
251 }
252
253 JSAPIArrayList::TrimToCurrentLength(thread, JSHandle<JSAPIArrayList>::Cast(self));
254
255 return JSTaggedValue::True();
256 }
257
Get(EcmaRuntimeCallInfo * argv)258 JSTaggedValue ContainersArrayList::Get(EcmaRuntimeCallInfo *argv)
259 {
260 ASSERT(argv);
261 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Get);
262 JSThread *thread = argv->GetThread();
263 [[maybe_unused]] EcmaHandleScope handleScope(thread);
264 JSHandle<JSTaggedValue> self = GetThis(argv);
265
266 if (!self->IsJSAPIArrayList()) {
267 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
268 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
269 } else {
270 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
271 "The get method cannot be bound");
272 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
273 }
274 }
275
276 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
277
278 JSTaggedValue element = JSHandle<JSAPIArrayList>::Cast(self)->Get(thread, JSTaggedValue::ToUint32(thread, value));
279
280 return element;
281 }
282
GetIndexOf(EcmaRuntimeCallInfo * argv)283 JSTaggedValue ContainersArrayList::GetIndexOf(EcmaRuntimeCallInfo *argv)
284 {
285 ASSERT(argv);
286 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, GetIndexOf);
287 JSThread *thread = argv->GetThread();
288 [[maybe_unused]] EcmaHandleScope handleScope(thread);
289 JSHandle<JSTaggedValue> self = GetThis(argv);
290
291 if (!self->IsJSAPIArrayList()) {
292 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
293 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
294 } else {
295 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
296 "The getIndexOf method cannot be bound");
297 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
298 }
299 }
300
301 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
302
303 return JSTaggedValue(JSAPIArrayList::GetIndexOf(thread, JSHandle<JSAPIArrayList>::Cast(self), value));
304 }
305
IsEmpty(EcmaRuntimeCallInfo * argv)306 JSTaggedValue ContainersArrayList::IsEmpty(EcmaRuntimeCallInfo *argv)
307 {
308 ASSERT(argv);
309 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, IsEmpty);
310 JSThread *thread = argv->GetThread();
311 [[maybe_unused]] EcmaHandleScope handleScope(thread);
312 JSHandle<JSTaggedValue> self = GetThis(argv);
313
314 if (!self->IsJSAPIArrayList()) {
315 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
316 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
317 } else {
318 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
319 "The isEmpty method cannot be bound");
320 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
321 }
322 }
323
324 return JSTaggedValue(JSAPIArrayList::IsEmpty(JSHandle<JSAPIArrayList>::Cast(self)));
325 }
326
GetLastIndexOf(EcmaRuntimeCallInfo * argv)327 JSTaggedValue ContainersArrayList::GetLastIndexOf(EcmaRuntimeCallInfo *argv)
328 {
329 ASSERT(argv);
330 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, GetLastIndexOf);
331 JSThread *thread = argv->GetThread();
332 [[maybe_unused]] EcmaHandleScope handleScope(thread);
333 JSHandle<JSTaggedValue> self = GetThis(argv);
334
335 if (!self->IsJSAPIArrayList()) {
336 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
337 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
338 } else {
339 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
340 "The getLastIndexOf method cannot be bound");
341 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
342 }
343 }
344
345 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
346
347 return JSTaggedValue(JSAPIArrayList::GetLastIndexOf(thread, JSHandle<JSAPIArrayList>::Cast(self), value));
348 }
349
RemoveByIndex(EcmaRuntimeCallInfo * argv)350 JSTaggedValue ContainersArrayList::RemoveByIndex(EcmaRuntimeCallInfo *argv)
351 {
352 ASSERT(argv);
353 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, RemoveByIndex);
354 JSThread *thread = argv->GetThread();
355 [[maybe_unused]] EcmaHandleScope handleScope(thread);
356 JSHandle<JSTaggedValue> self = GetThis(argv);
357
358 if (!self->IsJSAPIArrayList()) {
359 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
360 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
361 } else {
362 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
363 "The removeByIndex method cannot be bound");
364 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
365 }
366 }
367
368 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
369 if (!value->IsInteger()) {
370 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, value.GetTaggedValue());
371 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
372 CString errorMsg =
373 "The type of \"index\" must be number. Received value is: " + ConvertToString(*result);
374 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
375 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
376 }
377
378 JSTaggedValue result =
379 JSAPIArrayList::RemoveByIndex(thread,
380 JSHandle<JSAPIArrayList>::Cast(self), JSTaggedValue::ToUint32(thread, value));
381
382 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
383 return result;
384 }
385
Remove(EcmaRuntimeCallInfo * argv)386 JSTaggedValue ContainersArrayList::Remove(EcmaRuntimeCallInfo *argv)
387 {
388 ASSERT(argv);
389 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Remove);
390 JSThread *thread = argv->GetThread();
391 [[maybe_unused]] EcmaHandleScope handleScope(thread);
392 JSHandle<JSTaggedValue> self = GetThis(argv);
393
394 if (!self->IsJSAPIArrayList()) {
395 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
396 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
397 } else {
398 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
399 "The remove method cannot be bound");
400 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
401 }
402 }
403
404 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
405
406 bool isRemove = JSAPIArrayList::Remove(thread, JSHandle<JSAPIArrayList>::Cast(self), value);
407 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
408
409 return GetTaggedBoolean(isRemove);
410 }
411
RemoveByRange(EcmaRuntimeCallInfo * argv)412 JSTaggedValue ContainersArrayList::RemoveByRange(EcmaRuntimeCallInfo *argv)
413 {
414 ASSERT(argv);
415 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, RemoveByRange);
416 JSThread *thread = argv->GetThread();
417 [[maybe_unused]] EcmaHandleScope handleScope(thread);
418 JSHandle<JSTaggedValue> self = GetThis(argv);
419
420 if (!self->IsJSAPIArrayList()) {
421 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
422 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
423 } else {
424 JSTaggedValue error = ContainerError::BusinessError(thread, BIND_ERROR,
425 "The removeByRange method cannot be bound");
426 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
427 }
428 }
429
430 JSHandle<JSTaggedValue> startIndex = GetCallArg(argv, 0);
431 JSHandle<JSTaggedValue> endIndex = GetCallArg(argv, 1);
432 if (!startIndex->IsInteger()) {
433 std::ostringstream oss;
434 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, startIndex);
435 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
436 CString errorMsg =
437 "The type of \"fromIndex\" must be number. Received value is: " + ConvertToString(*result);
438 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
439 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
440 }
441 if (!endIndex->IsInteger()) {
442 std::ostringstream oss;
443 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, endIndex);
444 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
445 CString errorMsg =
446 "The type of \"toIndex\" must be number. Received value is: " + ConvertToString(*result);
447 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
448 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
449 }
450 JSTaggedValue result =
451 JSAPIArrayList::RemoveByRange(thread, JSHandle<JSAPIArrayList>::Cast(self), startIndex, endIndex);
452
453 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
454 return result;
455 }
456
ReplaceAllElements(EcmaRuntimeCallInfo * argv)457 JSTaggedValue ContainersArrayList::ReplaceAllElements(EcmaRuntimeCallInfo *argv)
458 {
459 ASSERT(argv);
460 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, ReplaceAllElements);
461 JSThread *thread = argv->GetThread();
462 [[maybe_unused]] EcmaHandleScope handleScope(thread);
463 JSHandle<JSTaggedValue> self = GetThis(argv);
464
465 if (!self->IsJSAPIArrayList()) {
466 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
467 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
468 } else {
469 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
470 "The replaceAllElements method cannot be bound");
471 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
472 }
473 }
474
475 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
476 if (!callbackFnHandle->IsCallable()) {
477 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, callbackFnHandle);
478 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
479 CString errorMsg =
480 "The type of \"callbackfn\" must be callable. Received value is: " + ConvertToString(*result);
481 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
482 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
483 }
484 JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
485
486 return JSAPIArrayList::ReplaceAllElements(thread, self, callbackFnHandle, thisArgHandle);
487 }
488
Set(EcmaRuntimeCallInfo * argv)489 JSTaggedValue ContainersArrayList::Set(EcmaRuntimeCallInfo *argv)
490 {
491 ASSERT(argv);
492 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, Set);
493 JSThread *thread = argv->GetThread();
494 [[maybe_unused]] EcmaHandleScope handleScope(thread);
495 JSHandle<JSTaggedValue> self = GetThis(argv);
496
497 if (!self->IsJSAPIArrayList()) {
498 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
499 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
500 } else {
501 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
502 "The set method cannot be bound");
503 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
504 }
505 }
506
507 JSHandle<JSTaggedValue> index = GetCallArg(argv, 0);
508 JSHandle<JSTaggedValue> value = GetCallArg(argv, 1);
509 JSHandle<JSAPIArrayList>::Cast(self)->Set(thread, JSTaggedValue::ToUint32(thread, index), value.GetTaggedValue());
510
511 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
512 return JSTaggedValue::Undefined();
513 }
514
SubArrayList(EcmaRuntimeCallInfo * argv)515 JSTaggedValue ContainersArrayList::SubArrayList(EcmaRuntimeCallInfo *argv)
516 {
517 ASSERT(argv);
518 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, SubArrayList);
519 JSThread *thread = argv->GetThread();
520 [[maybe_unused]] EcmaHandleScope handleScope(thread);
521 JSHandle<JSTaggedValue> self = GetThis(argv);
522
523 if (!self->IsJSAPIArrayList()) {
524 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
525 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
526 } else {
527 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
528 "The subArrayList method cannot be bound");
529 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
530 }
531 }
532 JSHandle<JSTaggedValue> value1 = GetCallArg(argv, 0);
533 JSHandle<JSTaggedValue> value2 = GetCallArg(argv, 1);
534 if (!value1->IsInteger()) {
535 std::ostringstream oss;
536 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, value1);
537 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
538 CString errorMsg =
539 "The type of \"fromIndex\" must be number. Received value is: " + ConvertToString(*result);
540 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
541 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
542 }
543 if (!value2->IsInteger()) {
544 std::ostringstream oss;
545 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, value2);
546 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
547 CString errorMsg =
548 "The type of \"toIndex\" must be number. Received value is: " + ConvertToString(*result);
549 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
550 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
551 }
552 JSTaggedValue newArrayList =
553 JSAPIArrayList::SubArrayList(thread, JSHandle<JSAPIArrayList>::Cast(self), value1, value2);
554
555 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
556 return newArrayList;
557 }
558
Sort(EcmaRuntimeCallInfo * argv)559 JSTaggedValue ContainersArrayList::Sort(EcmaRuntimeCallInfo *argv)
560 {
561 ASSERT(argv);
562 BUILTINS_API_TRACE(argv->GetThread(), Array, Sort);
563 JSThread *thread = argv->GetThread();
564 [[maybe_unused]] EcmaHandleScope handleScope(thread);
565 JSHandle<JSTaggedValue> self = GetThis(argv);
566 if (!self->IsJSAPIArrayList()) {
567 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
568 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
569 } else {
570 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
571 "The sort method cannot be bound");
572 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
573 }
574 }
575 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
576 if (!callbackFnHandle->IsUndefined() && !callbackFnHandle->IsCallable() && !callbackFnHandle->IsNull()) {
577 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, callbackFnHandle);
578 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
579 CString errorMsg =
580 "The type of \"comparator\" must be callable. Received value is: " + ConvertToString(*result);
581 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
582 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
583 }
584 JSHandle<TaggedArray> elements(thread, JSHandle<JSAPIArrayList>::Cast(self)->GetElements());
585 JSMutableHandle<JSTaggedValue> presentValue(thread, JSTaggedValue::Undefined());
586 JSMutableHandle<JSTaggedValue> middleValue(thread, JSTaggedValue::Undefined());
587 JSMutableHandle<JSTaggedValue> previousValue(thread, JSTaggedValue::Undefined());
588 uint32_t length = JSHandle<JSAPIArrayList>::Cast(self)->GetLength().GetArrayLength();
589 for (uint32_t i = 1; i < length; i++) {
590 uint32_t beginIndex = 0;
591 uint32_t endIndex = i;
592 presentValue.Update(elements->Get(i));
593 while (beginIndex < endIndex) {
594 uint32_t middleIndex = (beginIndex + endIndex) / 2; // 2 : half
595 middleValue.Update(elements->Get(middleIndex));
596 double compareResult = base::ArrayHelper::SortCompare(thread, callbackFnHandle,
597 middleValue, presentValue);
598 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
599 if (compareResult > 0) {
600 endIndex = middleIndex;
601 } else {
602 beginIndex = middleIndex + 1;
603 }
604 }
605 if (endIndex >= 0 && endIndex < i) {
606 for (uint32_t j = i; j > endIndex; j--) {
607 previousValue.Update(elements->Get(j - 1));
608 elements->Set(thread, j, previousValue.GetTaggedValue());
609 }
610 elements->Set(thread, endIndex, presentValue.GetTaggedValue());
611 }
612 }
613 return JSTaggedValue::Undefined();
614 }
615
GetSize(EcmaRuntimeCallInfo * argv)616 JSTaggedValue ContainersArrayList::GetSize(EcmaRuntimeCallInfo *argv)
617 {
618 ASSERT(argv);
619 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, GetSize);
620 JSThread *thread = argv->GetThread();
621 [[maybe_unused]] EcmaHandleScope handleScope(thread);
622 JSHandle<JSTaggedValue> self = GetThis(argv);
623
624 if (!self->IsJSAPIArrayList()) {
625 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
626 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
627 } else {
628 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
629 "The getSize method cannot be bound");
630 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
631 }
632 }
633
634 return JSTaggedValue(JSHandle<JSAPIArrayList>::Cast(self)->GetSize());
635 }
636
ConvertToArray(EcmaRuntimeCallInfo * argv)637 JSTaggedValue ContainersArrayList::ConvertToArray(EcmaRuntimeCallInfo *argv)
638 {
639 ASSERT(argv);
640 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, ConvertToArray);
641 JSThread *thread = argv->GetThread();
642 [[maybe_unused]] EcmaHandleScope handleScope(thread);
643 JSHandle<JSTaggedValue> self = GetThis(argv);
644
645 if (!self->IsJSAPIArrayList()) {
646 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
647 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
648 } else {
649 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
650 "The convertToArray method cannot be bound");
651 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
652 }
653 }
654
655 JSHandle<JSAPIArrayList> arrayList = JSHandle<JSAPIArrayList>::Cast(self);
656 auto factory = thread->GetEcmaVM()->GetFactory();
657 JSHandle<JSArray> array = factory->NewJSArray();
658
659 uint32_t length = arrayList->GetLength().GetArrayLength();
660 array->SetArrayLength(thread, length);
661
662 JSHandle<TaggedArray> srcElements(thread, arrayList->GetElements());
663 JSHandle<TaggedArray> dstElements = factory->NewAndCopyTaggedArray(srcElements, length, length);
664 array->SetElements(thread, dstElements);
665 return array.GetTaggedValue();
666 }
667
ForEach(EcmaRuntimeCallInfo * argv)668 JSTaggedValue ContainersArrayList::ForEach(EcmaRuntimeCallInfo *argv)
669 {
670 ASSERT(argv);
671 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, ForEach);
672 JSThread *thread = argv->GetThread();
673 [[maybe_unused]] EcmaHandleScope handleScope(thread);
674 JSHandle<JSTaggedValue> self = GetThis(argv);
675
676 if (!self->IsJSAPIArrayList()) {
677 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
678 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
679 } else {
680 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
681 "The forEach method cannot be bound");
682 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
683 }
684 }
685
686 JSHandle<JSTaggedValue> callbackFnHandle = GetCallArg(argv, 0);
687 if (!callbackFnHandle->IsCallable()) {
688 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, callbackFnHandle);
689 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
690 CString errorMsg =
691 "The type of \"callbackfn\" must be callable. Received value is: " + ConvertToString(*result);
692 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
693 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
694 }
695
696 JSHandle<JSTaggedValue> thisArgHandle = GetCallArg(argv, 1);
697
698 return JSAPIArrayList::ForEach(thread, self, callbackFnHandle, thisArgHandle);
699 }
700
GetIteratorObj(EcmaRuntimeCallInfo * argv)701 JSTaggedValue ContainersArrayList::GetIteratorObj(EcmaRuntimeCallInfo *argv)
702 {
703 ASSERT(argv);
704 BUILTINS_API_TRACE(argv->GetThread(), ArrayList, GetIteratorObj);
705 JSThread *thread = argv->GetThread();
706 [[maybe_unused]] EcmaHandleScope handleScope(thread);
707
708 JSHandle<JSTaggedValue> self = GetThis(argv);
709
710 if (!self->IsJSAPIArrayList()) {
711 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPIArrayList()) {
712 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget());
713 } else {
714 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR,
715 "The Symbol.iterator method cannot be bound");
716 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
717 }
718 }
719
720 JSTaggedValue values = JSAPIArrayList::GetIteratorObj(thread, JSHandle<JSAPIArrayList>::Cast(self));
721
722 return values;
723 }
724 } // namespace panda::ecmascript::containers
725