Replace glibc tsearch() with a custom red-black tree implementation.
The library supplied tree estructure is not enought for our needs, due to its limited API. Thus, we have implemented a suitable red-black tree.
This commit is contained in:
parent
5eb3a7e038
commit
e6bd1586d6
@ -29,6 +29,7 @@ src_libisofs_la_SOURCES = \
|
|||||||
src/stream.c \
|
src/stream.c \
|
||||||
src/util.h \
|
src/util.h \
|
||||||
src/util.c \
|
src/util.c \
|
||||||
|
src/util_rbtree.c \
|
||||||
src/filesrc.h \
|
src/filesrc.h \
|
||||||
src/filesrc.c \
|
src/filesrc.c \
|
||||||
src/ecma119.h \
|
src/ecma119.h \
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
#include "libisofs.h"
|
#include "libisofs.h"
|
||||||
#include "ecma119.h"
|
#include "ecma119.h"
|
||||||
#include "ecma119_tree.h"
|
#include "ecma119_tree.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "filesrc.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
@ -91,6 +93,7 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ecma119 = calloc(1, sizeof(Ecma119Image));
|
ecma119 = calloc(1, sizeof(Ecma119Image));
|
||||||
|
iso_rbtree_new(iso_file_src_cmp, &(ecma119->files));
|
||||||
ecma119->iso_level = 1;
|
ecma119->iso_level = 1;
|
||||||
ecma119->image = image;
|
ecma119->image = image;
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ void ecma119_image_free(Ecma119Image *t)
|
|||||||
|
|
||||||
ecma119_node_free(t->root);
|
ecma119_node_free(t->root);
|
||||||
iso_image_unref(t->image);
|
iso_image_unref(t->image);
|
||||||
iso_file_src_free(t);
|
iso_rbtree_destroy(t->files, iso_file_src_free);
|
||||||
|
|
||||||
for (i = 0; i < t->nwriters; ++i) {
|
for (i = 0; i < t->nwriters; ++i) {
|
||||||
IsoImageWriter *writer = t->writers[i];
|
IsoImageWriter *writer = t->writers[i];
|
||||||
@ -293,6 +293,13 @@ int ecma119_image_new(IsoImage *src, Ecma119WriteOpts *opts,
|
|||||||
return ISO_MEM_ERROR;
|
return ISO_MEM_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* create the tree for file caching */
|
||||||
|
ret = iso_rbtree_new(iso_file_src_cmp, &(target->files));
|
||||||
|
if (ret < 0) {
|
||||||
|
free(target);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
target->image = src;
|
target->image = src;
|
||||||
iso_image_ref(src);
|
iso_image_ref(src);
|
||||||
|
|
||||||
@ -303,6 +310,7 @@ int ecma119_image_new(IsoImage *src, Ecma119WriteOpts *opts,
|
|||||||
target->ms_block = 0;
|
target->ms_block = 0;
|
||||||
target->input_charset = strdup("UTF-8"); //TODO
|
target->input_charset = strdup("UTF-8"); //TODO
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 2. Based on those options, create needed writers: iso, joliet...
|
* 2. Based on those options, create needed writers: iso, joliet...
|
||||||
* Each writer inits its structures and stores needed info into
|
* Each writer inits its structures and stores needed info into
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#define LIBISO_ECMA119_H_
|
#define LIBISO_ECMA119_H_
|
||||||
|
|
||||||
#include "libisofs.h"
|
#include "libisofs.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
@ -72,8 +73,7 @@ struct ecma119_image {
|
|||||||
IsoImageWriter **writers;
|
IsoImageWriter **writers;
|
||||||
|
|
||||||
/* tree of files sources */
|
/* tree of files sources */
|
||||||
void *file_srcs;
|
IsoRBTree *files;
|
||||||
int file_count;
|
|
||||||
|
|
||||||
/* file descriptors for read and writing image */
|
/* file descriptors for read and writing image */
|
||||||
int wrfd; /* write to here */
|
int wrfd; /* write to here */
|
||||||
|
@ -9,15 +9,11 @@
|
|||||||
#include "filesrc.h"
|
#include "filesrc.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
/* tdestroy is a GNU specific function */
|
int iso_file_src_cmp(const void *n1, const void *n2)
|
||||||
#define __USE_GNU
|
|
||||||
#include <search.h>
|
|
||||||
|
|
||||||
static
|
|
||||||
int comp_iso_file_src(const void *n1, const void *n2)
|
|
||||||
{
|
{
|
||||||
const IsoFileSrc *f1, *f2;
|
const IsoFileSrc *f1, *f2;
|
||||||
int res;
|
int res;
|
||||||
@ -25,7 +21,6 @@ int comp_iso_file_src(const void *n1, const void *n2)
|
|||||||
dev_t dev_id1, dev_id2;
|
dev_t dev_id1, dev_id2;
|
||||||
ino_t ino_id1, ino_id2;
|
ino_t ino_id1, ino_id2;
|
||||||
|
|
||||||
|
|
||||||
f1 = (const IsoFileSrc *)n1;
|
f1 = (const IsoFileSrc *)n1;
|
||||||
f2 = (const IsoFileSrc *)n2;
|
f2 = (const IsoFileSrc *)n2;
|
||||||
|
|
||||||
@ -76,7 +71,7 @@ int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src)
|
|||||||
// care of it
|
// care of it
|
||||||
return ISO_ERROR;
|
return ISO_ERROR;
|
||||||
} else {
|
} else {
|
||||||
IsoFileSrc **inserted;
|
int ret;
|
||||||
|
|
||||||
fsrc = malloc(sizeof(IsoFileSrc));
|
fsrc = malloc(sizeof(IsoFileSrc));
|
||||||
if (fsrc == NULL) {
|
if (fsrc == NULL) {
|
||||||
@ -90,32 +85,18 @@ int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src)
|
|||||||
fsrc->stream = file->stream;
|
fsrc->stream = file->stream;
|
||||||
|
|
||||||
/* insert the filesrc in the tree */
|
/* insert the filesrc in the tree */
|
||||||
inserted = tsearch(fsrc, &(img->file_srcs), comp_iso_file_src);
|
ret = iso_rbtree_insert(img->files, fsrc, (void**)src);
|
||||||
if (inserted == NULL) {
|
if (ret <= 0) {
|
||||||
free(fsrc);
|
|
||||||
return ISO_MEM_ERROR;
|
|
||||||
} else if (*inserted == fsrc) {
|
|
||||||
/* the file was inserted */
|
|
||||||
img->file_count++;
|
|
||||||
} else {
|
|
||||||
/* the file was already on the tree */
|
|
||||||
free(fsrc);
|
free(fsrc);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
*src = *inserted;
|
|
||||||
}
|
}
|
||||||
return ISO_SUCCESS;
|
return ISO_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_node(void *nodep)
|
void iso_file_src_free(void *node)
|
||||||
{
|
{
|
||||||
/* nothing to do */
|
free(node);
|
||||||
}
|
|
||||||
|
|
||||||
void iso_file_src_free(Ecma119Image *img)
|
|
||||||
{
|
|
||||||
if (img->file_srcs != NULL) {
|
|
||||||
tdestroy(img->file_srcs, free_node);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
off_t iso_file_src_get_size(IsoFileSrc *file)
|
off_t iso_file_src_get_size(IsoFileSrc *file)
|
||||||
|
@ -21,6 +21,8 @@ struct Iso_File_Src {
|
|||||||
IsoStream *stream;
|
IsoStream *stream;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int iso_file_src_cmp(const void *n1, const void *n2);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new IsoFileSrc to get data from a specific IsoFile.
|
* Create a new IsoFileSrc to get data from a specific IsoFile.
|
||||||
*
|
*
|
||||||
@ -43,7 +45,7 @@ int iso_file_src_create(Ecma119Image *img, IsoFile *file, IsoFileSrc **src);
|
|||||||
/**
|
/**
|
||||||
* Free the IsoFileSrc especific data
|
* Free the IsoFileSrc especific data
|
||||||
*/
|
*/
|
||||||
void iso_file_src_free(Ecma119Image *img);
|
void iso_file_src_free(void *node);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the size of the file this IsoFileSrc represents
|
* Get the size of the file this IsoFileSrc represents
|
||||||
|
58
src/util.h
58
src/util.h
@ -89,4 +89,62 @@ void iso_datetime_7(uint8_t *buf, time_t t);
|
|||||||
/** Records the date/time into a 17 byte buffer (ECMA-119, 8.4.26.1) */
|
/** Records the date/time into a 17 byte buffer (ECMA-119, 8.4.26.1) */
|
||||||
void iso_datetime_17(uint8_t *buf, time_t t);
|
void iso_datetime_17(uint8_t *buf, time_t t);
|
||||||
|
|
||||||
|
typedef struct iso_rbtree IsoRBTree;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new binary tree. libisofs binary trees allow you to add any data
|
||||||
|
* passing it as a pointer. You must provide a function suitable for compare
|
||||||
|
* two elements.
|
||||||
|
*
|
||||||
|
* @param compare
|
||||||
|
* A function to compare two elements. It takes a pointer to both elements
|
||||||
|
* and return 0, -1 or 1 if the first element is equal, less or greater
|
||||||
|
* than the second one.
|
||||||
|
* @param tree
|
||||||
|
* Location where the tree structure will be stored.
|
||||||
|
*/
|
||||||
|
int iso_rbtree_new(int (*compare)(const void*, const void*), IsoRBTree **tree);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy a given tree.
|
||||||
|
*
|
||||||
|
* Note that only the structure itself is deleted. To delete the elements, you
|
||||||
|
* should provide a valid free_data function. It will be called for each
|
||||||
|
* element of the tree, so you can use it to free any related data.
|
||||||
|
*/
|
||||||
|
void iso_rbtree_destroy(IsoRBTree *tree, void (*free_data)(void *));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts a given element in a Red-Black tree.
|
||||||
|
*
|
||||||
|
* @param tree
|
||||||
|
* the tree where to insert
|
||||||
|
* @param data
|
||||||
|
* element to be inserted on the tree. It can't be NULL
|
||||||
|
* @param item
|
||||||
|
* if not NULL, it will point to a location where the tree element ptr
|
||||||
|
* will be stored. If data was inserted, *item == data. If data was
|
||||||
|
* already on the tree, *item points to the previously inserted object
|
||||||
|
* that is equal to data.
|
||||||
|
* @return
|
||||||
|
* 1 success, 0 element already inserted, < 0 error
|
||||||
|
*/
|
||||||
|
int iso_rbtree_insert(IsoRBTree *tree, void *data, void **item);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the number of elements in a given tree.
|
||||||
|
*/
|
||||||
|
size_t iso_rbtree_get_size(IsoRBTree *tree);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an array view of the elements of the tree.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* A sorted array with the contents of the tree, or NULL if there is not
|
||||||
|
* enought memory to allocate the array. You should free(3) the array when
|
||||||
|
* no more needed. Note that the array is NULL-terminated, and thus it
|
||||||
|
* has size + 1 length.
|
||||||
|
*/
|
||||||
|
void **iso_rbtree_to_array(IsoRBTree *tree);
|
||||||
|
|
||||||
#endif /*LIBISO_UTIL_H_*/
|
#endif /*LIBISO_UTIL_H_*/
|
||||||
|
284
src/util_rbtree.c
Normal file
284
src/util_rbtree.c
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2007 Vreixo Formoso
|
||||||
|
*
|
||||||
|
* This file is part of the libisofs project; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation. See COPYING file for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
#include "error.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This implementation of Red-Black tree is based on the public domain
|
||||||
|
* implementation of Julienne Walker.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct iso_rbnode {
|
||||||
|
void *data;
|
||||||
|
struct iso_rbnode *ch[2];
|
||||||
|
unsigned int red:1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct iso_rbtree {
|
||||||
|
struct iso_rbnode *root;
|
||||||
|
size_t size;
|
||||||
|
int (*compare)(const void *a, const void *b);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new binary tree. libisofs binary trees allow you to add any data
|
||||||
|
* passing it as a pointer. You must provide a function suitable for compare
|
||||||
|
* two elements.
|
||||||
|
*
|
||||||
|
* @param compare
|
||||||
|
* A function to compare two elements. It takes a pointer to both elements
|
||||||
|
* and return 0, -1 or 1 if the first element is equal, less or greater
|
||||||
|
* than the second one.
|
||||||
|
* @param tree
|
||||||
|
* Location where the tree structure will be stored.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
iso_rbtree_new(int (*compare)(const void*, const void*), IsoRBTree **tree)
|
||||||
|
{
|
||||||
|
if (compare == NULL || tree == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
*tree = calloc(1, sizeof(IsoRBTree));
|
||||||
|
if (*tree == NULL) {
|
||||||
|
return ISO_MEM_ERROR;
|
||||||
|
}
|
||||||
|
(*tree)->compare = compare;
|
||||||
|
return ISO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void rbtree_destroy_aux(struct iso_rbnode *root, void (*free_data)(void *))
|
||||||
|
{
|
||||||
|
if (root == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (free_data != NULL) {
|
||||||
|
free_data(root->data);
|
||||||
|
}
|
||||||
|
rbtree_destroy_aux(root->ch[0], free_data);
|
||||||
|
rbtree_destroy_aux(root->ch[1], free_data);
|
||||||
|
free(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy a given tree.
|
||||||
|
*
|
||||||
|
* Note that only the structure itself is deleted. To delete the elements, you
|
||||||
|
* should provide a valid free_data function. It will be called for each
|
||||||
|
* element of the tree, so you can use it to free any related data.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
iso_rbtree_destroy(IsoRBTree *tree, void (*free_data)(void *))
|
||||||
|
{
|
||||||
|
if (tree == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rbtree_destroy_aux(tree->root, free_data);
|
||||||
|
free(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
int is_red(struct iso_rbnode *root)
|
||||||
|
{
|
||||||
|
return root != NULL && root->red;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
struct iso_rbnode *iso_rbtree_single(struct iso_rbnode *root, int dir)
|
||||||
|
{
|
||||||
|
struct iso_rbnode *save = root->ch[!dir];
|
||||||
|
|
||||||
|
root->ch[!dir] = save->ch[dir];
|
||||||
|
save->ch[dir] = root;
|
||||||
|
|
||||||
|
root->red = 1;
|
||||||
|
save->red = 0;
|
||||||
|
return save;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
struct iso_rbnode *iso_rbtree_double(struct iso_rbnode *root, int dir)
|
||||||
|
{
|
||||||
|
root->ch[!dir] = iso_rbtree_single(root->ch[!dir], !dir);
|
||||||
|
return iso_rbtree_single(root, dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
struct iso_rbnode *iso_rbnode_new(void *data)
|
||||||
|
{
|
||||||
|
struct iso_rbnode *rn = malloc(sizeof(struct iso_rbnode));
|
||||||
|
|
||||||
|
if ( rn != NULL ) {
|
||||||
|
rn->data = data;
|
||||||
|
rn->red = 1;
|
||||||
|
rn->ch[0] = NULL;
|
||||||
|
rn->ch[1] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts a given element in a Red-Black tree.
|
||||||
|
*
|
||||||
|
* @param tree
|
||||||
|
* the tree where to insert
|
||||||
|
* @param data
|
||||||
|
* element to be inserted on the tree. It can't be NULL
|
||||||
|
* @param item
|
||||||
|
* if not NULL, it will point to a location where the tree element ptr
|
||||||
|
* will be stored. If data was inserted, *item == data. If data was
|
||||||
|
* already on the tree, *item points to the previously inserted object
|
||||||
|
* that is equal to data.
|
||||||
|
* @return
|
||||||
|
* 1 success, 0 element already inserted, < 0 error
|
||||||
|
*/
|
||||||
|
int iso_rbtree_insert(IsoRBTree *tree, void *data, void **item)
|
||||||
|
{
|
||||||
|
struct iso_rbnode *new;
|
||||||
|
int added = 0; /* has a new node been added? */
|
||||||
|
|
||||||
|
if (tree == NULL || data == NULL) {
|
||||||
|
return ISO_NULL_POINTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tree->root == NULL) {
|
||||||
|
/* Empty tree case */
|
||||||
|
tree->root = iso_rbnode_new(data);
|
||||||
|
if (tree->root == NULL) {
|
||||||
|
return ISO_MEM_ERROR;
|
||||||
|
}
|
||||||
|
new = data;
|
||||||
|
added = 1;
|
||||||
|
} else {
|
||||||
|
struct iso_rbnode head = {0}; /* False tree root */
|
||||||
|
|
||||||
|
struct iso_rbnode *g, *t; /* Grandparent & parent */
|
||||||
|
struct iso_rbnode *p, *q; /* Iterator & parent */
|
||||||
|
int dir = 0, last = 0;
|
||||||
|
int comp;
|
||||||
|
|
||||||
|
/* Set up helpers */
|
||||||
|
t = &head;
|
||||||
|
g = p = NULL;
|
||||||
|
q = t->ch[1] = tree->root;
|
||||||
|
|
||||||
|
/* Search down the tree */
|
||||||
|
while (1) {
|
||||||
|
if (q == NULL) {
|
||||||
|
/* Insert new node at the bottom */
|
||||||
|
p->ch[dir] = q = iso_rbnode_new(data);
|
||||||
|
if (q == NULL) {
|
||||||
|
return ISO_MEM_ERROR;
|
||||||
|
}
|
||||||
|
added = 1;
|
||||||
|
} else if (is_red(q->ch[0]) && is_red(q->ch[1])) {
|
||||||
|
/* Color flip */
|
||||||
|
q->red = 1;
|
||||||
|
q->ch[0]->red = 0;
|
||||||
|
q->ch[1]->red = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fix red violation */
|
||||||
|
if (is_red(q) && is_red(p)) {
|
||||||
|
int dir2 = (t->ch[1] == g);
|
||||||
|
|
||||||
|
if (q == p->ch[last]) {
|
||||||
|
t->ch[dir2] = iso_rbtree_single(g, !last);
|
||||||
|
} else {
|
||||||
|
t->ch[dir2] = iso_rbtree_double(g, !last);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
comp = tree->compare(q->data, data);
|
||||||
|
|
||||||
|
/* Stop if found */
|
||||||
|
if (comp == 0) {
|
||||||
|
new = q->data;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
last = dir;
|
||||||
|
dir = (comp < 0);
|
||||||
|
|
||||||
|
/* Update helpers */
|
||||||
|
if (g != NULL)
|
||||||
|
t = g;
|
||||||
|
g = p, p = q;
|
||||||
|
q = q->ch[dir];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update root */
|
||||||
|
tree->root = head.ch[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make root black */
|
||||||
|
tree->root->red = 0;
|
||||||
|
|
||||||
|
if (item != NULL) {
|
||||||
|
*item = new;
|
||||||
|
}
|
||||||
|
if (added) {
|
||||||
|
/* a new element has been added */
|
||||||
|
tree->size++;
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the number of elements in a given tree.
|
||||||
|
*/
|
||||||
|
size_t iso_rbtree_get_size(IsoRBTree *tree)
|
||||||
|
{
|
||||||
|
return tree->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static
|
||||||
|
int rbtree_to_array_aux(struct iso_rbnode *root, void **array, size_t pos)
|
||||||
|
{
|
||||||
|
if (root == NULL) {
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
pos = rbtree_to_array_aux(root->ch[0], array, pos);
|
||||||
|
array[pos++] = root->data;
|
||||||
|
pos = rbtree_to_array_aux(root->ch[1], array, pos);
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an array view of the elements of the tree.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* A sorted array with the contents of the tree, or NULL if there is not
|
||||||
|
* enought memory to allocate the array. You should free(3) the array when
|
||||||
|
* no more needed. Note that the array is NULL-terminated, and thus it
|
||||||
|
* has size + 1 length.
|
||||||
|
*/
|
||||||
|
void **
|
||||||
|
iso_rbtree_to_array(IsoRBTree *tree)
|
||||||
|
{
|
||||||
|
void **array;
|
||||||
|
|
||||||
|
array = malloc((tree->size + 1) * sizeof(void*));
|
||||||
|
if (array == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fill array */
|
||||||
|
rbtree_to_array_aux(tree->root, array, 0);
|
||||||
|
array[tree->size] = NULL;
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
@ -6,6 +6,8 @@
|
|||||||
#include "test.h"
|
#include "test.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
static void test_div_up()
|
static void test_div_up()
|
||||||
{
|
{
|
||||||
CU_ASSERT_EQUAL( div_up(1, 2), 1 );
|
CU_ASSERT_EQUAL( div_up(1, 2), 1 );
|
||||||
@ -27,10 +29,62 @@ static void test_round_up()
|
|||||||
CU_ASSERT_EQUAL( round_up(14, 7), 14 );
|
CU_ASSERT_EQUAL( round_up(14, 7), 14 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_iso_rbtree_insert()
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
IsoRBTree *tree;
|
||||||
|
char *str1, *str2, *str3, *str4, *str5;
|
||||||
|
void *str;
|
||||||
|
|
||||||
|
res = iso_rbtree_new(strcmp, &tree);
|
||||||
|
CU_ASSERT_EQUAL(res, 1);
|
||||||
|
|
||||||
|
/* ok, insert one str */
|
||||||
|
str1 = "first str";
|
||||||
|
res = iso_rbtree_insert(tree, str1, &str);
|
||||||
|
CU_ASSERT_EQUAL(res, 1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(str, str1);
|
||||||
|
|
||||||
|
str2 = "second str";
|
||||||
|
res = iso_rbtree_insert(tree, str2, &str);
|
||||||
|
CU_ASSERT_EQUAL(res, 1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(str, str2);
|
||||||
|
|
||||||
|
/* an already inserted string */
|
||||||
|
str3 = "second str";
|
||||||
|
res = iso_rbtree_insert(tree, str3, &str);
|
||||||
|
CU_ASSERT_EQUAL(res, 0);
|
||||||
|
CU_ASSERT_PTR_EQUAL(str, str2);
|
||||||
|
|
||||||
|
/* an already inserted string */
|
||||||
|
str3 = "first str";
|
||||||
|
res = iso_rbtree_insert(tree, str3, &str);
|
||||||
|
CU_ASSERT_EQUAL(res, 0);
|
||||||
|
CU_ASSERT_PTR_EQUAL(str, str1);
|
||||||
|
|
||||||
|
str4 = "a string to be inserted first";
|
||||||
|
res = iso_rbtree_insert(tree, str4, &str);
|
||||||
|
CU_ASSERT_EQUAL(res, 1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(str, str4);
|
||||||
|
|
||||||
|
str5 = "this to be inserted last";
|
||||||
|
res = iso_rbtree_insert(tree, str5, &str);
|
||||||
|
CU_ASSERT_EQUAL(res, 1);
|
||||||
|
CU_ASSERT_PTR_EQUAL(str, str5);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO write a really good test to check all possible estrange
|
||||||
|
* behaviors of a red-black tree
|
||||||
|
*/
|
||||||
|
|
||||||
|
iso_rbtree_destroy(tree, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
void add_util_suite()
|
void add_util_suite()
|
||||||
{
|
{
|
||||||
CU_pSuite pSuite = CU_add_suite("UtilSuite", NULL, NULL);
|
CU_pSuite pSuite = CU_add_suite("UtilSuite", NULL, NULL);
|
||||||
|
|
||||||
CU_add_test(pSuite, "div_up()", test_div_up);
|
CU_add_test(pSuite, "div_up()", test_div_up);
|
||||||
CU_add_test(pSuite, "round_up()", test_round_up);
|
CU_add_test(pSuite, "round_up()", test_round_up);
|
||||||
|
CU_add_test(pSuite, "iso_rbtree_insert()", test_iso_rbtree_insert);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user