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