• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 "containers_treeset.h"
17 #include "ecmascript/ecma_vm.h"
18 #include "ecmascript/internal_call_params.h"
19 #include "ecmascript/js_api_tree_set.h"
20 #include "ecmascript/js_api_tree_set_iterator.h"
21 #include "ecmascript/object_factory.h"
22 #include "ecmascript/tagged_array-inl.h"
23 #include "ecmascript/tagged_tree-inl.h"
24 
25 namespace panda::ecmascript::containers {
TreeSetConstructor(EcmaRuntimeCallInfo * argv)26 JSTaggedValue ContainersTreeSet::TreeSetConstructor(EcmaRuntimeCallInfo *argv)
27 {
28     ASSERT(argv);
29     BUILTINS_API_TRACE(argv->GetThread(), TreeSet, Constructor);
30     JSThread *thread = argv->GetThread();
31     [[maybe_unused]] EcmaHandleScope handleScope(thread);
32     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
33 
34     JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
35     if (newTarget->IsUndefined()) {
36         THROW_TYPE_ERROR_AND_RETURN(thread, "new target can't be undefined", JSTaggedValue::Exception());
37     }
38     // new TreeSet
39     JSHandle<JSTaggedValue> constructor = GetConstructor(argv);
40     JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), newTarget);
41     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
42 
43     // Set set’s internal slot with a new empty List.
44     JSHandle<JSAPITreeSet> set = JSHandle<JSAPITreeSet>::Cast(obj);
45     JSTaggedValue internal = TaggedTreeSet::Create(thread);
46     set->SetTreeSet(thread, internal);
47 
48     // If comparefn was supplied, let compare be comparefn; else let compare be hole.
49     JSHandle<JSTaggedValue> compareFn(GetCallArg(argv, 0));
50     if (compareFn->IsUndefined() || compareFn->IsNull()) {
51         return set.GetTaggedValue();
52     }
53     if (!compareFn->IsCallable()) {
54         THROW_TYPE_ERROR_AND_RETURN(thread, "comparefn is not Callable", JSTaggedValue::Exception());
55     }
56 
57     TaggedTreeSet::Cast(internal.GetTaggedObject())->SetCompare(thread, compareFn.GetTaggedValue());
58     return set.GetTaggedValue();
59 }
60 
Add(EcmaRuntimeCallInfo * argv)61 JSTaggedValue ContainersTreeSet::Add(EcmaRuntimeCallInfo *argv)
62 {
63     ASSERT(argv);
64     BUILTINS_API_TRACE(argv->GetThread(), TreeSet, Add);
65     JSThread *thread = argv->GetThread();
66     [[maybe_unused]] EcmaHandleScope handleScope(thread);
67     // get and check this set
68     JSHandle<JSTaggedValue> self = GetThis(argv);
69     if (!self->IsJSAPITreeSet()) {
70         THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPITreeSet", JSTaggedValue::Exception());
71     }
72 
73     JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
74     JSHandle<JSAPITreeSet> set = JSHandle<JSAPITreeSet>::Cast(self);
75     JSAPITreeSet::Add(thread, set, value);
76     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
77     return JSTaggedValue::True();
78 }
79 
Remove(EcmaRuntimeCallInfo * argv)80 JSTaggedValue ContainersTreeSet::Remove(EcmaRuntimeCallInfo *argv)
81 {
82     BUILTINS_API_TRACE(argv->GetThread(), TreeSet, Remove);
83     JSThread *thread = argv->GetThread();
84     [[maybe_unused]] EcmaHandleScope handleScope(thread);
85     // get and check this set
86     JSHandle<JSTaggedValue> self = GetThis(argv);
87     if (!self->IsJSAPITreeSet()) {
88         THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPITreeSet", JSTaggedValue::Exception());
89     }
90 
91     JSHandle<JSAPITreeSet> set = JSHandle<JSAPITreeSet>::Cast(self);
92     JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
93     return GetTaggedBoolean(JSAPITreeSet::Delete(thread, set, key));
94 }
95 
Has(EcmaRuntimeCallInfo * argv)96 JSTaggedValue ContainersTreeSet::Has(EcmaRuntimeCallInfo *argv)
97 {
98     BUILTINS_API_TRACE(argv->GetThread(), TreeSet, Has);
99     JSThread *thread = argv->GetThread();
100     [[maybe_unused]] EcmaHandleScope handleScope(thread);
101     // get and check this set
102     JSHandle<JSTaggedValue> self(GetThis(argv));
103     if (!self->IsJSAPITreeSet()) {
104         THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPITreeSet", JSTaggedValue::Exception());
105     }
106 
107     JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
108     JSHandle<JSAPITreeSet> set = JSHandle<JSAPITreeSet>::Cast(self);
109 
110     bool flag = JSAPITreeSet::Has(thread, JSHandle<JSAPITreeSet>::Cast(set), key);
111     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
112     return GetTaggedBoolean(flag);
113 }
114 
GetFirstValue(EcmaRuntimeCallInfo * argv)115 JSTaggedValue ContainersTreeSet::GetFirstValue(EcmaRuntimeCallInfo *argv)
116 {
117     BUILTINS_API_TRACE(argv->GetThread(), TreeSet, GetFirstValue);
118     JSThread *thread = argv->GetThread();
119     [[maybe_unused]] EcmaHandleScope handleScope(thread);
120     // get and check this set
121     JSHandle<JSTaggedValue> self(GetThis(argv));
122     if (!self->IsJSAPITreeSet()) {
123         THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPITreeSet", JSTaggedValue::Exception());
124     }
125 
126     JSHandle<JSAPITreeSet> set = JSHandle<JSAPITreeSet>::Cast(self);
127     return TaggedTreeSet::Cast(set->GetTreeSet().GetTaggedObject())->GetFirstKey();
128 }
129 
GetLastValue(EcmaRuntimeCallInfo * argv)130 JSTaggedValue ContainersTreeSet::GetLastValue(EcmaRuntimeCallInfo *argv)
131 {
132     BUILTINS_API_TRACE(argv->GetThread(), TreeSet, GetLastValue);
133     JSThread *thread = argv->GetThread();
134     [[maybe_unused]] EcmaHandleScope handleScope(thread);
135     // get and check this set
136     JSHandle<JSTaggedValue> self(GetThis(argv));
137     if (!self->IsJSAPITreeSet()) {
138         THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPITreeSet", JSTaggedValue::Exception());
139     }
140 
141     JSHandle<JSAPITreeSet> set = JSHandle<JSAPITreeSet>::Cast(self);
142     return TaggedTreeSet::Cast(set->GetTreeSet().GetTaggedObject())->GetLastKey();
143 }
144 
Clear(EcmaRuntimeCallInfo * argv)145 JSTaggedValue ContainersTreeSet::Clear(EcmaRuntimeCallInfo *argv)
146 {
147     BUILTINS_API_TRACE(argv->GetThread(), TreeSet, Clear);
148     JSThread *thread = argv->GetThread();
149     [[maybe_unused]] EcmaHandleScope handleScope(thread);
150     // get and check this set
151     JSHandle<JSTaggedValue> self(GetThis(argv));
152     if (!self->IsJSAPITreeSet()) {
153         THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPITreeSet", JSTaggedValue::Exception());
154     }
155 
156     JSAPITreeSet::Clear(thread, JSHandle<JSAPITreeSet>::Cast(self));
157     return JSTaggedValue::Undefined();
158 }
159 
GetLowerValue(EcmaRuntimeCallInfo * argv)160 JSTaggedValue ContainersTreeSet::GetLowerValue(EcmaRuntimeCallInfo *argv)
161 {
162     BUILTINS_API_TRACE(argv->GetThread(), TreeSet, GetLowerValue);
163     JSThread *thread = argv->GetThread();
164     [[maybe_unused]] EcmaHandleScope handleScope(thread);
165     // get and check this set
166     JSHandle<JSTaggedValue> self(GetThis(argv));
167     if (!self->IsJSAPITreeSet()) {
168         THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPITreeSet", JSTaggedValue::Exception());
169     }
170 
171     JSHandle<JSAPITreeSet> set = JSHandle<JSAPITreeSet>::Cast(self);
172     JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
173 
174     JSHandle<TaggedTreeSet> tset(thread, set->GetTreeSet());
175     return TaggedTreeSet::GetLowerKey(thread, tset, key);
176 }
177 
GetHigherValue(EcmaRuntimeCallInfo * argv)178 JSTaggedValue ContainersTreeSet::GetHigherValue(EcmaRuntimeCallInfo *argv)
179 {
180     BUILTINS_API_TRACE(argv->GetThread(), TreeSet, GetHigherValue);
181     JSThread *thread = argv->GetThread();
182     [[maybe_unused]] EcmaHandleScope handleScope(thread);
183     // get and check this set
184     JSHandle<JSTaggedValue> self(GetThis(argv));
185     if (!self->IsJSAPITreeSet()) {
186         THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPITreeSet", JSTaggedValue::Exception());
187     }
188 
189     JSHandle<JSAPITreeSet> set = JSHandle<JSAPITreeSet>::Cast(self);
190     JSHandle<JSTaggedValue> key = GetCallArg(argv, 0);
191     if (!key->IsString() && !key->IsNumber()) {
192         THROW_TYPE_ERROR_AND_RETURN(thread, "Incorrect key parameters", JSTaggedValue::Exception());
193     }
194     JSHandle<TaggedTreeSet> tset(thread, set->GetTreeSet());
195     return TaggedTreeSet::GetHigherKey(thread, tset, key);
196 }
197 
PopFirst(EcmaRuntimeCallInfo * argv)198 JSTaggedValue ContainersTreeSet::PopFirst(EcmaRuntimeCallInfo *argv)
199 {
200     BUILTINS_API_TRACE(argv->GetThread(), TreeSet, PopFirst);
201     JSThread *thread = argv->GetThread();
202     [[maybe_unused]] EcmaHandleScope handleScope(thread);
203     // get and check this set
204     JSHandle<JSTaggedValue> self(GetThis(argv));
205     if (!self->IsJSAPITreeSet()) {
206         THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPITreeSet", JSTaggedValue::Exception());
207     }
208 
209     JSHandle<JSAPITreeSet> set = JSHandle<JSAPITreeSet>::Cast(self);
210     return JSAPITreeSet::PopFirst(thread, set);
211 }
212 
PopLast(EcmaRuntimeCallInfo * argv)213 JSTaggedValue ContainersTreeSet::PopLast(EcmaRuntimeCallInfo *argv)
214 {
215     BUILTINS_API_TRACE(argv->GetThread(), TreeSet, PopLast);
216     JSThread *thread = argv->GetThread();
217     [[maybe_unused]] EcmaHandleScope handleScope(thread);
218     // get and check this set
219     JSHandle<JSTaggedValue> self(GetThis(argv));
220     if (!self->IsJSAPITreeSet()) {
221         THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPITreeSet", JSTaggedValue::Exception());
222     }
223 
224     JSHandle<JSAPITreeSet> set = JSHandle<JSAPITreeSet>::Cast(self);
225     return JSAPITreeSet::PopLast(thread, set);
226 }
227 
IsEmpty(EcmaRuntimeCallInfo * argv)228 JSTaggedValue ContainersTreeSet::IsEmpty(EcmaRuntimeCallInfo *argv)
229 {
230     BUILTINS_API_TRACE(argv->GetThread(), TreeSet, IsEmpty);
231     JSThread *thread = argv->GetThread();
232     [[maybe_unused]] EcmaHandleScope handleScope(thread);
233     // get and check this set
234     JSHandle<JSTaggedValue> self = GetThis(argv);
235     if (!self->IsJSAPITreeSet()) {
236         THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPITreeSet", JSTaggedValue::Exception());
237     }
238     JSHandle<JSAPITreeSet> set = JSHandle<JSAPITreeSet>::Cast(self);
239     return GetTaggedBoolean(set->GetSize() == 0);
240 }
241 
Values(EcmaRuntimeCallInfo * argv)242 JSTaggedValue ContainersTreeSet::Values(EcmaRuntimeCallInfo *argv)
243 {
244     BUILTINS_API_TRACE(argv->GetThread(), TreeSet, Values);
245     JSThread *thread = argv->GetThread();
246     [[maybe_unused]] EcmaHandleScope handleScope(thread);
247     JSHandle<JSTaggedValue> self = GetThis(argv);
248     JSHandle<JSTaggedValue> iter = JSAPITreeSetIterator::CreateTreeSetIterator(thread, self, IterationKind::KEY);
249     return iter.GetTaggedValue();
250 }
251 
Entries(EcmaRuntimeCallInfo * argv)252 JSTaggedValue ContainersTreeSet::Entries(EcmaRuntimeCallInfo *argv)
253 {
254     BUILTINS_API_TRACE(argv->GetThread(), TreeSet, Entries);
255     JSThread *thread = argv->GetThread();
256     [[maybe_unused]] EcmaHandleScope handleScope(thread);
257     JSHandle<JSTaggedValue> self = GetThis(argv);
258     JSHandle<JSTaggedValue> iter =
259         JSAPITreeSetIterator::CreateTreeSetIterator(thread, self, IterationKind::KEY_AND_VALUE);
260     return iter.GetTaggedValue();
261 }
262 
ForEach(EcmaRuntimeCallInfo * argv)263 JSTaggedValue ContainersTreeSet::ForEach(EcmaRuntimeCallInfo *argv)
264 {
265     BUILTINS_API_TRACE(argv->GetThread(), TreeSet, ForEach);
266     JSThread *thread = argv->GetThread();
267     [[maybe_unused]] EcmaHandleScope handleScope(thread);
268 
269     // get and check TreeSet object
270     JSHandle<JSTaggedValue> self = GetThis(argv);
271     if (!self->IsJSAPITreeSet()) {
272         THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPITreeSet", JSTaggedValue::Exception());
273     }
274 
275     // get and check callback function
276     JSHandle<JSTaggedValue> func(GetCallArg(argv, 0));
277     if (!func->IsCallable()) {
278         THROW_TYPE_ERROR_AND_RETURN(thread, "The first arg is not Callable", JSTaggedValue::Exception());
279     }
280 
281     // If thisArg was supplied, let T be thisArg; else let T be undefined.
282     JSHandle<JSTaggedValue> thisArg = GetCallArg(argv, 1);
283     JSHandle<JSAPITreeSet> tset = JSHandle<JSAPITreeSet>::Cast(self);
284     JSMutableHandle<TaggedTreeSet> iteratedSet(thread, tset->GetTreeSet());
285     int elements = iteratedSet->NumberOfElements();
286     JSMutableHandle<TaggedArray> entries(TaggedTreeSet::GetArrayFromSet(thread, iteratedSet));
287 
288     int index = 0;
289     int length = entries->GetLength();
290     InternalCallParams *arguments = thread->GetInternalCallParams();
291     JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined());
292     while (index < elements) {
293         int entriesIndex = entries->Get(index).GetInt();
294         key.Update(iteratedSet->GetKey(entriesIndex));
295 
296         // Let funcResult be Call(callbackfn, T, «e, e, S»).
297         arguments->MakeArgv(key, key, self);
298         JSTaggedValue ret = JSFunction::Call(thread, func, thisArg, 3, arguments->GetArgv());  // 3: three args
299         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ret);
300 
301         // check entries should be update, size will be update by set add and remove.
302         if (tset->GetSize() != length) {
303             iteratedSet.Update(tset->GetTreeSet());
304             entries.Update(TaggedTreeSet::GetArrayFromSet(thread, iteratedSet).GetTaggedValue());
305             elements = iteratedSet->NumberOfElements();
306             length = entries->GetLength();
307         }
308         index++;
309     }
310     return JSTaggedValue::Undefined();
311 }
312 
GetLength(EcmaRuntimeCallInfo * argv)313 JSTaggedValue ContainersTreeSet::GetLength(EcmaRuntimeCallInfo *argv)
314 {
315     ASSERT(argv);
316     BUILTINS_API_TRACE(argv->GetThread(), TreeSet, GetLength);
317     JSThread *thread = argv->GetThread();
318     [[maybe_unused]] EcmaHandleScope handleScope(thread);
319     // get and check this set
320     JSHandle<JSTaggedValue> self(GetThis(argv));
321     if (!self->IsJSAPITreeSet()) {
322         THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not JSAPITreeSet", JSTaggedValue::Exception());
323     }
324 
325     int count = JSHandle<JSAPITreeSet>::Cast(self)->GetSize();
326     return JSTaggedValue(count);
327 }
328 }  // namespace panda::ecmascript::containers
329