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