Browse Source

ckdb v0.0

master
kanoi 11 years ago
parent
commit
762fe5ebaf
  1. 3
      configure.ac
  2. 5
      src/Makefile.am
  3. 2101
      src/ckdb.c
  4. 380
      src/klist.c
  5. 93
      src/klist.h
  6. 872
      src/ktree.c
  7. 44
      src/ktree.h

3
configure.ac

@ -41,6 +41,7 @@ AC_CHECK_HEADERS(stdint.h netinet/in.h netinet/tcp.h sys/ioctl.h)
PTHREAD_LIBS="-lpthread" PTHREAD_LIBS="-lpthread"
MATH_LIBS="-lm" MATH_LIBS="-lm"
RT_LIBS="-lrt" RT_LIBS="-lrt"
PQ_LIBS="-lpq"
AC_CONFIG_SUBDIRS([src/jansson-2.6]) AC_CONFIG_SUBDIRS([src/jansson-2.6])
JANSSON_LIBS="jansson-2.6/src/.libs/libjansson.a" JANSSON_LIBS="jansson-2.6/src/.libs/libjansson.a"
@ -48,6 +49,7 @@ JANSSON_LIBS="jansson-2.6/src/.libs/libjansson.a"
AC_SUBST(PTHREAD_LIBS) AC_SUBST(PTHREAD_LIBS)
AC_SUBST(MATH_LIBS) AC_SUBST(MATH_LIBS)
AC_SUBST(RT_LIBS) AC_SUBST(RT_LIBS)
AC_SUBST(PQ_LIBS)
AC_SUBST(JANSSON_LIBS) AC_SUBST(JANSSON_LIBS)
AC_OUTPUT([Makefile] [src/Makefile]) AC_OUTPUT([Makefile] [src/Makefile])
@ -58,6 +60,7 @@ echo " CPPFLAGS.............: $CPPFLAGS"
echo " CFLAGS...............: $CFLAGS" echo " CFLAGS...............: $CFLAGS"
echo " LDFLAGS..............: $LDFLAGS" echo " LDFLAGS..............: $LDFLAGS"
echo " LDADD................: $PTHREAD_LIBS $MATH_LIBS $RT_LIBS $JANSSON_LIBS" echo " LDADD................: $PTHREAD_LIBS $MATH_LIBS $RT_LIBS $JANSSON_LIBS"
echo " db LDADD.............: $PQ_LIBS"
echo echo
echo "Installation...........: make install (as root if needed, with 'su' or 'sudo')" echo "Installation...........: make install (as root if needed, with 'su' or 'sudo')"
echo " prefix...............: $prefix" echo " prefix...............: $prefix"

5
src/Makefile.am

@ -6,7 +6,7 @@ lib_LTLIBRARIES = libckpool.la
libckpool_la_SOURCES = libckpool.c libckpool.h sha2.c sha2.h libckpool_la_SOURCES = libckpool.c libckpool.h sha2.c sha2.h
libckpool_la_LIBADD = @PTHREAD_LIBS@ @MATH_LIBS@ @RT_LIBS@ libckpool_la_LIBADD = @PTHREAD_LIBS@ @MATH_LIBS@ @RT_LIBS@
bin_PROGRAMS = ckpool ckpmsg bin_PROGRAMS = ckpool ckpmsg ckdb
ckpool_SOURCES = ckpool.c ckpool.h generator.c generator.h bitcoin.c bitcoin.h \ ckpool_SOURCES = ckpool.c ckpool.h generator.c generator.h bitcoin.c bitcoin.h \
stratifier.c stratifier.h connector.c connector.h uthash.h \ stratifier.c stratifier.h connector.c connector.h uthash.h \
utlist.h utlist.h
@ -14,3 +14,6 @@ ckpool_LDADD = libckpool.la @JANSSON_LIBS@
ckpmsg_SOURCES = ckpmsg.c ckpmsg_SOURCES = ckpmsg.c
ckpmsg_LDADD = libckpool.la @JANSSON_LIBS@ ckpmsg_LDADD = libckpool.la @JANSSON_LIBS@
ckdb_SOURCES = ckdb.c klist.c ktree.c klist.h ktree.h
ckdb_LDADD = libckpool.la @JANSSON_LIBS@ @PQ_LIBS@

2101
src/ckdb.c

File diff suppressed because it is too large Load Diff

380
src/klist.c

@ -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;
}

93
src/klist.h

@ -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

872
src/ktree.c

@ -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);
}

44
src/ktree.h

@ -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…
Cancel
Save