kanoi
11 years ago
7 changed files with 3497 additions and 1 deletions
@ -0,0 +1,380 @@ |
|||||||
|
/*
|
||||||
|
* Copyright 2013-2014 Andrew Smith - BlackArrow Ltd |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or modify it |
||||||
|
* under the terms of the GNU General Public License as published by the Free |
||||||
|
* Software Foundation; either version 3 of the License, or (at your option) |
||||||
|
* any later version. See COPYING for more details. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "klist.h" |
||||||
|
|
||||||
|
static void k_alloc_items(K_LIST *list, KLIST_FFL_ARGS) |
||||||
|
{ |
||||||
|
K_ITEM *item; |
||||||
|
int allocate, i; |
||||||
|
|
||||||
|
if (list->is_store) { |
||||||
|
quithere(1, "List %s store can't %s()" KLIST_FFL, |
||||||
|
list->name, __func__, KLIST_FFL_PASS); |
||||||
|
} |
||||||
|
|
||||||
|
if (list->limit > 0 && list->total >= list->limit) |
||||||
|
return; |
||||||
|
|
||||||
|
allocate = list->allocate; |
||||||
|
if (list->limit > 0 && (list->total + allocate) > list->limit) |
||||||
|
allocate = list->limit - list->total; |
||||||
|
|
||||||
|
list->item_mem_count++; |
||||||
|
if (!(list->item_memory = realloc(list->item_memory, |
||||||
|
list->item_mem_count * sizeof(*(list->item_memory))))) { |
||||||
|
quithere(1, "List %s item_memory failed to realloc count=%d", |
||||||
|
list->name, list->item_mem_count); |
||||||
|
} |
||||||
|
item = calloc(allocate, sizeof(*item)); |
||||||
|
if (!item) { |
||||||
|
quithere(1, "List %s failed to calloc %d new items - total was %d, limit was %d", |
||||||
|
list->name, allocate, list->total, list->limit); |
||||||
|
} |
||||||
|
list->item_memory[list->item_mem_count - 1] = (void *)item; |
||||||
|
|
||||||
|
list->total += allocate; |
||||||
|
list->count = allocate; |
||||||
|
list->count_up = allocate; |
||||||
|
|
||||||
|
item[0].name = list->name; |
||||||
|
item[0].prev = NULL; |
||||||
|
item[0].next = &(item[1]); |
||||||
|
for (i = 1; i < allocate-1; i++) { |
||||||
|
item[i].name = list->name; |
||||||
|
item[i].prev = &item[i-1]; |
||||||
|
item[i].next = &item[i+1]; |
||||||
|
} |
||||||
|
item[allocate-1].name = list->name; |
||||||
|
item[allocate-1].prev = &(item[allocate-2]); |
||||||
|
item[allocate-1].next = NULL; |
||||||
|
|
||||||
|
list->head = item; |
||||||
|
if (list->do_tail) |
||||||
|
list->tail = &(item[allocate-1]); |
||||||
|
|
||||||
|
item = list->head; |
||||||
|
while (item) { |
||||||
|
list->data_mem_count++; |
||||||
|
if (!(list->data_memory = realloc(list->data_memory, |
||||||
|
list->data_mem_count * |
||||||
|
sizeof(*(list->data_memory))))) { |
||||||
|
quithere(1, "List %s data_memory failed to realloc count=%d", |
||||||
|
list->name, list->data_mem_count); |
||||||
|
} |
||||||
|
item->data = calloc(1, list->siz); |
||||||
|
if (!(item->data)) |
||||||
|
quithere(1, "List %s failed to calloc item data", list->name); |
||||||
|
list->data_memory[list->data_mem_count - 1] = (void *)(item->data); |
||||||
|
item = item->next; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
K_STORE *k_new_store(K_LIST *list) |
||||||
|
{ |
||||||
|
K_STORE *store; |
||||||
|
|
||||||
|
store = calloc(1, sizeof(*store)); |
||||||
|
if (!store) |
||||||
|
quithere(1, "Failed to calloc store for %s", list->name); |
||||||
|
|
||||||
|
store->is_store = true; |
||||||
|
store->lock = list->lock; |
||||||
|
store->name = list->name; |
||||||
|
store->do_tail = list->do_tail; |
||||||
|
|
||||||
|
return store; |
||||||
|
} |
||||||
|
|
||||||
|
K_LIST *_k_new_list(const char *name, size_t siz, int allocate, int limit, bool do_tail, KLIST_FFL_ARGS) |
||||||
|
{ |
||||||
|
K_LIST *list; |
||||||
|
|
||||||
|
if (allocate < 1) |
||||||
|
quithere(1, "Invalid new list %s with allocate %d must be > 0", name, allocate); |
||||||
|
|
||||||
|
if (limit < 0) |
||||||
|
quithere(1, "Invalid new list %s with limit %d must be >= 0", name, limit); |
||||||
|
|
||||||
|
list = calloc(1, sizeof(*list)); |
||||||
|
if (!list) |
||||||
|
quithere(1, "Failed to calloc list %s", name); |
||||||
|
|
||||||
|
list->is_store = false; |
||||||
|
|
||||||
|
list->lock = calloc(1, sizeof(*(list->lock))); |
||||||
|
if (!(list->lock)) |
||||||
|
quithere(1, "Failed to calloc lock for list %s", name); |
||||||
|
|
||||||
|
cklock_init(list->lock); |
||||||
|
|
||||||
|
list->name = name; |
||||||
|
list->siz = siz; |
||||||
|
list->allocate = allocate; |
||||||
|
list->limit = limit; |
||||||
|
list->do_tail = do_tail; |
||||||
|
|
||||||
|
k_alloc_items(list, KLIST_FFL_PASS); |
||||||
|
|
||||||
|
return list; |
||||||
|
} |
||||||
|
|
||||||
|
/*
|
||||||
|
* Unlink and return the head of the list |
||||||
|
* If the list is empty: |
||||||
|
* 1) If it's a store - return NULL |
||||||
|
* 2) alloc a new list and return the head - |
||||||
|
* which is NULL if the list limit has been reached |
||||||
|
*/ |
||||||
|
K_ITEM *_k_unlink_head(K_LIST *list, KLIST_FFL_ARGS) |
||||||
|
{ |
||||||
|
K_ITEM *item; |
||||||
|
|
||||||
|
if (!(list->head) && !(list->is_store)) |
||||||
|
k_alloc_items(list, KLIST_FFL_PASS); |
||||||
|
|
||||||
|
if (!(list->head)) |
||||||
|
return NULL; |
||||||
|
|
||||||
|
item = list->head; |
||||||
|
list->head = item->next; |
||||||
|
if (list->head) |
||||||
|
list->head->prev = NULL; |
||||||
|
else { |
||||||
|
if (list->do_tail) |
||||||
|
list->tail = NULL; |
||||||
|
} |
||||||
|
|
||||||
|
item->prev = item->next = NULL; |
||||||
|
|
||||||
|
list->count--; |
||||||
|
|
||||||
|
return item; |
||||||
|
} |
||||||
|
|
||||||
|
// Zeros the head returned
|
||||||
|
K_ITEM *_k_unlink_head_zero(K_LIST *list, KLIST_FFL_ARGS) |
||||||
|
{ |
||||||
|
K_ITEM *item; |
||||||
|
|
||||||
|
item = _k_unlink_head(list, KLIST_FFL_PASS); |
||||||
|
|
||||||
|
if (item) |
||||||
|
memset(item->data, 0, list->siz); |
||||||
|
|
||||||
|
return item; |
||||||
|
} |
||||||
|
|
||||||
|
// Returns NULL if empty
|
||||||
|
K_ITEM *_k_unlink_tail(K_LIST *list, KLIST_FFL_ARGS) |
||||||
|
{ |
||||||
|
K_ITEM *item; |
||||||
|
|
||||||
|
if (!(list->do_tail)) { |
||||||
|
quithere(1, "List %s can't %s() - do_tail is false" KLIST_FFL, |
||||||
|
list->name, __func__, KLIST_FFL_PASS); |
||||||
|
} |
||||||
|
|
||||||
|
if (!(list->tail)) |
||||||
|
return NULL; |
||||||
|
|
||||||
|
item = list->tail; |
||||||
|
list->tail = item->prev; |
||||||
|
if (list->tail) |
||||||
|
list->tail->next = NULL; |
||||||
|
else |
||||||
|
list->head = NULL; |
||||||
|
|
||||||
|
item->prev = item->next = NULL; |
||||||
|
|
||||||
|
list->count--; |
||||||
|
|
||||||
|
return item; |
||||||
|
} |
||||||
|
|
||||||
|
void _k_add_head(K_LIST *list, K_ITEM *item, KLIST_FFL_ARGS) |
||||||
|
{ |
||||||
|
if (item->name != list->name) { |
||||||
|
quithere(1, "List %s can't %s() a %s item" KLIST_FFL, |
||||||
|
list->name, __func__, item->name, KLIST_FFL_PASS); |
||||||
|
} |
||||||
|
|
||||||
|
item->prev = NULL; |
||||||
|
item->next = list->head; |
||||||
|
if (list->head) |
||||||
|
list->head->prev = item; |
||||||
|
|
||||||
|
list->head = item; |
||||||
|
|
||||||
|
if (list->do_tail) { |
||||||
|
if (!(list->tail)) |
||||||
|
list->tail = item; |
||||||
|
} |
||||||
|
|
||||||
|
list->count++; |
||||||
|
list->count_up++; |
||||||
|
} |
||||||
|
|
||||||
|
/* slows it down (of course) - only for debugging
|
||||||
|
void _k_free_head(K_LIST *list, K_ITEM *item, KLIST_FFL_ARGS) |
||||||
|
{ |
||||||
|
memset(item->data, 0xff, list->siz); |
||||||
|
_k_add_head(list, item, KLIST_FFL_PASS); |
||||||
|
} |
||||||
|
*/ |
||||||
|
|
||||||
|
void _k_add_tail(K_LIST *list, K_ITEM *item, KLIST_FFL_ARGS) |
||||||
|
{ |
||||||
|
if (item->name != list->name) { |
||||||
|
quithere(1, "List %s can't %s() a %s item" KLIST_FFL, |
||||||
|
list->name, __func__, item->name, KLIST_FFL_PASS); |
||||||
|
} |
||||||
|
|
||||||
|
if (!(list->do_tail)) { |
||||||
|
quithere(1, "List %s can't %s() - do_tail is false" KLIST_FFL, |
||||||
|
list->name, __func__, KLIST_FFL_PASS); |
||||||
|
} |
||||||
|
|
||||||
|
item->prev = list->tail; |
||||||
|
item->next = NULL; |
||||||
|
if (list->tail) |
||||||
|
list->tail->next = item; |
||||||
|
|
||||||
|
list->tail = item; |
||||||
|
|
||||||
|
if (!(list->head)) |
||||||
|
list->head = item; |
||||||
|
|
||||||
|
list->count++; |
||||||
|
list->count_up++; |
||||||
|
} |
||||||
|
|
||||||
|
void _k_unlink_item(K_LIST *list, K_ITEM *item, KLIST_FFL_ARGS) |
||||||
|
{ |
||||||
|
if (item->name != list->name) { |
||||||
|
quithere(1, "List %s can't %s() a %s item" KLIST_FFL, |
||||||
|
list->name, __func__, item->name, KLIST_FFL_PASS); |
||||||
|
} |
||||||
|
|
||||||
|
if (item->prev) |
||||||
|
item->prev->next = item->next; |
||||||
|
|
||||||
|
if (item->next) |
||||||
|
item->next->prev = item->prev; |
||||||
|
|
||||||
|
if (list->head == item) |
||||||
|
list->head = item->next; |
||||||
|
|
||||||
|
if (list->do_tail) { |
||||||
|
if (list->tail == item) |
||||||
|
list->tail = item->prev; |
||||||
|
} |
||||||
|
|
||||||
|
item->prev = item->next = NULL; |
||||||
|
|
||||||
|
list->count--; |
||||||
|
} |
||||||
|
|
||||||
|
void _k_list_transfer_to_head(K_LIST *from, K_LIST *to, KLIST_FFL_ARGS) |
||||||
|
{ |
||||||
|
if (from->name != to->name) { |
||||||
|
quithere(1, "List %s can't %s() to a %s list" KLIST_FFL, |
||||||
|
from->name, __func__, to->name, KLIST_FFL_PASS); |
||||||
|
} |
||||||
|
|
||||||
|
if (!(from->do_tail)) { |
||||||
|
quithere(1, "List %s can't %s() - do_tail is false" KLIST_FFL, |
||||||
|
from->name, __func__, KLIST_FFL_PASS); |
||||||
|
} |
||||||
|
|
||||||
|
if (!(from->head)) |
||||||
|
return; |
||||||
|
|
||||||
|
if (to->head) |
||||||
|
to->head->prev = from->tail; |
||||||
|
else |
||||||
|
to->tail = from->tail; |
||||||
|
|
||||||
|
from->tail->next = to->head; |
||||||
|
to->head = from->head; |
||||||
|
|
||||||
|
from->head = from->tail = NULL; |
||||||
|
to->count += from->count; |
||||||
|
from->count = 0; |
||||||
|
to->count_up += from->count_up; |
||||||
|
from->count_up = 0; |
||||||
|
} |
||||||
|
|
||||||
|
void _k_list_transfer_to_tail(K_LIST *from, K_LIST *to, KLIST_FFL_ARGS) |
||||||
|
{ |
||||||
|
if (from->name != to->name) { |
||||||
|
quithere(1, "List %s can't %s() to a %s list" KLIST_FFL, |
||||||
|
from->name, __func__, to->name, KLIST_FFL_PASS); |
||||||
|
} |
||||||
|
|
||||||
|
if (!(from->do_tail)) { |
||||||
|
quithere(1, "List %s can't %s() - do_tail is false" KLIST_FFL, |
||||||
|
from->name, __func__, KLIST_FFL_PASS); |
||||||
|
} |
||||||
|
|
||||||
|
if (!(from->head)) |
||||||
|
return; |
||||||
|
|
||||||
|
if (to->tail) |
||||||
|
to->tail->next = from->head; |
||||||
|
else |
||||||
|
to->head = from->head; |
||||||
|
|
||||||
|
from->head->prev = to->tail; |
||||||
|
to->tail = from->tail; |
||||||
|
|
||||||
|
from->head = from->tail = NULL; |
||||||
|
to->count += from->count; |
||||||
|
from->count = 0; |
||||||
|
to->count_up += from->count_up; |
||||||
|
from->count_up = 0; |
||||||
|
} |
||||||
|
|
||||||
|
K_LIST *_k_free_list(K_LIST *list, KLIST_FFL_ARGS) |
||||||
|
{ |
||||||
|
int i; |
||||||
|
|
||||||
|
if (list->is_store) { |
||||||
|
quithere(1, "List %s can't %s() a store" KLIST_FFL, |
||||||
|
list->name, __func__, KLIST_FFL_PASS); |
||||||
|
} |
||||||
|
|
||||||
|
for (i = 0; i < list->item_mem_count; i++) |
||||||
|
free(list->item_memory[i]); |
||||||
|
free(list->item_memory); |
||||||
|
|
||||||
|
for (i = 0; i < list->data_mem_count; i++) |
||||||
|
free(list->data_memory[i]); |
||||||
|
free(list->data_memory); |
||||||
|
|
||||||
|
cklock_destroy(list->lock); |
||||||
|
|
||||||
|
free(list->lock); |
||||||
|
|
||||||
|
free(list); |
||||||
|
|
||||||
|
return NULL; |
||||||
|
} |
||||||
|
|
||||||
|
K_STORE *_k_free_store(K_STORE *store, KLIST_FFL_ARGS) |
||||||
|
{ |
||||||
|
if (!(store->is_store)) { |
||||||
|
quithere(1, "Store %s can't %s() the list" KLIST_FFL, |
||||||
|
store->name, __func__, KLIST_FFL_PASS); |
||||||
|
} |
||||||
|
|
||||||
|
free(store); |
||||||
|
|
||||||
|
return NULL; |
||||||
|
} |
@ -0,0 +1,93 @@ |
|||||||
|
/*
|
||||||
|
* Copyright 2013-2014 Andrew Smith - BlackArrow Ltd |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or modify it |
||||||
|
* under the terms of the GNU General Public License as published by the Free |
||||||
|
* Software Foundation; either version 3 of the License, or (at your option) |
||||||
|
* any later version. See COPYING for more details. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef KLIST_H |
||||||
|
#define KLIST_H |
||||||
|
|
||||||
|
#include "libckpool.h" |
||||||
|
|
||||||
|
#define quithere(status, fmt, ...) \ |
||||||
|
quitfrom(status, __FILE__, __func__, __LINE__, fmt, ##__VA_ARGS__) |
||||||
|
|
||||||
|
#define KLIST_FFL " - from %s %s() line %d" |
||||||
|
#define KLIST_FFL_HERE __FILE__, __func__, __LINE__ |
||||||
|
#define KLIST_FFL_PASS file, func, line |
||||||
|
#define KLIST_FFL_ARGS __maybe_unused const char *file, \ |
||||||
|
__maybe_unused const char *func, \
|
||||||
|
__maybe_unused const int line |
||||||
|
|
||||||
|
typedef struct k_item { |
||||||
|
const char *name; |
||||||
|
struct k_item *prev; |
||||||
|
struct k_item *next; |
||||||
|
void *data; |
||||||
|
} K_ITEM; |
||||||
|
|
||||||
|
typedef struct k_list { |
||||||
|
const char *name; |
||||||
|
bool is_store; |
||||||
|
cklock_t *lock; |
||||||
|
struct k_item *head; |
||||||
|
struct k_item *tail; |
||||||
|
size_t siz; // item data size
|
||||||
|
int total; // total allocated
|
||||||
|
int count; // in this list
|
||||||
|
int count_up; // incremented every time one is added
|
||||||
|
int allocate; // number to intially allocate and each time we run out
|
||||||
|
int limit; // total limit - 0 means unlimited
|
||||||
|
bool do_tail; // track the tail?
|
||||||
|
int item_mem_count; // how many item memory buffers have been allocated
|
||||||
|
void **item_memory; // allocated item memory buffers
|
||||||
|
int data_mem_count; // how many item data memory buffers have been allocated
|
||||||
|
void **data_memory; // allocated item data memory buffers
|
||||||
|
} K_LIST; |
||||||
|
|
||||||
|
/*
|
||||||
|
* K_STORE is for a list of items taken from a K_LIST |
||||||
|
* The restriction is, a K_STORE must not allocate new items, |
||||||
|
* only the K_LIST should do that |
||||||
|
* i.e. all K_STORE items came from a K_LIST |
||||||
|
*/ |
||||||
|
#define K_STORE K_LIST |
||||||
|
|
||||||
|
/*
|
||||||
|
* N.B. all locking is done in the code using the K_*LOCK macros |
||||||
|
*/ |
||||||
|
#define K_WLOCK(_list) ck_wlock(_list->lock) |
||||||
|
#define K_WUNLOCK(_list) ck_wunlock(_list->lock) |
||||||
|
#define K_RLOCK(_list) ck_rlock(_list->lock) |
||||||
|
#define K_RUNLOCK(_list) ck_runlock(_list->lock) |
||||||
|
|
||||||
|
extern K_STORE *k_new_store(K_LIST *list); |
||||||
|
extern K_LIST *_k_new_list(const char *name, size_t siz, int allocate, int limit, bool do_tail, KLIST_FFL_ARGS); |
||||||
|
#define k_new_list(_name, _siz, _allocate, _limit, _do_tail) _k_new_list(_name, _siz, _allocate, _limit, _do_tail, KLIST_FFL_HERE) |
||||||
|
extern K_ITEM *_k_unlink_head(K_LIST *list, KLIST_FFL_ARGS); |
||||||
|
#define k_unlink_head(_list) _k_unlink_head(_list, KLIST_FFL_HERE) |
||||||
|
extern K_ITEM *_k_unlink_head_zero(K_LIST *list, KLIST_FFL_ARGS); |
||||||
|
#define k_unlink_head_zero(_list) _k_unlink_head_zero(_list, KLIST_FFL_HERE) |
||||||
|
extern K_ITEM *_k_unlink_tail(K_LIST *list, KLIST_FFL_ARGS); |
||||||
|
#define k_unlink_tail(_list) _k_unlink_tail(_list, KLIST_FFL_HERE) |
||||||
|
extern void _k_add_head(K_LIST *list, K_ITEM *item, KLIST_FFL_ARGS); |
||||||
|
#define k_add_head(_list, _item) _k_add_head(_list, _item, KLIST_FFL_HERE) |
||||||
|
// extern void k_free_head(K_LIST *list, K_ITEM *item, KLIST_FFL_ARGS);
|
||||||
|
#define k_free_head(__list, __item) _k_add_head(__list, __item, KLIST_FFL_HERE) |
||||||
|
extern void _k_add_tail(K_LIST *list, K_ITEM *item, KLIST_FFL_ARGS); |
||||||
|
#define k_add_tail(_list, _item) _k_add_tail(_list, _item, KLIST_FFL_HERE) |
||||||
|
extern void _k_unlink_item(K_LIST *list, K_ITEM *item, KLIST_FFL_ARGS); |
||||||
|
#define k_unlink_item(_list, _item) _k_unlink_item(_list, _item, KLIST_FFL_HERE) |
||||||
|
void _k_list_transfer_to_head(K_LIST *from, K_LIST *to, KLIST_FFL_ARGS); |
||||||
|
#define k_list_transfer_to_head(_from, _to) _k_list_transfer_to_head(_from, _to, KLIST_FFL_HERE) |
||||||
|
void _k_list_transfer_to_tail(K_LIST *from, K_LIST *to, KLIST_FFL_ARGS); |
||||||
|
#define k_list_transfer_to_tail(_from, _to) _k_list_transfer_to_tail(_from, _to, KLIST_FFL_HERE) |
||||||
|
extern K_LIST *_k_free_list(K_LIST *list, KLIST_FFL_ARGS); |
||||||
|
#define k_free_list(_list) _k_free_list(_list, KLIST_FFL_HERE) |
||||||
|
extern K_STORE *_k_free_store(K_STORE *store, KLIST_FFL_ARGS); |
||||||
|
#define k_free_store(_store) _k_free_store(_store, KLIST_FFL_HERE) |
||||||
|
|
||||||
|
#endif |
@ -0,0 +1,872 @@ |
|||||||
|
/*
|
||||||
|
* Copyright 2003-2014 Andrew Smith |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or modify it |
||||||
|
* under the terms of the GNU General Public License as published by the Free |
||||||
|
* Software Foundation; either version 3 of the License, or (at your option) |
||||||
|
* any later version. See COPYING for more details. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "ktree.h" |
||||||
|
|
||||||
|
static const int dbg = 0; |
||||||
|
#define DBG if (dbg != 0) printf |
||||||
|
|
||||||
|
#define FAIL(fmt, ...) do \ |
||||||
|
{ \
|
||||||
|
quithere(1, fmt, ##__VA_ARGS__); \
|
||||||
|
} while (0); |
||||||
|
|
||||||
|
#define RED_RED true |
||||||
|
#define RED_BLACK false |
||||||
|
|
||||||
|
#define Yo true |
||||||
|
#define No false |
||||||
|
|
||||||
|
static K_TREE nil[1] = { Yo, RED_BLACK, NULL, NULL, NULL, NULL, 0 }; |
||||||
|
|
||||||
|
K_TREE *new_ktree() |
||||||
|
{ |
||||||
|
K_TREE *ktree = (K_TREE *)malloc(sizeof(*ktree)); |
||||||
|
|
||||||
|
if (ktree == NULL) |
||||||
|
FAIL("%s", "%K_TREE-F-OOM"); |
||||||
|
|
||||||
|
ktree->isNil = Yo; |
||||||
|
ktree->red = RED_BLACK; |
||||||
|
ktree->parent = nil; |
||||||
|
ktree->left = nil; |
||||||
|
ktree->right = nil; |
||||||
|
ktree->data = NULL; |
||||||
|
ktree->test = 0; |
||||||
|
|
||||||
|
return ktree; |
||||||
|
} |
||||||
|
|
||||||
|
static K_TREE *new_data(K_ITEM *data) |
||||||
|
{ |
||||||
|
K_TREE *ktree = (K_TREE *)malloc(sizeof(*ktree)); |
||||||
|
|
||||||
|
if (ktree == NULL) |
||||||
|
FAIL("%s", "%K_TREE-F-OOM"); |
||||||
|
|
||||||
|
ktree->isNil = No; |
||||||
|
ktree->red = RED_RED; |
||||||
|
ktree->parent = nil; |
||||||
|
ktree->left = nil; |
||||||
|
ktree->right = nil; |
||||||
|
ktree->data = data; |
||||||
|
ktree->test = 0; |
||||||
|
|
||||||
|
return ktree; |
||||||
|
} |
||||||
|
|
||||||
|
static int bCount = 0; |
||||||
|
static long bTestValue = 0; |
||||||
|
static long nilTestValue = 0; |
||||||
|
static long lrpTestValue = 0; |
||||||
|
|
||||||
|
static long testValue = 1231230L; |
||||||
|
|
||||||
|
static long getTestValue() |
||||||
|
{ |
||||||
|
return ++testValue; |
||||||
|
} |
||||||
|
|
||||||
|
static void show_ktree(K_TREE *root, char *path, int pos, char *(*dsp_funct)(K_ITEM *)) |
||||||
|
{ |
||||||
|
char col; |
||||||
|
|
||||||
|
if (root->isNil == Yo) |
||||||
|
return; |
||||||
|
|
||||||
|
if (root->left->isNil == No) |
||||||
|
{ |
||||||
|
path[pos] = 'L'; |
||||||
|
path[pos+1] = '\0'; |
||||||
|
show_ktree(root->left, path, pos+1, dsp_funct); |
||||||
|
} |
||||||
|
|
||||||
|
path[pos] = '\0'; |
||||||
|
|
||||||
|
switch(root->red) |
||||||
|
{ |
||||||
|
case RED_RED: |
||||||
|
col = 'R'; |
||||||
|
break; |
||||||
|
case RED_BLACK: |
||||||
|
col = 'B'; |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
printf(" %c %s=%s\n", col, path, dsp_funct(root->data)); |
||||||
|
|
||||||
|
if (root->right->isNil == No) |
||||||
|
{ |
||||||
|
path[pos] = 'R'; |
||||||
|
path[pos+1] = '\0'; |
||||||
|
show_ktree(root->right, path, pos+1, dsp_funct); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void dump_ktree(K_TREE *root, char *(*dsp_funct)(K_ITEM *)) |
||||||
|
{ |
||||||
|
char buf[42424]; |
||||||
|
|
||||||
|
printf("dump:\n"); |
||||||
|
if (root->isNil == No) |
||||||
|
{ |
||||||
|
buf[0] = 'T'; |
||||||
|
buf[1] = '\0'; |
||||||
|
show_ktree(root, buf, 1, dsp_funct); |
||||||
|
} |
||||||
|
else |
||||||
|
printf(" Empty ktree\n"); |
||||||
|
} |
||||||
|
|
||||||
|
static int nilTest(K_TREE *node, char *msg, int depth, int count, K_TREE *nil2) |
||||||
|
{ |
||||||
|
if (node->isNil == Yo || node == nil2) |
||||||
|
{ |
||||||
|
if (node == nil2 && node->isNil == No) |
||||||
|
FAIL("%%K_TREE-F-NIL2NOTNIL '%s' depth=%d count=%d", msg, depth, count); |
||||||
|
|
||||||
|
if (node != nil && node != nil2) |
||||||
|
FAIL("%%K_TREE-F-NOTNILNIL2 '%s' depth=%d count=%d", msg, depth, count); |
||||||
|
|
||||||
|
if (node->red == RED_RED) |
||||||
|
FAIL("%%K_TREE-F-NIRED '%s' depth=%d count=%d", msg, depth, count); |
||||||
|
|
||||||
|
if (node != nil2 && node->parent != NULL) |
||||||
|
FAIL("%%K_TREE-F-NILPARENT '%s' depth=%d count=%d", msg, depth, count); |
||||||
|
|
||||||
|
if (node != nil2 && node->left != NULL) |
||||||
|
FAIL("%%K_TREE-F-NILLEFT '%s' depth=%d count=%d", msg, depth, count); |
||||||
|
|
||||||
|
if (node == nil2 && node->left != nil) |
||||||
|
FAIL("%%K_TREE-F-NIL2LEFT '%s' depth=%d count=%d", msg, depth, count); |
||||||
|
|
||||||
|
if (node != nil2 && node->right != NULL) |
||||||
|
FAIL("%%K_TREE-F-NILRIGHT '%s' depth=%d count=%d", msg, depth, count); |
||||||
|
|
||||||
|
if (node == nil2 && node->right != nil) |
||||||
|
FAIL("%%K_TREE-F-NIL2RIGHT '%s' depth=%d count=%d", msg, depth, count); |
||||||
|
|
||||||
|
if (node->data != NULL) |
||||||
|
FAIL("%%K_TREE-F-NIDATA '%s' depth=%d count=%d", msg, depth, count); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
count++; |
||||||
|
|
||||||
|
if (node->parent == NULL) |
||||||
|
FAIL("%%K_TREE-F-NOPAR '%s' depth=%d count=%d", msg, depth, count); |
||||||
|
|
||||||
|
if (node->left == NULL) |
||||||
|
FAIL("%%K_TREE-F-NOLEFT '%s' depth=%d count=%d", msg, depth, count); |
||||||
|
|
||||||
|
if (node->right == NULL) |
||||||
|
FAIL("%%K_TREE-F-NORIGHT '%s' depth=%d count=%d", msg, depth, count); |
||||||
|
|
||||||
|
if (node->data == NULL) |
||||||
|
FAIL("%%K_TREE-F-NODATA '%s' depth=%d count=%d", msg, depth, count); |
||||||
|
|
||||||
|
if (node->test != nilTestValue) |
||||||
|
node->test = nilTestValue; |
||||||
|
else |
||||||
|
FAIL("%%K_TREE-F-NILTESTVALUE '%s' depth=%d count=%d", msg, depth, count); |
||||||
|
|
||||||
|
count = nilTest(node->left, msg, depth+1, count, nil2); |
||||||
|
count = nilTest(node->right, msg, depth+1, count, nil2); |
||||||
|
} |
||||||
|
|
||||||
|
return(count); |
||||||
|
} |
||||||
|
|
||||||
|
static void bTest(K_TREE *root, K_TREE *cur, char *msg, int count) |
||||||
|
{ |
||||||
|
if (cur->red != RED_RED) |
||||||
|
count++; |
||||||
|
else |
||||||
|
{ |
||||||
|
if (cur->left->red == RED_RED) |
||||||
|
FAIL("%%K_TREE-F-CURLR '%s' count=%d", msg, count); |
||||||
|
|
||||||
|
if (cur->right->red == RED_RED) |
||||||
|
FAIL("%%K_TREE-F-CURRR '%s' count=%d", msg, count); |
||||||
|
} |
||||||
|
|
||||||
|
if (cur->isNil == Yo) |
||||||
|
{ |
||||||
|
if (bCount == 0) |
||||||
|
bCount = count; |
||||||
|
|
||||||
|
if (count != bCount) |
||||||
|
FAIL("%%K_TREE-F-BCOUNT '%s' count=%d bCount=%d", msg, count, bCount); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
if (cur->test != bTestValue) |
||||||
|
cur->test = bTestValue; |
||||||
|
else |
||||||
|
FAIL("%%K_TREE-F-BTESTVALUE '%s' count=%d", msg, count); |
||||||
|
|
||||||
|
bTest(root, cur->left, msg, count); |
||||||
|
bTest(root, cur->right, msg, count); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static void bTestInit(K_TREE *root, char *msg) |
||||||
|
{ |
||||||
|
bCount = 0; |
||||||
|
bTestValue = getTestValue(); |
||||||
|
bTest(root, root, msg, 0); |
||||||
|
} |
||||||
|
|
||||||
|
static void lrpTest(K_TREE *top, char *msg) |
||||||
|
{ |
||||||
|
if (top->test != lrpTestValue) |
||||||
|
top->test = lrpTestValue; |
||||||
|
else |
||||||
|
FAIL("%%K_TREE-F-LRPTESTVALUE '%s'", msg); |
||||||
|
|
||||||
|
if (top->left->isNil == No) |
||||||
|
{ |
||||||
|
if (top->left->parent != top) |
||||||
|
FAIL("%%K_TREE-F-LRPTESTL '%s'", msg); |
||||||
|
|
||||||
|
lrpTest(top->left, msg); |
||||||
|
} |
||||||
|
|
||||||
|
if (top->right->isNil == No) |
||||||
|
{ |
||||||
|
if (top->right->parent != top) |
||||||
|
FAIL("%%K_TREE-F-LRPTESTR '%s'", msg); |
||||||
|
|
||||||
|
lrpTest(top->right, msg); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static __maybe_unused void check_ktree(K_TREE *root, char *msg, K_TREE *nil2, int debugNil, int debugLRP, int debugColor) |
||||||
|
{ |
||||||
|
if (root->isNil == Yo) |
||||||
|
return; |
||||||
|
|
||||||
|
if (debugNil) |
||||||
|
{ |
||||||
|
nilTestValue = getTestValue(); |
||||||
|
nilTest(root, msg, 1, 0, nil2); |
||||||
|
} |
||||||
|
|
||||||
|
if (debugLRP && root->isNil == No) |
||||||
|
{ |
||||||
|
lrpTestValue = getTestValue(); |
||||||
|
lrpTest(root, msg); |
||||||
|
} |
||||||
|
|
||||||
|
if (debugColor && root->isNil == No) |
||||||
|
bTestInit(root, msg); |
||||||
|
} |
||||||
|
|
||||||
|
K_ITEM *first_in_ktree(K_TREE *root, K_TREE_CTX *ctx) |
||||||
|
{ |
||||||
|
if (root->isNil == No) |
||||||
|
{ |
||||||
|
while (root->left->isNil == No) |
||||||
|
root = root->left; |
||||||
|
|
||||||
|
*ctx = root; |
||||||
|
return(root->data); |
||||||
|
} |
||||||
|
|
||||||
|
*ctx = NULL; |
||||||
|
return(NULL); |
||||||
|
} |
||||||
|
|
||||||
|
K_ITEM *last_in_ktree(K_TREE *root, K_TREE_CTX *ctx) |
||||||
|
{ |
||||||
|
if (root->isNil == No) |
||||||
|
{ |
||||||
|
while (root->right->isNil == No) |
||||||
|
root = root->right; |
||||||
|
|
||||||
|
*ctx = root; |
||||||
|
return(root->data); |
||||||
|
} |
||||||
|
|
||||||
|
*ctx = NULL; |
||||||
|
return(NULL); |
||||||
|
} |
||||||
|
|
||||||
|
K_ITEM *next_in_ktree(K_TREE_CTX *ctx) |
||||||
|
{ |
||||||
|
K_TREE *parent; |
||||||
|
K_TREE *ktree = (K_TREE *)(*ctx); |
||||||
|
|
||||||
|
if (ktree->isNil == No) |
||||||
|
{ |
||||||
|
if (ktree->right->isNil == No) |
||||||
|
return(first_in_ktree(ktree->right, ctx)); |
||||||
|
else |
||||||
|
{ |
||||||
|
parent = ktree->parent; |
||||||
|
while (parent->isNil == No && ktree == parent->right) |
||||||
|
{ |
||||||
|
ktree = parent; |
||||||
|
parent = parent->parent; |
||||||
|
} |
||||||
|
if (parent->isNil == No) |
||||||
|
{ |
||||||
|
*ctx = parent; |
||||||
|
return(parent->data); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
*ctx = NULL; |
||||||
|
return(NULL); |
||||||
|
} |
||||||
|
|
||||||
|
K_ITEM *prev_in_ktree(K_TREE_CTX *ctx) |
||||||
|
{ |
||||||
|
K_TREE *parent; |
||||||
|
K_TREE *ktree = (K_TREE *)(*ctx); |
||||||
|
|
||||||
|
if (ktree->isNil == No) |
||||||
|
{ |
||||||
|
if (ktree->left->isNil == No) |
||||||
|
return(last_in_ktree(ktree->left, ctx)); |
||||||
|
else |
||||||
|
{ |
||||||
|
parent = ktree->parent; |
||||||
|
while (parent->isNil == No && ktree == parent->left) |
||||||
|
{ |
||||||
|
ktree = parent; |
||||||
|
parent = parent->parent; |
||||||
|
} |
||||||
|
if (parent->isNil == No) |
||||||
|
{ |
||||||
|
*ctx = parent; |
||||||
|
return(parent->data); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
*ctx = NULL; |
||||||
|
return(NULL); |
||||||
|
} |
||||||
|
|
||||||
|
static K_TREE *left_rotate(K_TREE *root, K_TREE *about) |
||||||
|
{ |
||||||
|
K_TREE *rotate; |
||||||
|
|
||||||
|
rotate = about->right; |
||||||
|
about->right = rotate->left; |
||||||
|
|
||||||
|
if (rotate->left->isNil == No) |
||||||
|
rotate->left->parent = about; |
||||||
|
|
||||||
|
rotate->parent = about->parent; |
||||||
|
|
||||||
|
if (about->parent->isNil == Yo) |
||||||
|
root = rotate; |
||||||
|
else |
||||||
|
{ |
||||||
|
if (about == about->parent->left) |
||||||
|
about->parent->left = rotate; |
||||||
|
else |
||||||
|
about->parent->right = rotate; |
||||||
|
} |
||||||
|
|
||||||
|
rotate->left = about; |
||||||
|
about->parent = rotate; |
||||||
|
|
||||||
|
return(root); |
||||||
|
} |
||||||
|
|
||||||
|
static K_TREE *right_rotate(K_TREE *root, K_TREE *about) |
||||||
|
{ |
||||||
|
K_TREE *rotate; |
||||||
|
|
||||||
|
rotate = about->left; |
||||||
|
about->left = rotate->right; |
||||||
|
|
||||||
|
if (rotate->right->isNil == No) |
||||||
|
rotate->right->parent = about; |
||||||
|
|
||||||
|
rotate->parent = about->parent; |
||||||
|
|
||||||
|
if (about->parent->isNil == Yo) |
||||||
|
root = rotate; |
||||||
|
else |
||||||
|
if (about == about->parent->right) |
||||||
|
about->parent->right = rotate; |
||||||
|
else |
||||||
|
about->parent->left = rotate; |
||||||
|
|
||||||
|
rotate->right = about; |
||||||
|
about->parent = rotate; |
||||||
|
|
||||||
|
return(root); |
||||||
|
} |
||||||
|
|
||||||
|
K_TREE *add_to_ktree(K_TREE *root, K_ITEM *data, double (*cmp_funct)(K_ITEM *, K_ITEM *)) |
||||||
|
{ |
||||||
|
K_TREE *ktree; |
||||||
|
K_TREE *x, *y; |
||||||
|
K_TREE *pp; |
||||||
|
double cmp; |
||||||
|
|
||||||
|
if (root == NULL) |
||||||
|
FAIL("%s", "%K_TREE-F-ADDNULL add ktree is NULL"); |
||||||
|
|
||||||
|
//check_ktree(root, ">add", NULL, 1, 1, 1);
|
||||||
|
|
||||||
|
if (root->parent != nil && root->parent != NULL) |
||||||
|
FAIL("%s", "%K_TREE-F-ADDROOT add root isn't the root"); |
||||||
|
|
||||||
|
ktree = new_data(data); |
||||||
|
|
||||||
|
if (root->isNil == Yo) |
||||||
|
{ |
||||||
|
if (root != nil) |
||||||
|
free(root); |
||||||
|
|
||||||
|
root = ktree; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
x = root; |
||||||
|
y = nil; |
||||||
|
while (x->isNil == No) |
||||||
|
{ |
||||||
|
y = x; |
||||||
|
if ((cmp = (*cmp_funct)(ktree->data, x->data)) < 0.0) |
||||||
|
x = x->left; |
||||||
|
else |
||||||
|
x = x->right; |
||||||
|
} |
||||||
|
ktree->parent = y; |
||||||
|
if (cmp < 0.0) |
||||||
|
y->left = ktree; |
||||||
|
else |
||||||
|
y->right = ktree; |
||||||
|
|
||||||
|
x = ktree; |
||||||
|
while (x != root && x->parent->red == RED_RED) |
||||||
|
{ |
||||||
|
pp = x->parent->parent; |
||||||
|
if (x->parent == pp->left) |
||||||
|
{ |
||||||
|
y = pp->right; |
||||||
|
if (y->red == RED_RED) |
||||||
|
{ |
||||||
|
x->parent->red = RED_BLACK; |
||||||
|
y->red = RED_BLACK; |
||||||
|
pp->red = RED_RED; |
||||||
|
x = pp; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
if (x == x->parent->right) |
||||||
|
{ |
||||||
|
x = x->parent; |
||||||
|
root = left_rotate(root, x); |
||||||
|
pp = x->parent->parent; |
||||||
|
} |
||||||
|
x->parent->red = RED_BLACK; |
||||||
|
pp->red = RED_RED; |
||||||
|
root = right_rotate(root, pp); |
||||||
|
} |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
y = pp->left; |
||||||
|
if (y->red == RED_RED) |
||||||
|
{ |
||||||
|
x->parent->red = RED_BLACK; |
||||||
|
y->red = RED_BLACK; |
||||||
|
pp->red = RED_RED; |
||||||
|
x = pp; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
if (x == x->parent->left) |
||||||
|
{ |
||||||
|
x = x->parent; |
||||||
|
root = right_rotate(root, x); |
||||||
|
pp = x->parent->parent; |
||||||
|
} |
||||||
|
x->parent->red = RED_BLACK; |
||||||
|
pp->red = RED_RED; |
||||||
|
root = left_rotate(root, pp); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
root->red = RED_BLACK; |
||||||
|
|
||||||
|
//check_ktree(root, "<add", NULL, 1, 1, 1);
|
||||||
|
|
||||||
|
return(root); |
||||||
|
} |
||||||
|
|
||||||
|
K_ITEM *find_in_ktree(K_TREE *ktree, K_ITEM *data, double (*cmp_funct)(K_ITEM *, K_ITEM *), K_TREE_CTX *ctx) |
||||||
|
{ |
||||||
|
double cmp = -1.0; |
||||||
|
|
||||||
|
while (ktree->isNil == No && cmp != 0.0) |
||||||
|
{ |
||||||
|
if ((cmp = (*cmp_funct)(ktree->data, data))) |
||||||
|
{ |
||||||
|
if (cmp > 0.0) |
||||||
|
ktree = ktree->left; |
||||||
|
else |
||||||
|
ktree = ktree->right; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (ktree->isNil == No) |
||||||
|
{ |
||||||
|
*ctx = ktree; |
||||||
|
return(ktree->data); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
*ctx = NULL; |
||||||
|
return(NULL); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
K_ITEM *find_after_in_ktree(K_TREE *ktree, K_ITEM *data, double (*cmp_funct)(K_ITEM *, K_ITEM *), K_TREE_CTX *ctx) |
||||||
|
{ |
||||||
|
K_TREE *prev = NULL; |
||||||
|
double cmp = -1.0, prevcmp = -1; |
||||||
|
|
||||||
|
while (ktree->isNil == No && cmp != 0.0) |
||||||
|
{ |
||||||
|
if ((cmp = (*cmp_funct)(ktree->data, data))) |
||||||
|
{ |
||||||
|
prev = ktree; |
||||||
|
prevcmp = cmp; |
||||||
|
if (cmp > 0.0) |
||||||
|
ktree = ktree->left; |
||||||
|
else |
||||||
|
ktree = ktree->right; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (ktree->isNil == No) |
||||||
|
{ |
||||||
|
*ctx = ktree; |
||||||
|
return next_in_ktree(ctx); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
if (prev) |
||||||
|
{ |
||||||
|
if (prevcmp > 0.0) |
||||||
|
{ |
||||||
|
*ctx = prev; |
||||||
|
return(prev->data); |
||||||
|
} |
||||||
|
|
||||||
|
*ctx = prev; |
||||||
|
return next_in_ktree(ctx); |
||||||
|
} |
||||||
|
|
||||||
|
*ctx = NULL; |
||||||
|
return(NULL); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static K_TREE *removeFixup(K_TREE *root, K_TREE *fix) |
||||||
|
{ |
||||||
|
K_TREE *w = NULL; |
||||||
|
|
||||||
|
while (fix != root && fix->red != RED_RED) |
||||||
|
{ |
||||||
|
if (fix == fix->parent->left) |
||||||
|
{ |
||||||
|
w = fix->parent->right; |
||||||
|
if (w->red == RED_RED) |
||||||
|
{ |
||||||
|
w->red = RED_BLACK; |
||||||
|
fix->parent->red = RED_RED; |
||||||
|
root = left_rotate(root, fix->parent); |
||||||
|
w = fix->parent->right; |
||||||
|
} |
||||||
|
|
||||||
|
if (w->left->red != RED_RED && w->right->red != RED_RED) |
||||||
|
{ |
||||||
|
w->red = RED_RED; |
||||||
|
fix = fix->parent; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
if (w->right->red != RED_RED) |
||||||
|
{ |
||||||
|
w->left->red = RED_BLACK; |
||||||
|
w->red = RED_RED; |
||||||
|
root = right_rotate(root, w); |
||||||
|
w = fix->parent->right; |
||||||
|
} |
||||||
|
|
||||||
|
w->red = fix->parent->red; |
||||||
|
fix->parent->red = RED_BLACK; |
||||||
|
w->right->red = RED_BLACK; |
||||||
|
root = left_rotate(root, fix->parent); |
||||||
|
fix = root; |
||||||
|
} |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
w = fix->parent->left; |
||||||
|
if (w->red == RED_RED) |
||||||
|
{ |
||||||
|
w->red = RED_BLACK; |
||||||
|
fix->parent->red = RED_RED; |
||||||
|
root = right_rotate(root, fix->parent); |
||||||
|
w = fix->parent->left; |
||||||
|
} |
||||||
|
|
||||||
|
if (w->right->red != RED_RED && w->left->red != RED_RED) |
||||||
|
{ |
||||||
|
w->red = RED_RED; |
||||||
|
fix = fix->parent; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
if (w->left->red != RED_RED) |
||||||
|
{ |
||||||
|
w->right->red = RED_BLACK; |
||||||
|
w->red = RED_RED; |
||||||
|
root = left_rotate(root, w); |
||||||
|
w = fix->parent->left; |
||||||
|
} |
||||||
|
|
||||||
|
w->red = fix->parent->red; |
||||||
|
fix->parent->red = RED_BLACK; |
||||||
|
w->left->red = RED_BLACK; |
||||||
|
root = right_rotate(root, fix->parent); |
||||||
|
fix = root; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fix->red = RED_BLACK; |
||||||
|
|
||||||
|
return root; |
||||||
|
} |
||||||
|
|
||||||
|
// Does this work OK when you remove the last element in the ktree?
|
||||||
|
// It should return the root as 'nil'
|
||||||
|
K_TREE *remove_from_ktree(K_TREE *root, K_ITEM *data, double (*cmp_funct)(K_ITEM *, K_ITEM *), K_TREE_CTX *ctx) |
||||||
|
{ |
||||||
|
K_TREE_CTX tmpctx[1]; |
||||||
|
K_TREE *found; |
||||||
|
K_ITEM *fdata; |
||||||
|
K_TREE *x, *y, *nil2; |
||||||
|
// double cmp;
|
||||||
|
int yred; |
||||||
|
|
||||||
|
//check_ktree(root, ">remove", NULL, 1, 1, 1);
|
||||||
|
|
||||||
|
if (root == NULL) |
||||||
|
FAIL("%s", "%K_TREE-F-REMNULL remove ktree is NULL"); |
||||||
|
|
||||||
|
if (root->isNil == Yo) |
||||||
|
{ |
||||||
|
*ctx = NULL; |
||||||
|
return(root); |
||||||
|
} |
||||||
|
|
||||||
|
if (root->parent->isNil == No) |
||||||
|
FAIL("%s", "%K_TREE-F-REMROOT remove root isn't the root"); |
||||||
|
|
||||||
|
fdata = find_in_ktree(root, data, cmp_funct, ctx); |
||||||
|
|
||||||
|
if (fdata == NULL) |
||||||
|
return(root); |
||||||
|
|
||||||
|
if (cmp_funct(fdata, data) != 0.0) |
||||||
|
FAIL("%s", "%K_TREE-F-BADFIND cmp(found, remove) != 0"); |
||||||
|
|
||||||
|
found = *ctx; |
||||||
|
|
||||||
|
x = nil; |
||||||
|
y = nil; |
||||||
|
|
||||||
|
if (found->left->isNil == Yo || found->right->isNil == Yo) |
||||||
|
y = found; |
||||||
|
else |
||||||
|
{ |
||||||
|
*tmpctx = found; |
||||||
|
next_in_ktree(tmpctx); |
||||||
|
y = *tmpctx; |
||||||
|
} |
||||||
|
|
||||||
|
yred = y->red; |
||||||
|
|
||||||
|
if (y->left->isNil == No && y->right->isNil == No) |
||||||
|
FAIL("%s", "%K_TREE-F-REMBADY remove error"); |
||||||
|
|
||||||
|
if (y->left->isNil == Yo) |
||||||
|
x = y->right; |
||||||
|
else |
||||||
|
x = y->left; |
||||||
|
|
||||||
|
if (x != nil) |
||||||
|
nil2 = NULL; |
||||||
|
else |
||||||
|
{ |
||||||
|
nil2 = new_ktree(); |
||||||
|
x = nil2; |
||||||
|
} |
||||||
|
|
||||||
|
x->parent = y->parent; |
||||||
|
|
||||||
|
if (x->parent->isNil == Yo) |
||||||
|
root = x; |
||||||
|
else |
||||||
|
{ |
||||||
|
if (x->parent->left == y) |
||||||
|
x->parent->left = x; |
||||||
|
else |
||||||
|
x->parent->right = x; |
||||||
|
} |
||||||
|
|
||||||
|
if (y != found) |
||||||
|
{ |
||||||
|
if (root == found) |
||||||
|
root = y; |
||||||
|
|
||||||
|
if (x == found) |
||||||
|
x = y; |
||||||
|
|
||||||
|
y->red = found->red; |
||||||
|
y->parent = found->parent; |
||||||
|
|
||||||
|
if (y->parent->isNil == No) |
||||||
|
{ |
||||||
|
if (y->parent->left == found) |
||||||
|
y->parent->left = y; |
||||||
|
else |
||||||
|
y->parent->right = y; |
||||||
|
} |
||||||
|
|
||||||
|
y->left = found->left; |
||||||
|
if (y->left->isNil == No || y->left == nil2) |
||||||
|
y->left->parent = y; |
||||||
|
|
||||||
|
y->right = found->right; |
||||||
|
if (y->right->isNil == No || y->right == nil2) |
||||||
|
y->right->parent = y; |
||||||
|
} |
||||||
|
|
||||||
|
if (yred != RED_RED) |
||||||
|
root = removeFixup(root, x); |
||||||
|
|
||||||
|
if (nil2 != NULL) |
||||||
|
{ |
||||||
|
if (nil2->parent->isNil == No && nil2->parent->left == nil2) |
||||||
|
nil2->parent->left = nil; |
||||||
|
|
||||||
|
if (nil2->parent->isNil == No && nil2->parent->right == nil2) |
||||||
|
nil2->parent->right = nil; |
||||||
|
|
||||||
|
if (root == nil2) |
||||||
|
root = nil; |
||||||
|
|
||||||
|
/*
|
||||||
|
if (dbg != 0) |
||||||
|
{ |
||||||
|
if (nil2->left != nil) |
||||||
|
{ |
||||||
|
DBG("@remove nil2->left wasn't nil!!!\n"); |
||||||
|
} |
||||||
|
if (nil2->right != nil) |
||||||
|
{ |
||||||
|
DBG("@remove nil2->right wasn't nil!!!\n"); |
||||||
|
} |
||||||
|
cmp = 0.0; |
||||||
|
fdata = first_in_ktree(root, tmpctx);; |
||||||
|
while (fdata != NULL) |
||||||
|
{ |
||||||
|
cmp++; |
||||||
|
x = *tmpctx; |
||||||
|
if (x == nil2) |
||||||
|
{ |
||||||
|
DBG("@remove found nil2 in ktree %f!!!\n", cmp); |
||||||
|
} |
||||||
|
else |
||||||
|
if (x->left == nil2) |
||||||
|
{ |
||||||
|
DBG("@remove found nil2 in ktree(left) %f!!!\n", cmp); |
||||||
|
} |
||||||
|
else |
||||||
|
if (x->right == nil2) |
||||||
|
{ |
||||||
|
DBG("@remove found nil2 in ktree(right) %f!!!\n", cmp); |
||||||
|
} |
||||||
|
|
||||||
|
fdata = next_in_ktree(tmpctx);; |
||||||
|
} |
||||||
|
} |
||||||
|
*/ |
||||||
|
free(nil2); |
||||||
|
} |
||||||
|
|
||||||
|
/*
|
||||||
|
if (dbg != 0) |
||||||
|
{ |
||||||
|
cmp = 0.0 |
||||||
|
fdata = first_in_ktree(root, tmpctx);; |
||||||
|
while (fdata != NULL) |
||||||
|
{ |
||||||
|
if (cmp_funct(fdata, root->data) < 0) |
||||||
|
cmp--; |
||||||
|
else |
||||||
|
cmp++; |
||||||
|
|
||||||
|
fdata = next_in_ktree(tmpctx);; |
||||||
|
} |
||||||
|
if (cmp < -10.0 || cmp > 10.0) |
||||||
|
{ |
||||||
|
DBG("@remove after balance=%f :(\n", cmp); |
||||||
|
} |
||||||
|
} |
||||||
|
*/ |
||||||
|
|
||||||
|
|
||||||
|
//check_ktree(root, "<remove", NULL, 1, 1, 1);
|
||||||
|
|
||||||
|
return root; |
||||||
|
} |
||||||
|
|
||||||
|
static void free_ktree_sub(K_TREE *ktree, void (*free_funct)(void *)) |
||||||
|
{ |
||||||
|
if (ktree != NULL && ktree != nil) |
||||||
|
{ |
||||||
|
if (ktree->data != NULL && free_funct) |
||||||
|
(*free_funct)(ktree->data); |
||||||
|
|
||||||
|
free_ktree_sub(ktree->left, free_funct); |
||||||
|
free_ktree_sub(ktree->right, free_funct); |
||||||
|
|
||||||
|
free(ktree); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
K_TREE *free_ktree(K_TREE *ktree, void (*free_funct)(void *)) |
||||||
|
{ |
||||||
|
if (ktree == NULL) |
||||||
|
FAIL("%s", "%K_TREE-F-FREENULL free NULL ktree"); |
||||||
|
|
||||||
|
if (ktree->parent != NULL && ktree->parent != nil) |
||||||
|
FAIL("%s", "%K_TREE-F-FREENOTROOT free ktree not root"); |
||||||
|
|
||||||
|
free_ktree_sub(ktree, free_funct); |
||||||
|
|
||||||
|
return(nil); |
||||||
|
} |
@ -0,0 +1,44 @@ |
|||||||
|
/*
|
||||||
|
* Copyright 2003-2014 Andrew Smith |
||||||
|
* |
||||||
|
* This program is free software; you can redistribute it and/or modify it |
||||||
|
* under the terms of the GNU General Public License as published by the Free |
||||||
|
* Software Foundation; either version 3 of the License, or (at your option) |
||||||
|
* any later version. See COPYING for more details. |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef ___KTREE_H |
||||||
|
#define ___KTREE_H |
||||||
|
|
||||||
|
#include "klist.h" |
||||||
|
#include "libckpool.h" |
||||||
|
|
||||||
|
#define quithere(status, fmt, ...) \ |
||||||
|
quitfrom(status, __FILE__, __func__, __LINE__, fmt, ##__VA_ARGS__) |
||||||
|
|
||||||
|
typedef struct ktree |
||||||
|
{ |
||||||
|
bool isNil; |
||||||
|
bool red; |
||||||
|
struct ktree *parent; |
||||||
|
struct ktree *left; |
||||||
|
struct ktree *right; |
||||||
|
K_ITEM *data; |
||||||
|
long test; |
||||||
|
} K_TREE; |
||||||
|
|
||||||
|
typedef void *K_TREE_CTX; |
||||||
|
|
||||||
|
extern K_TREE *new_ktree(); |
||||||
|
extern void dump_ktree(K_TREE *root, char *(*dsp_funct)(K_ITEM *)); |
||||||
|
extern K_ITEM *first_in_ktree(K_TREE *root, K_TREE_CTX *ctx); |
||||||
|
extern K_ITEM *last_in_ktree(K_TREE *root, K_TREE_CTX *ctx); |
||||||
|
extern K_ITEM *next_in_ktree(K_TREE_CTX *ctx); |
||||||
|
extern K_ITEM *prev_in_ktree(K_TREE_CTX *ctx); |
||||||
|
extern K_TREE *add_to_ktree(K_TREE *root, K_ITEM *data, double (*cmp_func)(K_ITEM *, K_ITEM *)); |
||||||
|
extern K_ITEM *find_in_ktree(K_TREE *root, K_ITEM *data, double (*cmp_funct)(K_ITEM *, K_ITEM *), K_TREE_CTX *ctx); |
||||||
|
extern K_ITEM *find_after_in_ktree(K_TREE *ktree, K_ITEM *data, double (*cmp_funct)(K_ITEM *, K_ITEM *), K_TREE_CTX *ctx); |
||||||
|
extern K_TREE *remove_from_ktree(K_TREE *root, K_ITEM *data, double (*cmp_funct)(K_ITEM *, K_ITEM *), K_TREE_CTX *ctx); |
||||||
|
extern K_TREE *free_ktree(K_TREE *root, void (*free_funct)(void *)); |
||||||
|
|
||||||
|
#endif |
Loading…
Reference in new issue