diff --git a/include/comrogue/internals/rbtree.h b/include/comrogue/internals/rbtree.h new file mode 100644 index 0000000..13ede4e --- /dev/null +++ b/include/comrogue/internals/rbtree.h @@ -0,0 +1,102 @@ +/* + * This file is part of the COMROGUE Operating System for Raspberry Pi + * + * Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises + * All rights reserved. + * + * This program is free for commercial and non-commercial use as long as the following conditions are + * adhered to. + * + * Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices + * in the code are not to be removed. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * "Raspberry Pi" is a trademark of the Raspberry Pi Foundation. + */ +#ifndef __RBTREE_H_INCLUDED +#define __RBTREE_H_INCLUDED + +#ifndef __ASM__ + +#include +#include + +/*------------------------------------------------------------------------------------------------------ + * An implementation of left-leaning red-black 2-3 trees as detailed in "Left-leaning Red-Black Trees," + * Robert Sedgwick, Princeton University, 2008 (http://www.cs.princeton.edu/~rs/talks/LLRB/LLRB.pdf). + * See also Java source at https://gist.github.com/741080. + * + * Note that we store the node color as a single bit in the low-order bit of the "right" node pointer. + * This is do-able since, for all cases, pointers to instances of RBTREENODE will be 4-byte aligned. + *------------------------------------------------------------------------------------------------------ + */ + +/* Generic key and comparison function definitions */ +typedef PVOID TREEKEY; +typedef INT32 (*PFNTREECOMPARE)(TREEKEY, TREEKEY); + +/* A node may be colored red or black. */ +#define RED TRUE +#define BLACK FALSE + +/* The basic tree node. */ +typedef struct tagRBTREENODE { + struct tagRBTREENODE *ptnLeft; /* pointer to left child */ + UINT_PTR ptnRightColor; /* pointer to right child AND color stored in low-order bit */ + TREEKEY treekey; /* key value */ +} RBTREENODE, *PRBTREENODE; + +/* Tree node macros, mostly to access either color or pointer or both from the ptnRightColor field */ +#define rbtNodeRight(ptn) ((PRBTREENODE)((ptn)->ptnRightColor & ~1)) +#define rbtNodeColor(ptn) ((ptn)->ptnRightColor & 1) +#define rbtIsRed(ptn) ((ptn) ? rbtNodeColor(ptn) : FALSE) +#define rbtSetNodeRight(ptn, ptnRight) \ + do { (ptn)->ptnRightColor = (((UINT_PTR)(ptnRight)) & ~1) | ((ptn)->ptnRightColor & 1); } while (0) +#define rbtSetNodeColor(ptn, clr) \ + do { (ptn)->ptnRightColor = ((ptn)->ptnRightColor & ~1) | ((clr) ? 1 : 0); } while (0) +#define rbtToggleColor(ptn) do { if (ptn) (ptn)->ptnRightColor ^= 1; } while (0) +#define rbtInitNode(ptn, ptnLeft, ptnRight, clr, key) \ + do { (ptn)->ptnLeft = (ptnLeft); (ptn)->ptnRightColor = (((UINT_PTR)(ptnRight)) & ~1) | ((clr) ? 1 : 0); \ + (ptn)->treekey = (key); } while (0) +#define rbtNewNode(ptn, key) rbtInitNode(ptn, NULL, NULL, RED, key) + +/* The head-of-tree structure. */ +typedef struct tagRBTREE { + PFNTREECOMPARE pfnTreeCompare; /* pointer to comparison function */ + PRBTREENODE ptnRoot; /* pointer to root of tree */ +} RBTREE, *PRBTREE; + +/* Macro to initialize the tree head. */ +#define rbtInitTree(ptree, pfnCompare) \ + do { (ptree)->pfnTreeCompare = (pfnCompare); (ptree)->ptnRoot = NULL; } while (0) + +/* Function prototypes. */ +CDECL_BEGIN + +extern INT32 RbtStdCompareByValue(TREEKEY k1, TREEKEY k2); +extern void RbtInsert(PRBTREE ptree, PRBTREENODE ptnNew); +extern PRBTREENODE RbtFind(PRBTREE ptree, TREEKEY key); +extern PRBTREENODE RbtFindMin(PRBTREE ptree); +extern void RbtDelete(PRBTREE ptree, TREEKEY key); + +CDECL_END + +#endif /* __ASM__ */ + +#endif /* __RBTREE_H_INCLUDED */ diff --git a/include/comrogue/internals/seg.h b/include/comrogue/internals/seg.h index 4a0cc0f..0c41602 100644 --- a/include/comrogue/internals/seg.h +++ b/include/comrogue/internals/seg.h @@ -38,6 +38,11 @@ #include +/*---------------------- + * Segment declarations + *---------------------- + */ + #ifdef __COMROGUE_PRESTART__ #define SEG_INIT_CODE __attribute__((__section__(".prestart.text"))) @@ -58,9 +63,15 @@ #endif /* __COMROGUE_PRESTART__ */ -#define DECLARE_INIT_STRING8_CONST(name, value) const CHAR SEG_INIT_RODATA name [] = value -#define DECLARE_LIB_STRING8_CONST(name, value) const CHAR SEG_LIB_RODATA name [] = value -#define DECLARE_STRING8_CONST(name, value) const CHAR SEG_RODATA name [] = value +/*------------------------------------ + * String constant declaration macros + *------------------------------------ + */ + +#define DECLARE_STRING8_CONST_STGCLASS(name, value, stgclass) const CHAR stgclass name [] = value +#define DECLARE_INIT_STRING8_CONST(name, value) DECLARE_STRING8_CONST_STGCLASS(name, value, SEG_INIT_RODATA) +#define DECLARE_LIB_STRING8_CONST(name, value) DECLARE_STRING8_CONST_STGCLASS(name, value, SEG_LIB_RODATA) +#define DECLARE_STRING8_CONST(name, value) DECLARE_STRING8_CONST_STGCLASS(name, value, SEG_RODATA) #endif /* __ASM__ */ diff --git a/include/comrogue/internals/trace.h b/include/comrogue/internals/trace.h index bd16ec3..c3a8379 100644 --- a/include/comrogue/internals/trace.h +++ b/include/comrogue/internals/trace.h @@ -90,8 +90,12 @@ CDECL_END #if defined(__COMROGUE_PRESTART__) || defined(__COMROGUE_INIT__) #define DECLARE_THIS_FILE static DECLARE_INIT_STRING8_CONST(THIS_FILE, __FILE__); #else +#if defined(__COMROGUE_KERNEL_LIB__) +#define DECLARE_THIS_FILE static DECLARE_LIB_STRING8_CONST(THIS_FILE, __FILE__); +#else #define DECLARE_THIS_FILE static DECLARE_STRING8_CONST(THIS_FILE, __FILE__); #endif +#endif #define ASSERT(x) ((x) ? (void)0 : ASSERT_FAIL_FUNC(THIS_FILE, __LINE__)) #define VERIFY(x) ASSERT(x) diff --git a/include/comrogue/types.h b/include/comrogue/types.h index b42622b..029ce48 100644 --- a/include/comrogue/types.h +++ b/include/comrogue/types.h @@ -83,6 +83,8 @@ typedef unsigned long long uint64_t; #define MAKEBOOL(val) ((val) ? TRUE : FALSE) +#define OFFSETOF(struc, field) ((UINT_PTR)(&(((struc *)0)->field))) + #ifdef __COMROGUE_INTERNALS__ /* Internal system types */ diff --git a/kernel/Makefile b/kernel/Makefile index 26eddd0..e23bdd1 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -48,7 +48,7 @@ AFLAGS = -mcpu=arm1176jzf-s -mfloat-abi=hard ASM_CPP_FLAGS = $(INCLUDES) $(DEFS) -D__ASM__ PRESTART_OBJS = prestart.o early_trace.o collect_startup.o early_mm.o -LIB_OBJS = divide.o qdivrem.o intlib.o objhelp.o str.o strcopymem.o strcomparemem.o strsetmem.o lib_guids.o +LIB_OBJS = divide.o qdivrem.o intlib.o objhelp.o rbtree.o str.o strcopymem.o strcomparemem.o strsetmem.o lib_guids.o RES_OBJS = lowlevel.o trace.o memmgr.o vmmap.o pagealloc.o INIT_OBJS = start.o kistart.o init_heap.o diff --git a/kernel/intlib.c b/kernel/intlib.c index 2a7b68a..b06b303 100644 --- a/kernel/intlib.c +++ b/kernel/intlib.c @@ -29,6 +29,7 @@ * * "Raspberry Pi" is a trademark of the Raspberry Pi Foundation. */ +#define __COMROGUE_KERNEL_LIB__ #include #include #include diff --git a/kernel/lib_guids.c b/kernel/lib_guids.c index a7d5e66..af036d4 100644 --- a/kernel/lib_guids.c +++ b/kernel/lib_guids.c @@ -35,6 +35,7 @@ * AND in this order. *------------------------------------------------------------------------------------------------------ */ +#define __COMROGUE_KERNEL_LIB__ #include #define GUIDATTR SEG_LIB_RODATA #define INITGUID diff --git a/kernel/objhelp.c b/kernel/objhelp.c index df82e8e..b3746ea 100644 --- a/kernel/objhelp.c +++ b/kernel/objhelp.c @@ -1,3 +1,35 @@ +/* + * This file is part of the COMROGUE Operating System for Raspberry Pi + * + * Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises + * All rights reserved. + * + * This program is free for commercial and non-commercial use as long as the following conditions are + * adhered to. + * + * Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices + * in the code are not to be removed. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * "Raspberry Pi" is a trademark of the Raspberry Pi Foundation. + */ +#define __COMROGUE_KERNEL_LIB__ #include #include #include diff --git a/kernel/qdivrem.c b/kernel/qdivrem.c index f6c6f33..30b9744 100644 --- a/kernel/qdivrem.c +++ b/kernel/qdivrem.c @@ -31,6 +31,7 @@ * SUCH DAMAGE. */ /* Derived from FreeBSD libkern qdivrem.c, munged by Erbo to COMROGUE standards */ +#define __COMROGUE_KERNEL_LIB__ #include #include #include "quad.h" diff --git a/kernel/rbtree.c b/kernel/rbtree.c new file mode 100644 index 0000000..525b3d5 --- /dev/null +++ b/kernel/rbtree.c @@ -0,0 +1,403 @@ +/* + * This file is part of the COMROGUE Operating System for Raspberry Pi + * + * Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises + * All rights reserved. + * + * This program is free for commercial and non-commercial use as long as the following conditions are + * adhered to. + * + * Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices + * in the code are not to be removed. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * "Raspberry Pi" is a trademark of the Raspberry Pi Foundation. + */ +#define __COMROGUE_KERNEL_LIB__ +#include +#include +#include +#include + +#ifdef THIS_FILE +#undef THIS_FILE +DECLARE_THIS_FILE +#endif + +/*------------------------------------------------------------------------------------------------------ + * An implementation of left-leaning red-black 2-3 trees as detailed in "Left-leaning Red-Black Trees," + * Robert Sedgwick, Princeton University, 2008 (http://www.cs.princeton.edu/~rs/talks/LLRB/LLRB.pdf). + * See also Java source at https://gist.github.com/741080. + * + * Note that we store the node color as a single bit in the low-order bit of the "right" node pointer. + * This is do-able since, for all cases, pointers to instances of RBTREENODE will be 4-byte aligned. + *------------------------------------------------------------------------------------------------------ + */ + +/* + * A standard compare-by-value function for tree keys, which compares the numeric values of the keys as + * unsigned integers. + * + * Parameters: + * - k1 = First key value to compare. + * - k2 = Second key value to compare. + * + * Returns: + * 0 if the keys are equal; an integer less than 0 if k1 is less than k2; an integer greater than 0 if + * k1 is greater than k2. + */ +SEG_LIB_CODE INT32 RbtStdCompareByValue(TREEKEY k1, TREEKEY k2) +{ + if (k1 == k2) + return 0; + if (((UINT_PTR)k1) < ((UINT_PTR)k2)) + return -1; + return 1; +} + +/* + * Rotates a subtree "leftward," so that the root node of the tree is the former root node's right child. + * The new root node inherits the former root node's color, and the former root node turns red. + * + * Parameters: + * - ptn = Pointer to the root node of the subtree. + * + * Returns: + * Pointer to the new root node of the subtree after the rotation. + */ +SEG_LIB_CODE static PRBTREENODE rotate_left(PRBTREENODE ptn) +{ + register PRBTREENODE ptnNewRoot = rbtNodeRight(ptn); + ASSERT(ptnNewRoot); + rbtSetNodeRight(ptn, ptnNewRoot->ptnLeft); + ptnNewRoot->ptnLeft = ptn; + rbtSetNodeColor(ptnNewRoot, rbtNodeColor(ptn)); + rbtSetNodeColor(ptn, RED); + return ptnNewRoot; +} + +/* + * Rotates a subtree "rightward," so that the root node of the tree is the former root node's left child. + * The new root node inherits the former root node's color, and the former root node turns red. + * + * Parameters: + * - ptn = Pointer to theroot node of the subtree. + * + * Returns: + * Pointer to the new root node of the subtree after the rotation. + */ +SEG_LIB_CODE static PRBTREENODE rotate_right(PRBTREENODE ptn) +{ + register PRBTREENODE ptnNewRoot = ptn->ptnLeft; + ASSERT(ptnNewRoot); + ptn->ptnLeft = rbtNodeRight(ptnNewRoot); + rbtSetNodeRight(ptnNewRoot, ptn); + rbtSetNodeColor(ptnNewRoot, rbtNodeColor(ptn)); + rbtSetNodeColor(ptn, RED); + return ptnNewRoot; +} + +/* + * Flips the color of the specified node and both its immediate children. + * + * Parameters: + * - ptn = Pointer to the node to be color-flipped. + * + * Returns: + * Nothing. + */ +SEG_LIB_CODE static void color_flip(PRBTREENODE ptn) +{ + rbtToggleColor(ptn); + rbtToggleColor(ptn->ptnLeft); + rbtToggleColor(rbtNodeRight(ptn)); +} + +/* + * Fixes up the given subtree after an insertion or deletion, to ensure that it maintains the invariants + * that no two consecutive links in the tree may be red, and that all red links must lean left. + * + * Parameters: + * - ptn = Pointer to the root node of the subtree to be fixed up. + * + * Returns: + * Pointer to the new root node of the subtree after fixup is performed. + */ +SEG_LIB_CODE static PRBTREENODE fix_up(PRBTREENODE ptn) +{ + if (rbtIsRed(rbtNodeRight(ptn)) && !rbtIsRed(ptn->ptnLeft)) + ptn = rotate_left(ptn); + if (rbtIsRed(ptn->ptnLeft) && rbtIsRed(ptn->ptnLeft->ptnLeft)) + ptn = rotate_right(ptn); + if (rbtIsRed(ptn->ptnLeft) && rbtIsRed(rbtNodeRight(ptn))) + color_flip(ptn); + return ptn; +} + +/* + * Inserts a new node under the current subtree. An O(log n) operation. + * + * Parameters: + * - ptree = Pointer to the tree head structure, containing the compare function. + * - ptnCurrent = Pointer to the current subtree we're inserting into. + * - ptnNew = Pointer to the new tree node to be inserted. This node must have been initialized with + * the rbtInitNode macro to contain a key, NULL left and right pointers, and be red. It is + * assumed that the node's key does NOT already exist in the tree. + * + * Returns: + * The pointer to the new subtree after the insertion is performed. + * + * N.B.: + * This function is recursive; however, the nature of the tree guarantees that the stack space consumed + * by its stack frames will be O(log n). + */ +SEG_LIB_CODE static PRBTREENODE insert_under(PRBTREE ptree, PRBTREENODE ptnCurrent, PRBTREENODE ptnNew) +{ + register int cmp; /* compare result */ + + if (!ptnCurrent) + return ptnNew; /* degenerate case */ + cmp = (*(ptree->pfnTreeCompare))(ptnNew->treekey, ptnCurrent->treekey); + ASSERT(cmp != 0); + if (cmp < 0) + ptnCurrent->ptnLeft = insert_under(ptree, ptnCurrent->ptnLeft, ptnNew); + else + rbtSetNodeRight(ptnCurrent, insert_under(ptree, rbtNodeRight(ptnCurrent), ptnNew)); + return fix_up(ptnCurrent); +} + +/* + * Inserts a new node into the tree. An O(log n) operation. + * + * Parameters: + * - ptree = Pointer to the tree head structure. + * - ptnNew = Pointer to the new tree node to be inserted. This node must have been initialized with + * the rbtInitNode macro to contain a key, NULL left and right pointers, and be red. It is + * assumed that the node's key does NOT already exist in the tree. + * + * Returns: + * Nothing. + */ +SEG_LIB_CODE void RbtInsert(PRBTREE ptree, PRBTREENODE ptnNew) +{ + ptree->ptnRoot = insert_under(ptree, ptree->ptnRoot, ptnNew); + rbtSetNodeColor(ptree->ptnRoot, BLACK); +} + +/* + * Locates a node in the tree by key. An O(log n) operation. + * + * Parameters: + * - ptree = Pointer to the tree head structure. + * - key = Key value to be looked up. + * + * Returns: + * Pointer to the node where the key is found, or NULL if not found. + */ +SEG_LIB_CODE PRBTREENODE RbtFind(PRBTREE ptree, TREEKEY key) +{ + register PRBTREENODE ptn = ptree->ptnRoot; /* current node */ + register int cmp; /* compare result */ + + while (ptn) + { + cmp = (*(ptree->pfnTreeCompare))(key, ptn->treekey); + if (cmp == 0) + break; /* found */ + else if (cmp < 0) + ptn = ptn->ptnLeft; + else + ptn = rbtNodeRight(ptn); + } + + return ptn; +} + +/* + * Finds the "minimum" node in the subtree (the one at the bottom end of the left spine of the subtree). + * + * Parameters: + * - ptn = Pointer to the subtree to be searched. + * + * Returns: + * Pointer to the leftmost node in the subtree. + */ +SEG_LIB_CODE static PRBTREENODE find_min(PRBTREENODE ptn) +{ + while (ptn->ptnLeft) + ptn = ptn->ptnLeft; + return ptn; +} + +/* + * Finds the "minimum" node int he tree (the one at the bottom end of the left spine of the tree). + * + * Parameters: + * - ptree = Pointer to the tree head structure. + * + * Returns: + * Pointer to the leftmost node in the tree. If the tree has no nodes, NULL is returned. + */ +SEG_LIB_CODE PRBTREENODE RbtFindMin(PRBTREE ptree) +{ + return ptree->ptnRoot ? find_min(ptree->ptnRoot) : NULL; +} + +/* + * Fixup required to delete the leftmost node; we maintain the invariant that either the current node + * or its left child is red. After a color flip, we resolve any successive reds on the right with rotations + * and another color flip. + * + * Parameters: + * - ptn = Pointer to root of subtree to be fixed up. + * + * Returns: + * Pointer to root of subtree after fixup. + */ +SEG_LIB_CODE static PRBTREENODE move_red_left(PRBTREENODE ptn) +{ + color_flip(ptn); + if (rbtNodeRight(ptn) && rbtIsRed(rbtNodeRight(ptn)->ptnLeft)) + { + rbtSetNodeRight(ptn, rotate_right(rbtNodeRight(ptn))); + ptn = rotate_left(ptn); + color_flip(ptn); + } + return ptn; +} + +/* + * Fixup required to delete an internal node, rotating left-leaning red links to the right. + * + * Parameters: + * - ptn = Pointer to root of subtree to be fixed up. + * + * Returns: + * Pointer to root of subtree after fixup. + */ +SEG_LIB_CODE static PRBTREENODE move_red_right(PRBTREENODE ptn) +{ + color_flip(ptn); + if (ptn->ptnLeft && rbtIsRed(ptn->ptnLeft->ptnLeft)) + { + ptn = rotate_right(ptn); + color_flip(ptn); + } + return ptn; +} + +/* + * Deletes the leftmost node in the subtree. (Note that "deletes" means "removes from the tree." No memory + * delete operation is actually performed.) + * + * Parameters: + * - ptn = Pointer to root of subtree to have its leftmost node deleted. + * + * Returns: + * Pointer to root of subtree after having the leftmost node deleted. + * + * N.B.: + * This function is recursive; however, the nature of the tree guarantees that the stack space consumed + * by its stack frames will be O(log n). + */ +SEG_LIB_CODE static PRBTREENODE delete_min(PRBTREENODE ptn) +{ + if (!(ptn->ptnLeft)) + return rbtNodeRight(ptn); + if (!rbtIsRed(ptn->ptnLeft) && !rbtIsRed(ptn->ptnLeft->ptnLeft)) + ptn = move_red_left(ptn); + ptn->ptnLeft = delete_min(ptn->ptnLeft); + return fix_up(ptn); +} + +/* + * Detetes the node in the subtree having an arbitrary key. An O(log n) operation. + * + * Parameters: + * - ptree = Pointer to the tree head structure, containing the compare function. + * - ptnCurrent = Pointer to the root of the current subtree we're deleting from. + * - key = Key value we're deleting from the tree. It is assumed that this key value exists in the subtree. + * + * Returns: + * Pointer to the root of the subtree after the node has been deleted. + * + * N.B.: + * This function is recursive; however, the nature of the tree guarantees that the stack space consumed + * by its stack frames (and those of delete_min, where we call it) will be O(log n). + */ +SEG_LIB_CODE static PRBTREENODE delete_from_under(PRBTREE ptree, PRBTREENODE ptnCurrent, TREEKEY key) +{ + register int cmp = (*(ptree->pfnTreeCompare))(key, ptnCurrent->treekey); + if (cmp < 0) + { + /* hunt down the left subtree */ + if (!rbtIsRed(ptnCurrent->ptnLeft) && !rbtIsRed(ptnCurrent->ptnLeft->ptnLeft)) + ptnCurrent = move_red_left(ptnCurrent); + ptnCurrent->ptnLeft = delete_from_under(ptree, ptnCurrent->ptnLeft, key); + } + else + { + if (rbtIsRed(ptnCurrent->ptnLeft)) + { + ptnCurrent = rotate_right(ptnCurrent); + cmp = (*(ptree->pfnTreeCompare))(key, ptnCurrent->treekey); + } + if ((cmp == 0) && !rbtNodeRight(ptnCurrent)) + return ptnCurrent->ptnLeft; /* degenerate case */ + if ( !rbtIsRed(rbtNodeRight(ptnCurrent)) + && (!rbtNodeRight(ptnCurrent) || !rbtIsRed(rbtNodeRight(ptnCurrent)->ptnLeft))) + { + ptnCurrent = move_red_right(ptnCurrent); + cmp = (*(ptree->pfnTreeCompare))(key, ptnCurrent->treekey); + } + if (cmp == 0) + { + /* + * Here we find the minimum node in the right subtree, unlink it, and link it into place in place of + * ptnCurrent (i.e. node pointed to by ptnCurrent should no longer be referenced). We inherit the + * child pointers and color of ptnCurrent (minus the reference from the right-hand tree where applicable). + */ + register PRBTREENODE ptnMin = find_min(rbtNodeRight(ptnCurrent)); + rbtSetNodeRight(ptnMin, delete_min(rbtNodeRight(ptnCurrent))); + ptnMin->ptnLeft = ptnCurrent->ptnLeft; + rbtSetNodeColor(ptnMin, rbtNodeColor(ptnCurrent)); + ptnCurrent = ptnMin; + } + else /* hunt down the right subtree */ + rbtSetNodeRight(ptnCurrent, delete_from_under(ptree, rbtNodeRight(ptnCurrent), key)); + } + return fix_up(ptnCurrent); +} + +/* + * Detetes the node in the tree having an arbitrary key. An O(log n) operation. + * + * Parameters: + * - ptree = Pointer to the tree head structure. + * - key = Key value we're deleting from the tree. It is assumed that this key value exists in the subtree. + * + * Returns: + * Nothing. + */ +SEG_LIB_CODE void RbtDelete(PRBTREE ptree, TREEKEY key) +{ + ptree->ptnRoot = delete_from_under(ptree, ptree->ptnRoot, key); + if (ptree->ptnRoot) + rbtSetNodeColor(ptree->ptnRoot, BLACK); +} diff --git a/kernel/str.c b/kernel/str.c index 05164a7..b2c3e32 100644 --- a/kernel/str.c +++ b/kernel/str.c @@ -29,6 +29,7 @@ * * "Raspberry Pi" is a trademark of the Raspberry Pi Foundation. */ +#define __COMROGUE_KERNEL_LIB__ #include #include #include