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