| /////////////////////////////////////////////////////////////////////////////// |
| // // |
| // 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_RBtreeFloat_Functions |
| // |
| // Purpose: |
| // This module contains generic functions for TTCN-3 float Red-Black tree implementation. |
| // |
| // Module depends on: |
| // <EPTF_CLL_RBtree_Functions> |
| // <EPTF_CLL_RBtreeFloat_PrivateFunctions> |
| // <EPTF_CLL_RBtree_Definitions> |
| // <EPTF_CLL_Common_Definitions> |
| // |
| // Current Owner: |
| // Rita Kovacs (ERITKOV) |
| // |
| // Last Review Date: |
| // 2007-12-06 |
| // |
| // Detailed Comments: |
| // This module contains constants and functions for float-keyed event scheduling. |
| // |
| // - To register a float event for the tree, call <f_EPTF_RBTreeF_createNewFloatNode>. |
| // |
| // - To remove a registered float event from the tree, call <f_EPTF_RBTreeF_removeFloatNode>. |
| // |
| // - To to remove a float-identified event (node) from a cluster chain, call <f_EPTF_RBTreeF_removeFloatNodeWithSameKey>. |
| // |
| // - To initiate a tree of float-identified nodes, call <f_EPTF_RBTreeF_initFloatTree>. |
| // |
| // - To get float node by key, call <f_EPTF_RBTreeF_getFloatNodeByKey>. |
| // |
| // - To get smallest float key node, call <f_EPTF_RBTreeF_searchSmallestNode>. |
| // |
| /////////////////////////////////////////////////////////////// |
| |
| module EPTF_CLL_RBtreeFloat_Functions { |
| |
| import from EPTF_CLL_RBtree_Definitions all; |
| import from EPTF_CLL_RBtreeFloat_PrivateFunctions all; |
| import from EPTF_CLL_RBtree_PrivateFunctions all; |
| import from EPTF_CLL_RBtree_Functions all; |
| import from EPTF_CLL_Common_Definitions all; |
| |
| |
| |
| /////////////////////////////////////////////////////////// |
| // Function: f_EPTF_RBTreeF_createNewFloatNode |
| // |
| // Purpose: |
| // Function to register a float-identified event (new node) for the tree. |
| // |
| // Parameters: |
| // rb_Tree - *inout* <EPTF_Float_RedBlackTree> - the up-to-date red-black-tree |
| // key - *in* *float* - the node to be registered |
| // data - *in* <EPTF_IntegerList> - data field of the node identified by float key value |
| // |
| // Return Value: |
| // integer - the index of the new node in the given Tree |
| /////////////////////////////////////////////////////////// |
| public function f_EPTF_RBTreeF_createNewFloatNode(inout EPTF_Float_RedBlackTree rb_Tree, in float key, in EPTF_IntegerList data) return integer { |
| |
| var integer Result; |
| var integer I := f_EPTF_RBTreeF_getFreeSlotFloat(rb_Tree); |
| |
| rb_Tree.nodes[I] := c_EPTF_emptyRBTNode; |
| rb_Tree.nodes[I].left := rb_Tree.nil; |
| rb_Tree.nodes[I].right := rb_Tree.nil; |
| rb_Tree.nodes[I].parent := rb_Tree.nil; |
| |
| rb_Tree.floatKeyData[I] := {key, data}; |
| Result := I; |
| |
| if (rb_Tree.smallestKeyIndex == -1) { |
| rb_Tree.smallestKeyIndex := I; |
| rb_Tree.isSmallestCacheValid := true; |
| } else { |
| if ((rb_Tree.isSmallestCacheValid) and (rb_Tree.floatKeyData[rb_Tree.smallestKeyIndex].key > key)) { |
| rb_Tree.smallestKeyIndex := I; |
| } |
| } |
| |
| f_EPTF_RBTreeF_insertFloat(rb_Tree, I); |
| return Result; |
| } |
| |
| /////////////////////////////////////////////////////////// |
| // Function: f_EPTF_RBTreeF_removeFloatNodeWithSameKey |
| // |
| // Purpose: |
| // Function to remove a float-identified event (node) from a cluster chain. |
| // |
| // Parameters: |
| // rb_Tree - *inout* <EPTF_Float_RedBlackTree> - the up-to-date red-black-tree |
| // pl_nodeToDeleteIndex - *in* *integer* - the node to be removed |
| // |
| // Return Value: |
| // boolean - value returned by function <f_EPTF_RBTree_removeNodeWithSameKey> () |
| /////////////////////////////////////////////////////////// |
| public function f_EPTF_RBTreeF_removeFloatNodeWithSameKey(inout EPTF_Float_RedBlackTree rb_Tree, in integer pl_nodeToDeleteIndex) return boolean { |
| return f_EPTF_RBTree_removeNodeWithSameKey(rb_Tree.nodes, pl_nodeToDeleteIndex, rb_Tree.root, rb_Tree.nil); |
| } |
| |
| /////////////////////////////////////////////////////////// |
| // Function: f_EPTF_RBTreeF_removeFloatNode |
| // |
| // Purpose: |
| // Removes a float-identified node from the given tree. |
| // Also sets the appropriate index pointers... |
| // |
| // Parameters: |
| // rb_Tree - *inout* <EPTF_Float_RedBlackTree> - the up-to-date red-black-tree itself |
| // pl_z - *in* *integer* - the float node index to be removed |
| // pl_destroyNode - *in* *boolean* - If true: the node will be also destroyed and placed into the free nodes list. |
| // If false: the node will be marked as invalid and will not be placed into the free nodes list. |
| // HINT: <f_EPTF_RBTreeF_destroyInvalidFloatNode> should be called when this node is not needed anymore. |
| // |
| // Return Value: |
| // boolean - success |
| /////////////////////////////////////////////////////////// |
| public function f_EPTF_RBTreeF_removeFloatNode(inout EPTF_Float_RedBlackTree rb_Tree, in integer pl_z, in boolean pl_destroyNode) { |
| |
| // Storing number of nodes |
| rb_Tree.nOfElements := rb_Tree.nOfElements - 1; |
| |
| if (f_EPTF_RBTreeF_removeFloatNodeWithSameKey(rb_Tree, pl_z)) { |
| // The node pl_z was in a cluster (maybe was the head of a cluster) and |
| // it's removal has been handled. |
| // The same key (pl_z) further exists in the Tree. |
| |
| // We only finish the removal here. |
| if (pl_destroyNode) { |
| f_EPTF_RBTreeF_destroyFloatNode(rb_Tree, pl_z); |
| } else { |
| f_EPTF_RBTreeF_invalidateFloatNode(rb_Tree, pl_z); |
| } |
| // if we are to remove node with smallest key, content of cache shall be invalid from now on |
| if (rb_Tree.smallestKeyIndex == pl_z) { |
| rb_Tree.isSmallestCacheValid := false; //PERFORMANCE IMPROVEMENT POSSIBILITY: you can set cache true here after setting |
| //smallestKeyIndex to the new head item of cluster chain, if such item exists!! |
| } |
| |
| // EXIT |
| return; |
| } |
| |
| // if we are to remove node with smallest key, content of cache shall be invalid from now on |
| if (rb_Tree.smallestKeyIndex == pl_z) { |
| rb_Tree.isSmallestCacheValid := false; |
| } |
| |
| f_EPTF_RBTree_removeNode(rb_Tree.nodes, pl_z, rb_Tree.root, rb_Tree.nil); |
| if (pl_destroyNode) { |
| f_EPTF_RBTreeF_destroyFloatNode(rb_Tree, pl_z); |
| } else { |
| f_EPTF_RBTreeF_invalidateFloatNode(rb_Tree, pl_z); |
| } |
| } // f_EPTF_RBTreeF_removeFloatNode |
| |
| /////////////////////////////////////////////////////////// |
| // Function: f_EPTF_RBTreeF_destroyInvalidFloatNode |
| // |
| // Purpose: |
| // deletes invalid float node |
| // |
| // Parameters: |
| // pl_tree - *inout* <EPTF_Float_RedBlackTree> - the up-to-date float red-black-tree |
| // pl_z - *in* *integer* - index of the invalid float tree node to delete |
| // |
| // Return Value: |
| // boolean - success |
| /////////////////////////////////////////////////////////// |
| public function f_EPTF_RBTreeF_destroyInvalidFloatNode(inout EPTF_Float_RedBlackTree pl_tree, in integer pl_z) return boolean { |
| // if we are to remove node with smallest key, content of cache shall be invalid from now on |
| if (pl_tree.smallestKeyIndex == pl_z) { |
| pl_tree.isSmallestCacheValid := false; |
| } |
| return f_EPTF_RBTree_destroyInvalidNode(pl_tree.nodes, pl_tree.freeHead, pl_tree.freeTail, pl_z); |
| } |
| |
| /////////////////////////////////////////////////////////// |
| // Function: f_EPTF_RBTreeF_initFloatTree |
| // |
| // Purpose: |
| // Initiates a tree of float-identified nodes. |
| // Also initiates the appropriate index pointers |
| // |
| // Parameters: |
| // rb_Tree - *inout* <EPTF_Float_RedBlackTree> - the red-black-tree to init |
| // |
| // Return Value: |
| // (none) |
| /////////////////////////////////////////////////////////// |
| public function f_EPTF_RBTreeF_initFloatTree(inout EPTF_Float_RedBlackTree rb_Tree){ |
| rb_Tree := c_EPTF_emptyFloatRBTree; |
| rb_Tree.acceptableMaxSize := tsp_CLL_debug_acceptableMaxSizeOfGrowingVariables; |
| |
| // creating sentinel objects... |
| // ...leaf (nil) |
| var integer newSentinel := f_EPTF_RBTreeF_getFreeSlotFloat(rb_Tree); |
| rb_Tree.nodes[newSentinel] := c_EPTF_emptyRBTNode; |
| rb_Tree.floatKeyData[newSentinel] := {0.0,{}}; |
| |
| rb_Tree.nodes[newSentinel].left := newSentinel; |
| rb_Tree.nodes[newSentinel].right := newSentinel; |
| rb_Tree.nodes[newSentinel].parent := newSentinel; |
| rb_Tree.nodes[newSentinel].color := black; |
| rb_Tree.nodes[newSentinel].isSentinel := true; |
| |
| rb_Tree.nil := newSentinel; |
| |
| // ... and root |
| newSentinel := f_EPTF_RBTreeF_getFreeSlotFloat(rb_Tree); |
| |
| rb_Tree.nodes[newSentinel] := c_EPTF_emptyRBTNode; |
| rb_Tree.floatKeyData[newSentinel] := {0.0,{}}; |
| |
| rb_Tree.nodes[newSentinel].left := rb_Tree.nil; |
| rb_Tree.nodes[newSentinel].right := rb_Tree.nil; |
| rb_Tree.nodes[newSentinel].parent := rb_Tree.nil; |
| rb_Tree.nodes[newSentinel].color := black; |
| rb_Tree.nodes[newSentinel].isSentinel := true; |
| |
| rb_Tree.root := newSentinel; |
| |
| } // f_EPTF_RBTreeF_initFloatTree |
| |
| /////////////////////////////////////////////////////////// |
| // Function: f_EPTF_RBTreeF_getFloatNodeByKey |
| // |
| // Purpose: |
| // returns the given float-keyed node from the given tree |
| // |
| // Parameters: |
| // rb_Tree - *inout* <EPTF_Float_RedBlackTree> - the red-black-tree |
| // pl_key - *in* *float* - the float node index to find |
| // pl_nodeFound - *out* <EPTF_RBTreeNode> - the found float node |
| // pl_indexFound - *out* *integer* - the index of the found node |
| // |
| // Return Value: |
| // boolean - success |
| /////////////////////////////////////////////////////////// |
| public function f_EPTF_RBTreeF_getFloatNodeByKey(inout EPTF_Float_RedBlackTree rb_Tree, in float pl_key, out EPTF_FloatNode pl_nodeFound, out integer pl_indexFound) return boolean { |
| |
| var boolean vl_isFound := false; |
| pl_indexFound := -1; |
| |
| vl_isFound := f_EPTF_RBTreeF_getFloatNodeIndexByKey(rb_Tree, pl_key, pl_indexFound); |
| if (vl_isFound) { |
| pl_nodeFound := rb_Tree.floatKeyData[pl_indexFound]; |
| } |
| return vl_isFound; |
| } |
| |
| /////////////////////////////////////////////////////////// |
| // Function: f_EPTF_RBTreeF_searchSmallestNode |
| // |
| // Purpose: |
| // Get smallest float key node from the given tree. |
| // |
| // Parameters: |
| // tree - *inout* <EPTF_Float_RedBlackTree> - the float red-black-tree |
| // pl_nodeFound - *out* <EPTF_FloatNode> - smallest key float node |
| // pl_indexFound - *out* *integer* - the index of the found node |
| // |
| // Return Value: |
| // boolean - success |
| /////////////////////////////////////////////////////////// |
| public function f_EPTF_RBTreeF_searchSmallestNode(inout EPTF_Float_RedBlackTree tree, out EPTF_FloatNode pl_nodeFound, out integer pl_indexFound) return boolean { |
| |
| var boolean vl_isFound := false; |
| pl_indexFound := f_EPTF_RBTreeF_searchSmallestNodeIndex(tree); |
| if (pl_indexFound != -1) { |
| vl_isFound := true; |
| pl_nodeFound := tree.floatKeyData[pl_indexFound]; |
| } |
| return vl_isFound; |
| } |
| |
| /////////////////////////////////////////////////////////// |
| // Function: f_EPTF_RBTreeF_getSmallestNodeFromCache |
| // |
| // Purpose: |
| // Get smallest float key node from the given tree. Refreshes cache automatically. |
| // |
| // Parameters: |
| // rb_Tree - *inout* <EPTF_Float_RedBlackTree> - the float red-black-tree itself |
| // pl_nodeFound - *out* <EPTF_FloatNode> - shall be the smallest node of RBTree |
| // |
| // Return Value: |
| // boolean - success |
| /////////////////////////////////////////////////////////// |
| public function f_EPTF_RBTreeF_getSmallestNodeFromCache(inout EPTF_Float_RedBlackTree rb_Tree, out EPTF_FloatNode pl_nodeFound) return boolean { |
| var boolean isFound := true; |
| var integer x := -1; |
| |
| if (f_EPTF_RBTreeF_getSmallestNodeIndexFromCache(rb_Tree, x)) { |
| isFound := true; |
| pl_nodeFound := rb_Tree.floatKeyData[x]; |
| } else { |
| // The tree is empty. |
| isFound := false; |
| } |
| |
| return isFound; |
| } |
| |
| /////////////////////////////////////////////////////////// |
| // Function: f_RBTree_getBusyEventHeadIndex |
| // |
| // Purpose: |
| // Get the head node of busy event tree. |
| // |
| // Parameters: |
| // rb_Tree - *inout* <EPTF_Float_RedBlackTree> - the float red-black-tree itself |
| // pl_idx - *inout* *integer* - shall be the head element of busy event tree (smallest) |
| // |
| // Return Value: |
| // boolean - success |
| /////////////////////////////////////////////////////////// |
| public function f_RBTree_getBusyEventHeadIndex(inout EPTF_Float_RedBlackTree rb_Tree, inout integer pl_idx) return boolean { |
| |
| return f_EPTF_RBTreeF_getSmallestNodeIndexFromCache(rb_Tree, pl_idx); |
| } |
| |
| /////////////////////////////////////////////////////////// |
| // Function: f_RBTree_getNextSmallestFloatElementIndex |
| // |
| // Purpose: |
| // Get the next smallest node index of busy event tree. |
| // |
| // Parameters: |
| // pl_tree - *inout* <EPTF_Float_RedBlackTree> - the float red-black-tree itself |
| // pl_curSmallestIndex - *in* *integer* - is the node of busy event tree the search supposed to start from |
| // pl_indexFound - *out* *integer* - shall be the next node of busy event tree |
| // |
| // Return Value: |
| // boolean - success |
| /////////////////////////////////////////////////////////// |
| public function f_RBTree_getNextSmallestFloatElementIndex(in EPTF_Float_RedBlackTree pl_tree, |
| in integer pl_curSmallestIndex, out integer pl_indexFound) return boolean { |
| |
| var boolean vl_isFound := false; |
| var integer vl_root := pl_tree.nodes[pl_tree.root].left; // the real root of the tree |
| var integer vl_nil := pl_tree.nil; |
| |
| // Checking cluster stuffs ... |
| if (pl_tree.nodes[pl_curSmallestIndex].isHeadInSameKeysCluster) { |
| // returning the second node (after the head of cluster) |
| pl_indexFound := pl_tree.nodes[pl_curSmallestIndex].fwd; |
| return true; |
| } else if (pl_tree.nodes[pl_curSmallestIndex].color == incluster) { |
| if (pl_tree.nodes[pl_curSmallestIndex].fwd != -1) { |
| // we have next node forward in the cluster: returning it |
| pl_indexFound := pl_tree.nodes[pl_curSmallestIndex].fwd; |
| return true; |
| } // at the end of the cluster: there is no more node in the cluster, |
| // we continue searchig with the algorythm... |
| } |
| |
| // Finding next smallest node from the tree |
| var integer vl_x := vl_root; |
| var integer vl_lastGoodIndex := -1; |
| var float vl_curSmallestKey := pl_tree.floatKeyData[pl_curSmallestIndex].key; |
| while (vl_x != vl_nil) { |
| if (pl_tree.floatKeyData[vl_x].key > vl_curSmallestKey) { |
| // the current node (x) can be good (bigger than the minimum) |
| // we go to left, so we might have just found a smaller good node |
| // we store the current node as a last good node yet |
| vl_lastGoodIndex := vl_x; |
| vl_x := pl_tree.nodes[vl_x].left; |
| } else { |
| // the current node is not good for us: bigger than or equal to |
| // the currently smallest node that was provided as a parameter |
| // we are going to the right: we may find a bigger node |
| vl_x := pl_tree.nodes[vl_x].right; |
| } |
| } // while |
| |
| // Calculating results... |
| if (vl_lastGoodIndex == -1) { |
| vl_isFound := false; |
| } else { |
| vl_isFound := true; |
| } |
| pl_indexFound := vl_lastGoodIndex; |
| return vl_isFound; |
| } |
| |
| } //module |