Control RBTree root node as black

Issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/IAODIK

Signed-off-by: chenhantao <chenhantao3@huawei.com>
Change-Id: I3a8efbbf19e8b79924944b97425d9a9ca547b8d9
This commit is contained in:
chenhantao 2024-09-03 11:09:02 +08:00
parent 8faea49627
commit 9c2b8e8158
3 changed files with 159 additions and 0 deletions

View File

@ -245,6 +245,12 @@ JSTaggedValue TaggedHashArray::RemoveNode(JSThread *thread, int hash, JSTaggedVa
} else if (node.IsRBTreeNode()) {
JSTaggedValue oldValue = JSTaggedValue::Hole();
JSTaggedValue rootTreeNodeVa = RBTreeNode::Delete(thread, node, hash, key, oldValue);
//set root node as red
RBTreeNode *root = RBTreeNode::Cast(rootTreeNodeVa.GetTaggedObject());
if (root->GetIsRed().ToBoolean()) {
root->SetIsRed(thread, JSTaggedValue(false));
rootTreeNodeVa = JSTaggedValue(root);
}
if (!rootTreeNodeVa.IsHole()) {
Set(thread, index, rootTreeNodeVa);
return oldValue;

View File

@ -328,6 +328,7 @@ JSTaggedValue RBTreeNode::DeleteMin(JSThread *thread, RBTreeNode *treeNode)
RBTreeNode *leftChild = RBTreeNode::Cast(treeNode->GetLeft().GetTaggedObject());
if (!IsRed(treeNode->GetLeft()) && !IsRed(leftChild->GetLeft())) {
treeNode = treeNode->MoveRedLeft(thread);
leftChild = RBTreeNode::Cast(treeNode->GetLeft().GetTaggedObject());
}
treeNode->SetLeft(thread, DeleteMin(thread, leftChild));

View File

@ -253,6 +253,87 @@ HWTEST_F_L0(TaggedHashArrayTest, RemoveTreeNode)
EXPECT_EQ(hashTreeNode->GetCount(), 1U);
}
bool HasNode(JSTaggedValue hashTreeNodeVa, JSTaggedValue key)
{
if (hashTreeNodeVa.IsHole()) {
return false;
}
RBTreeNode *hashTreeNode = RBTreeNode::Cast(hashTreeNodeVa.GetTaggedObject());
JSTaggedValue rootKey = hashTreeNode->GetKey();
if (JSTaggedValue::SameValue(rootKey, key)) {
return true;
}
return HasNode(hashTreeNode->GetLeft(), key) || HasNode(hashTreeNode->GetRight(), key);
}
int CheckRBTreeNodeNums(JSTaggedValue hashTreeNodeVa, int count)
{
if (hashTreeNodeVa.IsHole()) {
return count;
}
count++;
int temp = count;
RBTreeNode *hashTreeNode = RBTreeNode::Cast(hashTreeNodeVa.GetTaggedObject());
return CheckRBTreeNodeNums(hashTreeNode->GetLeft(), count) +
CheckRBTreeNodeNums(hashTreeNode->GetRight(), count) - temp;
}
template <typename T>
bool CheckRBTreeOfAllPaths(JSHandle<T> &tree, int numsOfBlack, JSTaggedValue hashTreeNodeVa, int count)
{
if (hashTreeNodeVa.IsHole()) {
return count == numsOfBlack;
}
if (!RBTreeNode::IsRed(hashTreeNodeVa)) {
count++;
}
RBTreeNode *hashTreeNode = RBTreeNode::Cast(hashTreeNodeVa.GetTaggedObject());
if (CheckRBTreeOfAllPaths(tree, numsOfBlack, hashTreeNode->GetLeft(), count) &&
CheckRBTreeOfAllPaths(tree, numsOfBlack, hashTreeNode->GetRight(), count)) {
return true;
}
return false;
}
bool CheckRedNode(JSTaggedValue hashTreeNodeva)
{
if (hashTreeNodeva.IsHole()) {
return true;
}
RBTreeNode *hashTreeNode = RBTreeNode::Cast(hashTreeNodeva.GetTaggedObject());
JSTaggedValue leftChildVa = hashTreeNode->GetLeft();
JSTaggedValue rightChildVa = hashTreeNode->GetRight();
if (hashTreeNode->GetIsRed().ToBoolean()) {
if (!leftChildVa.IsHole() && RBTreeNode::IsRed(leftChildVa)) {
return false;
}
if (!rightChildVa.IsHole() && RBTreeNode::IsRed(rightChildVa)) {
return false;
}
}
return CheckRedNode(leftChildVa) && CheckRedNode(rightChildVa);
}
template <typename T>
bool CheckBlackNodeNumbers(JSHandle<T> &tree, JSHandle<RBTreeNode> hashTreeNode)
{
int numsOfBlack = 0;
JSTaggedValue ChildVa = hashTreeNode.GetTaggedValue();
while (!ChildVa.IsHole()) {
if (!RBTreeNode::IsRed(ChildVa)) {
numsOfBlack++;
}
ChildVa = RBTreeNode::Cast(ChildVa.GetTaggedObject())->GetLeft();
if (ChildVa.IsHole()) {
break;
}
}
return CheckRBTreeOfAllPaths(tree, numsOfBlack, hashTreeNode.GetTaggedValue(), 0);
}
template <typename T>
bool IsVaildRBTree(JSThread *thread, JSHandle<T> &tree, JSHandle<RBTreeNode> hashTreeNode)
{
@ -260,6 +341,10 @@ bool IsVaildRBTree(JSThread *thread, JSHandle<T> &tree, JSHandle<RBTreeNode> has
return true;
}
if (hashTreeNode->GetIsRed().ToBoolean()) {
return false;
}
JSTaggedValue leftChildVa = hashTreeNode->GetLeft();
JSTaggedValue rightChildVa = hashTreeNode->GetRight();
JSTaggedValue treeNodeKey = hashTreeNode->GetKey();
@ -279,9 +364,76 @@ bool IsVaildRBTree(JSThread *thread, JSHandle<T> &tree, JSHandle<RBTreeNode> has
}
}
// check red node
if (!CheckRedNode(leftChildVa) || !CheckRedNode(rightChildVa)) {
return false;
}
// check black node
if (!CheckBlackNodeNumbers(tree, hashTreeNode)) {
return false;
}
return true;
}
/**
* @tc.name: RemoveRBTreeNode
* @tc.desc: Call "Create" function Create TaggedHashArray object and "SetVal" function to add a key value pair to
* the taggedharray object,The value set is the RBTreeNode object,call "RemoveNode" function to delete a
* node, check if it can be hole then return.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(TaggedHashArrayTest, RemoveRBTreeNode)
{
int numOfElement = 1;
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<TaggedHashArray> taggedHashArray(thread, TaggedHashArray::Create(thread, numOfElement));
std::string myKey("mykey");
std::string myValue("myvalue");
HashCommon1(thread, taggedHashArray, myKey, myValue, static_cast<uint32_t>(numOfElement));
for (int i = numOfElement; i < numOfElement + 100; i++) {
JSHandle<JSTaggedValue> myKey1(factory->NewFromStdString(myKey + std::to_string(i)));
JSHandle<JSTaggedValue> myKey1Value(factory->NewFromStdString(myValue + std::to_string(i)));
auto keyHash = TaggedNode::Hash(thread, myKey1.GetTaggedValue());
TaggedHashArray::SetVal(thread, taggedHashArray, keyHash, myKey1, myKey1Value);
uint32_t keyHashIndex = static_cast<uint32_t>(numOfElement - 1) & keyHash;
JSHandle<RBTreeNode> hashTreeNode(thread, taggedHashArray->Get(keyHashIndex));
EXPECT_TRUE(IsVaildRBTree(thread, taggedHashArray, hashTreeNode));
}
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(2, 30);
for (int i = numOfElement; i < numOfElement + 20; i++) {
int index = dis(gen);
JSHandle<JSTaggedValue> myKey1(factory->NewFromStdString(myKey + std::to_string(index)));
auto keyHash = TaggedNode::Hash(thread, myKey1.GetTaggedValue());
uint32_t keyHashIndex = static_cast<uint32_t>(numOfElement - 1) & keyHash;
JSHandle<RBTreeNode> hashTreeNode(thread, taggedHashArray->Get(keyHashIndex));
EXPECT_EQ(taggedHashArray->GetLength(), numOfElement);
int beforeNum = CheckRBTreeNodeNums(taggedHashArray->Get(keyHashIndex), 0);
taggedHashArray->RemoveNode(thread, keyHash, myKey1.GetTaggedValue());
if (HasNode(taggedHashArray->Get(keyHashIndex), myKey1.GetTaggedValue())) {
EXPECT_EQ(beforeNum - 1, CheckRBTreeNodeNums(taggedHashArray->Get(keyHashIndex), 0));
}
EXPECT_TRUE(!HasNode(taggedHashArray->Get(keyHashIndex), myKey1.GetTaggedValue()));
JSHandle<RBTreeNode> hashTreeNode1(thread, taggedHashArray->Get(keyHashIndex));
EXPECT_TRUE(IsVaildRBTree(thread, taggedHashArray, hashTreeNode1));
JSHandle<JSTaggedValue> myKey2(factory->NewFromStdString(myKey + std::to_string(index + 100)));
JSHandle<JSTaggedValue> myKey2Value(factory->NewFromStdString(myValue + std::to_string(index + 100)));
auto keyHash1 = TaggedNode::Hash(thread, myKey2.GetTaggedValue());
uint32_t keyHashIndex1 = static_cast<uint32_t>(numOfElement - 1) & keyHash1;
beforeNum = CheckRBTreeNodeNums(taggedHashArray->Get(keyHashIndex1), 0);
TaggedHashArray::SetVal(thread, taggedHashArray, keyHash1, myKey2, myKey2Value);
if (!HasNode(taggedHashArray->Get(keyHashIndex1), myKey2.GetTaggedValue())) {
EXPECT_EQ(beforeNum + 1, CheckRBTreeNodeNums(taggedHashArray->Get(keyHashIndex1), 0));
}
EXPECT_TRUE(HasNode(taggedHashArray->Get(keyHashIndex1), myKey2.GetTaggedValue()));
JSHandle<RBTreeNode> hashTreeNode2(thread, taggedHashArray->Get(keyHashIndex1));
EXPECT_TRUE(IsVaildRBTree(thread, taggedHashArray, hashTreeNode2));
}
}
/**
* @tc.name: ResetLinkNodeSize
* @tc.desc: Call "Create" function Create TaggedHashArray object and "SetVal" function to add a key value pair to