blob: ad5df73e28c2e6dd22d2559caadb9d782b5768ed [file] [log] [blame]
///////////////////////////////////////////////////////////////////////////////
// //
// Copyright (c) 2000-2019 Ericsson Telecom AB //
// //
// All rights reserved. This program and the accompanying materials //
// are made available under the terms of the Eclipse Public License v2.0 //
// which accompanies this distribution, and is available at //
// https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html //
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
// Module: EPTF_CLL_RBtree_Functions
//
// Purpose:
// This module contains generic functions for TTCN-3 Red-Black tree implementation.
//
// Module depends on:
// <EPTF_CLL_Common_Functions>
// <EPTF_CLL_RBtree_Definitions>
// <EPTF_CLL_RBtree_PrivateFunctions>
//
// Current Owner:
// Rita Kovacs (ERITKOV)
//
// Last Review Date:
// 2007-12-06
//
// Detailed Comments:
// For detailed description on RBtree functionality, plse see <EPTF_CLL_RBtree_Definitions>.
//
// This module contains constants and generic functions for event scheduling.
// Using the functions of this module is recommended when design load module
// specific scheduler functions.
//
// - To remove a registered event from the tree <f_EPTF_RBTree_removeNode>.
//
// - To remove an event (node) from a cluster chain, call <f_EPTF_RBTree_removeNodeWithSameKey>.
//
// - For insertion and search-related functions, plse see <EPTF_CLL_RBtree_PrivateFunctions>.
//
///////////////////////////////////////////////////////////////
module EPTF_CLL_RBtree_Functions {
import from EPTF_CLL_Common_Functions all;
import from EPTF_CLL_RBtree_Definitions all;
import from EPTF_CLL_RBtree_PrivateFunctions all;
///////////////////////////////////////////////////////////
// Function: f_EPTF_RBTree_removeNodeWithSameKey
//
// Purpose:
// Function to remove an event (node) from a cluster chain.
//
// Parameters:
// rb_treeNodes - *inout* <EPTF_RBTreeNodeList> - red-black-tree nodes' list
// nodeToDeleteIndex - *in* *integer* - the node to be removed
// pl_root - *in* *integer* - root sentinel index of the tree
// pl_nil - *in* *integer* - leaf sentinel index of the tree
//
// Return Value:
// boolean - success
///////////////////////////////////////////////////////////
function f_EPTF_RBTree_removeNodeWithSameKey(
inout EPTF_RBTreeNodeList rb_treeNodes,
in integer nodeToDeleteIndex,
in integer pl_root,
in integer pl_nil
) return boolean {
var boolean vl_result := false;
// The node is in a cluster
if ( (rb_treeNodes[nodeToDeleteIndex].color == incluster) or (rb_treeNodes[nodeToDeleteIndex].isHeadInSameKeysCluster) ) {
// This element is not the first one in the cluster and so it is not in the tree.
if (rb_treeNodes[nodeToDeleteIndex].color == incluster) {
if(rb_treeNodes[nodeToDeleteIndex].fwd < 0) { // node is end of cluser
rb_treeNodes[rb_treeNodes[nodeToDeleteIndex].startOfClusterIdx].endOfClusterIdx :=
rb_treeNodes[nodeToDeleteIndex].bwd;
rb_treeNodes[rb_treeNodes[nodeToDeleteIndex].bwd].startOfClusterIdx :=
rb_treeNodes[nodeToDeleteIndex].startOfClusterIdx;
}
// [prevElement] [toDelete] [nextElement | -1]
// |--------->----------^
rb_treeNodes[rb_treeNodes[nodeToDeleteIndex].bwd].fwd := rb_treeNodes[nodeToDeleteIndex].fwd;
// If only one element left in the cluster, the cluster
// cease to exists and the Head element won't be head anymore.
if (rb_treeNodes[rb_treeNodes[nodeToDeleteIndex].bwd].fwd < 0) {
rb_treeNodes[rb_treeNodes[nodeToDeleteIndex].bwd].isHeadInSameKeysCluster := false;
}
// It is not the last element in the cluster: next element exists
if (rb_treeNodes[nodeToDeleteIndex].fwd > -1) {
// The next element of the node to delete
// will point back to the previous element of the node to delete.
// [prevElement] [toDelete] [nextElement]
// ^----------<---------------|
rb_treeNodes[rb_treeNodes[nodeToDeleteIndex].fwd].bwd := rb_treeNodes[nodeToDeleteIndex].bwd;
}
rb_treeNodes[nodeToDeleteIndex].color := unused; // ???
rb_treeNodes[nodeToDeleteIndex].bwd := -1;
rb_treeNodes[nodeToDeleteIndex].fwd := -1;
vl_result := true;
} else {
// color != incluster
// if this is the first element of the cluster and is on the tree
if (rb_treeNodes[nodeToDeleteIndex].isHeadInSameKeysCluster) {
// If a next element exists...
if (rb_treeNodes[nodeToDeleteIndex].fwd > -1) {
rb_treeNodes[rb_treeNodes[nodeToDeleteIndex].fwd].endOfClusterIdx :=
rb_treeNodes[nodeToDeleteIndex].endOfClusterIdx;
rb_treeNodes[rb_treeNodes[nodeToDeleteIndex].endOfClusterIdx].startOfClusterIdx :=
rb_treeNodes[nodeToDeleteIndex].fwd;
// ... the next element will be the head of the cluster.
// The next element replaces the head element in the tree.
rb_treeNodes[rb_treeNodes[nodeToDeleteIndex].fwd].parent := rb_treeNodes[nodeToDeleteIndex].parent;
rb_treeNodes[rb_treeNodes[nodeToDeleteIndex].fwd].right := rb_treeNodes[nodeToDeleteIndex].right;
rb_treeNodes[rb_treeNodes[nodeToDeleteIndex].fwd].left := rb_treeNodes[nodeToDeleteIndex].left;
rb_treeNodes[rb_treeNodes[nodeToDeleteIndex].fwd].color := rb_treeNodes[nodeToDeleteIndex].color;
rb_treeNodes[rb_treeNodes[nodeToDeleteIndex].fwd].isHeadInSameKeysCluster := true;
rb_treeNodes[rb_treeNodes[nodeToDeleteIndex].fwd].bwd := -1;
// The parents of the children of the element to be deleted are set to point to the new head.
if (rb_treeNodes[nodeToDeleteIndex].left > -1 and rb_treeNodes[nodeToDeleteIndex].left != pl_nil) {
// left child's parent
rb_treeNodes[rb_treeNodes[nodeToDeleteIndex].left].parent := rb_treeNodes[nodeToDeleteIndex].fwd;
}
if (rb_treeNodes[nodeToDeleteIndex].right > -1 and rb_treeNodes[nodeToDeleteIndex].right != pl_nil) {
// right child's parent
rb_treeNodes[rb_treeNodes[nodeToDeleteIndex].right].parent := rb_treeNodes[nodeToDeleteIndex].fwd;
}
// Existing tree parent element will point to
// the new head of cluster node. If the parent is exists...
if (rb_treeNodes[nodeToDeleteIndex].parent > -1 and rb_treeNodes[nodeToDeleteIndex].parent != pl_root) {
// the head element was a left or right?
if (rb_treeNodes[rb_treeNodes[nodeToDeleteIndex].parent].left == nodeToDeleteIndex) {
// left
rb_treeNodes[rb_treeNodes[nodeToDeleteIndex].parent].left := rb_treeNodes[nodeToDeleteIndex].fwd;
} else {
// right
rb_treeNodes[rb_treeNodes[nodeToDeleteIndex].parent].right := rb_treeNodes[nodeToDeleteIndex].fwd;
}
}
// !!! MODIFIED ---------------------
else if (rb_treeNodes[nodeToDeleteIndex].parent == pl_root) {
// The node to be deleted is the root (its parent is the root sentinel)
// The child become the root of the tree.
rb_treeNodes[pl_root].left := rb_treeNodes[nodeToDeleteIndex].fwd;
}
// !!! END OF MODIFIED ---------------------
// If only one element left in the cluster, the cluster
// cease to exist and the Head element won't be head anymore.
if (rb_treeNodes[rb_treeNodes[nodeToDeleteIndex].fwd].fwd < 0) {
rb_treeNodes[rb_treeNodes[nodeToDeleteIndex].fwd].isHeadInSameKeysCluster := false;
}
// The old head element won't be head any more
rb_treeNodes[nodeToDeleteIndex].isHeadInSameKeysCluster := false;
// --- The next element has replaced the previous head element in tree ---
vl_result := true;
}
}
}
}
return vl_result;
}
///////////////////////////////////////////////////////////
// Function: f_EPTF_RBTree_removeNode
//
// Purpose:
// Removes an element from the given tree.
//
// Parameters:
// rb_treeNodes - *inout* <EPTF_RBTreeNodeList> - red-black-tree nodes' list
// pl_z - *in* *integer* - the node's index to be removed
// pl_root - *in* *integer* - root sentinel index of the red-black-tree
// pl_nil - *in* *integer* - leaf sentinel index of the red-black-tree
//
// Return Value:
// (none)
///////////////////////////////////////////////////////////
function f_EPTF_RBTree_removeNode(
inout EPTF_RBTreeNodeList rb_treeNodes,
in integer pl_z,
in integer pl_root,
in integer pl_nil
)
{
if (pl_z == pl_root or pl_z == pl_nil) {f_EPTF_Common_error("ERROR: you are about to delete a sentinel node (NOT recommended)!!!");return;}
var integer vl_y;
var integer vl_x;
if ((rb_treeNodes[pl_z].left == pl_nil) or
(rb_treeNodes[pl_z].right == pl_nil)) {
vl_y := pl_z;
} else {
vl_y := f_EPTF_RBTree_getSuccessorOf(rb_treeNodes, pl_z, pl_root, pl_nil);
}
if (rb_treeNodes[vl_y].left == pl_nil) {
vl_x := rb_treeNodes[vl_y].right;
} else {
vl_x := rb_treeNodes[vl_y].left;
}
rb_treeNodes[vl_x].parent := rb_treeNodes[vl_y].parent;
if (pl_root == rb_treeNodes[vl_x].parent) {
rb_treeNodes[pl_root].left := vl_x; // setting the REAL root element to x.
} else {
if (vl_y == rb_treeNodes[rb_treeNodes[vl_y].parent].left) {
rb_treeNodes[rb_treeNodes[vl_y].parent].left := vl_x;
} else {
rb_treeNodes[rb_treeNodes[vl_y].parent].right := vl_x;
}
}
if (vl_y != pl_z) { // y should not be nil in this case
// y is the node to splice out and x is its child
if (rb_treeNodes[vl_y].color == black) {
f_EPTF_RBTree_helpTreeRemove(rb_treeNodes, vl_x, pl_root, pl_nil);
}
rb_treeNodes[vl_y].left := rb_treeNodes[pl_z].left;
rb_treeNodes[vl_y].right := rb_treeNodes[pl_z].right;
rb_treeNodes[vl_y].parent := rb_treeNodes[pl_z].parent;
rb_treeNodes[vl_y].color := rb_treeNodes[pl_z].color;
rb_treeNodes[rb_treeNodes[pl_z].left].parent := vl_y;
rb_treeNodes[rb_treeNodes[pl_z].right].parent := vl_y;
if (pl_z == rb_treeNodes[rb_treeNodes[pl_z].parent].left) {
rb_treeNodes[rb_treeNodes[pl_z].parent].left := vl_y;
} else {
rb_treeNodes[rb_treeNodes[pl_z].parent].right := vl_y;
}
// free (z)
} else {
if (rb_treeNodes[vl_y].color == black) {
f_EPTF_RBTree_helpTreeRemove(rb_treeNodes, vl_x, pl_root, pl_nil);
}
}
} // f_EPTF_RBTree_removeNode
} //module