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_hashset.h" 17 18#include "ecmascript/containers/containers_errors.h" 19#include "ecmascript/tagged_hash_array.h" 20 21namespace panda::ecmascript { 22using ContainerError = containers::ContainerError; 23using ErrorFlag = containers::ErrorFlag; 24JSTaggedValue JSAPIHashSet::IsEmpty() 25{ 26 return JSTaggedValue(GetSize() == 0); 27} 28 29JSTaggedValue JSAPIHashSet::Has(JSThread *thread, JSTaggedValue value) 30{ 31 if (!TaggedHashArray::IsKey(value)) { 32 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, value); 33 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 34 CString errorMsg = 35 "The type of \"value\" must be Key of JS. Received value is: " + ConvertToString(*result); 36 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); 37 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 38 } 39 TaggedHashArray *hashArray = TaggedHashArray::Cast(GetTable().GetTaggedObject()); 40 int hash = TaggedNode::Hash(thread, value); 41 return JSTaggedValue(!(hashArray->GetNode(thread, hash, value).IsHole())); 42} 43 44void JSAPIHashSet::Add(JSThread *thread, JSHandle<JSAPIHashSet> hashSet, JSHandle<JSTaggedValue> value) 45{ 46 if (!TaggedHashArray::IsKey(value.GetTaggedValue())) { 47 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, value.GetTaggedValue()); 48 CString errorMsg = 49 "The type of \"value\" must be Key of JS. Received value is: " + ConvertToString(*result); 50 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); 51 THROW_NEW_ERROR_AND_RETURN(thread, error); 52 } 53 JSHandle<TaggedHashArray> hashArray(thread, hashSet->GetTable()); 54 int hash = TaggedNode::Hash(thread, value.GetTaggedValue()); 55 JSHandle<JSTaggedValue> nullHandle(thread, JSTaggedValue::Null()); 56 JSTaggedValue setValue = TaggedHashArray::SetVal(thread, hashArray, hash, value, nullHandle); 57 uint32_t nodeNum = hashSet->GetSize(); 58 if (!setValue.IsUndefined()) { 59 hashSet->SetSize(++nodeNum); 60 } 61 uint32_t tableLength = hashArray->GetLength() * TaggedHashArray::DEFAULT_LOAD_FACTOR; 62 if (nodeNum > tableLength) { 63 hashArray = TaggedHashArray::Resize(thread, hashArray, hashArray->GetLength()); 64 } 65 hashSet->SetTable(thread, hashArray); 66} 67 68void JSAPIHashSet::Clear(JSThread *thread) 69{ 70 TaggedHashArray *hashArray = TaggedHashArray::Cast(GetTable().GetTaggedObject()); 71 uint32_t nodeLength = GetSize(); 72 if (nodeLength > 0) { 73 hashArray->Clear(thread); 74 SetSize(0); 75 } 76} 77 78JSTaggedValue JSAPIHashSet::Remove(JSThread *thread, JSHandle<JSAPIHashSet> hashSet, JSTaggedValue key) 79{ 80 if (!TaggedHashArray::IsKey(key)) { 81 JSHandle<EcmaString> result = JSTaggedValue::ToString(thread, key); 82 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 83 CString errorMsg = 84 "The type of \"key\" must be not null. Received value is: " + ConvertToString(*result); 85 JSTaggedValue error = ContainerError::BusinessError(thread, ErrorFlag::TYPE_ERROR, errorMsg.c_str()); 86 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); 87 } 88 89 JSHandle<TaggedHashArray> hashArray(thread, hashSet->GetTable()); 90 uint32_t nodeNum = hashSet->GetSize(); 91 if (nodeNum == 0) { 92 return JSTaggedValue::False(); 93 } 94 uint32_t hash = static_cast<uint32_t>(TaggedNode::Hash(thread, key)); 95 JSTaggedValue removeValue = hashArray->RemoveNode(thread, hash, key); 96 if (removeValue.IsHole()) { 97 return JSTaggedValue::False(); 98 } 99 hashSet->SetSize(--nodeNum); 100 uint32_t length = hashArray->GetLength(); 101 ASSERT(length > 0); 102 uint32_t index = (length - 1) & hash; 103 JSTaggedValue rootVa = hashArray->Get(index); 104 if (rootVa.IsRBTreeNode()) { 105 uint32_t numTreeNode = RBTreeNode::Count(rootVa); 106 if (numTreeNode < TaggedHashArray::UNTREEIFY_THRESHOLD) { 107 JSHandle<RBTreeNode> root(thread, rootVa); 108 JSHandle<LinkedNode> head = RBTreeNode::Detreeing(thread, root); 109 hashArray->Set(thread, index, head); 110 } 111 } 112 return JSTaggedValue::True(); 113} 114} 115