Ignore:
Timestamp:
Feb 4, 2008, 3:08:02 AM (18 years ago)
Author:
bird
Message:

kAVL: Implemented locking, root node and a direct cache.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/k/kAvlTmpl/kAvlBase.h

    r2 r7  
    4848 *
    4949 *  \#define KAVL_MAX_STACK
    50  *  Use this to specify the max number of stack entries the stack will use when inserting
    51  *  and removing nodes from the tree. The size should be something like
     50 *  Use this to specify the max number of stack entries the stack will use when
     51 *  inserting and removing nodes from the tree. The size should be something like
    5252 *      log2(<max nodes>) + 3
    5353 *  Must be defined.
     
    6262 *  the exact same distance.
    6363 *
     64 *  \#define KAVL_LOOKTHRU
     65 *  Define this to employ a lookthru cache (direct) to speed up lookup for
     66 *  some usage patterns. The value should be the number of members of the
     67 *   array.
     68 *
     69 *  \#define KAVL_LOOKTHRU_HASH(Key)
     70 *  Define this to specify a more efficient translation of the key into
     71 *  a lookthru array index. The default is key % size.
     72 *  For some key types this is required as the default will not compile.
     73 *
     74 *  \#define KAVL_LOCKED
     75 *  Define this if you wish for the tree to be locked via the
     76 *  KAVL_WRITE_LOCK,  KAVL_WRITE_UNLOCK, KAVL_READ_LOCK and
     77 *  KAVL_READ_UNLOCK macros. If not defined the tree will not be subject
     78 *  do any kind of locking and the problem of concurrency is left the user.
     79 *
     80 *  \#define KAVL_WRITE_LOCK(pRoot)
     81 *  Lock the tree for writing.
     82 *
     83 *  \#define KAVL_WRITE_UNLOCK(pRoot)
     84 *  Counteracts KAVL_WRITE_LOCK.
     85 *
     86 *  \#define KAVL_READ_LOCK(pRoot)
     87 *  Lock the tree for reading.
     88 *
     89 *  \#define KAVL_READ_UNLOCK(pRoot)
     90 *  Counteracts KAVL_READ_LOCK.
     91 *
    6492 *  \#define KAVLKEY
    6593 *  Define this to the name of the AVL key type.
     
    6896 *  Define this to use the standard key compare macros. If not set all the
    6997 *  compare operations for KAVLKEY have to be defined: KAVL_G, KAVL_E, KAVL_NE,
    70  *  KAVL_R_IS_IDENTICAL, KAVL_R_IS_INTERSECTING and KAVL_R_IS_IN_RANGE. The latter
    71  *  three are only required when KAVL_RANGE is defined.
     98 *  KAVL_R_IS_IDENTICAL, KAVL_R_IS_INTERSECTING and KAVL_R_IS_IN_RANGE. The
     99 *  latter three are only required when KAVL_RANGE is defined.
    72100 *
    73101 *  \#define KAVLNODE
     
    83111 *  to KAVLNODE *.
    84112 *
     113 *  \#define KAVLROOT
     114 *  Define this to the name (typedef) of the AVL root structure. This
     115 *  is optional. However, if specified it must at least have a mpRoot
     116 *  member of KAVLTREEPTR type. If KAVL_LOOKTHRU is non-zero a
     117 *  maLookthru[KAVL_LOOKTHRU] member of the KAVLTREEPTR type is also
     118 *  required.
     119 *
    85120 *  \#define KAVL_FN
    86121 *  Use this to alter the names of the AVL functions.
     
    160195#ifndef KAVLTREEPTR
    161196# define KAVLTREEPTR                        KAVLNODE *
     197#endif
     198
     199#ifndef KAVLROOT
     200# define KAVLROOT                           KAVL_TYPE(,ROOT)
     201# define KAVL_NEED_KAVLROOT
     202#endif
     203
     204#ifdef KAVL_LOOKTHRU
     205# ifndef KAVL_LOOKTHRU_HASH
     206#  define KAVL_LOOKTHRU_HASH(Key)           ( (Key) % (KAVL_LOOKTHRU) )
     207# endif
     208#elif defined(KAVL_LOOKTHRU_HASH)
     209# error "KAVL_LOOKTHRU_HASH without KAVL_LOOKTHRU!"
     210#endif
     211
     212#ifdef KAVL_LOOKTHRU
     213# define KAVL_LOOKTHRU_INVALIDATE_NODE(pRoot, pNode, Key) \
     214    do { \
     215        KAVLTREEPTR **ppEntry = &pRoot->maLookthru[KAVL_LOOKTHRU_HASH(Key)]; \
     216        if ((pNode) == KAVL_GET_POINTER_NULL(ppEntry)) \
     217            *ppEntry = KAVL_NULL; \
     218    } while (0)
     219#else
     220# define KAVL_LOOKTHRU_INVALIDATE_NODE(pRoot, pNode, Key) do { } while (0)
     221#endif
     222
     223#ifndef KAVL_LOCKED
     224# define KAVL_WRITE_LOCK(pRoot)             do { } while (0)
     225# define KAVL_WRITE_UNLOCK(pRoot)           do { } while (0)
     226# define KAVL_READ_LOCK(pRoot)              do { } while (0)
     227# define KAVL_READ_UNLOCK(pRoot)            do { } while (0)
    162228#endif
    163229
     
    219285typedef int (* KAVL_TYPE(PFN,CALLBACK))(KAVLNODE *, void *);
    220286
     287#ifdef KAVL_NEED_KAVLROOT
     288/**
     289 * The AVL root structure.
     290 */
     291typedef struct
     292{
     293    KAVLTREEPTR     mpRoot;
     294# ifdef KAVL_LOOKTHRU
     295    KAVLTREEPTR     maLookthru[KAVL_LOOKTHRU];
     296# endif
     297} KAVLROOT;
     298#endif
    221299
    222300
     
    343421
    344422/**
     423 * Initializes the root of the AVL-tree.
     424 *
     425 * @param     pTree     Pointer to the root structure.
     426 */
     427KAVL_DECL(void) KAVL_FN(Init)(KAVLROOT *pRoot)
     428{
     429#ifdef KAVL_LOOKTHRU
     430    unsigned i;
     431#endif
     432
     433    pRoot->mpRoot = KAVL_NULL;
     434#ifdef KAVL_LOOKTHRU
     435    for (i = 0; i < (KAVL_LOOKTHRU); i++)
     436        pRoot->maLookthru[i] = KAVL_NULL;
     437#endif
     438}
     439
     440
     441/**
    345442 * Inserts a node into the AVL-tree.
    346  * @returns   TRUE if inserted.
    347  *            FALSE if node exists in tree.
    348  * @param     ppTree  Pointer to the AVL-tree root node pointer.
    349  * @param     pNode   Pointer to the node which is to be added.
     443 * @returns   K_TRUE if inserted.
     444 *            K_FALSE if node exists in tree.
     445 * @param     pRoot     Pointer to the AVL-tree root structure.
     446 * @param     pNode     Pointer to the node which is to be added.
    350447 * @sketch    Find the location of the node (using binary tree algorithm.):
    351448 *            LOOP until NULL leaf pointer
     
    360457 *            Rebalance the tree.
    361458 */
    362 KAVL_DECL(KBOOL) KAVL_FN(Insert)(KAVLTREEPTR *ppTree, KAVLNODE *pNode)
     459KAVL_DECL(KBOOL) KAVL_FN(Insert)(KAVLROOT *pRoot, KAVLNODE *pNode)
    363460{
    364461    KAVL_INT(STACK)     AVLStack;
    365     KAVLTREEPTR        *ppCurNode = ppTree;
     462    KAVLTREEPTR        *ppCurNode = &pRoot->mpRoot;
    366463    register KAVLKEY    Key = pNode->mKey;
    367464#ifdef KAVL_RANGE
     
    373470        return false;
    374471#endif
     472
     473    KAVL_WRITE_LOCK(pRoot);
    375474
    376475    AVLStack.cEntries = 0;
     
    391490            KAVL_SET_POINTER_NULL(&pNode->mpList, &pCurNode->mpList);
    392491            KAVL_SET_POINTER(&pCurNode->mpList, pNode);
     492            KAVL_WRITE_UNLOCK(pRoot);
    393493            return K_TRUE;
    394494        }
     
    396496#ifdef KAVL_CHECK_FOR_EQUAL_INSERT
    397497        if (KAVL_R_IS_INTERSECTING(pCurNode->mKey, Key, pCurNode->mKeyLast, KeyLast))
     498        {
     499            KAVL_WRITE_UNLOCK(pRoot);
    398500            return K_FALSE;
     501        }
    399502#endif
    400503        if (KAVL_G(pCurNode->mKey, Key))
     
    412515
    413516    KAVL_FN(Rebalance)(&AVLStack);
     517
     518    KAVL_WRITE_UNLOCK(pRoot);
    414519    return K_TRUE;
    415520}
     
    419524 * Removes a node from the AVL-tree.
    420525 * @returns   Pointer to the node.
    421  * @param     ppTree  Pointer to the AVL-tree root node pointer.
    422  * @param     Key     Key value of the node which is to be removed.
     526 * @param     pRoot     Pointer to the AVL-tree root structure.
     527 * @param     Key       Key value of the node which is to be removed.
    423528 * @sketch    Find the node which is to be removed:
    424529 *            LOOP until not found
     
    455560 *            return pointer to the removed node (if found).
    456561 */
    457 KAVL_DECL(KAVLNODE *) KAVL_FN(Remove)(KAVLTREEPTR *ppTree, KAVLKEY Key)
     562KAVL_DECL(KAVLNODE *) KAVL_FN(Remove)(KAVLROOT *pRoot, KAVLKEY Key)
    458563{
    459564    KAVL_INT(STACK)     AVLStack;
    460     KAVLTREEPTR        *ppDeleteNode = ppTree;
     565    KAVLTREEPTR        *ppDeleteNode = &pRoot->mpRoot;
    461566    register KAVLNODE  *pDeleteNode;
     567
     568    KAVL_WRITE_LOCK(pRoot);
    462569
    463570    AVLStack.cEntries = 0;
     
    465572    {
    466573        if (*ppDeleteNode == KAVL_NULL)
     574        {
     575            KAVL_WRITE_UNLOCK(pRoot);
    467576            return NULL;
     577        }
    468578        pDeleteNode = KAVL_GET_POINTER(ppDeleteNode);
    469579
     
    511621
    512622    KAVL_FN(Rebalance)(&AVLStack);
     623
     624    KAVL_LOOKTHRU_INVALIDATE_NODE(pRoot, pDeleteNode, Key);
     625
     626    KAVL_WRITE_UNLOCK(pRoot);
    513627    return pDeleteNode;
    514628}
Note: See TracChangeset for help on using the changeset viewer.