#include "memory.h" #include "rbtree.h" #include #include #define COMPARE(T, X, Y) ((T->compare) == Py_None ? \ T->cmp_func(X, Y) : \ rbtree_pycmp(T->compare, X, Y)) static int rbtree_pycmp(PyObject *compare, PyObject *x, PyObject *y) { // Invoke a Python compare function returning the result as an int. PyObject *res; PyObject *args; int i; args = PyTuple_New(2); if (args == NULL) return -1; Py_INCREF(x); Py_INCREF(y); PyTuple_SET_ITEM(args, 0, x); PyTuple_SET_ITEM(args, 1, y); res = PyObject_Call(compare, args, NULL); Py_DECREF(args); if (res == NULL) return -1; if (!PyInt_Check(res)) { Py_DECREF(res); PyErr_SetString(PyExc_TypeError, "comparison function must return int"); return -1; } i = PyInt_AsLong(res); Py_DECREF(res); return i; } static int rbtree_node_compare(PyObject *x, PyObject *y) { /* a three way compare that should work with whatever objects support */ int gt = PyObject_RichCompareBool(x,y, Py_GT); if (gt == 1) return 1; int lt = PyObject_RichCompareBool(x,y, Py_LT); if (lt == 1) return -1; return 0; } static int rbtree_node_compare_string(PyObject *x, PyObject *y) { return strcmp((char*)PyString_AS_STRING(x), (char*)PyString_AS_STRING(y)); } void rbtree_dump_node(rbtree_t *T, rbtree_node_t *n) { printf("rbtree_node_t 0x%x\n", (unsigned int) n); printf("\tL-> 0x%x\n", (unsigned int) n->l); printf("\tR-> 0x%x\n", (unsigned int) n->r); printf("\tC-> %s\n", n->color == BLACK ? "BLACK" : "RED"); _PyObject_Dump(n->key); _PyObject_Dump(n->value); } static void __rotate_left (rbtree_t *T, rbtree_node_t *x) { rbtree_node_t *y = x->r; x->r = y->l; if (x->r != T->nil) { x->r->p = x; } y->p = x->p; if (y->p == T->nil) { T->root = y; goto gc; } if (y->p->l == x) { y->p->l = y; goto gc; } { y->p->r = y; } gc: y->l = x; x->p = y; } static void __rotate_right (rbtree_t *T, rbtree_node_t *x) { rbtree_node_t *y = x->l; x->l = y->r; if (x->l != T->nil) { x->l->p = x; } y->p = x->p; if (y->p == T->nil) { T->root = y; goto gc; } if (y->p->l == x) { y->p->l = y; goto gc; } { y->p->r = y; } gc: y->r = x; x->p = y; } static rbtree_node_t * __tree_min (rbtree_t *T, rbtree_node_t *x) { while (x->l != T->nil) { x = x->l; } return x; } static rbtree_node_t * __tree_max (rbtree_t *T, rbtree_node_t *x) { while (x->r != T->nil) { x = x->r; } return x; } static rbtree_node_t * __tree_successor (rbtree_t *T, rbtree_node_t *x) { rbtree_node_t *y; if (x->r != T->nil) { return __tree_min(T, x->r); } for (y = x->p; (y != T->nil) && (x == y->r); ) { x = y; y = y->p; } return y; } static rbtree_node_t * __tree_predecessor(rbtree_t *T, rbtree_node_t *x) { rbtree_node_t *y; if (x->l != T->nil) { return __tree_max(T, x->l); } for (y = x->p; (y != T->nil) && (x == y->l); ) { x = y; y = y->p; } return y; } static rbtree_node_t * __tree_search (rbtree_t *T, rbtree_node_t *x, const PyObject *k, int *rc) { rbtree_node_t *y = T->nil; for ((*rc) = -1; (x != T->nil); ) { (*rc) = COMPARE(T, (PyObject *)k, x->key); y = x; if ((*rc) == 0) return x; if ((*rc) < 0) x = x->l; else x = x->r; } return ((*rc) < 0) ? y : __tree_successor(T, y); } static rbtree_node_t * __tree_insert (rbtree_t *T, PyObject *k, PyObject *v) { rbtree_node_t *x = T->root; rbtree_node_t *y = T->nil; int rc = 0; // Use the optimized function until we can't if (!PyString_CheckExact(k)) { T->cmp_func = rbtree_node_compare; } while (x != T->nil) { rc = COMPARE(T, k, x->key); y = x; if (rc == 0) { // force a value update // XXX: (later) validate this? Py_XDECREF(x->key); Py_XDECREF(x->value); x->key = k; x->value = v; return 0; } if (rc < 0) x = x->l; else x = x->r; } NEW(x, rbtree_node_t); x->key = k; x->value = v; x->p = y; x->l = T->nil; x->r = T->nil; MAKE_BLACK(x); T->ct++; if (y == T->nil) { T->root = x; return x; } if (rc < 0) { y->l = x; return x; } { y->r = x; return x; } } static int __rb_insert (rbtree_t *T, PyObject *k, PyObject *v) { rbtree_node_t *x = __tree_insert(T, k, v); rbtree_node_t *y; Py_INCREF(k); Py_INCREF(v); if (x == NULL) { return 0; } if (x) { MAKE_RED (x); while ((x != T->root) && (COLOR(x->p) == RED)) { if (x->p == x->p->p->l) { y = x->p->p->r; if (COLOR(y) == RED) { MAKE_BLACK(x->p); MAKE_BLACK(y); MAKE_RED (x->p->p); x = x->p->p; } else { if (x == x->p->r) { x = x->p; __rotate_left(T, x); } MAKE_BLACK(x->p); MAKE_RED (x->p->p); __rotate_right(T, x->p->p); break; } } else { y = x->p->p->l; if (COLOR(y) == RED) { MAKE_BLACK(x->p); MAKE_BLACK(y); MAKE_RED (x->p->p); x = x->p->p; } else { if (x == x->p->l) { x = x->p; __rotate_right(T, x); } MAKE_BLACK(x->p); MAKE_RED (x->p->p); __rotate_left(T, x->p->p); break; } } } MAKE_BLACK(T->root); return 0; } return 1; } static void __rb_del_fix(rbtree_t *T, rbtree_node_t *x) { rbtree_node_t *w; while ((x != T->root) && (COLOR(x) == BLACK)) { if (x == x->p->l) { w = x->p->r; if (COLOR(w) == RED) { MAKE_BLACK(w); MAKE_RED (x->p); __rotate_left(T, x->p); w = x->p->r; } if ((COLOR(w->l) == BLACK) && (COLOR(w->r) == BLACK)) { MAKE_RED(w); x = x->p; } else { if (COLOR(w->r) == BLACK) { MAKE_BLACK(w->l); MAKE_RED (w); __rotate_right(T, w); w = x->p->r; } w->color = COLOR(x->p); MAKE_BLACK(x->p); MAKE_BLACK(w->r); __rotate_left(T, x->p); x = T->root; break; } } else { w = x->p->l; if (COLOR(w) == RED) { MAKE_BLACK(w); MAKE_RED (x->p); __rotate_right(T, x->p); w = x->p->l; } if ((COLOR(w->l) == BLACK) && (COLOR(w->r) == BLACK)) { MAKE_RED(w); x = x->p; } else { if (COLOR(w->l) == BLACK) { MAKE_BLACK(w->r); MAKE_RED (w); __rotate_left(T, w); w = x->p->l; } w->color = COLOR(x->p); MAKE_BLACK(x->p); MAKE_BLACK(w->l); __rotate_right(T, x->p); x = T->root; break; } } } MAKE_BLACK(x); } static rbtree_node_t * __rb_del_node(rbtree_t *T, rbtree_node_t *z) { // Delete a node and return successor rbtree_node_t *y; rbtree_node_t *x; rbtree_node_t *remainder = NULL; if (z == NULL) return NULL; remainder = __tree_successor(T, z); if ((z->l == T->nil) || (z->r == T->nil)) y = z; else y = remainder; if (y->l != T->nil) x = y->l; else x = y->r; x->p = y->p; if (y->p == T->nil) T->root = x; else { // Disconnect y from tree if (y == y->p->l) y->p->l = x; else y->p->r = x; } if (y != z) { // copy y to z replace z, the delete target with y's data, then // remove the old shell. saves a rotate. Py_DECREF(z->key); Py_DECREF(z->value); z->key = y->key; z->value = y->value; remainder = z; } if (COLOR(y) == BLACK) { __rb_del_fix(T, x); } DEL(y); T->ct--; return remainder; } static int __rb_del (rbtree_t *T, PyObject *k) { rbtree_node_t *z; int rc; z = __tree_search(T, T->root, k, &rc); if (rc == 0) { __rb_del_node(T, z); return 0; } return 1; } rbtree_node_t * rbtree_node_del(rbtree_t *T, rbtree_node_t *n) { if (n == NULL) return 0; if (n == T->nil) return 0; return __rb_del_node(T, n); } rbtree_t * rbtree_alloc (void) { rbtree_t *l_rbt; NEW(l_rbt, rbtree_t); return l_rbt; } int rbtree_init (rbtree_t *T) { NEW (T->nil, rbtree_node_t); memset(T->nil, 0, sizeof(rbtree_node_t)); MAKE_BLACK(T->nil); T->nil->l = T->nil; T->nil->r = T->nil; T->nil->p = T->nil; T->root = T->nil; T->ct = 0; T->cmp_func = rbtree_node_compare_string; T->compare = Py_None; Py_INCREF(Py_None); return 0; } void rbtree_set_compare(rbtree_t *T, PyObject *compare) { if (T->ct == 0) { // We can only set the compare function when the tree is empty Py_DECREF(T->compare); T->compare = compare; Py_INCREF(T->compare); } } static void __destroy (rbtree_t *T, rbtree_node_t *n) { if (n != T->nil) { Py_DECREF(n->key); Py_DECREF(n->value); __destroy(T, n->l); __destroy(T, n->r); DEL (n); } } void rbtree_dealloc(rbtree_t *T) { __destroy(T, T->root); Py_XDECREF(T->compare); DEL(T->nil); } void rbtree_free (rbtree_t *T) { DEL(T); } int rbtree_add (rbtree_t *T, PyObject *a_ptr, PyObject *value) { return __rb_insert(T, a_ptr, value); } int rbtree_del (rbtree_t *T, PyObject *a_ptr) { return __rb_del (T, a_ptr); } void * rbtree_get (rbtree_t *T, PyObject *key) { rbtree_node_t *x; int rc; x = __tree_search(T, T->root, key, &rc); return (rc != 0) ? NULL : (x->value); } rbtree_node_t * rbtree_get_node (rbtree_t *T, PyObject *key) { rbtree_node_t *x; int rc; x = __tree_search(T, T->root, key, &rc); return (rc != 0) ? NULL : x; } rbtree_node_t * tree_min(rbtree_t *T, rbtree_node_t *x) { if (x == NULL) x = T->root; rbtree_node_t *n = __tree_min(T, x); if (n == T->nil) n = NULL; return n; } rbtree_node_t * tree_max(rbtree_t *T, rbtree_node_t *x) { if (x == NULL) x = T->root; rbtree_node_t *n = __tree_max(T, x); if (n == T->nil) n = NULL; return n; } rbtree_node_t * tree_successor(rbtree_t *T, rbtree_node_t *x) { rbtree_node_t *n = __tree_successor(T, x); if (n == T->nil) n = NULL; return n; } rbtree_node_t * tree_predecessor(rbtree_t *T, rbtree_node_t *x) { rbtree_node_t *n = __tree_predecessor(T, x); if (n == T->nil) n = NULL; return n; } #define ABS( a ) ( (a) < 0 ? -(a) : (a) ) void rbtree_do_slice(rbtree_t *T, PyObject *start, PyObject *end, PyObject *stride, rbtree_t *new) { // Return a new RBTree object built from the key slice. Because keys // are ordered we slice on the actual keys and not their // index/offsets rbtree_node_t *sn, *en, *cursor; long step = 0; long offset = 0; int rc = 0; // Look for the nearest inclusive match if (start == Py_None) sn = tree_min(T, NULL); else sn = __tree_search(T, T->root, start, &rc); if (end == Py_None) en = T->nil; else en = __tree_search(T, T->root, end, &rc); if (stride != Py_None) { step = PyInt_AsLong(stride); // negative step makes no sense when keys are added via a cmp function if (step < 0) step = ABS(step); } for(cursor = sn; cursor!= en; offset++) { if (step == 0 || (offset % step == 0)) rbtree_add(new, cursor->key, cursor->value); cursor = __tree_successor(T, cursor); } } void rbtree_do_del_slice(rbtree_t *T, PyObject *start, PyObject *end, PyObject *stride) { rbtree_node_t *sn, *en, *cursor, *next; long step = 0; long offset = 0; int rc = 0; // Look for the nearest inclusive match if (start == Py_None) sn = tree_min(T, NULL); else sn = __tree_search(T, T->root, start, &rc); if (end == Py_None) en = T->nil; else en = __tree_search(T, T->root, end, &rc); if (stride != Py_None) { step = PyInt_AsLong(stride); // negative step makes no sense when keys are added via a cmp function if (step < 0) step = ABS(step); } for(cursor = sn; cursor!= en; offset++) { if (step == 0 || (offset % step == 0)) { cursor = rbtree_node_del(T, cursor); } else { cursor = __tree_successor(T, cursor); } if (cursor == T->nil) break; } } static void __dump (rbtree_t *T, rbtree_node_t *n, FILE *fp, int l) { if (n != T->nil) { __dump(T, n->r, fp, (l + 1)); __dump(T, n->l, fp, (l + 1)); fprintf(fp, "\"%x\" [style=\"filled\" fillcolor=\"%s\" label=\"", (unsigned int)n, ((COLOR(n) == BLACK) ? "#ececec" : "#ee0000")); PyObject_Print(n->key, fp, 0); fprintf(fp, "::"); PyObject_Print(n->value, fp, 0); fprintf(fp, "\"]\n"); fprintf(fp, "\"%x\" -> \"%x\"", (unsigned int)n, (unsigned int)(n->l)); if (n->l != T->nil) fprintf(fp, "[label=\"L: %x\"]", (unsigned int)(n->l)); fprintf(fp, "\n"); fprintf(fp, "\"%x\" -> \"%x\"", (unsigned int)(n), (unsigned int)(n->r)); if (n->r != T->nil) fprintf(fp, "[label=\"R: %x\"]", (unsigned int)(n->r)); fprintf(fp, "\n"); } } void rbtree_validate(rbtree_t *T, int verbose) { rbtree_node_t *cursor; int i = 0; for(cursor = __tree_min(T, T->root); cursor != T->nil; cursor = __tree_successor(T, cursor)) { if (cursor->key == NULL) printf("INVALID KEY\n"); if (cursor->value == NULL) printf("INVALID VALUE\n"); if (verbose > 1) { fputs("Key\n", stderr); _PyObject_Dump(cursor->key); fputs("Value\n", stderr); _PyObject_Dump(cursor->value); fputs("\n", stderr); } else if (verbose == 1){ fprintf(stderr, "%s ", cursor->key->ob_type->tp_name); fprintf(stderr, "%s ", cursor->value->ob_type->tp_name); fprintf(stderr, "%x ", (unsigned int)(cursor->key)); fprintf(stderr, "%x ", (unsigned int)(cursor->value)); } i++; } if (T->ct != i) fprintf(stderr, "exepected %ld saw %d\n", T->ct, i); } void rbtree_dump_dot (rbtree_t *T, char *filename) { FILE *fp = 0; fp = fopen(filename, "w"); fprintf(fp, "digraph G {\n"); fflush(fp); __dump(T, T->root, fp, 0); fprintf(fp, "}\n"); fclose(fp); }