1/*
2 * Copyright (c) 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_bitvector.h"
17
18#include "ecmascript/tagged_array-inl.h"
19#include "ecmascript/shared_objects/concurrent_api_scope.h"
20
21namespace panda::ecmascript {
22using ContainerError = containers::ContainerError;
23using ErrorFlag = containers::ErrorFlag;
24bool JSAPIBitVector::Push(
25    JSThread* thread, const JSHandle<JSAPIBitVector>& bitVector, const JSHandle<JSTaggedValue>& value)
26{
27    [[maybe_unused]] ConcurrentApiScope<JSAPIBitVector, ModType::WRITE> scope(thread,
28        JSHandle<JSTaggedValue>::Cast(bitVector));
29    uint32_t length = static_cast<uint32_t>(bitVector->GetLength());
30    JSHandle<JSNativePointer> np(thread, bitVector->GetNativePointer());
31    auto elements = reinterpret_cast<std::vector<std::bitset<BIT_SET_LENGTH>>*>(np->GetExternalPointer());
32    if ((length & TAGGED_VALUE_BIT_OFFSET) == 0) {
33        std::bitset<BIT_SET_LENGTH> increaseSet;
34        if (!value->IsZero()) {
35            increaseSet.set(0);
36        }
37        elements->push_back(increaseSet);
38    } else {
39        SetBit(elements, length, value.GetTaggedValue());
40    }
41    bitVector->SetLength(++length);
42    return true;
43}
44
45JSTaggedValue JSAPIBitVector::Pop(JSThread* thread, const JSHandle<JSAPIBitVector>& bitVector)
46{
47    [[maybe_unused]] ConcurrentApiScope<JSAPIBitVector, ModType::WRITE> scope(thread,
48        JSHandle<JSTaggedValue>::Cast(bitVector));
49    if (bitVector->GetLength() <= 0) {
50        return JSTaggedValue::Undefined();
51    }
52    uint32_t lastIndex = static_cast<uint32_t>(bitVector->GetLength() - 1);
53    JSHandle<JSNativePointer> np(thread, bitVector->GetNativePointer());
54    auto elements = reinterpret_cast<std::vector<std::bitset<BIT_SET_LENGTH>>*>(np->GetExternalPointer());
55
56    JSTaggedValue bit = GetBit(elements, lastIndex);
57    if ((lastIndex & TAGGED_VALUE_BIT_OFFSET) == 0) {
58        elements->pop_back();
59    } else {
60        SetBit(elements, lastIndex, JSTaggedValue(0));
61    }
62    bitVector->SetLength(lastIndex);
63    return bit;
64}
65
66JSTaggedValue JSAPIBitVector::Set(JSThread* thread, const uint32_t index, JSTaggedValue value)
67{
68    uint32_t length = static_cast<uint32_t>(GetLength());
69    if (index >= length) {
70        std::ostringstream oss;
71        oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (length - 1)
72            << ". Received value is: " << index;
73        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
74        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
75    }
76    JSNativePointer* np = JSNativePointer::Cast(GetNativePointer().GetTaggedObject());
77    auto elements = reinterpret_cast<std::vector<std::bitset<BIT_SET_LENGTH>>*>(np->GetExternalPointer());
78    SetBit(elements, index, value);
79    return JSTaggedValue::Undefined();
80}
81
82JSTaggedValue JSAPIBitVector::Get(JSThread* thread, const uint32_t index)
83{
84    uint32_t length = static_cast<uint32_t>(GetLength());
85    if (index >= length) {
86        std::ostringstream oss;
87        oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (length - 1)
88            << ". Received value is: " << index;
89        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
90        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
91    }
92    JSNativePointer* np = JSNativePointer::Cast(GetNativePointer().GetTaggedObject());
93    auto elements = reinterpret_cast<std::vector<std::bitset<BIT_SET_LENGTH>>*>(np->GetExternalPointer());
94    return GetBit(elements, index);
95}
96
97bool JSAPIBitVector::Has(JSThread* thread, const JSHandle<JSAPIBitVector>& bitVector,
98    const JSHandle<JSTaggedValue>& value, const JSHandle<JSTaggedValue>& start, const JSHandle<JSTaggedValue>& end)
99{
100    int32_t startIndex = JSTaggedValue::ToInt32(thread, start);
101    int32_t endIndex = JSTaggedValue::ToInt32(thread, end);
102    int32_t length = bitVector->GetLength();
103    int32_t size = length > endIndex ? endIndex : length;
104    if (endIndex < 0 || endIndex > length) {
105        std::ostringstream oss;
106        oss << "The value of \"toIndex\" is out of range. It must be >= 0 && <= " << length
107            << ". Received value is: " << endIndex;
108        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
109        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
110    }
111    if (startIndex < 0 || startIndex >= size) {
112        std::ostringstream oss;
113        oss << "The value of \"fromIndex\" is out of range. It must be >= 0 && <= " << (size - 1)
114            << ". Received value is: " << startIndex;
115        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
116        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
117    }
118    if (length == 0) {
119        return false;
120    }
121    JSHandle<JSNativePointer> np(thread, bitVector->GetNativePointer());
122    auto elements = reinterpret_cast<std::vector<std::bitset<BIT_SET_LENGTH>>*>(np->GetExternalPointer());
123    for (int index = startIndex; index <= endIndex; index++) {
124        std::pair<uint32_t, uint32_t> pair = ComputeElementIdAndBitId(index);
125        uint32_t elementId = pair.first;
126        uint32_t bitId = pair.second;
127        if ((value->IsZero() && (*elements)[elementId].test(bitId) == 0) ||
128            (!value->IsZero() && (*elements)[elementId].test(bitId) != 0)) {
129            return true;
130        }
131    }
132    return false;
133}
134
135bool JSAPIBitVector::Has(const JSTaggedValue& value) const
136{
137    uint32_t length = GetSize();
138    if (length == 0) {
139        return false;
140    }
141    JSNativePointer* np = JSNativePointer::Cast(GetNativePointer().GetTaggedObject());
142    auto elements = reinterpret_cast<std::vector<std::bitset<BIT_SET_LENGTH>>*>(np->GetExternalPointer());
143    for (uint32_t index = 0; index < length; index++) {
144        std::pair<uint32_t, uint32_t> pair = ComputeElementIdAndBitId(index);
145        uint32_t elementId = pair.first;
146        uint32_t bitId = pair.second;
147        if ((value.IsZero() && (*elements)[elementId].test(bitId) == 0) ||
148            (!value.IsZero() && (*elements)[elementId].test(bitId) != 0)) {
149            return true;
150        }
151    }
152    return false;
153}
154
155JSTaggedValue JSAPIBitVector::SetBitsByRange(JSThread* thread, const JSHandle<JSAPIBitVector>& bitVector,
156    const JSHandle<JSTaggedValue>& value, const JSHandle<JSTaggedValue>& start, const JSHandle<JSTaggedValue>& end)
157{
158    [[maybe_unused]] ConcurrentApiScope<JSAPIBitVector, ModType::WRITE> scope(thread,
159        JSHandle<JSTaggedValue>::Cast(bitVector));
160    int32_t startIndex = JSTaggedValue::ToInt32(thread, start);
161    int32_t endIndex = JSTaggedValue::ToInt32(thread, end);
162    int32_t length = bitVector->GetLength();
163    int32_t size = length > endIndex ? endIndex : length;
164    if (endIndex < 0 || endIndex > length) {
165        std::ostringstream oss;
166        oss << "The value of \"toIndex\" is out of range. It must be >= 0 && <= " << length
167            << ". Received value is: " << endIndex;
168        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
169        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
170    }
171    if (startIndex < 0 || startIndex >= size) {
172        std::ostringstream oss;
173        oss << "The value of \"fromIndex\" is out of range. It must be >= 0 && <= " << (size - 1)
174            << ". Received value is: " << startIndex;
175        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
176        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
177    }
178
179    JSHandle<JSNativePointer> np(thread, bitVector->GetNativePointer());
180    auto elements = reinterpret_cast<std::vector<std::bitset<BIT_SET_LENGTH>>*>(np->GetExternalPointer());
181    for (int32_t index = startIndex; index < endIndex; index++) {
182        SetBit(elements, index, value.GetTaggedValue());
183    }
184    return JSTaggedValue::Undefined();
185}
186
187JSTaggedValue JSAPIBitVector::GetBitsByRange(JSThread* thread, const JSHandle<JSAPIBitVector>& bitVector,
188    const JSHandle<JSTaggedValue>& start, const JSHandle<JSTaggedValue>& end)
189{
190    [[maybe_unused]] ConcurrentApiScope<JSAPIBitVector, ModType::WRITE> scope(thread,
191        JSHandle<JSTaggedValue>::Cast(bitVector));
192    int32_t startIndex = JSTaggedValue::ToInt32(thread, start);
193    int32_t endIndex = JSTaggedValue::ToInt32(thread, end);
194    int32_t length = bitVector->GetLength();
195    int32_t size = length > endIndex ? endIndex : length;
196    if (endIndex < 0 || endIndex > length) {
197        std::ostringstream oss;
198        oss << "The value of \"toIndex\" is out of range. It must be >= 0 && <= " << length
199            << ". Received value is: " << endIndex;
200        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
201        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
202    }
203    if (startIndex < 0 || startIndex >= size) {
204        std::ostringstream oss;
205        oss << "The value of \"fromIndex\" is out of range. It must be >= 0 && <= " << (size - 1)
206            << ". Received value is: " << startIndex;
207        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
208        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
209    }
210    int32_t dstLength = endIndex - startIndex;
211    auto factory = thread->GetEcmaVM()->GetFactory();
212    JSHandle<JSNativePointer> srcNp(thread, bitVector->GetNativePointer());
213    auto srcElements = reinterpret_cast<std::vector<std::bitset<BIT_SET_LENGTH>>*>(srcNp->GetExternalPointer());
214
215    JSHandle<JSAPIBitVector> newBitVector = factory->NewJSAPIBitVector(dstLength);
216    JSHandle<JSNativePointer> dstNp(thread, newBitVector->GetNativePointer());
217    auto dstElements = reinterpret_cast<std::vector<std::bitset<BIT_SET_LENGTH>>*>(dstNp->GetExternalPointer());
218
219    for (int32_t index = 0; index < dstLength; index++) {
220        JSTaggedValue value = GetBit(srcElements, index + startIndex);
221        SetBit(dstElements, index, value);
222    }
223    newBitVector->SetLength(dstLength);
224    newBitVector->SetNativePointer(thread, dstNp);
225
226    return newBitVector.GetTaggedValue();
227}
228
229JSTaggedValue JSAPIBitVector::SetAllBits(
230    JSThread* thread, const JSHandle<JSAPIBitVector>& bitVector, const JSHandle<JSTaggedValue>& value)
231{
232    [[maybe_unused]] ConcurrentApiScope<JSAPIBitVector, ModType::WRITE> scope(thread,
233        JSHandle<JSTaggedValue>::Cast(bitVector));
234    JSHandle<JSNativePointer> np(thread, bitVector->GetNativePointer());
235    auto elements = reinterpret_cast<std::vector<std::bitset<BIT_SET_LENGTH>>*>(np->GetExternalPointer());
236    int size = static_cast<int>(elements->size());
237    if (value->IsZero()) {
238        for (int index = 0; index < size; index++) {
239            (*elements)[index] = std::bitset<BIT_SET_LENGTH>(0);
240        }
241    } else {
242        for (int index = 0; index < size; index++) {
243            (*elements)[index] = std::bitset<BIT_SET_LENGTH>(UINT64_MAX);
244        }
245    }
246    return JSTaggedValue::Undefined();
247}
248
249JSTaggedValue JSAPIBitVector::GetBitCountByRange(JSThread* thread, const JSHandle<JSAPIBitVector>& bitVector,
250    const JSHandle<JSTaggedValue>& value, const JSHandle<JSTaggedValue>& start, const JSHandle<JSTaggedValue>& end)
251{
252    [[maybe_unused]] ConcurrentApiScope<JSAPIBitVector> scope(thread, JSHandle<JSTaggedValue>::Cast(bitVector));
253    int32_t startIndex = JSTaggedValue::ToInt32(thread, start);
254    int32_t endIndex = JSTaggedValue::ToInt32(thread, end);
255    int32_t length = bitVector->GetLength();
256    int32_t size = length > endIndex ? endIndex : length;
257    int32_t count = 0;
258    if (endIndex < 0 || endIndex > length) {
259        std::ostringstream oss;
260        oss << "The value of \"toIndex\" is out of range. It must be >= 0 && <= " << length
261            << ". Received value is: " << endIndex;
262        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
263        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
264    }
265    if (startIndex < 0 || startIndex >= size) {
266        std::ostringstream oss;
267        oss << "The value of \"fromIndex\" is out of range. It must be >= 0 && <= " << (size - 1)
268            << ". Received value is: " << startIndex;
269        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
270        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
271    }
272    JSHandle<JSNativePointer> np(thread, bitVector->GetNativePointer());
273    auto elements = reinterpret_cast<std::vector<std::bitset<BIT_SET_LENGTH>>*>(np->GetExternalPointer());
274    for (int32_t index = startIndex; index < endIndex; index++) {
275        std::pair<uint32_t, uint32_t> pair = ComputeElementIdAndBitId(index);
276        uint32_t elementId = pair.first;
277        uint32_t bitId = pair.second;
278        if ((value->IsZero() && (*elements)[elementId].test(bitId) == 0) ||
279            (!value->IsZero() && (*elements)[elementId].test(bitId) != 0)) {
280            count++;
281        }
282    }
283    return JSTaggedValue(count);
284}
285
286int JSAPIBitVector::GetIndexOf(JSThread* thread, const JSHandle<JSAPIBitVector>& bitVector,
287    const JSHandle<JSTaggedValue>& value, const JSHandle<JSTaggedValue>& start, const JSHandle<JSTaggedValue>& end)
288{
289    [[maybe_unused]] ConcurrentApiScope<JSAPIBitVector> scope(thread, JSHandle<JSTaggedValue>::Cast(bitVector));
290    int32_t startIndex = JSTaggedValue::ToInt32(thread, start);
291    int32_t endIndex = JSTaggedValue::ToInt32(thread, end);
292    int32_t length = bitVector->GetLength();
293    int32_t size = length > endIndex ? endIndex : length;
294    if (endIndex < 0 || endIndex > length) {
295        std::ostringstream oss;
296        oss << "The value of \"toIndex\" is out of range. It must be >= 0 && <= " << length
297            << ". Received value is: " << endIndex;
298        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
299        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, -1);
300    }
301    if (startIndex < 0 || startIndex >= size) {
302        std::ostringstream oss;
303        oss << "The value of \"fromIndex\" is out of range. It must be >= 0 && <= " << (size - 1)
304            << ". Received value is: " << startIndex;
305        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
306        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, -1);
307    }
308    JSHandle<JSNativePointer> np(thread, bitVector->GetNativePointer());
309    auto elements = reinterpret_cast<std::vector<std::bitset<BIT_SET_LENGTH>>*>(np->GetExternalPointer());
310    for (int32_t index = startIndex; index < endIndex; index++) {
311        std::pair<uint32_t, uint32_t> pair = ComputeElementIdAndBitId(index);
312        uint32_t elementId = pair.first;
313        uint32_t bitId = pair.second;
314        if ((value->IsZero() && (*elements)[elementId].test(bitId) == 0) ||
315            (!value->IsZero() && (*elements)[elementId].test(bitId) != 0)) {
316            return index;
317        }
318    }
319    return -1;
320}
321
322int JSAPIBitVector::GetLastIndexOf(JSThread* thread, const JSHandle<JSAPIBitVector>& bitVector,
323    const JSHandle<JSTaggedValue>& value, const JSHandle<JSTaggedValue>& start, const JSHandle<JSTaggedValue>& end)
324{
325    [[maybe_unused]] ConcurrentApiScope<JSAPIBitVector> scope(thread, JSHandle<JSTaggedValue>::Cast(bitVector));
326    int32_t startIndex = JSTaggedValue::ToInt32(thread, start);
327    int32_t endIndex = JSTaggedValue::ToInt32(thread, end);
328    int32_t length = bitVector->GetLength();
329    int32_t size = length > endIndex ? endIndex : length;
330    if (endIndex < 0 || endIndex > length) {
331        std::ostringstream oss;
332        oss << "The value of \"toIndex\" is out of range. It must be >= 0 && <= " << length
333            << ". Received value is: " << endIndex;
334        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
335        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, -1);
336    }
337    if (startIndex < 0 || startIndex >= size) {
338        std::ostringstream oss;
339        oss << "The value of \"fromIndex\" is out of range. It must be >= 0 && <= " << (size - 1)
340            << ". Received value is: " << startIndex;
341        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
342        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, -1);
343    }
344    JSHandle<JSNativePointer> np(thread, bitVector->GetNativePointer());
345    auto elements = reinterpret_cast<std::vector<std::bitset<BIT_SET_LENGTH>>*>(np->GetExternalPointer());
346    for (int32_t index = endIndex - 1; index >= startIndex; index--) {
347        std::pair<uint32_t, uint32_t> pair = ComputeElementIdAndBitId(index);
348        uint32_t elementId = pair.first;
349        uint32_t bitId = pair.second;
350        if ((value->IsZero() && (*elements)[elementId].test(bitId) == 0) ||
351            (!value->IsZero() && (*elements)[elementId].test(bitId) != 0)) {
352            return index;
353        }
354    }
355    return -1;
356}
357
358JSTaggedValue JSAPIBitVector::FlipBitByIndex(JSThread* thread, const JSHandle<JSAPIBitVector>& bitVector, int index)
359{
360    [[maybe_unused]] ConcurrentApiScope<JSAPIBitVector, ModType::WRITE> scope(thread,
361        JSHandle<JSTaggedValue>::Cast(bitVector));
362    if (index >= bitVector->GetLength()) {
363        std::ostringstream oss;
364        oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (bitVector->GetLength() - 1)
365            << ". Received value is: " << index;
366        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
367        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
368    }
369
370    JSHandle<JSNativePointer> np(thread, bitVector->GetNativePointer());
371    auto elements = reinterpret_cast<std::vector<std::bitset<BIT_SET_LENGTH>>*>(np->GetExternalPointer());
372
373    std::pair<uint32_t, uint32_t> pair = ComputeElementIdAndBitId(index);
374    uint32_t elementId = pair.first;
375    uint32_t bitId = pair.second;
376    (*elements)[elementId].flip(bitId);
377    return JSTaggedValue::Undefined();
378}
379
380JSTaggedValue JSAPIBitVector::FlipBitsByRange(JSThread* thread, const JSHandle<JSAPIBitVector>& bitVector,
381    const JSHandle<JSTaggedValue>& start, const JSHandle<JSTaggedValue>& end)
382{
383    [[maybe_unused]] ConcurrentApiScope<JSAPIBitVector, ModType::WRITE> scope(thread,
384        JSHandle<JSTaggedValue>::Cast(bitVector));
385    int32_t startIndex = JSTaggedValue::ToInt32(thread, start);
386    int32_t endIndex = JSTaggedValue::ToInt32(thread, end);
387    int32_t length = bitVector->GetLength();
388    int32_t size = length > endIndex ? endIndex : length;
389    if (endIndex < 0 || endIndex > length) {
390        std::ostringstream oss;
391        oss << "The value of \"toIndex\" is out of range. It must be >= 0 && <= " << length
392            << ". Received value is: " << endIndex;
393        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
394        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
395    }
396    if (startIndex < 0 || startIndex >= size) {
397        std::ostringstream oss;
398        oss << "The value of \"fromIndex\" is out of range. It must be >= 0 && <= " << (size - 1)
399            << ". Received value is: " << startIndex;
400        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
401        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
402    }
403    JSHandle<JSNativePointer> np(thread, bitVector->GetNativePointer());
404    auto elements = reinterpret_cast<std::vector<std::bitset<BIT_SET_LENGTH>>*>(np->GetExternalPointer());
405    for (int32_t index = startIndex; index < endIndex; index++) {
406        std::pair<uint32_t, uint32_t> pair = ComputeElementIdAndBitId(index);
407        uint32_t elementId = pair.first;
408        uint32_t bitId = pair.second;
409        (*elements)[elementId].flip(bitId);
410    }
411    return JSTaggedValue::Undefined();
412}
413
414void JSAPIBitVector::Resize(JSThread* thread, const JSHandle<JSAPIBitVector>& bitVector, int newSize)
415{
416    if (newSize < 0) {
417        std::ostringstream oss;
418        oss << "The value of \"length\" is out of range. It must be >= 0" << ". Received value is: " << newSize;
419        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
420        THROW_NEW_ERROR_AND_RETURN(thread, error);
421    }
422    [[maybe_unused]] ConcurrentApiScope<JSAPIBitVector, ModType::WRITE> scope(thread,
423        JSHandle<JSTaggedValue>::Cast(bitVector));
424    int length = bitVector->GetLength();
425    uint32_t elementsLength = static_cast<uint32_t>((length - 1) / BIT_SET_LENGTH + 1);
426    uint32_t newElementsLength = static_cast<uint32_t>((newSize - 1) / BIT_SET_LENGTH + 1);
427
428    JSHandle<JSNativePointer> np(thread, bitVector->GetNativePointer());
429    auto elements = reinterpret_cast<std::vector<std::bitset<BIT_SET_LENGTH>>*>(np->GetExternalPointer());
430    if (elementsLength == newElementsLength && length < newSize) {
431        for (int32_t index = length; index < newSize; index++) {
432            SetBit(elements, index, JSTaggedValue(0));
433        }
434    } else if (elementsLength < newElementsLength) {
435        std::bitset<JSAPIBitVector::BIT_SET_LENGTH> initBitSet;
436        elements->resize(newElementsLength, initBitSet);
437    } else if (elementsLength > newElementsLength) {
438        elements->resize(newElementsLength);
439    }
440    bitVector->SetLength(newSize);
441}
442
443JSHandle<TaggedArray> JSAPIBitVector::OwnKeys(JSThread* thread, const JSHandle<JSAPIBitVector>& obj)
444{
445    uint32_t numOfElements = static_cast<uint32_t>(obj->GetLength());
446    JSHandle<TaggedArray> keyArray = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(numOfElements);
447
448    if (numOfElements > 0) {
449        for (uint32_t i = 0; i < numOfElements; ++i) {
450            auto key = base::NumberHelper::IntToEcmaString(thread, i);
451            keyArray->Set(thread, i, key);
452        }
453    }
454
455    return keyArray;
456}
457
458JSHandle<TaggedArray> JSAPIBitVector::OwnEnumKeys(JSThread* thread, const JSHandle<JSAPIBitVector>& obj)
459{
460    return OwnKeys(thread, obj);
461}
462
463bool JSAPIBitVector::GetOwnProperty(
464    JSThread* thread, const JSHandle<JSAPIBitVector>& obj, const JSHandle<JSTaggedValue>& key)
465{
466    uint32_t index = 0;
467    if (UNLIKELY(!JSTaggedValue::ToElementIndex(key.GetTaggedValue(), &index))) {
468        JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, key.GetTaggedValue());
469        RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
470        CString errorMsg = "The type of \"index\" can not obtain attributes of no-number type. Received value is: " +
471                           ConvertToString(*result);
472        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
473        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
474    }
475
476    uint32_t length = static_cast<uint32_t>(obj->GetLength());
477    if (index >= length) {
478        std::ostringstream oss;
479        oss << "The value of \"index\" is out of range. It must be > " << (length - 1)
480            << ". Received value is: " << index;
481        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
482        THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
483    }
484
485    obj->Get(thread, index);
486    RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
487    return true;
488}
489
490JSTaggedValue JSAPIBitVector::GetIteratorObj(JSThread* thread, const JSHandle<JSAPIBitVector>& obj)
491{
492    ObjectFactory* factory = thread->GetEcmaVM()->GetFactory();
493    JSHandle<JSAPIBitVectorIterator> iter(factory->NewJSAPIBitVectorIterator(obj));
494
495    return iter.GetTaggedValue();
496}
497
498OperationResult JSAPIBitVector::GetProperty(
499    JSThread* thread, const JSHandle<JSAPIBitVector>& obj, const JSHandle<JSTaggedValue>& key)
500{
501    int length = obj->GetLength();
502    int index = key->GetInt();
503    if (index < 0 || index >= length) {
504        std::ostringstream oss;
505        oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (length - 1)
506            << ". Received value is: " << index;
507        JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
508        THROW_NEW_ERROR_AND_RETURN_VALUE(
509            thread, error, OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
510    }
511
512    return OperationResult(thread, obj->Get(thread, index), PropertyMetaData(false));
513}
514bool JSAPIBitVector::SetProperty(JSThread* thread, const JSHandle<JSAPIBitVector>& obj,
515    const JSHandle<JSTaggedValue>& key, const JSHandle<JSTaggedValue>& value)
516{
517    int length = obj->GetLength();
518    int index = key->GetInt();
519    if (index < 0 || index >= length) {
520        return false;
521    }
522
523    obj->Set(thread, index, value.GetTaggedValue());
524    return true;
525}
526
527} // namespace panda::ecmascript
528