/**************************************************************** * * * Copyright 2011 Fidelity Information Services, Inc * * * * This source code contains the intellectual property * * of its copyright holder(s), and is made available * * under a license. If you do not know the terms of * * the license, please stop and do not read further. * * * ****************************************************************/ #ifndef _TREE_H #define _TREE_H #include /* The "lvTree" typedef defines an AVL tree. One such structure exists for each local variable subscript level (starting from 0) * The "lvTreeNode" typedef defines the layout of the tree node. One structure exists for each tree node in an AVL tree. * e.g. if "a" is a local variable that has the following nodes defined * a(1)=1 * a(1,"a")=2 * a(1,"b")=3 * a(2,"c")=4 * There is ONE "lv_val" structure corresponding to the base local variable "a". * There are THREE "lvTree" structures (i.e. AVL trees) underneath the base local variable "a". * 1) One for the base variable "a". This contains the keys/subscripts 1 and 2. * 2) One for the subscripted variable "a(1)". This contains the keys/subscripts "a" and "b". * 3) One for the subscripted variable "a(2)". This contains the key/subscript "c". * There are FIVE "lvTreeNode" structures underneath the base local variable "a". * 1) One for subscript 1. * 2) One for subscript 2. * 3) One for subscript "a". * 4) One for subscript "b". * 5) One for subscript "c". */ typedef mval lvTreeNodeVal; typedef mval treeKeySubscr; /* A numeric key value stored in the AVL tree is represented in a lvTreeNodeNum structure. Additionally, a string type key can * also be stored in the same AVL tree. Instead of using an "mstr" type directly, we explicitly define the necessary fields * from the mstr (no char_len field) so we can save 8 bytes in the lvTreeNode struct on 64-bit platforms). This way both the * numeric and string lvTreeNode structures require 12 bytes thus have 8-byte alignment for the lvTreeNode* typedefs (on 64-bit * platforms) without any wasted padding space. This means that any code that interprets the key in a lvTreeNode structure * needs to examine the "key_mvtype" field and accordingly use a lvTreeNodeNum or lvTreeNodeStr structure to get at the key. */ typedef struct lvTreeNodeNumStruct { lvTreeNodeVal v; /* If string, will point to stringpool location */ struct lvTreeStruct *sbs_child; /* pointer to lvTreeStruct storing next level subscripts under this node */ struct lvTreeStruct *tree_parent; /* pointer to lvTreeStruct under whose avl tree this node belongs to */ unsigned short key_mvtype; /* will be (if non-integer) or (if integer) */ signed char balance; /* height(left) - height(right). Can be -1, 0, or 1 */ unsigned char descent_dir; /* direction of descent (LEFT = 0, RIGHT = 1) */ /* the value of the numeric key is stored in the key_* members below */ union { struct { unsigned char key_sgne; /* Contains sgn & e fields - fewer instructions to move this one byte * rather than two bit fields when copying to/from an mval */ } key_bytes; struct { # ifdef BIGENDIAN unsigned int key_sgn : 1; /* same as mval layout */ unsigned int key_e : 7; /* same as mval layout */ # else unsigned int key_e : 7; /* same as mval layout */ unsigned int key_sgn : 1; /* same as mval layout */ # endif unsigned int key_iconv : 1; /* 1 if (key_mvtype & MV_INT is TRUE) && (key_m0 field stores the * mval->m[1] value of the integer before it was converted into the * float representation. */ unsigned int filler :23; } key_bits; } key_flags; int4 key_m0; int4 key_m1; struct treeNodeStruct *avl_left; /* left AVL subtree at this subscript level */ struct treeNodeStruct *avl_right; /* right AVL subtree at this subscript level */ struct treeNodeStruct *avl_parent; /* parent node within the current subscript level AVL tree */ } lvTreeNodeNum; typedef struct treeNodeStruct { lvTreeNodeVal v; /* If string, will point to stringpool location */ struct lvTreeStruct *sbs_child; /* pointer to lvTreeStruct storing next level subscripts under this node; * overloaded as the free list pointer if this "lvTreeNode" is in the free list. */ struct lvTreeStruct *tree_parent; /* pointer to lvTreeStruct under whose avl tree this node belongs to */ unsigned short key_mvtype; /* will have MV_STR bit set */ signed char balance; /* height(left) - height(right). Can be -1, 0, or 1 */ unsigned char descent_dir; /* direction of descent (LEFT = 0, RIGHT = 1) */ uint4 key_len; /* byte length of string */ char *key_addr; /* pointer to string */ NON_GTM64_ONLY(uint4 filler_8byte;) /* needed to ensure lvTreeNodeNum & lvTreeNode structures have * same size & layout for 32-bit platforms also */ struct treeNodeStruct *avl_left; /* left AVL subtree at this subscript level */ struct treeNodeStruct *avl_right; /* right AVL subtree at this subscript level */ struct treeNodeStruct *avl_parent; /* parent node within the current subscript level AVL tree */ } lvTreeNode; /* Given a pointer to a "lvTreeNode" structure, the mvtype field will tell us whether it is a lvTreeNodeStr or lvTreeNodeNum type. * key_mvtype will have the MV_STR bit set in case of lvTreeNodeStr and otherwise if lvTreeNodeNum. */ typedef lvTreeNode lvTreeNodeStr; /* last lookup clue structure */ typedef struct { lvTreeNode *lastNodeLookedUp; /* pointer to the node that was last looked up using lvAvlTreeLookup function */ lvTreeNode *lastNodeMin; /* minimum value of key that can be underneath the last looked up node's subtree */ lvTreeNode *lastNodeMax; /* maximum value of key that can be underneath the last looked up node's subtree */ } treeSrchStatus; typedef struct lvTreeStruct { unsigned short ident; /* 2-byte field (same size as mvtype) set to the value MV_LV_TREE */ unsigned short sbs_depth; /* == "n" => all nodes in current avl tree represent lvns with "n" subscripts */ uint4 avl_height; /* Height of the AVL tree rooted at "avl_root" */ struct lv_val_struct *base_lv; /* back pointer to base var lv_val (subscript depth 0) */ lvTreeNode *avl_root; /* pointer to the root of the AVL tree corresponding to this subscript level; * overloaded as the free list pointer if this "lvTree" structure is in the free list. */ lvTreeNode *sbs_parent;/* pointer to parent (points to lv_val if sbs_depth==1 and lvTreeNode if sbs_depth>1) */ treeSrchStatus lastLookup; /* clue to last node lookup in the AVL tree rooted at "avl_root" */ } lvTree; /* This section defines macros for the AVL tree implementation. Note that an AVL tree maintains its log(n) height by ensuring * the left and right subtrees at any level never differ in height by more than 1. */ #define MAX_BALANCE 1 /* the maximum difference in height of the left and right subtrees of a tree, * balance > MAX_BALANCE will trigger a re-balance */ #define TREE_DESCEND_LEFT 0 #define TREE_DESCEND_RIGHT 1 /* AVL tree algorithms talk about balance factor as being -1 (left heavy), 1 (right heavy) or 0 (balanced) * but we use 0, 1 and 2 instead for this implementation. */ #define TREE_LEFT_HEAVY 0 /* should be same as TREE_DESCEND_LEFT (an implementation efficiency) */ #define TREE_RIGHT_HEAVY 1 /* should be same as TREE_DESCEND_RIGHT (an implementation efficiency) */ #define TREE_BALANCED 2 #define TREE_IS_LEFT_HEAVY(bal) (bal) == TREE_LEFT_HEAVY #define TREE_IS_RIGHT_HEAVY(bal) (bal) == TREE_RIGHT_HEAVY #define TREE_IS_BALANCED(bal) ((bal) == TREE_BALANCED) #define TREE_IS_NOT_BALANCED(bal) (!(TREE_IS_BALANCED(bal))) #define TREE_INVERT_BALANCE_FACTOR(bal) (tree_balance_invert[bal]) #define TREE_KEY_SUBSCR_IS_CANONICAL(A_MVTYPE) (A_MVTYPE & MV_CANONICAL) #define TREE_KEY_SUBSCR_SET_MV_CANONICAL_BIT(A_MVAL) (A_MVAL)->mvtype |= MV_CANONICAL #define TREE_KEY_SUBSCR_RESET_MV_CANONICAL_BIT(A_MVAL) (A_MVAL)->mvtype &= MV_CANONICAL_OFF /* Macro to get numeric valued subscript in an lv node */ #define LV_NUM_NODE_GET_KEY(NODE, KEY) \ { \ lvTreeNodeNum *lcl_flt_node; \ int lcl_mvtype; \ \ lcl_flt_node = (lvTreeNodeNum *)NODE; \ lcl_mvtype = lcl_flt_node->key_mvtype; \ assert(MVTYPE_IS_NUMERIC(lcl_mvtype)); \ if (MV_INT & lcl_mvtype) \ (KEY)->m[1] = lcl_flt_node->key_m0; \ else \ { \ assert(lcl_flt_node->key_flags.key_bits.key_e || !lcl_flt_node->key_m1); \ ((mval_b *)(KEY))->sgne = lcl_flt_node->key_flags.key_bytes.key_sgne; \ (KEY)->m[0] = lcl_flt_node->key_m0; \ (KEY)->m[1] = lcl_flt_node->key_m1; \ } \ (KEY)->mvtype = lcl_mvtype; \ } /* Macro to get string valued subscript in an lv node */ #define LV_STR_NODE_GET_KEY(NODE, KEY) \ { \ assert(MVTYPE_IS_STRING(NODE->key_mvtype)); \ (KEY)->mvtype = NODE->key_mvtype; \ (KEY)->str.len = NODE->key_len; \ (KEY)->str.addr = NODE->key_addr; \ } /* If NODE contains a numeric key, before returning the key's mval to non-lv code make sure we * reset any bit(s) that are set only in lv code. Non-lv code does not know to handle this bit. * The only one at this point in time is MV_CANONICAL. */ #define LV_NODE_GET_KEY(NODE, KEY_MVAL) \ { \ if (TREE_KEY_SUBSCR_IS_CANONICAL(NODE->key_mvtype)) \ { /* "NODE" is of type "lvTreeNodeNum *" */ \ LV_NUM_NODE_GET_KEY(NODE, KEY_MVAL); \ (KEY_MVAL)->mvtype &= MV_CANONICAL_OFF; \ } else /* "NODE" is of type "lvTreeNode *" */ \ LV_STR_NODE_GET_KEY(NODE, KEY_MVAL); \ } /* Macro to return if a given "lvTreeNode *" pointer is a null subscript string. * Input "node" could actually be any one of "lvTreeNodeNum *" or "lvTreeNode *". * A null subscript string is of actual type "lvTreeNode *". To minimize the checks, we check for the MV_STR bit in the mvtype. * This is asserted below. For "lvTreeNodeNum *", the MV_STR bit is guaranteed not to be set. That leaves us with "lvTreeNode *". */ #define LV_NODE_KEY_IS_STRING(NODE) (DBG_ASSERT(NULL != NODE) \ MVTYPE_IS_STRING(NODE->key_mvtype)) #define LV_NODE_KEY_IS_NULL_SUBS(NODE) (LV_NODE_KEY_IS_STRING(NODE) && (0 == NODE->key_len)) #ifdef DEBUG int lvAvlTreeKeySubscrCmp(treeKeySubscr *aSubscr, lvTreeNode *bNode); int lvAvlTreeNodeSubscrCmp(lvTreeNode *aNode, lvTreeNode *bNode); #endif lvTreeNode *lvAvlTreeFirst(lvTree *lvt); lvTreeNode *lvAvlTreeLast(lvTree *lvt); lvTreeNode *lvAvlTreePrev(lvTreeNode *node); lvTreeNode *lvAvlTreeKeyPrev(lvTree *lvt, treeKeySubscr *key); lvTreeNode *lvAvlTreeNext(lvTreeNode *node); lvTreeNode *lvAvlTreeKeyNext(lvTree *lvt, treeKeySubscr *key); lvTreeNode *lvAvlTreeFirstPostOrder(lvTree *lvt); lvTreeNode *lvAvlTreeNextPostOrder(lvTreeNode *node); lvTreeNode *lvAvlTreeKeyCollatedNext(lvTree *lvt, treeKeySubscr *key); lvTreeNode *lvAvlTreeNodeCollatedNext(lvTreeNode *node); lvTreeNode *lvAvlTreeCloneSubTree(lvTreeNode *node, lvTree *lvt, lvTreeNode *avl_parent); #ifdef DEBUG boolean_t lvTreeIsWellFormed(lvTree *lvt); void assert_tree_member_offsets(void); #endif lvTreeNode *lvAvlTreeLookupInt(lvTree *lvt, treeKeySubscr *key, lvTreeNode **lookupNode); lvTreeNode *lvAvlTreeLookupNum(lvTree *lvt, treeKeySubscr *key, lvTreeNode **lookupNode); lvTreeNode *lvAvlTreeLookupStr(lvTree *lvt, treeKeySubscr *key, lvTreeNode **lookupNode); lvTreeNode *lvAvlTreeLookup(lvTree *lvt, treeKeySubscr *key, lvTreeNode **lookupNode); lvTreeNode *lvAvlTreeNodeInsert(lvTree *lvt, treeKeySubscr *key, lvTreeNode *parent); void lvAvlTreeNodeDelete(lvTree *lvt, lvTreeNode *node); /* The following LV_TREE_* macros are not defined as functions for performance reasons (to avoid overhead of parameter passing * and C stack push and pop) */ #define LV_TREE_CREATE(NEWTREE, SBS_PARENT, SBS_DEPTH, BASE_LV) \ { \ DEBUG_ONLY(assert_tree_member_offsets()); \ NEWTREE = lvtree_getslot(LV_GET_SYMVAL(base_lv)); \ /* Note: the fields are initialized below in the order in which they are defined in the "lvTree" structure */ \ NEWTREE->ident = MV_LV_TREE; \ assert(0 < SBS_DEPTH); \ NEWTREE->sbs_depth = SBS_DEPTH; \ NEWTREE->avl_height = 0; \ NEWTREE->base_lv = BASE_LV; \ NEWTREE->avl_root = NULL; \ NEWTREE->sbs_parent = SBS_PARENT; /* note: LVT_PARENT macro not used as otherwise one would wonder why \ * all members of "lvTree" structure except "sbs_parent" are initialized. \ */ \ (SBS_PARENT)->sbs_child = NEWTREE; \ NEWTREE->lastLookup.lastNodeLookedUp = NULL; \ } #define LV_TREE_NODE_DELETE(LVT, NODE) \ { \ assert(NULL != LVT); \ lvAvlTreeNodeDelete(LVT, NODE); \ /* Now that "NODE" has been removed from the AVL tree, it is safe to free the slot */ \ LVTREENODE_FREESLOT(NODE); \ TREE_DEBUG_ONLY(assert(lvTreeIsWellFormed(LVT));) \ } #define LV_TREE_CLONE(LVT, SBS_PARENT, BASE_LV) \ { \ lvTree *cloneTree; \ lvTreeNode *avl_root; \ \ cloneTree = lvtree_getslot(LV_GET_SYMVAL(BASE_LV)); \ /* The following is optimized to do the initialization of just the needed structure members. \ * For that it assumes a particular "lvTree" structure layout. The assumed layout is asserted \ * so any changes to the layout will automatically alert us (by an assert failure) here and \ * cause the below initialization to be accordingly reworked. \ */ \ assert(8 == OFFSETOF(lvTree, base_lv)); \ assert(OFFSETOF(lvTree, base_lv) + SIZEOF(LVT->base_lv) == OFFSETOF(lvTree, avl_root)); \ assert(OFFSETOF(lvTree, avl_root) + SIZEOF(LVT->avl_root) == OFFSETOF(lvTree, sbs_parent)); \ assert(OFFSETOF(lvTree, sbs_parent) + SIZEOF(LVT->sbs_parent) == OFFSETOF(lvTree, lastLookup)); \ assert(OFFSETOF(lvTree, lastLookup) + SIZEOF(LVT->lastLookup) == SIZEOF(lvTree)); \ /* Note: We use "qw_num *" instead of "uint8 *" below because the former works on 32-bit platforms too. */ \ GTM64_ONLY(assert(IS_PTR_8BYTE_ALIGNED(cloneTree));) \ NON_GTM64_ONLY(assert(IS_PTR_4BYTE_ALIGNED(cloneTree));) \ GTM64_ONLY(assert(IS_PTR_8BYTE_ALIGNED(LVT));) \ NON_GTM64_ONLY(assert(IS_PTR_4BYTE_ALIGNED(LVT));) \ *(qw_num *)cloneTree = *(qw_num *)LVT; \ cloneTree->base_lv = BASE_LV; \ cloneTree->sbs_parent = SBS_PARENT; /* see comment in LV_TREE_CREATE macro (against sbs_parent \ * initialization) for why LVT_PARENT macro is not used */ \ (SBS_PARENT)->sbs_child = cloneTree; \ /* reset clue in cloned tree as source tree pointers are no longer relevant in cloned tree */ \ cloneTree->lastLookup.lastNodeLookedUp = NULL; \ if (NULL != (avl_root = (LVT)->avl_root)) \ cloneTree->avl_root = lvAvlTreeCloneSubTree(avl_root, cloneTree, NULL); \ else \ cloneTree->avl_root = NULL; \ } #ifdef TREE_DEBUG # define TREE_DEBUG1(p) {printf(p); fflush(stdout);} # define TREE_DEBUG2(p, q) {printf(p, q); fflush(stdout);} # define TREE_DEBUG3(p, q, r) {printf(p, q, r); fflush(stdout);} # define TREE_DEBUG4(p, q, r, s) {printf(p, q, r, s); fflush(stdout);} # define TREE_DEBUG5(p, q, r, s, t) {printf(p, q, r, s, t); fflush(stdout);} # define TREE_DEBUG_ONLY(X) X #else # define TREE_DEBUG1(p) # define TREE_DEBUG2(p, q) # define TREE_DEBUG3(p, q, r) # define TREE_DEBUG4(p, q, r, s) # define TREE_DEBUG5(p, q, r, s, t) # define TREE_DEBUG_ONLY(X) #endif #endif