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/js_api/js_api_plain_array.h"
17
18 #include "ecmascript/containers/containers_errors.h"
19 #include "ecmascript/interpreter/interpreter.h"
20 #include "ecmascript/js_function.h"
21 #include <codecvt>
22
23 namespace panda::ecmascript {
24 using ContainerError = containers::ContainerError;
25 using ErrorFlag = containers::ErrorFlag;
Add(JSThread * thread,const JSHandle<JSAPIPlainArray> & obj,JSHandle<JSTaggedValue> key,JSHandle<JSTaggedValue> value)26 void JSAPIPlainArray::Add(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj, JSHandle<JSTaggedValue> key,
27 JSHandle<JSTaggedValue> value)
28 {
29 JSHandle<TaggedArray> keyArray(thread, obj->GetKeys());
30 JSHandle<TaggedArray> valueArray(thread, obj->GetValues());
31 uint32_t size = obj->GetLength();
32 int32_t index = obj->BinarySearch(*keyArray, 0, size, key.GetTaggedValue().GetNumber());
33 if (index >= 0) {
34 keyArray->Set(thread, index, key);
35 valueArray->Set(thread, index, value);
36 return;
37 }
38 index ^= 0xFFFFFFFF;
39 if (index < static_cast<int32_t>(size)) {
40 obj->AdjustArray(thread, *keyArray, index, size, true);
41 obj->AdjustArray(thread, *valueArray, index, size, true);
42 }
43 uint32_t capacity = valueArray->GetLength();
44 if (size + 1 >= capacity) {
45 uint32_t newCapacity = capacity << 1U;
46 keyArray =
47 thread->GetEcmaVM()->GetFactory()->CopyArray(keyArray, capacity, newCapacity);
48 valueArray =
49 thread->GetEcmaVM()->GetFactory()->CopyArray(valueArray, capacity, newCapacity);
50 obj->SetKeys(thread, keyArray);
51 obj->SetValues(thread, valueArray);
52 }
53 keyArray->Set(thread, index, key);
54 valueArray->Set(thread, index, value);
55 size++;
56 obj->SetLength(size);
57 }
58
CreateSlot(const JSThread * thread,const uint32_t capacity)59 JSHandle<TaggedArray> JSAPIPlainArray::CreateSlot(const JSThread *thread, const uint32_t capacity)
60 {
61 ASSERT_PRINT(capacity > 0, "size must be a non-negative integer");
62 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
63 JSHandle<TaggedArray> taggedArray = factory->NewTaggedArray(capacity, JSTaggedValue::Hole());
64 return taggedArray;
65 }
66
AdjustForward(JSThread * thread,int32_t index,int32_t forwardSize)67 bool JSAPIPlainArray::AdjustForward(JSThread *thread, int32_t index, int32_t forwardSize)
68 {
69 uint32_t size = GetLength();
70 TaggedArray *keys = TaggedArray::Cast(GetKeys().GetTaggedObject());
71 TaggedArray *values = TaggedArray::Cast(GetValues().GetTaggedObject());
72 AdjustPrimitiveArray(keys, index + forwardSize, index);
73 AdjustArray(thread, values, index + forwardSize, index, false);
74 size = size - static_cast<uint32_t>(forwardSize);
75 SetLength(size);
76 return true;
77 }
78
AdjustPrimitiveArray(TaggedArray * srcArray,int32_t fromIndex,int32_t toIndex)79 void JSAPIPlainArray::AdjustPrimitiveArray(TaggedArray *srcArray, int32_t fromIndex, int32_t toIndex)
80 {
81 uint32_t size = GetLength();
82 auto srcPtr = reinterpret_cast<JSTaggedType *>(
83 ToUintPtr(srcArray->GetData()) + fromIndex * JSTaggedValue::TaggedTypeSize());
84 auto dstPtr = reinterpret_cast<JSTaggedType *>(
85 ToUintPtr(srcArray->GetData()) + toIndex * JSTaggedValue::TaggedTypeSize());
86 // move Array element from srcPtr to dstPtr
87 for (uint32_t count = size - fromIndex; count > 0; --count) {
88 *dstPtr = *srcPtr;
89 ++srcPtr;
90 ++dstPtr;
91 }
92 for (uint32_t count = fromIndex - toIndex; count > 0; --count) {
93 *dstPtr = JSTaggedValue::Hole().GetRawData();
94 ++dstPtr;
95 }
96 }
97
AdjustArray(JSThread * thread,TaggedArray * srcArray,int32_t fromIndex,int32_t toIndex,bool direction)98 void JSAPIPlainArray::AdjustArray(JSThread *thread, TaggedArray *srcArray, int32_t fromIndex,
99 int32_t toIndex, bool direction)
100 {
101 uint32_t size = GetLength();
102 ASSERT(size > 0);
103 uint32_t idx = size - 1;
104 if (direction) {
105 while (fromIndex < toIndex) {
106 JSTaggedValue value = srcArray->Get(idx);
107 srcArray->Set(thread, idx + 1, value);
108 idx--;
109 fromIndex++;
110 }
111 } else {
112 if (srcArray->IsYoungAndNotMarking(thread)) {
113 AdjustPrimitiveArray(srcArray, fromIndex, toIndex);
114 } else {
115 auto srcPtr = reinterpret_cast<JSTaggedType *>(
116 ToUintPtr(srcArray->GetData()) + fromIndex * JSTaggedValue::TaggedTypeSize());
117 uint32_t dstIndex = toIndex;
118 for (uint32_t count = size - fromIndex; count > 0; --count) {
119 srcArray->Set(thread, dstIndex, JSTaggedValue(*srcPtr));
120 ++srcPtr;
121 ++dstIndex;
122 }
123 for (uint32_t count = fromIndex - toIndex; count > 0; --count) {
124 srcArray->Set(thread, dstIndex, JSTaggedValue::Hole());
125 ++dstIndex;
126 }
127 }
128 }
129 }
130
BinarySearch(TaggedArray * array,int32_t fromIndex,int32_t toIndex,int32_t key)131 int32_t JSAPIPlainArray::BinarySearch(TaggedArray *array, int32_t fromIndex, int32_t toIndex, int32_t key)
132 {
133 int32_t low = fromIndex;
134 int32_t high = toIndex - 1;
135 while (low <= high) {
136 int32_t mid = static_cast<int32_t>(static_cast<uint32_t>(low + high) >> 1U);
137 int32_t midVal = static_cast<int32_t>(array->Get(mid).GetNumber());
138 if (midVal < key) {
139 low = mid + 1;
140 } else {
141 if (midVal <= key) {
142 return mid;
143 }
144 high = mid - 1;
145 }
146 }
147 return -(low + 1);
148 }
149
Clear(JSThread * thread)150 void JSAPIPlainArray::Clear(JSThread *thread)
151 {
152 TaggedArray *keys = TaggedArray::Cast(GetKeys().GetTaggedObject());
153 TaggedArray *values = TaggedArray::Cast(GetValues().GetTaggedObject());
154 uint32_t size = GetLength();
155 for (uint32_t index = 0; index < size; index++) {
156 keys->Set(thread, index, JSTaggedValue::Hole());
157 values->Set(thread, index, JSTaggedValue::Hole());
158 }
159 SetLength(0);
160 }
161
RemoveRangeFrom(JSThread * thread,int32_t index,int32_t batchSize)162 JSTaggedValue JSAPIPlainArray::RemoveRangeFrom(JSThread *thread, int32_t index, int32_t batchSize)
163 {
164 int32_t size = static_cast<int32_t>(GetLength());
165 if (size <= 0) {
166 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
167 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
168 }
169 if (index < 0 || index >= size) {
170 std::ostringstream oss;
171 oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (size - 1)
172 << ". Received value is: " << index;
173 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
174 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
175 }
176 if (batchSize < 1) {
177 std::ostringstream oss;
178 oss << "The value of \"size\" is out of range. It must be > 0" << ". Received value is: " << batchSize;
179 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
180 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
181 }
182 int32_t safeSize = (size - (index + batchSize)) < 0 ? size - index : batchSize;
183 AdjustForward(thread, index, safeSize);
184 return JSTaggedValue(safeSize);
185 }
186
Set(JSThread * thread,const JSHandle<JSAPIPlainArray> & obj,const uint32_t index,JSTaggedValue value)187 JSTaggedValue JSAPIPlainArray::Set(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj,
188 const uint32_t index, JSTaggedValue value)
189 {
190 JSHandle<JSTaggedValue> key(thread, JSTaggedValue(index));
191 JSHandle<JSTaggedValue> valueHandle(thread, value);
192 JSAPIPlainArray::Add(thread, obj, key, valueHandle);
193 return JSTaggedValue::Undefined();
194 }
195
GetOwnProperty(JSThread * thread,const JSHandle<JSAPIPlainArray> & obj,const JSHandle<JSTaggedValue> & key)196 bool JSAPIPlainArray::GetOwnProperty(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj,
197 const JSHandle<JSTaggedValue> &key)
198 {
199 TaggedArray *keyArray = TaggedArray::Cast(obj->GetKeys().GetTaggedObject());
200 uint32_t size = obj->GetLength();
201 if (size == 0) {
202 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
203 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
204 }
205 int32_t index = obj->BinarySearch(keyArray, 0, size, key.GetTaggedValue().GetInt());
206 if (index < 0 || index >= static_cast<int32_t>(size)) {
207 ASSERT(size > 0);
208 std::ostringstream oss;
209 oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (size - 1)
210 << ". Received value is: " << index;
211 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
212 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
213 }
214
215 obj->Get(key.GetTaggedValue());
216 return true;
217 }
218
GetProperty(JSThread * thread,const JSHandle<JSAPIPlainArray> & obj,const JSHandle<JSTaggedValue> & key)219 OperationResult JSAPIPlainArray::GetProperty(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj,
220 const JSHandle<JSTaggedValue> &key)
221 {
222 TaggedArray *keyArray = TaggedArray::Cast(obj->GetKeys().GetTaggedObject());
223 uint32_t size = obj->GetLength();
224 if (size == 0) {
225 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
226 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, OperationResult(thread,
227 JSTaggedValue::Exception(),
228 PropertyMetaData(false)));
229 }
230 JSHandle<JSTaggedValue> indexKey = key;
231 if (indexKey->IsDouble()) {
232 // Math.floor(1) will produce TaggedDouble, we need to cast into TaggedInt
233 // For integer which is greater than INT32_MAX, it will remain TaggedDouble
234 indexKey = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(indexKey->GetDouble()));
235 }
236 if (!indexKey->IsInt()) {
237 CString errorMsg = "The type of \"index\" must be small integer.";
238 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
239 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error,
240 OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
241 }
242
243 int keyVal = indexKey->GetInt();
244 int32_t index = obj->BinarySearch(keyArray, 0, size, keyVal);
245 if (index < 0 || index >= static_cast<int32_t>(size)) {
246 std::ostringstream oss;
247 ASSERT(size > 0);
248 oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (size - 1)
249 << ". Received value is: " << index;
250 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
251 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, OperationResult(thread,
252 JSTaggedValue::Exception(),
253 PropertyMetaData(false)));
254 }
255
256 return OperationResult(thread, obj->Get(JSTaggedValue(index)), PropertyMetaData(false));
257 }
258
SetProperty(JSThread * thread,const JSHandle<JSAPIPlainArray> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)259 bool JSAPIPlainArray::SetProperty(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj,
260 const JSHandle<JSTaggedValue> &key,
261 const JSHandle<JSTaggedValue> &value)
262 {
263 TaggedArray *keyArray = TaggedArray::Cast(obj->GetKeys().GetTaggedObject());
264 uint32_t size = obj->GetLength();
265 JSHandle<JSTaggedValue> indexKey = key;
266 if (indexKey->IsDouble()) {
267 // Math.floor(1) will produce TaggedDouble, we need to cast into TaggedInt
268 // For integer which is greater than INT32_MAX, it will remain TaggedDouble
269 indexKey = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(indexKey->GetDouble()));
270 }
271 if (!indexKey->IsInt()) {
272 return false;
273 }
274 int32_t index = obj->BinarySearch(keyArray, 0, size, indexKey->GetInt());
275 if (index < 0 || index >= static_cast<int32_t>(size)) {
276 return false;
277 }
278
279 obj->Set(thread, obj, index, value.GetTaggedValue());
280 return true;
281 }
282
Clone(JSThread * thread,const JSHandle<JSAPIPlainArray> & obj)283 JSHandle<JSAPIPlainArray> JSAPIPlainArray::Clone(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj)
284 {
285 JSHandle<TaggedArray> srckeys(thread, obj->GetKeys());
286 JSHandle<TaggedArray> srcvalues(thread, obj->GetValues());
287 auto factory = thread->GetEcmaVM()->GetFactory();
288 JSHandle<JSAPIPlainArray> newPlainArray = factory->NewJSAPIPlainArray(0);
289
290 uint32_t length = obj->GetLength();
291 newPlainArray->SetLength(length);
292 JSHandle<TaggedArray> srcKeyArray(thread, obj->GetKeys());
293 JSHandle<TaggedArray> srcValueArray(thread, obj->GetValues());
294
295 JSHandle<TaggedArray> dstKeyArray = factory->NewAndCopyTaggedArray(srcKeyArray, length, length);
296 JSHandle<TaggedArray> dstValueArray = factory->NewAndCopyTaggedArray(srcValueArray, length, length);
297
298 newPlainArray->SetKeys(thread, dstKeyArray);
299 newPlainArray->SetValues(thread, dstValueArray);
300 return newPlainArray;
301 }
302
Has(const int32_t key)303 bool JSAPIPlainArray::Has(const int32_t key)
304 {
305 uint32_t size = GetLength();
306 TaggedArray *keyArray = TaggedArray::Cast(GetKeys().GetTaggedObject());
307 int32_t index = BinarySearch(keyArray, 0, size, key);
308 if (index < 0) {
309 return false;
310 }
311 return true;
312 }
313
Get(const JSTaggedValue key)314 JSTaggedValue JSAPIPlainArray::Get(const JSTaggedValue key)
315 {
316 uint32_t size = GetLength();
317 TaggedArray *keyArray = TaggedArray::Cast(GetKeys().GetTaggedObject());
318 int32_t index = BinarySearch(keyArray, 0, size, key.GetNumber());
319 if (index < 0) {
320 return JSTaggedValue::Undefined();
321 }
322 TaggedArray *values = TaggedArray::Cast(GetValues().GetTaggedObject());
323 return values->Get(index);
324 }
325
GetIteratorObj(JSThread * thread,const JSHandle<JSAPIPlainArray> & obj,IterationKind kind)326 JSHandle<JSTaggedValue> JSAPIPlainArray::GetIteratorObj(JSThread *thread, const JSHandle<JSAPIPlainArray> &obj,
327 IterationKind kind)
328 {
329 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
330 JSHandle<JSTaggedValue> iter =
331 JSHandle<JSTaggedValue>::Cast(factory->NewJSAPIPlainArrayIterator(obj, kind));
332 return iter;
333 }
334
ForEach(JSThread * thread,const JSHandle<JSTaggedValue> & thisHandle,const JSHandle<JSTaggedValue> & callbackFn,const JSHandle<JSTaggedValue> & thisArg)335 JSTaggedValue JSAPIPlainArray::ForEach(JSThread *thread, const JSHandle<JSTaggedValue> &thisHandle,
336 const JSHandle<JSTaggedValue> &callbackFn,
337 const JSHandle<JSTaggedValue> &thisArg)
338 {
339 JSAPIPlainArray *plainarray = JSAPIPlainArray::Cast(thisHandle->GetTaggedObject());
340 uint32_t length = plainarray->GetLength();
341 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
342 JSHandle<TaggedArray> keyArray(thread, plainarray->GetKeys());
343 JSHandle<TaggedArray> valueArray(thread, plainarray->GetValues());
344 for (uint32_t k = 0; k < length; k++) {
345 JSTaggedValue kValue = valueArray->Get(k);
346 JSTaggedValue key = keyArray->Get(k);
347 EcmaRuntimeCallInfo *info =
348 EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFn, thisArg, undefined, 3); // 3: three args
349 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception());
350 info->SetCallArg(kValue, key, thisHandle.GetTaggedValue());
351 JSTaggedValue funcResult = JSFunction::Call(info);
352 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult);
353 }
354 return JSTaggedValue::Undefined();
355 }
356
ToString(JSThread * thread,const JSHandle<JSAPIPlainArray> & plainarray)357 JSTaggedValue JSAPIPlainArray::ToString(JSThread *thread, const JSHandle<JSAPIPlainArray> &plainarray)
358 {
359 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
360 std::u16string sepStr = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {}.from_bytes(",");
361 std::u16string colonStr = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {}.from_bytes(":");
362
363 uint32_t length = plainarray->GetLength();
364 std::u16string concatStr = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {}.from_bytes("");
365 std::u16string concatStrNew = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {}.from_bytes("");
366 JSMutableHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue::Undefined());
367 JSMutableHandle<JSTaggedValue> keyHandle(thread, JSTaggedValue::Undefined());
368 for (uint32_t k = 0; k < length; k++) {
369 std::u16string valueStr;
370 valueHandle.Update(plainarray->GetValueAt(thread, k));
371 if (!valueHandle->IsUndefined() && !valueHandle->IsNull()) {
372 JSHandle<EcmaString> valueStringHandle = JSTaggedValue::ToString(thread, valueHandle);
373 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
374 valueStr = EcmaStringAccessor(valueStringHandle).ToU16String();
375 }
376
377 std::u16string nextStr;
378 keyHandle.Update(plainarray->GetKeyAt(k));
379 if (!keyHandle->IsUndefined() && !keyHandle->IsNull()) {
380 JSHandle<EcmaString> keyStringHandle = JSTaggedValue::ToString(thread, keyHandle);
381 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
382 nextStr = EcmaStringAccessor(keyStringHandle).ToU16String();
383 }
384
385 nextStr.append(colonStr);
386 nextStr.append(valueStr);
387 if (k > 0) {
388 concatStr.append(sepStr);
389 concatStr.append(nextStr);
390 continue;
391 }
392 concatStr.append(nextStr);
393 }
394
395 char16_t *char16tData = concatStr.data();
396 auto *uint16tData = reinterpret_cast<uint16_t *>(char16tData);
397 uint32_t u16strSize = concatStr.size();
398 return factory->NewFromUtf16Literal(uint16tData, u16strSize).GetTaggedValue();
399 }
400
GetIndexOfKey(int32_t key)401 JSTaggedValue JSAPIPlainArray::GetIndexOfKey(int32_t key)
402 {
403 uint32_t size = GetLength();
404 TaggedArray *keyArray = TaggedArray::Cast(GetKeys().GetTaggedObject());
405 int32_t index = BinarySearch(keyArray, 0, size, key);
406 if (index < 0) {
407 return JSTaggedValue(-1);
408 }
409 return JSTaggedValue(index);
410 }
411
TryFastGetIndexOfValue(TaggedArray * values,JSTaggedValue value)412 JSTaggedValue JSAPIPlainArray::TryFastGetIndexOfValue(TaggedArray *values, JSTaggedValue value)
413 {
414 uint32_t size = GetLength();
415 for (uint32_t i = 0; i < size; ++i) {
416 JSTaggedValue currVal = values->Get(i);
417 if (currVal.IsInt() && (currVal == value)) {
418 return JSTaggedValue(i);
419 }
420 }
421 return JSTaggedValue(-1);
422 }
423
GetIndexOfValue(JSTaggedValue value)424 JSTaggedValue JSAPIPlainArray::GetIndexOfValue(JSTaggedValue value)
425 {
426 TaggedArray *values = TaggedArray::Cast(GetValues().GetTaggedObject());
427 if (value.IsInt()) {
428 return TryFastGetIndexOfValue(values, value);
429 } else {
430 uint32_t size = GetLength();
431 for (uint32_t i = 0; i < size; ++i) {
432 if (JSTaggedValue::SameValue(values->Get(i), value)) {
433 return JSTaggedValue(i);
434 }
435 }
436 }
437 return JSTaggedValue(-1);
438 }
439
IsEmpty()440 bool JSAPIPlainArray::IsEmpty()
441 {
442 uint32_t length = GetLength();
443 return length == 0;
444 }
445
GetKeyAt(int32_t index)446 JSTaggedValue JSAPIPlainArray::GetKeyAt(int32_t index)
447 {
448 uint32_t size = GetLength();
449 TaggedArray *keyArray = TaggedArray::Cast(GetKeys().GetTaggedObject());
450 if (index < 0 || index >= static_cast<int32_t>(size)) {
451 return JSTaggedValue::Undefined();
452 }
453 return keyArray->Get(index);
454 }
455
GetValueAt(JSThread * thread,int32_t index)456 JSTaggedValue JSAPIPlainArray::GetValueAt(JSThread *thread, int32_t index)
457 {
458 uint32_t size = GetLength();
459 if (size == 0) {
460 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
461 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
462 }
463 if (index < 0 || index >= static_cast<int32_t>(size)) {
464 ASSERT(size > 0);
465 std::ostringstream oss;
466 oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (size - 1)
467 << ". Received value is: " << index;
468 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
469 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
470 }
471 TaggedArray *values = TaggedArray::Cast(GetValues().GetTaggedObject());
472 return values->Get(index);
473 }
474
Remove(JSThread * thread,JSTaggedValue key)475 JSTaggedValue JSAPIPlainArray::Remove(JSThread *thread, JSTaggedValue key)
476 {
477 uint32_t size = GetLength();
478 TaggedArray *keyArray = TaggedArray::Cast(GetKeys().GetTaggedObject());
479 int32_t index = BinarySearch(keyArray, 0, size, key.GetNumber());
480 if (index < 0 || index >= static_cast<int32_t>(size)) {
481 return JSTaggedValue::Undefined();
482 }
483 TaggedArray *values = TaggedArray::Cast(GetValues().GetTaggedObject());
484 JSTaggedValue value = values->Get(index);
485 AdjustForward(thread, index, 1); // 1 means the length of array
486 return value;
487 }
488
RemoveAt(JSThread * thread,JSTaggedValue index)489 JSTaggedValue JSAPIPlainArray::RemoveAt(JSThread *thread, JSTaggedValue index)
490 {
491 uint32_t size = GetLength();
492 int32_t seat = index.GetNumber();
493 if (seat < 0 || static_cast<uint32_t>(seat) >= size) {
494 return JSTaggedValue::Undefined();
495 }
496 TaggedArray *values = TaggedArray::Cast(GetValues().GetTaggedObject());
497 JSTaggedValue value = values->Get(seat);
498 AdjustForward(thread, seat, 1);
499 return value;
500 }
501
SetValueAt(JSThread * thread,JSTaggedValue index,JSTaggedValue value)502 bool JSAPIPlainArray::SetValueAt(JSThread *thread, JSTaggedValue index, JSTaggedValue value)
503 {
504 uint32_t size = GetLength();
505 if (size == 0) {
506 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
507 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
508 }
509 int32_t seat = index.GetNumber();
510 if (seat < 0 || static_cast<uint32_t>(seat) >= size) {
511 std::ostringstream oss;
512 oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (size - 1)
513 << ". Received value is: " << seat;
514 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
515 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
516 }
517 TaggedArray *values = TaggedArray::Cast(GetValues().GetTaggedObject());
518 values->Set(thread, seat, value);
519 return true;
520 }
521 } // namespace panda::ecmascript
522