• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_linked_list.h"
17 
18 #include "ecmascript/containers/containers_errors.h"
19 namespace panda::ecmascript {
20 using ContainerError = containers::ContainerError;
21 using ErrorFlag = containers::ErrorFlag;
Insert(JSThread * thread,const JSHandle<JSAPILinkedList> & list,const JSHandle<JSTaggedValue> & value,const int index)22 JSTaggedValue JSAPILinkedList::Insert(JSThread *thread, const JSHandle<JSAPILinkedList> &list,
23                                       const JSHandle<JSTaggedValue> &value, const int index)
24 {
25     JSHandle<TaggedDoubleList> doubleList(thread, list->GetDoubleList(thread));
26     int nodeLength = doubleList->Length();
27     if (index < 0 || index > nodeLength) {
28         std::ostringstream oss;
29         oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << nodeLength
30             << ". Received value is: " << index;
31         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
32         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
33     }
34     JSTaggedValue newList = TaggedDoubleList::Insert(thread, doubleList, value, index);
35     list->SetDoubleList(thread, newList);
36     return JSTaggedValue::True();
37 }
38 
Clear(JSThread * thread)39 void JSAPILinkedList::Clear(JSThread *thread)
40 {
41     TaggedDoubleList *doubleList = TaggedDoubleList::Cast(GetDoubleList(thread).GetTaggedObject());
42     if (doubleList->NumberOfNodes() > 0) {
43         doubleList->Clear(thread);
44     }
45 }
46 
Clone(JSThread * thread,const JSHandle<JSAPILinkedList> & list)47 JSHandle<JSAPILinkedList> JSAPILinkedList::Clone(JSThread *thread, const JSHandle<JSAPILinkedList> &list)
48 {
49     JSTaggedValue doubleListTaggedValue = list->GetDoubleList(thread);
50     JSHandle<TaggedDoubleList> srcDoubleList(thread, doubleListTaggedValue);
51     JSHandle<TaggedArray> srcTaggedArray(thread, doubleListTaggedValue);
52     ASSERT(!srcDoubleList->IsDictionaryMode());
53     uint32_t numberOfNodes = static_cast<uint32_t>(srcDoubleList->NumberOfNodes());
54     uint32_t numberOfDeletedNodes = static_cast<uint32_t>(srcDoubleList->NumberOfDeletedNodes());
55     uint32_t effectiveCapacity = TaggedDoubleList::ELEMENTS_START_INDEX +
56                             (numberOfNodes + numberOfDeletedNodes + 1) * TaggedDoubleList::ENTRY_SIZE;
57     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
58     JSHandle<JSAPILinkedList> newLinkedList = factory->NewJSAPILinkedList();
59     JSHandle<TaggedArray> dstTaggedArray = factory->NewAndCopyTaggedArray(srcTaggedArray,
60                                                                           effectiveCapacity, effectiveCapacity);
61     newLinkedList->SetDoubleList(thread, dstTaggedArray.GetTaggedValue());
62     return newLinkedList;
63 }
64 
RemoveFirst(JSThread * thread,const JSHandle<JSAPILinkedList> & list)65 JSTaggedValue JSAPILinkedList::RemoveFirst(JSThread *thread, const JSHandle<JSAPILinkedList> &list)
66 {
67     JSHandle<TaggedDoubleList> doubleList(thread, list->GetDoubleList(thread));
68     int nodeLength = doubleList->Length();
69     if (nodeLength <= 0) {
70         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::IS_EMPTY_ERROR, "Container is empty");
71         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
72     }
73     return doubleList->RemoveFirst(thread);
74 }
75 
RemoveLast(JSThread * thread,const JSHandle<JSAPILinkedList> & list)76 JSTaggedValue JSAPILinkedList::RemoveLast(JSThread *thread, const JSHandle<JSAPILinkedList> &list)
77 {
78     JSHandle<TaggedDoubleList> doubleList(thread, list->GetDoubleList(thread));
79     int nodeLength = doubleList->Length();
80     if (nodeLength <= 0) {
81         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::IS_EMPTY_ERROR, "Container is empty");
82         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
83     }
84     return doubleList->RemoveLast(thread);
85 }
86 
RemoveByIndex(JSThread * thread,JSHandle<JSAPILinkedList> & list,const int index)87 JSTaggedValue JSAPILinkedList::RemoveByIndex(JSThread *thread, JSHandle<JSAPILinkedList> &list, const int index)
88 {
89     JSHandle<TaggedDoubleList> doubleList(thread, list->GetDoubleList(thread));
90     int nodeLength = doubleList->Length();
91     if (nodeLength <= 0) {
92         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
93         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
94     }
95     if (index < 0 || index >= nodeLength) {
96         int size = (nodeLength > 0) ? (nodeLength - 1) : 0;
97         std::ostringstream oss;
98         oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << size
99             << ". Received value is: " << index;
100         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
101         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
102     }
103     return doubleList->RemoveByIndex(thread, index);
104 }
105 
Remove(JSThread * thread,const JSTaggedValue & element)106 JSTaggedValue JSAPILinkedList::Remove(JSThread *thread, const JSTaggedValue &element)
107 {
108     TaggedDoubleList *doubleList = TaggedDoubleList::Cast(GetDoubleList(thread).GetTaggedObject());
109     int nodeLength = doubleList->Length();
110     if (nodeLength < 0) {
111         return JSTaggedValue::False();
112     }
113     return doubleList->Remove(thread, element);
114 }
115 
RemoveFirstFound(JSThread * thread,JSHandle<JSAPILinkedList> & list,const JSTaggedValue & element)116 JSTaggedValue JSAPILinkedList::RemoveFirstFound(JSThread *thread, JSHandle<JSAPILinkedList> &list,
117                                                 const JSTaggedValue &element)
118 {
119     JSHandle<TaggedDoubleList> doubleList(thread, list->GetDoubleList(thread));
120     int nodeLength = doubleList->Length();
121     if (nodeLength <= 0) {
122         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::IS_EMPTY_ERROR, "Container is empty");
123         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
124     }
125     return TaggedDoubleList::RemoveFirstFound(thread, doubleList, element);
126 }
127 
RemoveLastFound(JSThread * thread,JSHandle<JSAPILinkedList> & list,const JSTaggedValue & element)128 JSTaggedValue JSAPILinkedList::RemoveLastFound(JSThread *thread, JSHandle<JSAPILinkedList> &list,
129                                                const JSTaggedValue &element)
130 {
131     JSHandle<TaggedDoubleList> doubleList(thread, list->GetDoubleList(thread));
132     int nodeLength = doubleList->Length();
133     if (nodeLength < 0) {
134         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::IS_EMPTY_ERROR, "Container is empty");
135         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
136     }
137     return TaggedDoubleList::RemoveLastFound(thread, doubleList, element);
138 }
139 
Add(JSThread * thread,const JSHandle<JSAPILinkedList> & list,const JSHandle<JSTaggedValue> & value)140 void JSAPILinkedList::Add(JSThread *thread, const JSHandle<JSAPILinkedList> &list, const JSHandle<JSTaggedValue> &value)
141 {
142     JSHandle<TaggedDoubleList> doubleList(thread, list->GetDoubleList(thread));
143     JSTaggedValue newLinkedList = TaggedDoubleList::Add(thread, doubleList, value);
144     list->SetDoubleList(thread, newLinkedList);
145 }
146 
AddFirst(JSThread * thread,const JSHandle<JSAPILinkedList> & list,const JSHandle<JSTaggedValue> & value)147 void JSAPILinkedList::AddFirst(JSThread *thread, const JSHandle<JSAPILinkedList> &list,
148                                const JSHandle<JSTaggedValue> &value)
149 {
150     JSHandle<TaggedDoubleList> doubleList(thread, list->GetDoubleList(thread));
151     JSTaggedValue newLinkedList = TaggedDoubleList::AddFirst(thread, doubleList, value);
152     list->SetDoubleList(thread, newLinkedList);
153 }
154 
GetFirst(const JSThread * thread)155 JSTaggedValue JSAPILinkedList::GetFirst(const JSThread *thread)
156 {
157     JSTaggedValue res = TaggedDoubleList::Cast(GetDoubleList(thread).GetTaggedObject())->GetFirst(thread);
158     if (res.IsHole()) {
159         return JSTaggedValue::Undefined();
160     }
161     return res;
162 }
163 
GetLast(const JSThread * thread)164 JSTaggedValue JSAPILinkedList::GetLast(const JSThread *thread)
165 {
166     JSTaggedValue res = TaggedDoubleList::Cast(GetDoubleList(thread).GetTaggedObject())->GetLast(thread);
167     if (res.IsHole()) {
168         return JSTaggedValue::Undefined();
169     }
170     return res;
171 }
172 
Set(JSThread * thread,const JSHandle<JSAPILinkedList> & list,const int index,const JSHandle<JSTaggedValue> & value)173 JSTaggedValue JSAPILinkedList::Set(JSThread *thread, const JSHandle<JSAPILinkedList> &list,
174                                    const int index, const JSHandle<JSTaggedValue> &value)
175 {
176     JSHandle<TaggedDoubleList> doubleList(thread, list->GetDoubleList(thread));
177     int nodeLength = doubleList->Length();
178     if (nodeLength <= 0) {
179         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
180         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
181     }
182     if (index < 0 || index >= nodeLength) {
183         std::ostringstream oss;
184         oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (nodeLength - 1)
185             << ". Received value is: " << index;
186         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
187         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception());
188     }
189     TaggedDoubleList::Set(thread, doubleList, index, value);
190     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
191     return value.GetTaggedValue();
192 }
193 
Has(const JSThread * thread,const JSTaggedValue & element)194 bool JSAPILinkedList::Has(const JSThread *thread, const JSTaggedValue &element)
195 {
196     TaggedDoubleList *doubleList = TaggedDoubleList::Cast(GetDoubleList(thread).GetTaggedObject());
197     return doubleList->Has(thread, element);
198 }
199 
Get(const JSThread * thread,const int index)200 JSTaggedValue JSAPILinkedList::Get(const JSThread *thread, const int index)
201 {
202     TaggedDoubleList *doubleList = TaggedDoubleList::Cast(GetDoubleList(thread).GetTaggedObject());
203     int nodeLength = doubleList->Length();
204     if (index < 0 || index >= nodeLength) {
205         return JSTaggedValue::Undefined();
206     }
207     return doubleList->Get(thread, index);
208 }
209 
GetIndexOf(const JSThread * thread,const JSTaggedValue & element)210 JSTaggedValue JSAPILinkedList::GetIndexOf(const JSThread *thread, const JSTaggedValue &element)
211 {
212     TaggedDoubleList *doubleList = TaggedDoubleList::Cast(GetDoubleList(thread).GetTaggedObject());
213     return JSTaggedValue(doubleList->GetIndexOf(thread, element));
214 }
215 
GetLastIndexOf(const JSThread * thread,const JSTaggedValue & element)216 JSTaggedValue JSAPILinkedList::GetLastIndexOf(const JSThread *thread, const JSTaggedValue &element)
217 {
218     TaggedDoubleList *doubleList = TaggedDoubleList::Cast(GetDoubleList(thread).GetTaggedObject());
219     return JSTaggedValue(doubleList->GetLastIndexOf(thread, element));
220 }
221 
ConvertToArray(const JSThread * thread,const JSHandle<JSAPILinkedList> & list)222 JSTaggedValue JSAPILinkedList::ConvertToArray(const JSThread *thread, const JSHandle<JSAPILinkedList> &list)
223 {
224     JSHandle<TaggedDoubleList> doubleList(thread, list->GetDoubleList(thread));
225     return TaggedDoubleList::ConvertToArray(thread, doubleList);
226 }
227 
OwnKeys(JSThread * thread,const JSHandle<JSAPILinkedList> & list)228 JSHandle<TaggedArray> JSAPILinkedList::OwnKeys(JSThread *thread, const JSHandle<JSAPILinkedList> &list)
229 {
230     JSHandle<TaggedDoubleList> doubleList(thread, list->GetDoubleList(thread).GetTaggedObject());
231     return TaggedDoubleList::OwnKeys(thread, doubleList);
232 }
233 
GetOwnProperty(JSThread * thread,const JSHandle<JSAPILinkedList> & list,const JSHandle<JSTaggedValue> & key)234 bool JSAPILinkedList::GetOwnProperty(JSThread *thread, const JSHandle<JSAPILinkedList> &list,
235                                      const JSHandle<JSTaggedValue> &key)
236 {
237     uint32_t index = 0;
238     if (UNLIKELY(!JSTaggedValue::ToElementIndex(thread, key.GetTaggedValue(), &index))) {
239         JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, key.GetTaggedValue());
240         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
241         CString errorMsg =
242             "The type of \"index\" can not obtain attributes of no-number type. Received value is: "
243             + ConvertToString(thread, *result);
244         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
245         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
246     }
247     JSHandle<TaggedDoubleList> doubleList(thread, list->GetDoubleList(thread));
248     uint32_t length = static_cast<uint32_t>(doubleList->Length());
249     if (length == 0) {
250         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, "Container is empty");
251         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
252     }
253     if (index >= length) {
254         ASSERT(length > 0);
255         std::ostringstream oss;
256         oss << "The value of \"index\" is out of range. It must be > " << (length - 1)
257             << ". Received value is: " << index;
258         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
259         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, false);
260     }
261 
262     list->Get(thread, index);
263     return true;
264 }
265 
GetProperty(JSThread * thread,const JSHandle<JSAPILinkedList> & list,const JSHandle<JSTaggedValue> & key)266 OperationResult JSAPILinkedList::GetProperty(JSThread *thread, const JSHandle<JSAPILinkedList> &list,
267                                              const JSHandle<JSTaggedValue> &key)
268 {
269     JSHandle<TaggedDoubleList> doubleList(thread, list->GetDoubleList(thread));
270     int nodeLength = doubleList->Length();
271     JSHandle<JSTaggedValue> indexKey = key;
272     if (indexKey->IsDouble()) {
273         // Math.floor(1) will produce TaggedDouble, we need to cast into TaggedInt
274         // For integer which is greater than INT32_MAX, it will remain TaggedDouble
275         indexKey = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(indexKey->GetDouble()));
276     }
277     if (!indexKey->IsInt()) {
278         CString errorMsg = "The type of \"index\" must be small integer.";
279         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str());
280         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error,
281                                          OperationResult(thread, JSTaggedValue::Exception(), PropertyMetaData(false)));
282     }
283 
284     int index = indexKey->GetInt();
285     if (index < 0 || index >= nodeLength) {
286         std::ostringstream oss;
287         oss << "The value of \"index\" is out of range. It must be >= 0 && <= " << (nodeLength - 1)
288             << ". Received value is: " << index;
289         JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::RANGE_ERROR, oss.str().c_str());
290         THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, OperationResult(thread,
291                                                                         JSTaggedValue::Exception(),
292                                                                         PropertyMetaData(false)));
293     }
294 
295     return OperationResult(thread, doubleList->Get(thread, index), PropertyMetaData(false));
296 }
297 
SetProperty(JSThread * thread,const JSHandle<JSAPILinkedList> & obj,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)298 bool JSAPILinkedList::SetProperty(JSThread *thread, const JSHandle<JSAPILinkedList> &obj,
299                                   const JSHandle<JSTaggedValue> &key,
300                                   const JSHandle<JSTaggedValue> &value)
301 {
302     JSHandle<TaggedDoubleList> doubleList(thread, obj->GetDoubleList(thread));
303     int nodeLength = doubleList->Length();
304     JSHandle<JSTaggedValue> indexKey = key;
305     if (indexKey->IsDouble()) {
306         indexKey = JSHandle<JSTaggedValue>(thread, JSTaggedValue::TryCastDoubleToInt32(indexKey->GetDouble()));
307     }
308     if (!indexKey->IsInt()) {
309         return false;
310     }
311     int index = indexKey->GetInt();
312     if (index < 0 || index >= nodeLength) {
313         return false;
314     }
315 
316     TaggedDoubleList::Set(thread, doubleList, index, value);
317     return true;
318 }
319 }  // namespace panda::ecmascript
320