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/containers/containers_treemap.h" 17 18#include "ecmascript/containers/containers_errors.h" 19#include "ecmascript/interpreter/interpreter.h" 20#include "ecmascript/js_api/js_api_tree_map.h" 21#include "ecmascript/js_api/js_api_tree_map_iterator.h" 22#include "ecmascript/js_function.h" 23#include "ecmascript/tagged_tree.h" 24 25namespace panda::ecmascript::containers { 26JSTaggedValue ContainersTreeMap::TreeMapConstructor(EcmaRuntimeCallInfo *argv) 27{ 28 ASSERT(argv); 29 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, 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 JSTaggedValue error = 37 ContainerError::BusinessError(thread, ErrorFlag::IS_NULL_ERROR, 38 "The TreeMap's constructor cannot be directly invoked"); 39 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 40 } 41 42 // new TreeMap 43 JSHandle<JSTaggedValue> constructor = GetConstructor(argv); 44 JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), newTarget); 45 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 46 47 // Set map’s internal slot with a new empty List. 48 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(obj); 49 JSTaggedValue internal = TaggedTreeMap::Create(thread); 50 map->SetTreeMap(thread, internal); 51 52 // If comparefn was supplied, let compare be comparefn; else let compare be hole. 53 JSHandle<JSTaggedValue> compareFn(GetCallArg(argv, 0)); 54 if (compareFn->IsUndefined() || compareFn->IsNull()) { 55 return map.GetTaggedValue(); 56 } 57 if (!compareFn->IsCallable()) { 58 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, compareFn.GetTaggedValue()); 59 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 60 CString errorMsg = 61 "The type of \"comparefn\" must be callable. Received value is: " + ConvertToString(*result); 62 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); 63 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 64 } 65 66 TaggedTreeMap::Cast(internal.GetTaggedObject())->SetCompare(thread, compareFn.GetTaggedValue()); 67 return map.GetTaggedValue(); 68} 69 70JSTaggedValue ContainersTreeMap::Set(EcmaRuntimeCallInfo *argv) 71{ 72 ASSERT(argv); 73 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Set); 74 JSThread *thread = argv->GetThread(); 75 [[maybe_unused]] EcmaHandleScope handleScope(thread); 76 JSHandle<JSTaggedValue> self = GetThis(argv); 77 // get and check this map 78 if (!self->IsJSAPITreeMap()) { 79 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) { 80 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 81 } else { 82 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 83 "The set method cannot be bound"); 84 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 85 } 86 } 87 88 JSHandle<JSTaggedValue> key = GetCallArg(argv, 0); 89 JSHandle<JSTaggedValue> value = GetCallArg(argv, 1); 90 91 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self); 92 JSAPITreeMap::Set(thread, map, key, value); 93 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 94 return map.GetTaggedValue(); 95} 96 97JSTaggedValue ContainersTreeMap::Get(EcmaRuntimeCallInfo *argv) 98{ 99 ASSERT(argv); 100 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Get); 101 JSThread *thread = argv->GetThread(); 102 [[maybe_unused]] EcmaHandleScope handleScope(thread); 103 // get and check this map 104 JSHandle<JSTaggedValue> self(GetThis(argv)); 105 if (!self->IsJSAPITreeMap()) { 106 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) { 107 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 108 } else { 109 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 110 "The get method cannot be bound"); 111 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 112 } 113 } 114 115 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self); 116 JSHandle<JSTaggedValue> key = GetCallArg(argv, 0); 117 return JSAPITreeMap::Get(thread, map, key); 118} 119 120JSTaggedValue ContainersTreeMap::Remove(EcmaRuntimeCallInfo *argv) 121{ 122 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Remove); 123 JSThread *thread = argv->GetThread(); 124 [[maybe_unused]] EcmaHandleScope handleScope(thread); 125 JSHandle<JSTaggedValue> self = GetThis(argv); 126 // get and check this map 127 if (!self->IsJSAPITreeMap()) { 128 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) { 129 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 130 } else { 131 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 132 "The remove method cannot be bound"); 133 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 134 } 135 } 136 137 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self); 138 JSHandle<JSTaggedValue> key = GetCallArg(argv, 0); 139 return JSAPITreeMap::Delete(thread, map, key); 140} 141 142JSTaggedValue ContainersTreeMap::HasKey(EcmaRuntimeCallInfo *argv) 143{ 144 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, HasKey); 145 JSThread *thread = argv->GetThread(); 146 [[maybe_unused]] EcmaHandleScope handleScope(thread); 147 // get and check this map 148 JSHandle<JSTaggedValue> self(GetThis(argv)); 149 if (!self->IsJSAPITreeMap()) { 150 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) { 151 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 152 } else { 153 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 154 "The hasKey method cannot be bound"); 155 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 156 } 157 } 158 159 JSHandle<JSTaggedValue> key = GetCallArg(argv, 0); 160 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self); 161 162 bool flag = JSAPITreeMap::HasKey(thread, JSHandle<JSAPITreeMap>::Cast(map), key); 163 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 164 return GetTaggedBoolean(flag); 165} 166 167JSTaggedValue ContainersTreeMap::HasValue(EcmaRuntimeCallInfo *argv) 168{ 169 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, HasValue); 170 JSThread *thread = argv->GetThread(); 171 [[maybe_unused]] EcmaHandleScope handleScope(thread); 172 // get and check this map 173 JSHandle<JSTaggedValue> self(GetThis(argv)); 174 if (!self->IsJSAPITreeMap()) { 175 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) { 176 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 177 } else { 178 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 179 "The hasValue method cannot be bound"); 180 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 181 } 182 } 183 184 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self); 185 bool flag = map->HasValue(thread, GetCallArg(argv, 0)); 186 return GetTaggedBoolean(flag); 187} 188 189JSTaggedValue ContainersTreeMap::GetFirstKey(EcmaRuntimeCallInfo *argv) 190{ 191 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, GetFirstKey); 192 JSThread *thread = argv->GetThread(); 193 [[maybe_unused]] EcmaHandleScope handleScope(thread); 194 // get and check this map 195 JSHandle<JSTaggedValue> self(GetThis(argv)); 196 if (!self->IsJSAPITreeMap()) { 197 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) { 198 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 199 } else { 200 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 201 "The getFirstKey method cannot be bound"); 202 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 203 } 204 } 205 206 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self); 207 return TaggedTreeMap::Cast(map->GetTreeMap().GetTaggedObject())->GetFirstKey(); 208} 209 210JSTaggedValue ContainersTreeMap::GetLastKey(EcmaRuntimeCallInfo *argv) 211{ 212 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, GetLastKey); 213 JSThread *thread = argv->GetThread(); 214 [[maybe_unused]] EcmaHandleScope handleScope(thread); 215 // get and check this map 216 JSHandle<JSTaggedValue> self(GetThis(argv)); 217 if (!self->IsJSAPITreeMap()) { 218 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) { 219 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 220 } else { 221 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 222 "The getLastKey method cannot be bound"); 223 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 224 } 225 } 226 227 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self); 228 return TaggedTreeMap::Cast(map->GetTreeMap().GetTaggedObject())->GetLastKey(); 229} 230 231JSTaggedValue ContainersTreeMap::SetAll(EcmaRuntimeCallInfo *argv) 232{ 233 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, SetAll); 234 JSThread *thread = argv->GetThread(); 235 [[maybe_unused]] EcmaHandleScope handleScope(thread); 236 // get and check this map 237 JSHandle<JSTaggedValue> self(GetThis(argv)); 238 if (!self->IsJSAPITreeMap()) { 239 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) { 240 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 241 } else { 242 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 243 "The setAll method cannot be bound"); 244 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 245 } 246 } 247 248 JSHandle<JSTaggedValue> obj = GetCallArg(argv, 0); 249 if (!obj->IsJSAPITreeMap()) { 250 if (obj->IsJSProxy() && JSHandle<JSProxy>::Cast(obj)->GetTarget().IsJSAPITreeMap()) { 251 obj = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(obj)->GetTarget()); 252 } else { 253 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, obj.GetTaggedValue()); 254 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 255 CString errorMsg = 256 "The type of \"map\" must be TreeMap. Received value is: " + ConvertToString(*result); 257 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); 258 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 259 } 260 } 261 262 JSHandle<JSAPITreeMap> dst = JSHandle<JSAPITreeMap>::Cast(self); 263 JSHandle<TaggedTreeMap> dmap(thread, dst->GetTreeMap()); 264 JSHandle<TaggedTreeMap> smap(thread, JSHandle<JSAPITreeMap>::Cast(obj)->GetTreeMap()); 265 266 if (JSHandle<JSAPITreeMap>::Cast(obj)->GetSize() > 0) { 267 JSTaggedValue tmap = TaggedTreeMap::SetAll(thread, dmap, smap); 268 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 269 dst->SetTreeMap(thread, tmap); 270 } 271 return JSTaggedValue::Undefined(); 272} 273 274JSTaggedValue ContainersTreeMap::Clear(EcmaRuntimeCallInfo *argv) 275{ 276 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Clear); 277 JSThread *thread = argv->GetThread(); 278 [[maybe_unused]] EcmaHandleScope handleScope(thread); 279 // get and check this map 280 JSHandle<JSTaggedValue> self(GetThis(argv)); 281 if (!self->IsJSAPITreeMap()) { 282 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) { 283 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 284 } else { 285 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 286 "The clear method cannot be bound"); 287 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 288 } 289 } 290 291 JSAPITreeMap::Clear(thread, JSHandle<JSAPITreeMap>::Cast(self)); 292 return JSTaggedValue::Undefined(); 293} 294 295JSTaggedValue ContainersTreeMap::GetLowerKey(EcmaRuntimeCallInfo *argv) 296{ 297 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, GetLowerKey); 298 JSThread *thread = argv->GetThread(); 299 [[maybe_unused]] EcmaHandleScope handleScope(thread); 300 // get and check this map 301 JSHandle<JSTaggedValue> self(GetThis(argv)); 302 if (!self->IsJSAPITreeMap()) { 303 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) { 304 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 305 } else { 306 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 307 "The getLowerKey method cannot be bound"); 308 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 309 } 310 } 311 312 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self); 313 JSHandle<JSTaggedValue> key = GetCallArg(argv, 0); 314 315 JSHandle<TaggedTreeMap> tmap(thread, map->GetTreeMap()); 316 return TaggedTreeMap::GetLowerKey(thread, tmap, key); 317} 318 319JSTaggedValue ContainersTreeMap::GetHigherKey(EcmaRuntimeCallInfo *argv) 320{ 321 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, GetHigherKey); 322 JSThread *thread = argv->GetThread(); 323 [[maybe_unused]] EcmaHandleScope handleScope(thread); 324 // get and check this map 325 JSHandle<JSTaggedValue> self(GetThis(argv)); 326 if (!self->IsJSAPITreeMap()) { 327 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) { 328 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 329 } else { 330 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 331 "The getHigherKey method cannot be bound"); 332 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 333 } 334 } 335 336 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self); 337 JSHandle<JSTaggedValue> key = GetCallArg(argv, 0); 338 339 JSHandle<TaggedTreeMap> tmap(thread, map->GetTreeMap()); 340 return TaggedTreeMap::GetHigherKey(thread, tmap, key); 341} 342 343JSTaggedValue ContainersTreeMap::Replace(EcmaRuntimeCallInfo *argv) 344{ 345 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Replace); 346 JSThread *thread = argv->GetThread(); 347 [[maybe_unused]] EcmaHandleScope handleScope(thread); 348 // get and check this map 349 JSHandle<JSTaggedValue> self(GetThis(argv)); 350 if (!self->IsJSAPITreeMap()) { 351 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) { 352 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 353 } else { 354 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 355 "The replace method cannot be bound"); 356 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 357 } 358 } 359 360 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self); 361 JSHandle<JSTaggedValue> key = GetCallArg(argv, 0); 362 JSHandle<JSTaggedValue> value = GetCallArg(argv, 1); 363 364 bool success = JSAPITreeMap::Replace(thread, map, key, value); 365 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 366 return GetTaggedBoolean(success); 367} 368 369JSTaggedValue ContainersTreeMap::Keys(EcmaRuntimeCallInfo *argv) 370{ 371 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Keys); 372 JSThread *thread = argv->GetThread(); 373 [[maybe_unused]] EcmaHandleScope handleScope(thread); 374 JSHandle<JSTaggedValue> self = GetThis(argv); 375 JSHandle<JSTaggedValue> iter = JSAPITreeMapIterator::CreateTreeMapIterator(thread, self, IterationKind::KEY); 376 return iter.GetTaggedValue(); 377} 378 379JSTaggedValue ContainersTreeMap::Values(EcmaRuntimeCallInfo *argv) 380{ 381 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Values); 382 JSThread *thread = argv->GetThread(); 383 [[maybe_unused]] EcmaHandleScope handleScope(thread); 384 JSHandle<JSTaggedValue> self = GetThis(argv); 385 JSHandle<JSTaggedValue> iter = JSAPITreeMapIterator::CreateTreeMapIterator(thread, self, IterationKind::VALUE); 386 return iter.GetTaggedValue(); 387} 388 389JSTaggedValue ContainersTreeMap::Entries(EcmaRuntimeCallInfo *argv) 390{ 391 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, Entries); 392 JSThread *thread = argv->GetThread(); 393 [[maybe_unused]] EcmaHandleScope handleScope(thread); 394 JSHandle<JSTaggedValue> self = GetThis(argv); 395 JSHandle<JSTaggedValue> iter = 396 JSAPITreeMapIterator::CreateTreeMapIterator(thread, self, IterationKind::KEY_AND_VALUE); 397 return iter.GetTaggedValue(); 398} 399 400JSTaggedValue ContainersTreeMap::ForEach(EcmaRuntimeCallInfo *argv) 401{ 402 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, ForEach); 403 JSThread *thread = argv->GetThread(); 404 [[maybe_unused]] EcmaHandleScope handleScope(thread); 405 // get and check TreeMap object 406 JSHandle<JSTaggedValue> self = GetThis(argv); 407 if (!self->IsJSAPITreeMap()) { 408 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) { 409 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 410 } else { 411 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 412 "The forEach method cannot be bound"); 413 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 414 } 415 } 416 // get and check callback function 417 JSHandle<JSTaggedValue> func(GetCallArg(argv, 0)); 418 if (!func->IsCallable()) { 419 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, func.GetTaggedValue()); 420 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 421 CString errorMsg = 422 "The type of \"callbackfn\" must be callable. Received value is: " + ConvertToString(*result); 423 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); 424 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 425 } 426 // If thisArg was supplied, let T be thisArg; else let T be undefined. 427 JSHandle<JSTaggedValue> thisArg = GetCallArg(argv, 1); 428 JSHandle<JSAPITreeMap> tmap = JSHandle<JSAPITreeMap>::Cast(self); 429 JSMutableHandle<TaggedTreeMap> iteratedMap(thread, tmap->GetTreeMap()); 430 uint32_t elements = iteratedMap->NumberOfElements(); 431 JSHandle<TaggedArray> entries = TaggedTreeMap::GetArrayFromMap(thread, iteratedMap); 432 uint32_t index = 0; 433 size_t length = entries->GetLength(); 434 const uint32_t argsLength = 3; 435 JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined(); 436 JSMutableHandle<JSTaggedValue> key(thread, JSTaggedValue::Undefined()); 437 JSMutableHandle<JSTaggedValue> value(thread, JSTaggedValue::Undefined()); 438 while (index < elements) { 439 int entriesIndex = entries->Get(index).GetInt(); 440 key.Update(iteratedMap->GetKey(entriesIndex)); 441 value.Update(iteratedMap->GetValue(entriesIndex)); 442 // Let funcResult be Call(callbackfn, T, «e, e, S»). 443 EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, func, thisArg, undefined, argsLength); 444 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 445 info->SetCallArg(value.GetTaggedValue(), key.GetTaggedValue(), self.GetTaggedValue()); 446 JSTaggedValue ret = JSFunction::Call(info); 447 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ret); 448 // check entries should be update, size will be update in tmap set or remove. 449 if (tmap->GetSize() != static_cast<int>(length)) { 450 iteratedMap.Update(tmap->GetTreeMap()); 451 entries = TaggedTreeMap::GetArrayFromMap(thread, iteratedMap); 452 elements = iteratedMap->NumberOfElements(); 453 length = entries->GetLength(); 454 } 455 index++; 456 } 457 return JSTaggedValue::Undefined(); 458} 459 460JSTaggedValue ContainersTreeMap::GetLength(EcmaRuntimeCallInfo *argv) 461{ 462 ASSERT(argv); 463 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, GetLength); 464 JSThread *thread = argv->GetThread(); 465 [[maybe_unused]] EcmaHandleScope handleScope(thread); 466 // get and check this map 467 JSHandle<JSTaggedValue> self(GetThis(argv)); 468 if (!self->IsJSAPITreeMap()) { 469 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) { 470 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 471 } else { 472 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 473 "The getLength method cannot be bound"); 474 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 475 } 476 } 477 int count = JSHandle<JSAPITreeMap>::Cast(self)->GetSize(); 478 return JSTaggedValue(count); 479} 480 481JSTaggedValue ContainersTreeMap::IsEmpty(EcmaRuntimeCallInfo *argv) 482{ 483 BUILTINS_API_TRACE(argv->GetThread(), TreeMap, IsEmpty); 484 JSThread *thread = argv->GetThread(); 485 [[maybe_unused]] EcmaHandleScope handleScope(thread); 486 // get and check this map 487 JSHandle<JSTaggedValue> self = GetThis(argv); 488 if (!self->IsJSAPITreeMap()) { 489 if (self->IsJSProxy() && JSHandle<JSProxy>::Cast(self)->GetTarget().IsJSAPITreeMap()) { 490 self = JSHandle<JSTaggedValue>(thread, JSHandle<JSProxy>::Cast(self)->GetTarget()); 491 } else { 492 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::BIND_ERROR, 493 "The isEmpty method cannot be bound"); 494 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 495 } 496 } 497 JSHandle<JSAPITreeMap> map = JSHandle<JSAPITreeMap>::Cast(self); 498 return GetTaggedBoolean(map->GetSize() == 0); 499} 500} // namespace panda::ecmascript::containers 501