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