Commit c14d94bc authored by Yoni Fogel's avatar Yoni Fogel

Addresses #479

Modified tokuredblack to be more readable, support user malloc functions

git-svn-id: file:///svn/tokudb@2699 c7de825b-a66e-492c-adef-691d508d4ae1
parent c7ea2581
#include <rangetree.h>
// These are the redblack directives
/* rbgen generated code begins here */
/* rbgen: $Id: rbgen.in,v 1.3 2003/10/24 01:31:21 damo Exp $ */
#define RB_CUSTOMIZE
#define toku_rbt_data_t toku_range
#define RB_CMP(s, t) toku_rbt_dummy_ignore(s, t)
#define RB_ENTRY(name) toku_rbt_##name
#define RB_INLINE
#define no_find
#define no_walk
#define no_delete
#define no_readlist
#define no_search
#define no_walk
#define RB_STATIC
/*
* RCS $Id: redblack.h,v 1.9 2003/10/24 01:31:21 damo Exp $
*/
/*
Redblack balanced tree algorithm
Copyright (C) Damian Ivereigh 2000
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version. See the file COPYING for details.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* Header file for redblack.c, should be included by any code that
** uses redblack.c since it defines the functions
*/
/* Stop multiple includes */
#ifndef _REDBLACK_H
#ifndef RB_CUSTOMIZE
/*
* Without customization, the data member in the tree nodes is a void
* pointer, and you need to pass in a comparison function to be
* applied at runtime. With customization, you specify the data type
* as the macro RB_ENTRY(data_t) (has to be a macro because compilers
* gag on typdef void) and the name of the compare function as the
* value of the macro RB_COMPARE. Because the comparison function is
* compiled in, RB_COMPARE only needs to take two arguments. If your
* content type is not a pointer, define INLINE to get direct access.
*/
#define rbdata_t void
#define RB_COMPARE(s, t, e) (*rbinfo->rb_cmp)(s, t, e)
#undef RB_INLINE
#define RB_ENTRY(name) rb##name
#else
//Not Customized
#define RB_COMPARE(s, t) (*rbinfo->rb_cmp)(s, t)
#endif /* RB_CUSTOMIZE */
#ifndef RB_STATIC
#define RB_STATIC
#endif
/* Modes for rblookup */
#define RB_NONE -1 /* None of those below */
#define RB_LUEQUAL 0 /* Only exact match */
#define RB_LUGTEQ 1 /* Exact match or greater */
#define RB_LULTEQ 2 /* Exact match or less */
#define RB_LULESS 3 /* Less than key (not equal to) */
#define RB_LUGREAT 4 /* Greater than key (not equal to) */
#define RB_LUNEXT 5 /* Next key after current */
#define RB_LUPREV 6 /* Prev key before current */
#define RB_LUFIRST 7 /* First key in index */
#define RB_LULAST 8 /* Last key in index */
/* For rbwalk - pinched from search.h */
typedef enum
{
preorder,
postorder,
endorder,
leaf
}
VISIT;
struct RB_ENTRY(lists) {
const struct RB_ENTRY(node) *rootp;
const struct RB_ENTRY(node) *nextp;
};
#define RBLIST struct RB_ENTRY(lists)
struct RB_ENTRY(tree) {
#ifndef RB_CUSTOMIZE
/* comparison routine */
int (*rb_cmp)(const void *, const void *, const void *);
/* config data to be passed to rb_cmp */
const void *rb_config;
/* root of tree */
#else
int (*rb_cmp)(const RB_ENTRY(data_t)*, const RB_ENTRY(data_t)*);
#endif /* RB_CUSTOMIZE */
struct RB_ENTRY(node) *rb_root;
};
RB_STATIC int RB_ENTRY(init) (
#ifndef RB_CUSTOMIZE
int (*cmp)(const void *, const void *, const void *), const void *config,
#else
int (*cmp)(const RB_ENTRY(data_t)*, const RB_ENTRY(data_t)*),
#endif /* RB_CUSTOMIZE */
struct RB_ENTRY(tree)** ptree
);
#ifndef no_delete
RB_STATIC const RB_ENTRY(data_t) *RB_ENTRY(delete)(const RB_ENTRY(data_t) *, struct RB_ENTRY(tree) *);
#endif
#ifndef no_find
RB_STATIC const RB_ENTRY(data_t) *RB_ENTRY(find)(const RB_ENTRY(data_t) *, struct RB_ENTRY(tree) *);
#endif
#ifndef no_lookup
RB_STATIC int RB_ENTRY(lookup)(
int mode,
const RB_ENTRY(data_t)* key,
struct RB_ENTRY(tree)* rbinfo,
struct RB_ENTRY(node)** pinsert_finger,
struct RB_ENTRY(node)** pelement_finger,
const RB_ENTRY(data_t)** pdata
);
#endif
#ifndef no_search
RB_STATIC const RB_ENTRY(data_t) *RB_ENTRY(search)(const RB_ENTRY(data_t) *, struct RB_ENTRY(tree) *);
#endif
#ifndef no_finger_insert
RB_STATIC const RB_ENTRY(data_t)* RB_ENTRY(finger_insert)(
const RB_ENTRY(data_t)* key,
struct RB_ENTRY(tree)* rbinfo,
struct RB_ENTRY(node)* parent
);
#endif
#ifndef no_finger_delete
RB_STATIC int RB_ENTRY(finger_delete)(struct RB_ENTRY(node)* node, struct RB_ENTRY(tree) *rbinfo);
#endif
#ifndef no_pred
RB_STATIC int RB_ENTRY(finger_predecessor)(const struct RB_ENTRY(node)** pfinger, const RB_ENTRY(data_t)** ppred_data);
#endif
#ifndef no_succ
RB_STATIC int RB_ENTRY(finger_successor)(const struct RB_ENTRY(node)** pfinger, const RB_ENTRY(data_t)** psucc_data);
#endif
#ifndef no_destroy
RB_STATIC void RB_ENTRY(destroy)(struct RB_ENTRY(tree) *);
#endif
#ifndef no_walk
RB_STATIC void RB_ENTRY(walk)(const struct RB_ENTRY(tree) *,
void (*)(const RB_ENTRY(data_t) *, const VISIT, const int, void *),
void *);
#endif
#ifndef no_readlist
RB_STATIC RBLIST *RB_ENTRY(openlist)(const struct RB_ENTRY(tree) *);
RB_STATIC const RB_ENTRY(data_t) *RB_ENTRY(readlist)(RBLIST *);
RB_STATIC void RB_ENTRY(closelist)(RBLIST *);
#endif
/* Some useful macros */
#define rbmin(rbinfo) RB_ENTRY(lookup)(RB_LUFIRST, NULL, (rbinfo))
#define rbmax(rbinfo) RB_ENTRY(lookup)(RB_LULAST, NULL, (rbinfo))
#define _REDBLACK_H
#endif /* _REDBLACK_H */
/*
*
* $Log: redblack.h,v $
* Revision 1.9 2003/10/24 01:31:21 damo
* Patches from Eric Raymond: %prefix is implemented.  Various other small
* changes avoid stepping on global namespaces and improve the documentation.
*
* Revision 1.8 2003/10/23 04:18:47 damo
* Fixed up the rbgen stuff ready for the 1.3 release
*
* Revision 1.7 2002/08/26 03:11:40 damo
* Fixed up a bunch of compiler warnings when compiling example4
*
* Tidies up the Makefile.am & Specfile.
*
* Renamed redblack to rbgen
*
* Revision 1.6 2002/08/26 01:03:35 damo
* Patch from Eric Raymond to change the way the library is used:-
*
* Eric's idea is to convert libredblack into a piece of in-line code
* generated by another program. This should be faster, smaller and easier
* to use.
*
* This is the first check-in of his code before I start futzing with it!
*
* Revision 1.5 2002/01/30 07:54:53 damo
* Fixed up the libtool versioning stuff (finally)
* Fixed bug 500600 (not detecting a NULL return from malloc)
* Fixed bug 509485 (no longer needs search.h)
* Cleaned up debugging section
* Allow multiple inclusions of redblack.h
* Thanks to Matthias Andree for reporting (and fixing) these
*
* Revision 1.4 2000/06/06 14:43:43 damo
* Added all the rbwalk & rbopenlist stuff. Fixed up malloc instead of sbrk.
* Added two new examples
*
* Revision 1.3 2000/05/24 06:45:27 damo
* Converted everything over to using const
* Added a new example1.c file to demonstrate the worst case scenario
* Minor fixups of the spec file
*
* Revision 1.2 2000/05/24 06:17:10 damo
* Fixed up the License (now the LGPL)
*
* Revision 1.1 2000/05/24 04:15:53 damo
* Initial import of files. Versions are now all over the place. Oh well
*
*/
/* /*
Redblack balanced tree algorithm Redblack balanced tree algorithm
Copyright (C) Damian Ivereigh 2000 Copyright (C) Damian Ivereigh 2000
...@@ -267,33 +27,7 @@ RB_STATIC void RB_ENTRY(closelist)(RBLIST *); ...@@ -267,33 +27,7 @@ RB_STATIC void RB_ENTRY(closelist)(RBLIST *);
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#include "redblack.h" #include "redblack.h"
#include <assert.h>
#define assert(expr)
/* Uncomment this if you would rather use a raw sbrk to get memory
** (however the memory is never released again (only re-used). Can't
** see any point in using this these days.
*/
/* #define USE_SBRK */
enum nodecolour { BLACK, RED };
struct RB_ENTRY(node)
{
struct RB_ENTRY(node) *left; /* Left down */
struct RB_ENTRY(node) *right; /* Right down */
struct RB_ENTRY(node) *up; /* Up */
enum nodecolour colour; /* Node colour */
#ifdef RB_INLINE
RB_ENTRY(data_t) key; /* User's key (and data) */
#define RB_GET(x,y) &x->y
#define RB_SET(x,y,v) x->y = *(v)
#else
const RB_ENTRY(data_t) *key; /* Pointer to user's key (and data) */
#define RB_GET(x,y) x->y
#define RB_SET(x,y,v) x->y = v
#endif /* RB_INLINE */
};
/* Dummy (sentinel) node, so that we can make X->left->up = X /* Dummy (sentinel) node, so that we can make X->left->up = X
** We then use this instead of NULL to mean the top or bottom ** We then use this instead of NULL to mean the top or bottom
...@@ -302,59 +36,33 @@ struct RB_ENTRY(node) ...@@ -302,59 +36,33 @@ struct RB_ENTRY(node)
** Initialization of the last field in this initializer is left implicit ** Initialization of the last field in this initializer is left implicit
** because it could be of any type. We count on the compiler to zero it. ** because it could be of any type. We count on the compiler to zero it.
*/ */
static struct RB_ENTRY(node) RB_ENTRY(_null); static struct toku_rbt_node toku_rbt__null;
#define RBNULL (&RB_ENTRY(_null)) static struct toku_rbt_node* RBNULL = &toku_rbt__null;
#if defined(USE_SBRK)
static struct RB_ENTRY(node) *RB_ENTRY(_alloc)();
static void RB_ENTRY(_free)(struct RB_ENTRY(node) *);
#else
static struct RB_ENTRY(node) *RB_ENTRY(_alloc)() {return (struct RB_ENTRY(node) *) malloc(sizeof(struct RB_ENTRY(node)));}
static void RB_ENTRY(_free)(struct RB_ENTRY(node) *x) {free(x);}
#endif static struct toku_rbt_node *toku_rbt__alloc(struct toku_rbt_tree *rbinfo) {return (struct toku_rbt_node *) rbinfo->rb_malloc(sizeof(struct toku_rbt_node));}
static void toku_rbt__free(struct toku_rbt_tree *rbinfo, struct toku_rbt_node *x) {rbinfo->rb_free(x);}
/* These functions are always needed */ /* These functions are always needed */
static void RB_ENTRY(_left_rotate)(struct RB_ENTRY(node) **, struct RB_ENTRY(node) *); static void toku_rbt__left_rotate(struct toku_rbt_node **, struct toku_rbt_node *);
static void RB_ENTRY(_right_rotate)(struct RB_ENTRY(node) **, struct RB_ENTRY(node) *); static void toku_rbt__right_rotate(struct toku_rbt_node **, struct toku_rbt_node *);
static struct RB_ENTRY(node) *RB_ENTRY(_successor)(const struct RB_ENTRY(node) *); static struct toku_rbt_node *toku_rbt__successor(const struct toku_rbt_node *);
static struct RB_ENTRY(node) *RB_ENTRY(_predecessor)(const struct RB_ENTRY(node) *); static struct toku_rbt_node *toku_rbt__predecessor(const struct toku_rbt_node *);
static struct RB_ENTRY(node) *RB_ENTRY(_traverse)(int, const RB_ENTRY(data_t) * , struct RB_ENTRY(tree) *); static struct toku_rbt_node *toku_rbt__traverse(int, const toku_range * , struct toku_rbt_tree *);
/* These functions may not be needed */ /* These functions may not be needed */
#if !defined(no_search) || !defined(no_insert) static struct toku_rbt_node* toku_rbt__insert(
static struct RB_ENTRY(node)* RB_ENTRY(_insert)( const toku_range* key,
const RB_ENTRY(data_t)* key, struct toku_rbt_tree* rbinfo,
struct RB_ENTRY(tree)* rbinfo, struct toku_rbt_node* parent
struct RB_ENTRY(node)* parent
); );
#endif
#ifndef no_lookup static struct toku_rbt_node *toku_rbt__lookup(int, const toku_range * , struct toku_rbt_tree *, struct toku_rbt_node**);
static struct RB_ENTRY(node) *RB_ENTRY(_lookup)(int, const RB_ENTRY(data_t) * , struct RB_ENTRY(tree) *, struct RB_ENTRY(node)**);
#endif
#ifndef no_destroy static void toku_rbt__destroy(struct toku_rbt_node *);
static void RB_ENTRY(_destroy)(struct RB_ENTRY(node) *);
#endif
#if !defined(no_delete) || !defined(no_finger_delete) static void toku_rbt__delete(struct toku_rbt_node **, struct toku_rbt_node *);
static void RB_ENTRY(_delete)(struct RB_ENTRY(node) **, struct RB_ENTRY(node) *); static void toku_rbt__delete_fix(struct toku_rbt_node **, struct toku_rbt_node *);
static void RB_ENTRY(_delete_fix)(struct RB_ENTRY(node) **, struct RB_ENTRY(node) *);
#endif
#ifndef no_walk
static void RB_ENTRY(_walk)(const struct RB_ENTRY(node) *, void (*)(const RB_ENTRY(data_t) *, const VISIT, const int, void *), void *, int);
#endif
#ifndef no_readlist
static RBLIST *RB_ENTRY(_openlist)(const struct RB_ENTRY(node) *);
static const RB_ENTRY(data_t) * RB_ENTRY(_readlist)(RBLIST *);
static void RB_ENTRY(_closelist)(RBLIST *);
#endif
/* /*
** OK here we go, the balanced tree stuff. The algorithm is the ** OK here we go, the balanced tree stuff. The algorithm is the
...@@ -379,169 +87,73 @@ static void RB_ENTRY(_closelist)(RBLIST *); ...@@ -379,169 +87,73 @@ static void RB_ENTRY(_closelist)(RBLIST *);
* data that must be sent to it when called. * data that must be sent to it when called.
* Returns a pointer to the top of the tree. * Returns a pointer to the top of the tree.
*/ */
RB_STATIC int RB_ENTRY(init) ( int toku_rbt_init (
#ifndef RB_CUSTOMIZE int (*cmp)(const toku_range*, const toku_range*),
int (*cmp)(const void *, const void *, const void *), const void *config, struct toku_rbt_tree** ptree,
#else void* (*user_malloc) (size_t),
int (*cmp)(const RB_ENTRY(data_t)*, const RB_ENTRY(data_t)*), void (*user_free) (void*),
#endif /* RB_CUSTOMIZE */ void* (*user_realloc)(void*, size_t)
struct RB_ENTRY(tree)** ptree
) )
{ {
struct RB_ENTRY(tree)* temptree = NULL; struct toku_rbt_tree* temptree = NULL;
int r = ENOSYS; int r = ENOSYS;
static int RB_ENTRY(_null_is_initialized) = 0; static int toku_rbt__null_is_initialized = 0;
if (!RB_ENTRY(_null_is_initialized)) { if (!toku_rbt__null_is_initialized) {
RB_ENTRY(_null_is_initialized) = 1; toku_rbt__null_is_initialized = 1;
RB_ENTRY(_null).up = &RB_ENTRY(_null); toku_rbt__null.up = &toku_rbt__null;
RB_ENTRY(_null).left = &RB_ENTRY(_null); toku_rbt__null.left = &toku_rbt__null;
RB_ENTRY(_null).right = &RB_ENTRY(_null); toku_rbt__null.right = &toku_rbt__null;
RB_ENTRY(_null).colour = BLACK; toku_rbt__null.colour = BLACK;
/* Key is initialized since the RB_ENTRY(_null) is static. */ /* Key is initialized since the toku_rbt__null is static. */
} }
if (!ptree) { r = EINVAL; goto cleanup; } if (!ptree) { r = EINVAL; goto cleanup; }
temptree=(struct RB_ENTRY(tree) *) malloc(sizeof(struct RB_ENTRY(tree))); temptree=(struct toku_rbt_tree *) user_malloc(sizeof(struct toku_rbt_tree));
if (!temptree) { r = ENOMEM; goto cleanup; } if (!temptree) { r = ENOMEM; goto cleanup; }
temptree->rb_cmp=cmp; temptree->rb_cmp=cmp;
#ifndef RB_CUSTOMIZE temptree->rb_root=RBNULL;
temptree->rb_config=config; temptree->rb_malloc = user_malloc;
#endif /* RB_CUSTOMIZE */ temptree->rb_free = user_free;
temptree->rb_root=RBNULL; temptree->rb_realloc = user_realloc;
*ptree = temptree; *ptree = temptree;
r = 0; r = 0;
cleanup: cleanup:
return r; return r;
} }
#ifndef no_destroy void
RB_STATIC void toku_rbt_destroy(struct toku_rbt_tree *rbinfo)
RB_ENTRY(destroy)(struct RB_ENTRY(tree) *rbinfo)
{
if (rbinfo==NULL)
return;
if (rbinfo->rb_root!=RBNULL)
RB_ENTRY(_destroy)(rbinfo->rb_root);
free(rbinfo);
}
#endif /* no_destroy */
#ifndef no_search
RB_STATIC const RB_ENTRY(data_t) *
RB_ENTRY(search)(const RB_ENTRY(data_t) *key, struct RB_ENTRY(tree) *rbinfo)
{
struct RB_ENTRY(node) *x;
if (rbinfo==NULL)
return(NULL);
x=RB_ENTRY(_traverse)(1, key, rbinfo);
return((x==RBNULL) ? NULL : RB_GET(x, key));
}
#endif /* no_search */
#ifndef no_find
RB_STATIC const RB_ENTRY(data_t) *
RB_ENTRY(find)(const RB_ENTRY(data_t) *key, struct RB_ENTRY(tree) *rbinfo)
{ {
struct RB_ENTRY(node) *x; if (rbinfo==NULL)
return;
if (rbinfo==NULL)
return(NULL);
/* If we have a NULL root (empty tree) then just return */
if (rbinfo->rb_root==RBNULL)
return(NULL);
x=RB_ENTRY(_traverse)(0, key, rbinfo);
return((x==RBNULL) ? NULL : RB_GET(x, key));
}
#endif /* no_find */
#ifndef no_delete
RB_STATIC const RB_ENTRY(data_t) *
RB_ENTRY(delete)(const RB_ENTRY(data_t) *key, struct RB_ENTRY(tree) *rbinfo)
{
struct RB_ENTRY(node) *x;
if (rbinfo==NULL)
return(NULL);
x=RB_ENTRY(_traverse)(0, key, rbinfo); if (rbinfo->rb_root!=RBNULL)
toku_rbt__destroy(rbinfo->rb_root);
RB_ENTRY(finger_delete)(x, rbinfo);
assert(0); rbinfo->rb_free(rbinfo);
exit(1);
} }
#endif /* no_delete */
#ifndef no_finger_delete int toku_rbt_finger_delete(struct toku_rbt_node* node, struct toku_rbt_tree *rbinfo) {
RB_STATIC int RB_ENTRY(finger_delete)(struct RB_ENTRY(node)* node, struct RB_ENTRY(tree) *rbinfo) {
int r = ENOSYS; int r = ENOSYS;
if (!rbinfo || !node || node == RBNULL) { r = EINVAL; goto cleanup; } if (!rbinfo || !node || node == RBNULL) { r = EINVAL; goto cleanup; }
RB_ENTRY(_delete)(&rbinfo->rb_root, node); toku_rbt__delete(&rbinfo->rb_root, node);
r = 0; r = 0;
cleanup: cleanup:
return r; return r;
} }
#endif /* no_finger_delete */
#ifndef no_walk
RB_STATIC void
RB_ENTRY(walk)(const struct RB_ENTRY(tree) *rbinfo, void (*action)(const RB_ENTRY(data_t) *, const VISIT, const int, void *), void *arg)
{
if (rbinfo==NULL)
return;
RB_ENTRY(_walk)(rbinfo->rb_root, action, arg, 0);
}
#endif /* no_walk */
#ifndef no_readlist
RB_STATIC RBLIST *
RB_ENTRY(openlist)(const struct RB_ENTRY(tree) *rbinfo)
{
if (rbinfo==NULL)
return(NULL);
return(RB_ENTRY(_openlist)(rbinfo->rb_root));
}
RB_STATIC const RB_ENTRY(data_t) *
RB_ENTRY(readlist)(RBLIST *rblistp)
{
if (rblistp==NULL)
return(NULL);
return(RB_ENTRY(_readlist)(rblistp));
}
RB_STATIC void
RB_ENTRY(closelist)(RBLIST *rblistp)
{
if (rblistp==NULL)
return;
RB_ENTRY(_closelist)(rblistp); int toku_rbt_lookup(
}
#endif /* no_readlist */
#ifndef no_lookup
RB_STATIC int RB_ENTRY(lookup)(
int mode, int mode,
const RB_ENTRY(data_t)* key, const toku_range* key,
struct RB_ENTRY(tree)* rbinfo, struct toku_rbt_tree* rbinfo,
struct RB_ENTRY(node)** pinsert_finger, struct toku_rbt_node** pinsert_finger,
struct RB_ENTRY(node)** pelement_finger, struct toku_rbt_node** pelement_finger,
const RB_ENTRY(data_t)** pdata const toku_range** pdata
) )
{ {
int r = ENOSYS; int r = ENOSYS;
...@@ -553,295 +165,276 @@ RB_STATIC int RB_ENTRY(lookup)( ...@@ -553,295 +165,276 @@ RB_STATIC int RB_ENTRY(lookup)(
)) { )) {
r = EINVAL; goto cleanup; } r = EINVAL; goto cleanup; }
*pelement_finger = RB_ENTRY(_lookup)(mode, key, rbinfo, pinsert_finger); *pelement_finger = toku_rbt__lookup(mode, key, rbinfo, pinsert_finger);
*pdata = *pelement_finger == RBNULL ? NULL : RB_GET((*pelement_finger), key); *pdata = *pelement_finger == RBNULL ? NULL : RB_GET((*pelement_finger), key);
r = 0; r = 0;
cleanup: cleanup:
return r; return r;
} }
#endif /* no_lookup */
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
/* Search for and if not found and insert is true, will add a new /* Search for and if not found and insert is true, will add a new
** node in. Returns a pointer to the new node, or the node found ** node in. Returns a pointer to the new node, or the node found
*/ */
static struct RB_ENTRY(node) * static struct toku_rbt_node *
RB_ENTRY(_traverse)(int insert, const RB_ENTRY(data_t) *key, struct RB_ENTRY(tree) *rbinfo) toku_rbt__traverse(int insert, const toku_range *key, struct toku_rbt_tree *rbinfo)
{ {
struct RB_ENTRY(node) *x,*y; struct toku_rbt_node *x,*y;
int cmp; int cmp;
int found=0; int found=0;
int cmpmods(); int cmpmods();
y=RBNULL; /* points to the parent of x */ y=RBNULL; /* points to the parent of x */
x=rbinfo->rb_root; x=rbinfo->rb_root;
/* walk x down the tree */ /* walk x down the tree */
while(x!=RBNULL && found==0) while(x!=RBNULL && found==0)
{ {
y=x; y=x;
/* printf("key=%s, RB_GET(x, key)=%s\n", key, RB_GET(x, key)); */ /* printf("key=%s, RB_GET(x, key)=%s\n", key, RB_GET(x, key)); */
#ifndef RB_CUSTOMIZE cmp=rbinfo->rb_cmp(key, RB_GET(x, key));
cmp=RB_COMPARE(key, RB_GET(x, key), rbinfo->rb_config);
#else if (cmp<0)
cmp=RB_COMPARE(key, RB_GET(x, key)); x=x->left;
#endif /* RB_CUSTOMIZE */ else if (cmp>0)
x=x->right;
if (cmp<0) else
x=x->left; found=1;
else if (cmp>0) }
x=x->right;
else if (found || !insert)
found=1; return(x);
}
return toku_rbt__insert(key, rbinfo, y);
if (found || !insert)
return(x);
return RB_ENTRY(_insert)(key, rbinfo, y);
} }
#if !defined(no_search) || !defined(no_insert) static struct toku_rbt_node* toku_rbt__insert(
static struct RB_ENTRY(node)* RB_ENTRY(_insert)( const toku_range* key,
const RB_ENTRY(data_t)* key, struct toku_rbt_tree* rbinfo,
struct RB_ENTRY(tree)* rbinfo, struct toku_rbt_node* parent
struct RB_ENTRY(node)* parent
) { ) {
struct RB_ENTRY(node)* x; struct toku_rbt_node* x;
struct RB_ENTRY(node)* y = parent; struct toku_rbt_node* y = parent;
struct RB_ENTRY(node)* z; struct toku_rbt_node* z;
int cmp; int cmp;
if (parent == NULL) { if (parent == NULL) {
/* This means we have NOT actually located the right spot. /* This means we have NOT actually located the right spot.
Locate it with traverse and then insert. */ Locate it with traverse and then insert. */
return RB_ENTRY(_traverse)(1, key, rbinfo); return toku_rbt__traverse(1, key, rbinfo);
} }
if ((z=RB_ENTRY(_alloc)())==NULL) if ((z=toku_rbt__alloc(rbinfo))==NULL)
{ {
/* Whoops, no memory */ /* Whoops, no memory */
return(RBNULL); return(RBNULL);
} }
RB_SET(z, key, key); RB_SET(z, key, key);
z->up=y; z->up=y;
if (y==RBNULL) if (y==RBNULL)
{ {
rbinfo->rb_root=z; rbinfo->rb_root=z;
} }
else else
{ {
#ifndef RB_CUSTOMIZE cmp=rbinfo->rb_cmp(RB_GET(z, key), RB_GET(y, key));
cmp=RB_COMPARE(RB_GET(z, key), RB_GET(y, key), rbinfo->rb_config); if (cmp<0)
#else y->left=z;
cmp=RB_COMPARE(RB_GET(z, key), RB_GET(y, key)); else
#endif /* RB_CUSTOMIZE */ y->right=z;
if (cmp<0) }
y->left=z;
else z->left=RBNULL;
y->right=z; z->right=RBNULL;
}
/* colour this new node red */
z->left=RBNULL; z->colour=RED;
z->right=RBNULL;
/* Having added a red node, we must now walk back up the tree balancing
/* colour this new node red */ ** it, by a series of rotations and changing of colours
z->colour=RED; */
x=z;
/* Having added a red node, we must now walk back up the tree balancing
** it, by a series of rotations and changing of colours /* While we are not at the top and our parent node is red
*/ ** N.B. Since the root node is garanteed black, then we
x=z; ** are also going to stop if we are the child of the root
*/
/* While we are not at the top and our parent node is red
** N.B. Since the root node is garanteed black, then we while(x != rbinfo->rb_root && (x->up->colour == RED))
** are also going to stop if we are the child of the root {
*/ /* if our parent is on the left side of our grandparent */
if (x->up == x->up->up->left)
while(x != rbinfo->rb_root && (x->up->colour == RED)) {
{ /* get the right side of our grandparent (uncle?) */
/* if our parent is on the left side of our grandparent */ y=x->up->up->right;
if (x->up == x->up->up->left) if (y->colour == RED)
{ {
/* get the right side of our grandparent (uncle?) */ /* make our parent black */
y=x->up->up->right; x->up->colour = BLACK;
if (y->colour == RED) /* make our uncle black */
{ y->colour = BLACK;
/* make our parent black */ /* make our grandparent red */
x->up->colour = BLACK; x->up->up->colour = RED;
/* make our uncle black */
y->colour = BLACK; /* now consider our grandparent */
/* make our grandparent red */ x=x->up->up;
x->up->up->colour = RED; }
else
/* now consider our grandparent */ {
x=x->up->up; /* if we are on the right side of our parent */
} if (x == x->up->right)
else {
{ /* Move up to our parent */
/* if we are on the right side of our parent */ x=x->up;
if (x == x->up->right) toku_rbt__left_rotate(&rbinfo->rb_root, x);
{ }
/* Move up to our parent */
x=x->up; /* make our parent black */
RB_ENTRY(_left_rotate)(&rbinfo->rb_root, x); x->up->colour = BLACK;
} /* make our grandparent red */
x->up->up->colour = RED;
/* make our parent black */ /* right rotate our grandparent */
x->up->colour = BLACK; toku_rbt__right_rotate(&rbinfo->rb_root, x->up->up);
/* make our grandparent red */ }
x->up->up->colour = RED; }
/* right rotate our grandparent */ else
RB_ENTRY(_right_rotate)(&rbinfo->rb_root, x->up->up); {
} /* everything here is the same as above, but
} ** exchanging left for right
else */
{
/* everything here is the same as above, but y=x->up->up->left;
** exchanging left for right if (y->colour == RED)
*/ {
x->up->colour = BLACK;
y=x->up->up->left; y->colour = BLACK;
if (y->colour == RED) x->up->up->colour = RED;
{
x->up->colour = BLACK; x=x->up->up;
y->colour = BLACK; }
x->up->up->colour = RED; else
{
x=x->up->up; if (x == x->up->left)
} {
else x=x->up;
{ toku_rbt__right_rotate(&rbinfo->rb_root, x);
if (x == x->up->left) }
{
x=x->up; x->up->colour = BLACK;
RB_ENTRY(_right_rotate)(&rbinfo->rb_root, x); x->up->up->colour = RED;
} toku_rbt__left_rotate(&rbinfo->rb_root, x->up->up);
}
x->up->colour = BLACK; }
x->up->up->colour = RED; }
RB_ENTRY(_left_rotate)(&rbinfo->rb_root, x->up->up);
} /* Set the root node black */
} (rbinfo->rb_root)->colour = BLACK;
}
return(z);
/* Set the root node black */
(rbinfo->rb_root)->colour = BLACK;
return(z);
} }
#endif /* no search || no_insert */
#ifndef no_lookup
/* Search for a key according to mode (see redblack.h) /* Search for a key according to mode (see redblack.h)
*/ */
static struct RB_ENTRY(node) * static struct toku_rbt_node *
RB_ENTRY(_lookup)(int mode, const RB_ENTRY(data_t) *key, struct RB_ENTRY(tree) *rbinfo, struct RB_ENTRY(node)** pinsert_finger) toku_rbt__lookup(int mode, const toku_range *key, struct toku_rbt_tree *rbinfo, struct toku_rbt_node** pinsert_finger)
{ {
struct RB_ENTRY(node) *x,*y; struct toku_rbt_node *x,*y;
int cmp = 0; int cmp = 0;
int found=0; int found=0;
y=RBNULL; /* points to the parent of x */ y=RBNULL; /* points to the parent of x */
x=rbinfo->rb_root; x=rbinfo->rb_root;
if (mode==RB_LUFIRST) if (mode==RB_LUFIRST)
{ {
/* Keep going left until we hit a NULL */ /* Keep going left until we hit a NULL */
while(x!=RBNULL) while(x!=RBNULL)
{ {
y=x; y=x;
x=x->left; x=x->left;
} }
return(y); return(y);
} }
else if (mode==RB_LULAST) else if (mode==RB_LULAST)
{ {
/* Keep going right until we hit a NULL */ /* Keep going right until we hit a NULL */
while(x!=RBNULL) while(x!=RBNULL)
{ {
y=x; y=x;
x=x->right; x=x->right;
} }
return(y); return(y);
} }
/* walk x down the tree */ /* walk x down the tree */
while(x!=RBNULL && found==0) while(x!=RBNULL && found==0)
{ {
y=x; y=x;
/* printf("key=%s, RB_GET(x, key)=%s\n", key, RB_GET(x, key)); */ /* printf("key=%s, RB_GET(x, key)=%s\n", key, RB_GET(x, key)); */
#ifndef RB_CUSTOMIZE cmp=rbinfo->rb_cmp(key, RB_GET(x, key));
cmp=RB_COMPARE(key, RB_GET(x, key), rbinfo->rb_config);
#else
cmp=RB_COMPARE(key, RB_GET(x, key)); if (cmp<0)
#endif /* RB_CUSTOMIZE */ x=x->left;
else if (cmp>0)
x=x->right;
if (cmp<0) else
x=x->left; found=1;
else if (cmp>0) }
x=x->right; if (pinsert_finger) *pinsert_finger = y;
else
found=1; if (found && (mode==RB_LUEQUAL || mode==RB_LUGTEQ || mode==RB_LULTEQ))
} return(x);
if (pinsert_finger) *pinsert_finger = y;
if (!found && (mode==RB_LUEQUAL || mode==RB_LUNEXT || mode==RB_LUPREV))
if (found && (mode==RB_LUEQUAL || mode==RB_LUGTEQ || mode==RB_LULTEQ)) return(RBNULL);
return(x);
if (mode==RB_LUGTEQ || (!found && mode==RB_LUGREAT))
if (!found && (mode==RB_LUEQUAL || mode==RB_LUNEXT || mode==RB_LUPREV)) {
return(RBNULL); if (cmp>0)
return(toku_rbt__successor(y));
if (mode==RB_LUGTEQ || (!found && mode==RB_LUGREAT)) else
{ return(y);
if (cmp>0) }
return(RB_ENTRY(_successor)(y));
else if (mode==RB_LULTEQ || (!found && mode==RB_LULESS))
return(y); {
} if (cmp<0)
return(toku_rbt__predecessor(y));
if (mode==RB_LULTEQ || (!found && mode==RB_LULESS)) else
{ return(y);
if (cmp<0) }
return(RB_ENTRY(_predecessor)(y));
else if (mode==RB_LUNEXT || (found && mode==RB_LUGREAT))
return(y); return(toku_rbt__successor(x));
}
if (mode==RB_LUPREV || (found && mode==RB_LULESS))
if (mode==RB_LUNEXT || (found && mode==RB_LUGREAT)) return(toku_rbt__predecessor(x));
return(RB_ENTRY(_successor)(x));
/* Shouldn't get here */
if (mode==RB_LUPREV || (found && mode==RB_LULESS)) return(RBNULL);
return(RB_ENTRY(_predecessor)(x));
/* Shouldn't get here */
return(RBNULL);
} }
#endif /* no_lookup */
#ifndef no_destroy
/* /*
* Destroy all the elements blow us in the tree * Destroy all the elements blow us in the tree
* only useful as part of a complete tree destroy. * only useful as part of a complete tree destroy.
*/ */
static void static void
RB_ENTRY(_destroy)(struct RB_ENTRY(node) *x) toku_rbt__destroy(struct toku_rbt_node *x)
{ {
if (x!=RBNULL) if (x!=RBNULL)
{ {
if (x->left!=RBNULL) if (x->left!=RBNULL)
RB_ENTRY(_destroy)(x->left); toku_rbt__destroy(x->left);
if (x->right!=RBNULL) if (x->right!=RBNULL)
RB_ENTRY(_destroy)(x->right); toku_rbt__destroy(x->right);
RB_ENTRY(_free)(x); toku_rbt__free(rbinfo,x);
} }
} }
#endif /* no_destroy */
/* /*
** Rotate our tree thus:- ** Rotate our tree thus:-
...@@ -858,631 +451,312 @@ RB_ENTRY(_destroy)(struct RB_ENTRY(node) *x) ...@@ -858,631 +451,312 @@ RB_ENTRY(_destroy)(struct RB_ENTRY(node) *x)
*/ */
static void static void
RB_ENTRY(_left_rotate)(struct RB_ENTRY(node) **rootp, struct RB_ENTRY(node) *x) toku_rbt__left_rotate(struct toku_rbt_node **rootp, struct toku_rbt_node *x)
{ {
struct RB_ENTRY(node) *y; struct toku_rbt_node *y;
assert(x!=RBNULL); assert(x!=RBNULL);
assert(x->right!=RBNULL); assert(x->right!=RBNULL);
y=x->right; /* set Y */ y=x->right; /* set Y */
/* Turn Y's left subtree into X's right subtree (move B)*/ /* Turn Y's left subtree into X's right subtree (move B)*/
x->right = y->left; x->right = y->left;
/* If B is not null, set it's parent to be X */ /* If B is not null, set it's parent to be X */
if (y->left != RBNULL) if (y->left != RBNULL)
y->left->up = x; y->left->up = x;
/* Set Y's parent to be what X's parent was */ /* Set Y's parent to be what X's parent was */
y->up = x->up; y->up = x->up;
/* if X was the root */ /* if X was the root */
if (x->up == RBNULL) if (x->up == RBNULL)
{ {
*rootp=y; *rootp=y;
} }
else else
{ {
/* Set X's parent's left or right pointer to be Y */ /* Set X's parent's left or right pointer to be Y */
if (x == x->up->left) if (x == x->up->left)
{ {
x->up->left=y; x->up->left=y;
} }
else else
{ {
x->up->right=y; x->up->right=y;
} }
} }
/* Put X on Y's left */ /* Put X on Y's left */
y->left=x; y->left=x;
/* Set X's parent to be Y */ /* Set X's parent to be Y */
x->up = y; x->up = y;
} }
static void static void
RB_ENTRY(_right_rotate)(struct RB_ENTRY(node) **rootp, struct RB_ENTRY(node) *y) toku_rbt__right_rotate(struct toku_rbt_node **rootp, struct toku_rbt_node *y)
{ {
struct RB_ENTRY(node) *x; struct toku_rbt_node *x;
assert(y!=RBNULL); assert(y!=RBNULL);
assert(y->left!=RBNULL); assert(y->left!=RBNULL);
x=y->left; /* set X */ x=y->left; /* set X */
/* Turn X's right subtree into Y's left subtree (move B) */ /* Turn X's right subtree into Y's left subtree (move B) */
y->left = x->right; y->left = x->right;
/* If B is not null, set it's parent to be Y */ /* If B is not null, set it's parent to be Y */
if (x->right != RBNULL) if (x->right != RBNULL)
x->right->up = y; x->right->up = y;
/* Set X's parent to be what Y's parent was */ /* Set X's parent to be what Y's parent was */
x->up = y->up; x->up = y->up;
/* if Y was the root */ /* if Y was the root */
if (y->up == RBNULL) if (y->up == RBNULL)
{ {
*rootp=x; *rootp=x;
} }
else else
{ {
/* Set Y's parent's left or right pointer to be X */ /* Set Y's parent's left or right pointer to be X */
if (y == y->up->left) if (y == y->up->left)
{ {
y->up->left=x; y->up->left=x;
} }
else else
{ {
y->up->right=x; y->up->right=x;
} }
} }
/* Put Y on X's right */ /* Put Y on X's right */
x->right=y; x->right=y;
/* Set Y's parent to be X */ /* Set Y's parent to be X */
y->up = x; y->up = x;
} }
/* Return a pointer to the smallest key greater than x /* Return a pointer to the smallest key greater than x
*/ */
static struct RB_ENTRY(node) * static struct toku_rbt_node *
RB_ENTRY(_successor)(const struct RB_ENTRY(node) *x) toku_rbt__successor(const struct toku_rbt_node *x)
{ {
struct RB_ENTRY(node) *y; struct toku_rbt_node *y;
if (x->right!=RBNULL) if (x->right!=RBNULL)
{ {
/* If right is not NULL then go right one and /* If right is not NULL then go right one and
** then keep going left until we find a node with ** then keep going left until we find a node with
** no left pointer. ** no left pointer.
*/ */
for (y=x->right; y->left!=RBNULL; y=y->left); for (y=x->right; y->left!=RBNULL; y=y->left);
} }
else else
{ {
/* Go up the tree until we get to a node that is on the /* Go up the tree until we get to a node that is on the
** left of its parent (or the root) and then return the ** left of its parent (or the root) and then return the
** parent. ** parent.
*/ */
y=x->up; y=x->up;
while(y!=RBNULL && x==y->right) while(y!=RBNULL && x==y->right)
{ {
x=y; x=y;
y=y->up; y=y->up;
} }
} }
return(y); return(y);
} }
/* Return a pointer to the largest key smaller than x /* Return a pointer to the largest key smaller than x
*/ */
static struct RB_ENTRY(node) * static struct toku_rbt_node *
RB_ENTRY(_predecessor)(const struct RB_ENTRY(node) *x) toku_rbt__predecessor(const struct toku_rbt_node *x)
{ {
struct RB_ENTRY(node) *y; struct toku_rbt_node *y;
if (x->left!=RBNULL) if (x->left!=RBNULL)
{ {
/* If left is not NULL then go left one and /* If left is not NULL then go left one and
** then keep going right until we find a node with ** then keep going right until we find a node with
** no right pointer. ** no right pointer.
*/ */
for (y=x->left; y->right!=RBNULL; y=y->right); for (y=x->left; y->right!=RBNULL; y=y->right);
} }
else else
{ {
/* Go up the tree until we get to a node that is on the /* Go up the tree until we get to a node that is on the
** right of its parent (or the root) and then return the ** right of its parent (or the root) and then return the
** parent. ** parent.
*/ */
y=x->up; y=x->up;
while(y!=RBNULL && x==y->left) while(y!=RBNULL && x==y->left)
{ {
x=y; x=y;
y=y->up; y=y->up;
} }
} }
return(y); return(y);
} }
#ifndef no_pred int toku_rbt_finger_predecessor(const struct toku_rbt_node** pfinger,
RB_STATIC int RB_ENTRY(finger_predecessor)(const struct RB_ENTRY(node)** pfinger, const toku_range** ppred_data) {
const RB_ENTRY(data_t)** ppred_data) {
int r = ENOSYS; int r = ENOSYS;
if (!pfinger || !*pfinger || if (!pfinger || !*pfinger ||
*pfinger == RBNULL || !ppred_data) { r = EINVAL; goto cleanup; } *pfinger == RBNULL || !ppred_data) { r = EINVAL; goto cleanup; }
*pfinger = RB_ENTRY(_predecessor)(*pfinger); *pfinger = toku_rbt__predecessor(*pfinger);
*ppred_data = ((*pfinger==RBNULL) ? NULL : RB_GET((*pfinger), key)); *ppred_data = ((*pfinger==RBNULL) ? NULL : RB_GET((*pfinger), key));
r = 0; r = 0;
cleanup: cleanup:
return r; return r;
} }
#endif
#ifndef no_succ int toku_rbt_finger_succecessor(const struct toku_rbt_node** pfinger,
RB_STATIC int RB_ENTRY(finger_succecessor)(const struct RB_ENTRY(node)** pfinger, const toku_range** psucc_data) {
const RB_ENTRY(data_t)** psucc_data) {
int r = ENOSYS; int r = ENOSYS;
if (!pfinger || !*pfinger || if (!pfinger || !*pfinger ||
*pfinger == RBNULL || !psucc_data) { r = EINVAL; goto cleanup; } *pfinger == RBNULL || !psucc_data) { r = EINVAL; goto cleanup; }
*pfinger = RB_ENTRY(_successor)(*pfinger); *pfinger = toku_rbt__successor(*pfinger);
*psucc_data = ((*pfinger==RBNULL) ? NULL : RB_GET((*pfinger), key)); *psucc_data = ((*pfinger==RBNULL) ? NULL : RB_GET((*pfinger), key));
r = 0; r = 0;
cleanup: cleanup:
return r; return r;
} }
#endif
#ifndef no_finger_insert const toku_range* toku_rbt_finger_insert(
RB_STATIC const RB_ENTRY(data_t)* RB_ENTRY(finger_insert)( const toku_range* key,
const RB_ENTRY(data_t)* key, struct toku_rbt_tree* rbinfo,
struct RB_ENTRY(tree)* rbinfo, struct toku_rbt_node* parent
struct RB_ENTRY(node)* parent
) { ) {
struct RB_ENTRY(node)* x; struct toku_rbt_node* x;
if (!parent) return NULL; if (!parent) return NULL;
x = RB_ENTRY(_insert)(key, rbinfo, parent); x = toku_rbt__insert(key, rbinfo, parent);
return ((x==RBNULL) ? NULL : RB_GET(x, key)); return ((x==RBNULL) ? NULL : RB_GET(x, key));
} }
#endif /* no_finger_insert */
#if !defined(no_delete) || !defined (no_finger_delete)
/* Delete the node z, and free up the space /* Delete the node z, and free up the space
*/ */
static void static void
RB_ENTRY(_delete)(struct RB_ENTRY(node) **rootp, struct RB_ENTRY(node) *z) toku_rbt__delete(struct toku_rbt_node **rootp, struct toku_rbt_node *z)
{
struct RB_ENTRY(node) *x, *y;
if (z->left == RBNULL || z->right == RBNULL)
y=z;
else
y=RB_ENTRY(_successor)(z);
if (y->left != RBNULL)
x=y->left;
else
x=y->right;
x->up = y->up;
if (y->up == RBNULL)
{
*rootp=x;
}
else
{
if (y==y->up->left)
y->up->left = x;
else
y->up->right = x;
}
if (y!=z)
{
RB_SET(z, key, RB_GET(y, key));
}
if (y->colour == BLACK)
RB_ENTRY(_delete_fix)(rootp, x);
RB_ENTRY(_free)(y);
}
/* Restore the reb-black properties after a delete */
static void
RB_ENTRY(_delete_fix)(struct RB_ENTRY(node) **rootp, struct RB_ENTRY(node) *x)
{
struct RB_ENTRY(node) *w;
while (x!=*rootp && x->colour==BLACK)
{
if (x==x->up->left)
{
w=x->up->right;
if (w->colour==RED)
{
w->colour=BLACK;
x->up->colour=RED;
RB_ENTRY(_left_rotate)(rootp, x->up);
w=x->up->right;
}
if (w->left->colour==BLACK && w->right->colour==BLACK)
{
w->colour=RED;
x=x->up;
}
else
{
if (w->right->colour == BLACK)
{
w->left->colour=BLACK;
w->colour=RED;
RB_ENTRY(_right_rotate)(rootp, w);
w=x->up->right;
}
w->colour=x->up->colour;
x->up->colour = BLACK;
w->right->colour = BLACK;
RB_ENTRY(_left_rotate)(rootp, x->up);
x=*rootp;
}
}
else
{
w=x->up->left;
if (w->colour==RED)
{
w->colour=BLACK;
x->up->colour=RED;
RB_ENTRY(_right_rotate)(rootp, x->up);
w=x->up->left;
}
if (w->right->colour==BLACK && w->left->colour==BLACK)
{
w->colour=RED;
x=x->up;
}
else
{
if (w->left->colour == BLACK)
{
w->right->colour=BLACK;
w->colour=RED;
RB_ENTRY(_left_rotate)(rootp, w);
w=x->up->left;
}
w->colour=x->up->colour;
x->up->colour = BLACK;
w->left->colour = BLACK;
RB_ENTRY(_right_rotate)(rootp, x->up);
x=*rootp;
}
}
}
x->colour=BLACK;
}
#endif /* no_delete */
#ifndef no_walk
static void
RB_ENTRY(_walk)(const struct RB_ENTRY(node) *x, void (*action)(const RB_ENTRY(data_t) *, const VISIT, const int, void *), void *arg, int level)
{ {
if (x==RBNULL) struct toku_rbt_node *x, *y;
return;
if (x->left==RBNULL && x->right==RBNULL)
{
/* leaf */
(*action)(RB_GET(x, key), leaf, level, arg);
}
else
{
(*action)(RB_GET(x, key), preorder, level, arg);
RB_ENTRY(_walk)(x->left, action, arg, level+1);
(*action)(RB_GET(x, key), postorder, level, arg);
RB_ENTRY(_walk)(x->right, action, arg, level+1);
(*action)(RB_GET(x, key), endorder, level, arg);
}
}
#endif /* no_walk */
#ifndef no_readlist
static RBLIST *
RB_ENTRY(_openlist)(const struct RB_ENTRY(node) *rootp)
{
RBLIST *rblistp;
rblistp=(RBLIST *) malloc(sizeof(RBLIST));
if (!rblistp)
return(NULL);
rblistp->rootp=rootp;
rblistp->nextp=rootp;
if (rootp!=RBNULL)
{
while(rblistp->nextp->left!=RBNULL)
{
rblistp->nextp=rblistp->nextp->left;
}
}
return(rblistp); if (z->left == RBNULL || z->right == RBNULL)
} y=z;
else
y=toku_rbt__successor(z);
static const RB_ENTRY(data_t) * if (y->left != RBNULL)
RB_ENTRY(_readlist)(RBLIST *rblistp) x=y->left;
{ else
const RB_ENTRY(data_t) *key=NULL; x=y->right;
if (rblistp!=NULL && rblistp->nextp!=RBNULL) x->up = y->up;
{
key=RB_GET(rblistp->nextp, key);
rblistp->nextp=RB_ENTRY(_successor)(rblistp->nextp);
}
return(key); if (y->up == RBNULL)
} {
*rootp=x;
}
else
{
if (y==y->up->left)
y->up->left = x;
else
y->up->right = x;
}
static void if (y!=z)
rb_closelist(RBLIST *rblistp) {
{ RB_SET(z, key, RB_GET(y, key));
if (rblistp) }
free(rblistp);
}
#endif /* no_readlist */
#if defined(RB_USE_SBRK) if (y->colour == BLACK)
/* Allocate space for our nodes, allowing us to get space from toku_rbt__delete_fix(rootp, x);
** sbrk in larger chucks.
*/
static struct RB_ENTRY(node) *rbfreep=NULL;
#define RB_ENTRY(NODE)ALLOC_CHUNK_SIZE 1000 toku_rbt__free(rbinfo,y);
static struct RB_ENTRY(node) *
RB_ENTRY(_alloc)()
{
struct RB_ENTRY(node) *x;
int i;
if (rbfreep==NULL)
{
/* must grab some more space */
rbfreep=(struct RB_ENTRY(node) *) sbrk(sizeof(struct RB_ENTRY(node)) * RB_ENTRY(NODE)ALLOC_CHUNK_SIZE);
if (rbfreep==(struct RB_ENTRY(node) *) -1)
{
return(NULL);
}
/* tie them together in a linked list (use the up pointer) */
for (i=0, x=rbfreep; i<RB_ENTRY(NODE)ALLOC_CHUNK_SIZE-1; i++, x++)
{
x->up = (x+1);
}
x->up=NULL;
}
x=rbfreep;
rbfreep = rbfreep->up;
#ifdef RB_ALLOC
RB_ALLOC(ACCESS(x, key));
#endif /* RB_ALLOC */
return(x);
} }
/* free (dealloc) an RB_ENTRY(node) structure - add it onto the front of the list /* Restore the reb-black properties after a delete */
** N.B. RB_ENTRY(node) need not have been allocated through rb_alloc()
*/
static void static void
RB_ENTRY(_free)(struct RB_ENTRY(node) *x) toku_rbt__delete_fix(struct toku_rbt_node **rootp, struct toku_rbt_node *x)
{ {
#ifdef RB_FREE struct toku_rbt_node *w;
RB_FREE(ACCESS(x, key));
#endif /* RB_FREE */ while (x!=*rootp && x->colour==BLACK)
x->up=rbfreep; {
rbfreep=x; if (x==x->up->left)
} {
w=x->up->right;
#endif if (w->colour==RED)
{
#if 0 w->colour=BLACK;
int x->up->colour=RED;
RB_ENTRY(_check)(struct RB_ENTRY(node) *rootp) toku_rbt__left_rotate(rootp, x->up);
{ w=x->up->right;
if (rootp==NULL || rootp==RBNULL) }
return(0);
if (w->left->colour==BLACK && w->right->colour==BLACK)
if (rootp->up!=RBNULL) {
{ w->colour=RED;
fprintf(stderr, "Root up pointer not RBNULL"); x=x->up;
dumptree(rootp, 0); }
return(1); else
} {
if (w->right->colour == BLACK)
if (RB_ENTRY(_check)1(rootp)) {
{ w->left->colour=BLACK;
RB_ENTRY(dumptree)(rootp, 0); w->colour=RED;
return(1); toku_rbt__right_rotate(rootp, w);
} w=x->up->right;
}
if (RB_ENTRY(count_black)(rootp)==-1)
{
RB_ENTRY(dumptree)(rootp, 0); w->colour=x->up->colour;
return(-1); x->up->colour = BLACK;
} w->right->colour = BLACK;
toku_rbt__left_rotate(rootp, x->up);
return(0); x=*rootp;
} }
}
int else
RB_ENTRY(_check1)(struct RB_ENTRY(node) *x) {
{ w=x->up->left;
if (x->left==NULL || x->right==NULL) if (w->colour==RED)
{ {
fprintf(stderr, "Left or right is NULL"); w->colour=BLACK;
return(1); x->up->colour=RED;
} toku_rbt__right_rotate(rootp, x->up);
w=x->up->left;
if (x->colour==RED) }
{
if (x->left->colour!=BLACK && x->right->colour!=BLACK) if (w->right->colour==BLACK && w->left->colour==BLACK)
{ {
fprintf(stderr, "Children of red node not both black, x=%ld", x); w->colour=RED;
return(1); x=x->up;
} }
} else
{
if (x->left != RBNULL) if (w->left->colour == BLACK)
{ {
if (x->left->up != x) w->right->colour=BLACK;
{ w->colour=RED;
fprintf(stderr, "x->left->up != x, x=%ld", x); toku_rbt__left_rotate(rootp, w);
return(1); w=x->up->left;
} }
if (rb_check1(x->left)) w->colour=x->up->colour;
return(1); x->up->colour = BLACK;
} w->left->colour = BLACK;
toku_rbt__right_rotate(rootp, x->up);
if (x->right != RBNULL) x=*rootp;
{ }
if (x->right->up != x) }
{ }
fprintf(stderr, "x->right->up != x, x=%ld", x);
return(1);
}
if (rb_check1(x->right))
return(1);
}
return(0);
}
RB_ENTRY(count_black)(struct RB_ENTRY(node) *x)
{
int nleft, nright;
if (x==RBNULL)
return(1);
nleft=RB_ENTRY(count_black)(x->left);
nright=RB_ENTRY(count_black)(x->right);
if (nleft==-1 || nright==-1)
return(-1);
if (nleft != nright)
{
fprintf(stderr, "Black count not equal on left & right, x=%ld", x);
return(-1);
}
if (x->colour == BLACK)
{
nleft++;
}
return(nleft);
}
RB_ENTRY(dumptree)(struct RB_ENTRY(node) *x, int n) x->colour=BLACK;
{
char *prkey();
if (x!=NULL && x!=RBNULL)
{
n++;
fprintf(stderr, "Tree: %*s %ld: left=%ld, right=%ld, colour=%s, key=%s",
n,
"",
x,
x->left,
x->right,
(x->colour==BLACK) ? "BLACK" : "RED",
prkey(RB_GET(x, key)));
RB_ENTRY(dumptree)(x->left, n);
RB_ENTRY(dumptree)(x->right, n);
}
} }
#endif
/*
* $Log: redblack.c,v $
* Revision 1.9 2003/10/24 01:31:21 damo
* Patches from Eric Raymond: %prefix is implemented.  Various other small
* changes avoid stepping on global namespaces and improve the documentation.
*
* Revision 1.8 2002/08/26 05:33:47 damo
* Some minor fixes:-
* Stopped ./configure warning about stuff being in the wrong order
* Fixed compiler warning about const (not sure about this)
* Changed directory of redblack.c in documentation
*
* Revision 1.7 2002/08/26 03:11:40 damo
* Fixed up a bunch of compiler warnings when compiling example4
*
* Tidies up the Makefile.am & Specfile.
*
* Renamed redblack to rbgen
*
* Revision 1.6 2002/08/26 01:03:35 damo
* Patch from Eric Raymond to change the way the library is used:-
*
* Eric's idea is to convert libredblack into a piece of in-line code
* generated by another program. This should be faster, smaller and easier
* to use.
*
* This is the first check-in of his code before I start futzing with it!
*
* Revision 1.5 2002/01/30 07:54:53 damo
* Fixed up the libtool versioning stuff (finally)
* Fixed bug 500600 (not detecting a NULL return from malloc)
* Fixed bug 509485 (no longer needs search.h)
* Cleaned up debugging section
* Allow multiple inclusions of redblack.h
* Thanks to Matthias Andree for reporting (and fixing) these
*
* Revision 1.4 2000/06/06 14:43:43 damo
* Added all the rbwalk & rbopenlist stuff. Fixed up malloc instead of sbrk.
* Added two new examples
*
* Revision 1.3 2000/05/24 06:45:27 damo
* Converted everything over to using const
* Added a new example1.c file to demonstrate the worst case scenario
* Minor fixups of the spec file
*
* Revision 1.2 2000/05/24 06:17:10 damo
* Fixed up the License (now the LGPL)
*
* Revision 1.1 2000/05/24 04:15:53 damo
* Initial import of files. Versions are now all over the place. Oh well
*
*/
/* rbgen generated code ends here */
// The following sets edit modes for GNU EMACS
// Local Variables:
// mode:c
// End:
#include <rangetree.h>
// These are the redblack directives
/* rbgen generated code begins here */
/* rbgen: $Id: rbgen.in,v 1.3 2003/10/24 01:31:21 damo Exp $ */
#define toku_range toku_range
#define RB_INLINE
/* /*
* RCS $Id: redblack.h,v 1.9 2003/10/24 01:31:21 damo Exp $ * RCS $Id: redblack.h,v 1.9 2003/10/24 01:31:21 damo Exp $
*/ */
...@@ -28,196 +35,79 @@ ...@@ -28,196 +35,79 @@
/* Stop multiple includes */ /* Stop multiple includes */
#ifndef _REDBLACK_H #ifndef _REDBLACK_H
#ifndef RB_CUSTOMIZE
/*
* Without customization, the data member in the tree nodes is a void
* pointer, and you need to pass in a comparison function to be
* applied at runtime. With customization, you specify the data type
* as the macro RB_ENTRY(data_t) (has to be a macro because compilers
* gag on typdef void) and the name of the compare function as the
* value of the macro RB_COMPARE. Because the comparison function is
* compiled in, RB_COMPARE only needs to take two arguments. If your
* content type is not a pointer, define INLINE to get direct access.
*/
#define rbdata_t void
#define RB_COMPARE(s, t, e) (*rbinfo->rb_cmp)(s, t, e)
#undef RB_INLINE
#define RB_ENTRY(name) rb##name
#else
//Not Customized
#define RB_COMPARE(s, t) (*rbinfo->rb_cmp)(s, t)
#endif /* RB_CUSTOMIZE */
#ifndef RB_STATIC
#define RB_STATIC
#endif
/* Modes for rblookup */ /* Modes for rblookup */
#define RB_NONE -1 /* None of those below */ typedef enum {
#define RB_LUEQUAL 0 /* Only exact match */ RB_NONE = -1, /* None of those below */
#define RB_LUGTEQ 1 /* Exact match or greater */ RB_LUEQUAL = 0, /* Only exact match */
#define RB_LULTEQ 2 /* Exact match or less */ RB_LUGTEQ = 1, /* Exact match or greater */
#define RB_LULESS 3 /* Less than key (not equal to) */ RB_LULTEQ = 2, /* Exact match or less */
#define RB_LUGREAT 4 /* Greater than key (not equal to) */ RB_LULESS = 3, /* Less than key (not equal to) */
#define RB_LUNEXT 5 /* Next key after current */ RB_LUGREAT = 4, /* Greater than key (not equal to) */
#define RB_LUPREV 6 /* Prev key before current */ RB_LUNEXT = 5, /* Next key after current */
#define RB_LUFIRST 7 /* First key in index */ RB_LUPREV = 6, /* Prev key before current */
#define RB_LULAST 8 /* Last key in index */ RB_LUFIRST = 7, /* First key in index */
RB_LULAST = 8 /* Last key in index */
/* For rbwalk - pinched from search.h */ } toku_rbt_look_mode;
typedef enum
{ struct toku_rbt_lists {
preorder, const struct toku_rbt_node *rootp;
postorder, const struct toku_rbt_node *nextp;
endorder,
leaf
}
VISIT;
struct RB_ENTRY(lists) {
const struct RB_ENTRY(node) *rootp;
const struct RB_ENTRY(node) *nextp;
}; };
#define RBLIST struct RB_ENTRY(lists) struct toku_rbt_tree {
int (*rb_cmp)(const toku_range*, const toku_range*);
struct RB_ENTRY(tree) { struct toku_rbt_node *rb_root;
#ifndef RB_CUSTOMIZE void* (*rb_malloc) (size_t);
/* comparison routine */ void (*rb_free) (void*);
int (*rb_cmp)(const void *, const void *, const void *); void* (*rb_realloc)(void*, size_t);
/* config data to be passed to rb_cmp */
const void *rb_config;
/* root of tree */
#else
int (*rb_cmp)(const RB_ENTRY(data_t)*, const RB_ENTRY(data_t)*);
#endif /* RB_CUSTOMIZE */
struct RB_ENTRY(node) *rb_root;
}; };
RB_STATIC int RB_ENTRY(init) ( int toku_rbt_init (
#ifndef RB_CUSTOMIZE int (*cmp)(const toku_range*, const toku_range*),
int (*cmp)(const void *, const void *, const void *), const void *config, struct toku_rbt_tree** ptree
#else
int (*cmp)(const RB_ENTRY(data_t)*, const RB_ENTRY(data_t)*),
#endif /* RB_CUSTOMIZE */
struct RB_ENTRY(tree)** ptree
); );
#ifndef no_delete int toku_rbt_lookup(
RB_STATIC const RB_ENTRY(data_t) *RB_ENTRY(delete)(const RB_ENTRY(data_t) *, struct RB_ENTRY(tree) *);
#endif
#ifndef no_find
RB_STATIC const RB_ENTRY(data_t) *RB_ENTRY(find)(const RB_ENTRY(data_t) *, struct RB_ENTRY(tree) *);
#endif
#ifndef no_lookup
RB_STATIC int RB_ENTRY(lookup)(
int mode, int mode,
const RB_ENTRY(data_t)* key, const toku_range* key,
struct RB_ENTRY(tree)* rbinfo, struct toku_rbt_tree* rbinfo,
struct RB_ENTRY(node)** pinsert_finger, struct toku_rbt_node** pinsert_finger,
struct RB_ENTRY(node)** pelement_finger, struct toku_rbt_node** pelement_finger,
const RB_ENTRY(data_t)** pdata const toku_range** pdata
); );
#endif
#ifndef no_search
RB_STATIC const RB_ENTRY(data_t) *RB_ENTRY(search)(const RB_ENTRY(data_t) *, struct RB_ENTRY(tree) *);
#endif
#ifndef no_finger_insert const toku_range* toku_rbt_finger_insert(
RB_STATIC const RB_ENTRY(data_t)* RB_ENTRY(finger_insert)( const toku_range* key,
const RB_ENTRY(data_t)* key, struct toku_rbt_tree* rbinfo,
struct RB_ENTRY(tree)* rbinfo, struct toku_rbt_node* parent
struct RB_ENTRY(node)* parent
); );
#endif
#ifndef no_finger_delete
RB_STATIC int RB_ENTRY(finger_delete)(struct RB_ENTRY(node)* node, struct RB_ENTRY(tree) *rbinfo);
#endif
#ifndef no_pred int toku_rbt_finger_delete(struct toku_rbt_node* node, struct toku_rbt_tree *rbinfo);
RB_STATIC int RB_ENTRY(finger_predecessor)(const struct RB_ENTRY(node)** pfinger, const RB_ENTRY(data_t)** ppred_data);
#endif
#ifndef no_succ int toku_rbt_finger_predecessor(const struct toku_rbt_node** pfinger, const toku_range** ppred_data);
RB_STATIC int RB_ENTRY(finger_successor)(const struct RB_ENTRY(node)** pfinger, const RB_ENTRY(data_t)** psucc_data);
#endif
#ifndef no_destroy int toku_rbt_finger_successor(const struct toku_rbt_node** pfinger, const toku_range** psucc_data);
RB_STATIC void RB_ENTRY(destroy)(struct RB_ENTRY(tree) *);
#endif
#ifndef no_walk void toku_rbt_destroy(struct toku_rbt_tree *);
RB_STATIC void RB_ENTRY(walk)(const struct RB_ENTRY(tree) *,
void (*)(const RB_ENTRY(data_t) *, const VISIT, const int, void *),
void *);
#endif
#ifndef no_readlist enum nodecolour { BLACK, RED };
RB_STATIC RBLIST *RB_ENTRY(openlist)(const struct RB_ENTRY(tree) *);
RB_STATIC const RB_ENTRY(data_t) *RB_ENTRY(readlist)(RBLIST *);
RB_STATIC void RB_ENTRY(closelist)(RBLIST *);
#endif
/* Some useful macros */ struct toku_rbt_node
#define rbmin(rbinfo) RB_ENTRY(lookup)(RB_LUFIRST, NULL, (rbinfo)) {
#define rbmax(rbinfo) RB_ENTRY(lookup)(RB_LULAST, NULL, (rbinfo)) struct toku_rbt_node *left; /* Left down */
struct toku_rbt_node *right; /* Right down */
struct toku_rbt_node *up; /* Up */
enum nodecolour colour; /* Node colour */
#ifdef RB_INLINE
toku_range key; /* User's key (and data) */
#define RB_GET(x,y) &x->y
#define RB_SET(x,y,v) x->y = *(v)
#else
const toku_range *key; /* Pointer to user's key (and data) */
#define RB_GET(x,y) x->y
#define RB_SET(x,y,v) x->y = v
#endif /* RB_INLINE */
};
#define _REDBLACK_H #define _REDBLACK_H
#endif /* _REDBLACK_H */ #endif /* _REDBLACK_H */
/*
*
* $Log: redblack.h,v $
* Revision 1.9 2003/10/24 01:31:21 damo
* Patches from Eric Raymond: %prefix is implemented.  Various other small
* changes avoid stepping on global namespaces and improve the documentation.
*
* Revision 1.8 2003/10/23 04:18:47 damo
* Fixed up the rbgen stuff ready for the 1.3 release
*
* Revision 1.7 2002/08/26 03:11:40 damo
* Fixed up a bunch of compiler warnings when compiling example4
*
* Tidies up the Makefile.am & Specfile.
*
* Renamed redblack to rbgen
*
* Revision 1.6 2002/08/26 01:03:35 damo
* Patch from Eric Raymond to change the way the library is used:-
*
* Eric's idea is to convert libredblack into a piece of in-line code
* generated by another program. This should be faster, smaller and easier
* to use.
*
* This is the first check-in of his code before I start futzing with it!
*
* Revision 1.5 2002/01/30 07:54:53 damo
* Fixed up the libtool versioning stuff (finally)
* Fixed bug 500600 (not detecting a NULL return from malloc)
* Fixed bug 509485 (no longer needs search.h)
* Cleaned up debugging section
* Allow multiple inclusions of redblack.h
* Thanks to Matthias Andree for reporting (and fixing) these
*
* Revision 1.4 2000/06/06 14:43:43 damo
* Added all the rbwalk & rbopenlist stuff. Fixed up malloc instead of sbrk.
* Added two new examples
*
* Revision 1.3 2000/05/24 06:45:27 damo
* Converted everything over to using const
* Added a new example1.c file to demonstrate the worst case scenario
* Minor fixups of the spec file
*
* Revision 1.2 2000/05/24 06:17:10 damo
* Fixed up the License (now the LGPL)
*
* Revision 1.1 2000/05/24 04:15:53 damo
* Initial import of files. Versions are now all over the place. Oh well
*
*/
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment