mirror of
https://github.com/owntone/owntone-server.git
synced 2024-12-24 22:25:56 -05:00
Embed libavl (v0.3.5), it is no longer available upstream and the dependency is a hassle
This commit is contained in:
parent
3aa5a4df30
commit
df9bcade5a
8
INSTALL
8
INSTALL
@ -23,8 +23,7 @@ sudo apt-get install \
|
||||
build-essential git autotools-dev autoconf libtool gettext gawk gperf \
|
||||
antlr3 libantlr3c-dev libconfuse-dev libunistring-dev libsqlite3-dev \
|
||||
libavcodec-dev libavformat-dev libswscale-dev libavutil-dev libasound2-dev \
|
||||
libmxml-dev libgcrypt11-dev libavahi-client-dev libavl-dev zlib1g-dev \
|
||||
libevent-dev
|
||||
libmxml-dev libgcrypt11-dev libavahi-client-dev zlib1g-dev libevent-dev
|
||||
|
||||
Depending on the version of libav/ffmpeg in your distribution you may also need
|
||||
libavresample-dev.
|
||||
@ -92,8 +91,6 @@ Libraries:
|
||||
from <http://www.nongnu.org/confuse/>
|
||||
- libevent 1.4+ (best with version 1.4 or 2.1.4+)
|
||||
from <http://libevent.org/>
|
||||
- libavl 0.3.5
|
||||
from <http://ftp.debian.org/debian/pool/main/liba/libavl>
|
||||
- MiniXML (aka mxml or libmxml)
|
||||
from <http://minixml.org/software.php>
|
||||
- gcrypt 1.2.0+
|
||||
@ -118,9 +115,6 @@ Libraries:
|
||||
If using binary packages, remember that you need the development packages to
|
||||
build forked-daapd (usually named -dev or -devel).
|
||||
|
||||
libavl is not the GNU libavl. There doesn't seem to be an upstream website
|
||||
anymore, but you can fetch it from any Debian mirror.
|
||||
|
||||
sqlite3 needs to be built with support for the unlock notify API; this isn't
|
||||
always the case in binary packages, so you may need to rebuild sqlite3 to
|
||||
enable the unlock notify API (you can check for the presence of the
|
||||
|
@ -183,10 +183,6 @@ else
|
||||
)
|
||||
fi
|
||||
|
||||
AC_CHECK_HEADER(avl.h, , AC_MSG_ERROR([avl.h not found]))
|
||||
AC_CHECK_LIB([avl], [avl_alloc_tree], [LIBAVL_LIBS="-lavl"], AC_MSG_ERROR([libavl not found]))
|
||||
AC_SUBST(LIBAVL_LIBS)
|
||||
|
||||
AC_CHECK_HEADER(antlr3.h, , AC_MSG_ERROR([antlr3.h not found]))
|
||||
AC_CHECK_LIB([antlr3c], [antlr3BaseRecognizerNew], [ANTLR3C_LIBS="-lantlr3c"], AC_MSG_ERROR([ANTLR3 C runtime (libantlr3c) not found]))
|
||||
AC_CHECK_LIB([antlr3c], [antlr3NewAsciiStringInPlaceStream],
|
||||
|
@ -50,6 +50,8 @@ EVHTTP_SRC=
|
||||
RTSP_SRC=evrtsp/rtsp.c evrtp/evrtsp.h evrtsp/rtsp-internal.h evrtsp/log.h
|
||||
endif
|
||||
|
||||
AVL_SRC=avl/avl.c avl/avl.h
|
||||
|
||||
GPERF_FILES = \
|
||||
daap_query.gperf \
|
||||
rsp_query.gperf \
|
||||
@ -87,7 +89,7 @@ forked_daapd_CFLAGS = \
|
||||
forked_daapd_LDADD = -lrt \
|
||||
@ZLIB_LIBS@ @AVAHI_LIBS@ @SQLITE3_LIBS@ @LIBAV_LIBS@ \
|
||||
@CONFUSE_LIBS@ @FLAC_LIBS@ @TAGLIB_LIBS@ @LIBEVENT_LIBS@ \
|
||||
@LIBAVL_LIBS@ @MINIXML_LIBS@ @ANTLR3C_LIBS@ @LIBPLIST_LIBS@ \
|
||||
@MINIXML_LIBS@ @ANTLR3C_LIBS@ @LIBPLIST_LIBS@ \
|
||||
@LIBGCRYPT_LIBS@ @GPG_ERROR_LIBS@ @ALSA_LIBS@ @LIBUNISTRING@ @SPOTIFY_LIBS@ \
|
||||
@LIBCURL_LIBS@
|
||||
|
||||
@ -95,7 +97,8 @@ forked_daapd_SOURCES = main.c \
|
||||
db.c db.h \
|
||||
logger.c logger.h \
|
||||
conffile.c conffile.h \
|
||||
cache.h cache.c \
|
||||
cache.c cache.h \
|
||||
$(AVL_SRC) \
|
||||
filescanner.c filescanner.h \
|
||||
filescanner_ffmpeg.c filescanner_playlist.c filescanner_icy.c $(ITUNES_SRC) \
|
||||
mdns_avahi.c mdns.h \
|
||||
|
91
src/avl/README
Normal file
91
src/avl/README
Normal file
@ -0,0 +1,91 @@
|
||||
========================================================================
|
||||
|
||||
WHAT IS AVLTREE?
|
||||
|
||||
AVLTree is a small implementation of AVL trees for the C programming
|
||||
language. It is distributed under the Library GNU Public License.
|
||||
|
||||
This library does the basic stuff. It allows for inserts, searches, and
|
||||
deletes in O(log n) time. It also allows the tree to be used as a linked
|
||||
indexable list (search/insert functions cannot be used in that case).
|
||||
|
||||
If you find a bug, you should mail Wessel Dankers <wsl@nl.linux.org>,
|
||||
who produced this version of the library and therefore is to blame.
|
||||
|
||||
The original author is Michael H. Buselli <cosine@cosine.org>, who can
|
||||
be reached at the following address:
|
||||
|
||||
Michael H. Buselli
|
||||
4334 N. Hazel St. #515
|
||||
Chicago, IL 60613-1456
|
||||
|
||||
========================================================================
|
||||
|
||||
COMPILING THE LIBRARY
|
||||
|
||||
There is a Makefile included in the distribution.
|
||||
|
||||
========================================================================
|
||||
|
||||
USING THE LIBRARIES
|
||||
|
||||
There are no real usage documents yet. Look at avl.h (you need to
|
||||
include these headers in your programs to use the library) to see what
|
||||
functions and structures are available. As a small example:
|
||||
|
||||
#define BUFSIZE 8192
|
||||
|
||||
int main(void) {
|
||||
char *buf[BUFSIZE];
|
||||
AVLTree *tree;
|
||||
AVLTree *node;
|
||||
|
||||
tree = avl_alloc_tree((avl_compare_t)strcmp, (avl_freeitem_t)free);
|
||||
|
||||
while(fgets(buf, BUFSIZE, stdin))
|
||||
avl_insert(tree, strdup(buf));
|
||||
|
||||
for(node = tree->head; node; node = node->next)
|
||||
printf("%s", node->item);
|
||||
|
||||
avl_free_tree(tree, free);
|
||||
}
|
||||
|
||||
A real implementation would check the return values of avl_alloc_tree,
|
||||
avl_insert and strdup of course.
|
||||
|
||||
========================================================================
|
||||
|
||||
HISTORY
|
||||
|
||||
Version 0.1.0 (alpha):
|
||||
This is the initial alpha version of AVLTree. It's already fully
|
||||
functional for many applications, including the one that I developed it
|
||||
for. I've only tested it on my Linux 2.0.35/glibc2 system, so I have no
|
||||
idea what it will do anywhere else so far. Let me know if you have good
|
||||
results or bad if you try a platform that I don't mention above.
|
||||
|
||||
This version is considered alpha because it does not yet contain
|
||||
all of the features that I plan for version 1.0.0. It should not
|
||||
contain any bugs as it is.
|
||||
|
||||
Version 0.2.0 2000-11-28 Wessel Dankers <wsl@nl.linux.org>
|
||||
Modifications to support fast traversal and accessing by index.
|
||||
The tree is generalized to allow arbitrary comparison functions.
|
||||
Fixed bug: when deleting, in some cases rebalancing would not occur
|
||||
|
||||
Version 0.3.0 2001-01-07 Wessel Dankers <wsl@nl.linux.org>
|
||||
Tree can now be balanced on count or depth (but depth works better).
|
||||
Fixed bug: balancing on count now is done correctly.
|
||||
|
||||
Version 0.3.1 2001-07-17 Wessel Dankers <wsl@nl.linux.org>
|
||||
Node initialization is moved to make matters a bit more robust
|
||||
|
||||
Version 0.3.4 2002-06-11 Wessel Dankers <wsl@fruit.eu.org>
|
||||
Fixed a bug in the node counting.
|
||||
|
||||
Version 0.3.5 2002-11-15 Wessel Dankers <wsl@fruit.eu.org>
|
||||
Added avl_node_fixup() and avl_clear_tree().
|
||||
Removed obsolete files from source tree.
|
||||
|
||||
========================================================================
|
590
src/avl/avl.c
Normal file
590
src/avl/avl.c
Normal file
@ -0,0 +1,590 @@
|
||||
/*****************************************************************************
|
||||
|
||||
avl.c - Source code for the AVL-tree library.
|
||||
|
||||
Copyright (C) 1998 Michael H. Buselli <cosine@cosine.org>
|
||||
Copyright (C) 2000-2002 Wessel Dankers <wsl@nl.linux.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Augmented AVL-tree. Original by Michael H. Buselli <cosine@cosine.org>.
|
||||
|
||||
Modified by Wessel Dankers <wsl@nl.linux.org> to add a bunch of bloat to
|
||||
the sourcecode, change the interface and squash a few bugs.
|
||||
Mail him if you find new bugs.
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include "avl.h"
|
||||
|
||||
static void avl_rebalance(avl_tree_t *, avl_node_t *);
|
||||
|
||||
#ifdef AVL_COUNT
|
||||
#define NODE_COUNT(n) ((n) ? (n)->count : 0)
|
||||
#define L_COUNT(n) (NODE_COUNT((n)->left))
|
||||
#define R_COUNT(n) (NODE_COUNT((n)->right))
|
||||
#define CALC_COUNT(n) (L_COUNT(n) + R_COUNT(n) + 1)
|
||||
#endif
|
||||
|
||||
#ifdef AVL_DEPTH
|
||||
#define NODE_DEPTH(n) ((n) ? (n)->depth : 0)
|
||||
#define L_DEPTH(n) (NODE_DEPTH((n)->left))
|
||||
#define R_DEPTH(n) (NODE_DEPTH((n)->right))
|
||||
#define CALC_DEPTH(n) ((L_DEPTH(n)>R_DEPTH(n)?L_DEPTH(n):R_DEPTH(n)) + 1)
|
||||
#endif
|
||||
|
||||
#ifndef AVL_DEPTH
|
||||
/* Also known as ffs() (from BSD) */
|
||||
static int lg(unsigned int u) {
|
||||
int r = 1;
|
||||
if(!u) return 0;
|
||||
if(u & 0xffff0000) { u >>= 16; r += 16; }
|
||||
if(u & 0x0000ff00) { u >>= 8; r += 8; }
|
||||
if(u & 0x000000f0) { u >>= 4; r += 4; }
|
||||
if(u & 0x0000000c) { u >>= 2; r += 2; }
|
||||
if(u & 0x00000002) r++;
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int avl_check_balance(avl_node_t *avlnode) {
|
||||
#ifdef AVL_DEPTH
|
||||
int d;
|
||||
d = R_DEPTH(avlnode) - L_DEPTH(avlnode);
|
||||
return d<-1?-1:d>1?1:0;
|
||||
#else
|
||||
/* int d;
|
||||
* d = lg(R_COUNT(avlnode)) - lg(L_COUNT(avlnode));
|
||||
* d = d<-1?-1:d>1?1:0;
|
||||
*/
|
||||
#ifdef AVL_COUNT
|
||||
int pl, r;
|
||||
|
||||
pl = lg(L_COUNT(avlnode));
|
||||
r = R_COUNT(avlnode);
|
||||
|
||||
if(r>>pl+1)
|
||||
return 1;
|
||||
if(pl<2 || r>>pl-2)
|
||||
return 0;
|
||||
return -1;
|
||||
#else
|
||||
#error No balancing possible.
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef AVL_COUNT
|
||||
unsigned int avl_count(const avl_tree_t *avltree) {
|
||||
return NODE_COUNT(avltree->top);
|
||||
}
|
||||
|
||||
avl_node_t *avl_at(const avl_tree_t *avltree, unsigned int index) {
|
||||
avl_node_t *avlnode;
|
||||
unsigned int c;
|
||||
|
||||
avlnode = avltree->top;
|
||||
|
||||
while(avlnode) {
|
||||
c = L_COUNT(avlnode);
|
||||
|
||||
if(index < c) {
|
||||
avlnode = avlnode->left;
|
||||
} else if(index > c) {
|
||||
avlnode = avlnode->right;
|
||||
index -= c+1;
|
||||
} else {
|
||||
return avlnode;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned int avl_index(const avl_node_t *avlnode) {
|
||||
avl_node_t *next;
|
||||
unsigned int c;
|
||||
|
||||
c = L_COUNT(avlnode);
|
||||
|
||||
while((next = avlnode->parent)) {
|
||||
if(avlnode == next->right)
|
||||
c += L_COUNT(next) + 1;
|
||||
avlnode = next;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
#endif
|
||||
|
||||
int avl_search_closest(const avl_tree_t *avltree, const void *item, avl_node_t **avlnode) {
|
||||
avl_node_t *node;
|
||||
avl_compare_t cmp;
|
||||
int c;
|
||||
|
||||
if(!avlnode)
|
||||
avlnode = &node;
|
||||
|
||||
node = avltree->top;
|
||||
|
||||
if(!node)
|
||||
return *avlnode = NULL, 0;
|
||||
|
||||
cmp = avltree->cmp;
|
||||
|
||||
for(;;) {
|
||||
c = cmp(item, node->item);
|
||||
|
||||
if(c < 0) {
|
||||
if(node->left)
|
||||
node = node->left;
|
||||
else
|
||||
return *avlnode = node, -1;
|
||||
} else if(c > 0) {
|
||||
if(node->right)
|
||||
node = node->right;
|
||||
else
|
||||
return *avlnode = node, 1;
|
||||
} else {
|
||||
return *avlnode = node, 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* avl_search:
|
||||
* Return a pointer to a node with the given item in the tree.
|
||||
* If no such item is in the tree, then NULL is returned.
|
||||
*/
|
||||
avl_node_t *avl_search(const avl_tree_t *avltree, const void *item) {
|
||||
avl_node_t *node;
|
||||
return avl_search_closest(avltree, item, &node) ? NULL : node;
|
||||
}
|
||||
|
||||
avl_tree_t *avl_init_tree(avl_tree_t *rc, avl_compare_t cmp, avl_freeitem_t freeitem) {
|
||||
if(rc) {
|
||||
rc->head = NULL;
|
||||
rc->tail = NULL;
|
||||
rc->top = NULL;
|
||||
rc->cmp = cmp;
|
||||
rc->freeitem = freeitem;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
avl_tree_t *avl_alloc_tree(avl_compare_t cmp, avl_freeitem_t freeitem) {
|
||||
return avl_init_tree(malloc(sizeof(avl_tree_t)), cmp, freeitem);
|
||||
}
|
||||
|
||||
void avl_clear_tree(avl_tree_t *avltree) {
|
||||
avltree->top = avltree->head = avltree->tail = NULL;
|
||||
}
|
||||
|
||||
void avl_free_nodes(avl_tree_t *avltree) {
|
||||
avl_node_t *node, *next;
|
||||
avl_freeitem_t freeitem;
|
||||
|
||||
freeitem = avltree->freeitem;
|
||||
|
||||
for(node = avltree->head; node; node = next) {
|
||||
next = node->next;
|
||||
if(freeitem)
|
||||
freeitem(node->item);
|
||||
free(node);
|
||||
}
|
||||
|
||||
return avl_clear_tree(avltree);
|
||||
}
|
||||
|
||||
/*
|
||||
* avl_free_tree:
|
||||
* Free all memory used by this tree. If freeitem is not NULL, then
|
||||
* it is assumed to be a destructor for the items referenced in the avl_
|
||||
* tree, and they are deleted as well.
|
||||
*/
|
||||
void avl_free_tree(avl_tree_t *avltree) {
|
||||
avl_free_nodes(avltree);
|
||||
free(avltree);
|
||||
}
|
||||
|
||||
static void avl_clear_node(avl_node_t *newnode) {
|
||||
newnode->left = newnode->right = NULL;
|
||||
#ifdef AVL_COUNT
|
||||
newnode->count = 1;
|
||||
#endif
|
||||
#ifdef AVL_DEPTH
|
||||
newnode->depth = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
avl_node_t *avl_init_node(avl_node_t *newnode, void *item) {
|
||||
if(newnode) {
|
||||
/* avl_clear_node(newnode); */
|
||||
newnode->item = item;
|
||||
}
|
||||
return newnode;
|
||||
}
|
||||
|
||||
avl_node_t *avl_insert_top(avl_tree_t *avltree, avl_node_t *newnode) {
|
||||
avl_clear_node(newnode);
|
||||
newnode->prev = newnode->next = newnode->parent = NULL;
|
||||
avltree->head = avltree->tail = avltree->top = newnode;
|
||||
return newnode;
|
||||
}
|
||||
|
||||
avl_node_t *avl_insert_before(avl_tree_t *avltree, avl_node_t *node, avl_node_t *newnode) {
|
||||
if(!node)
|
||||
return avltree->tail
|
||||
? avl_insert_after(avltree, avltree->tail, newnode)
|
||||
: avl_insert_top(avltree, newnode);
|
||||
|
||||
if(node->left)
|
||||
return avl_insert_after(avltree, node->prev, newnode);
|
||||
|
||||
avl_clear_node(newnode);
|
||||
|
||||
newnode->next = node;
|
||||
newnode->parent = node;
|
||||
|
||||
newnode->prev = node->prev;
|
||||
if(node->prev)
|
||||
node->prev->next = newnode;
|
||||
else
|
||||
avltree->head = newnode;
|
||||
node->prev = newnode;
|
||||
|
||||
node->left = newnode;
|
||||
avl_rebalance(avltree, node);
|
||||
return newnode;
|
||||
}
|
||||
|
||||
avl_node_t *avl_insert_after(avl_tree_t *avltree, avl_node_t *node, avl_node_t *newnode) {
|
||||
if(!node)
|
||||
return avltree->head
|
||||
? avl_insert_before(avltree, avltree->head, newnode)
|
||||
: avl_insert_top(avltree, newnode);
|
||||
|
||||
if(node->right)
|
||||
return avl_insert_before(avltree, node->next, newnode);
|
||||
|
||||
avl_clear_node(newnode);
|
||||
|
||||
newnode->prev = node;
|
||||
newnode->parent = node;
|
||||
|
||||
newnode->next = node->next;
|
||||
if(node->next)
|
||||
node->next->prev = newnode;
|
||||
else
|
||||
avltree->tail = newnode;
|
||||
node->next = newnode;
|
||||
|
||||
node->right = newnode;
|
||||
avl_rebalance(avltree, node);
|
||||
return newnode;
|
||||
}
|
||||
|
||||
avl_node_t *avl_insert_node(avl_tree_t *avltree, avl_node_t *newnode) {
|
||||
avl_node_t *node;
|
||||
|
||||
if(!avltree->top)
|
||||
return avl_insert_top(avltree, newnode);
|
||||
|
||||
switch(avl_search_closest(avltree, newnode->item, &node)) {
|
||||
case -1:
|
||||
return avl_insert_before(avltree, node, newnode);
|
||||
case 1:
|
||||
return avl_insert_after(avltree, node, newnode);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* avl_insert:
|
||||
* Create a new node and insert an item there.
|
||||
* Returns the new node on success or NULL if no memory could be allocated.
|
||||
*/
|
||||
avl_node_t *avl_insert(avl_tree_t *avltree, void *item) {
|
||||
avl_node_t *newnode;
|
||||
|
||||
newnode = avl_init_node(malloc(sizeof(avl_node_t)), item);
|
||||
if(newnode) {
|
||||
if(avl_insert_node(avltree, newnode))
|
||||
return newnode;
|
||||
free(newnode);
|
||||
errno = EEXIST;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* avl_unlink_node:
|
||||
* Removes the given node. Does not delete the item at that node.
|
||||
* The item of the node may be freed before calling avl_unlink_node.
|
||||
* (In other words, it is not referenced by this function.)
|
||||
*/
|
||||
void avl_unlink_node(avl_tree_t *avltree, avl_node_t *avlnode) {
|
||||
avl_node_t *parent;
|
||||
avl_node_t **superparent;
|
||||
avl_node_t *subst, *left, *right;
|
||||
avl_node_t *balnode;
|
||||
|
||||
if(avlnode->prev)
|
||||
avlnode->prev->next = avlnode->next;
|
||||
else
|
||||
avltree->head = avlnode->next;
|
||||
|
||||
if(avlnode->next)
|
||||
avlnode->next->prev = avlnode->prev;
|
||||
else
|
||||
avltree->tail = avlnode->prev;
|
||||
|
||||
parent = avlnode->parent;
|
||||
|
||||
superparent = parent
|
||||
? avlnode == parent->left ? &parent->left : &parent->right
|
||||
: &avltree->top;
|
||||
|
||||
left = avlnode->left;
|
||||
right = avlnode->right;
|
||||
if(!left) {
|
||||
*superparent = right;
|
||||
if(right)
|
||||
right->parent = parent;
|
||||
balnode = parent;
|
||||
} else if(!right) {
|
||||
*superparent = left;
|
||||
left->parent = parent;
|
||||
balnode = parent;
|
||||
} else {
|
||||
subst = avlnode->prev;
|
||||
if(subst == left) {
|
||||
balnode = subst;
|
||||
} else {
|
||||
balnode = subst->parent;
|
||||
balnode->right = subst->left;
|
||||
if(balnode->right)
|
||||
balnode->right->parent = balnode;
|
||||
subst->left = left;
|
||||
left->parent = subst;
|
||||
}
|
||||
subst->right = right;
|
||||
subst->parent = parent;
|
||||
right->parent = subst;
|
||||
*superparent = subst;
|
||||
}
|
||||
|
||||
avl_rebalance(avltree, balnode);
|
||||
}
|
||||
|
||||
void *avl_delete_node(avl_tree_t *avltree, avl_node_t *avlnode) {
|
||||
void *item = NULL;
|
||||
if(avlnode) {
|
||||
item = avlnode->item;
|
||||
avl_unlink_node(avltree, avlnode);
|
||||
if(avltree->freeitem)
|
||||
avltree->freeitem(item);
|
||||
free(avlnode);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
void *avl_delete(avl_tree_t *avltree, const void *item) {
|
||||
return avl_delete_node(avltree, avl_search(avltree, item));
|
||||
}
|
||||
|
||||
avl_node_t *avl_fixup_node(avl_tree_t *avltree, avl_node_t *newnode) {
|
||||
avl_node_t *oldnode = NULL, *node;
|
||||
|
||||
if(!avltree || !newnode)
|
||||
return NULL;
|
||||
|
||||
node = newnode->prev;
|
||||
if(node) {
|
||||
oldnode = node->next;
|
||||
node->next = newnode;
|
||||
} else {
|
||||
avltree->head = newnode;
|
||||
}
|
||||
|
||||
node = newnode->next;
|
||||
if(node) {
|
||||
oldnode = node->prev;
|
||||
node->prev = newnode;
|
||||
} else {
|
||||
avltree->tail = newnode;
|
||||
}
|
||||
|
||||
node = newnode->parent;
|
||||
if(node) {
|
||||
if(node->left == oldnode)
|
||||
node->left = newnode;
|
||||
else
|
||||
node->right = newnode;
|
||||
} else {
|
||||
oldnode = avltree->top;
|
||||
avltree->top = newnode;
|
||||
}
|
||||
|
||||
return oldnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* avl_rebalance:
|
||||
* Rebalances the tree if one side becomes too heavy. This function
|
||||
* assumes that both subtrees are AVL-trees with consistant data. The
|
||||
* function has the additional side effect of recalculating the count of
|
||||
* the tree at this node. It should be noted that at the return of this
|
||||
* function, if a rebalance takes place, the top of this subtree is no
|
||||
* longer going to be the same node.
|
||||
*/
|
||||
void avl_rebalance(avl_tree_t *avltree, avl_node_t *avlnode) {
|
||||
avl_node_t *child;
|
||||
avl_node_t *gchild;
|
||||
avl_node_t *parent;
|
||||
avl_node_t **superparent;
|
||||
|
||||
parent = avlnode;
|
||||
|
||||
while(avlnode) {
|
||||
parent = avlnode->parent;
|
||||
|
||||
superparent = parent
|
||||
? avlnode == parent->left ? &parent->left : &parent->right
|
||||
: &avltree->top;
|
||||
|
||||
switch(avl_check_balance(avlnode)) {
|
||||
case -1:
|
||||
child = avlnode->left;
|
||||
#ifdef AVL_DEPTH
|
||||
if(L_DEPTH(child) >= R_DEPTH(child)) {
|
||||
#else
|
||||
#ifdef AVL_COUNT
|
||||
if(L_COUNT(child) >= R_COUNT(child)) {
|
||||
#else
|
||||
#error No balancing possible.
|
||||
#endif
|
||||
#endif
|
||||
avlnode->left = child->right;
|
||||
if(avlnode->left)
|
||||
avlnode->left->parent = avlnode;
|
||||
child->right = avlnode;
|
||||
avlnode->parent = child;
|
||||
*superparent = child;
|
||||
child->parent = parent;
|
||||
#ifdef AVL_COUNT
|
||||
avlnode->count = CALC_COUNT(avlnode);
|
||||
child->count = CALC_COUNT(child);
|
||||
#endif
|
||||
#ifdef AVL_DEPTH
|
||||
avlnode->depth = CALC_DEPTH(avlnode);
|
||||
child->depth = CALC_DEPTH(child);
|
||||
#endif
|
||||
} else {
|
||||
gchild = child->right;
|
||||
avlnode->left = gchild->right;
|
||||
if(avlnode->left)
|
||||
avlnode->left->parent = avlnode;
|
||||
child->right = gchild->left;
|
||||
if(child->right)
|
||||
child->right->parent = child;
|
||||
gchild->right = avlnode;
|
||||
if(gchild->right)
|
||||
gchild->right->parent = gchild;
|
||||
gchild->left = child;
|
||||
if(gchild->left)
|
||||
gchild->left->parent = gchild;
|
||||
*superparent = gchild;
|
||||
gchild->parent = parent;
|
||||
#ifdef AVL_COUNT
|
||||
avlnode->count = CALC_COUNT(avlnode);
|
||||
child->count = CALC_COUNT(child);
|
||||
gchild->count = CALC_COUNT(gchild);
|
||||
#endif
|
||||
#ifdef AVL_DEPTH
|
||||
avlnode->depth = CALC_DEPTH(avlnode);
|
||||
child->depth = CALC_DEPTH(child);
|
||||
gchild->depth = CALC_DEPTH(gchild);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
child = avlnode->right;
|
||||
#ifdef AVL_DEPTH
|
||||
if(R_DEPTH(child) >= L_DEPTH(child)) {
|
||||
#else
|
||||
#ifdef AVL_COUNT
|
||||
if(R_COUNT(child) >= L_COUNT(child)) {
|
||||
#else
|
||||
#error No balancing possible.
|
||||
#endif
|
||||
#endif
|
||||
avlnode->right = child->left;
|
||||
if(avlnode->right)
|
||||
avlnode->right->parent = avlnode;
|
||||
child->left = avlnode;
|
||||
avlnode->parent = child;
|
||||
*superparent = child;
|
||||
child->parent = parent;
|
||||
#ifdef AVL_COUNT
|
||||
avlnode->count = CALC_COUNT(avlnode);
|
||||
child->count = CALC_COUNT(child);
|
||||
#endif
|
||||
#ifdef AVL_DEPTH
|
||||
avlnode->depth = CALC_DEPTH(avlnode);
|
||||
child->depth = CALC_DEPTH(child);
|
||||
#endif
|
||||
} else {
|
||||
gchild = child->left;
|
||||
avlnode->right = gchild->left;
|
||||
if(avlnode->right)
|
||||
avlnode->right->parent = avlnode;
|
||||
child->left = gchild->right;
|
||||
if(child->left)
|
||||
child->left->parent = child;
|
||||
gchild->left = avlnode;
|
||||
if(gchild->left)
|
||||
gchild->left->parent = gchild;
|
||||
gchild->right = child;
|
||||
if(gchild->right)
|
||||
gchild->right->parent = gchild;
|
||||
*superparent = gchild;
|
||||
gchild->parent = parent;
|
||||
#ifdef AVL_COUNT
|
||||
avlnode->count = CALC_COUNT(avlnode);
|
||||
child->count = CALC_COUNT(child);
|
||||
gchild->count = CALC_COUNT(gchild);
|
||||
#endif
|
||||
#ifdef AVL_DEPTH
|
||||
avlnode->depth = CALC_DEPTH(avlnode);
|
||||
child->depth = CALC_DEPTH(child);
|
||||
gchild->depth = CALC_DEPTH(gchild);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
default:
|
||||
#ifdef AVL_COUNT
|
||||
avlnode->count = CALC_COUNT(avlnode);
|
||||
#endif
|
||||
#ifdef AVL_DEPTH
|
||||
avlnode->depth = CALC_DEPTH(avlnode);
|
||||
#endif
|
||||
}
|
||||
avlnode = parent;
|
||||
}
|
||||
}
|
186
src/avl/avl.h
Normal file
186
src/avl/avl.h
Normal file
@ -0,0 +1,186 @@
|
||||
/*****************************************************************************
|
||||
|
||||
avl.h - Source code for the AVL-tree library.
|
||||
|
||||
Copyright (C) 1998 Michael H. Buselli <cosine@cosine.org>
|
||||
Copyright (C) 2000-2002 Wessel Dankers <wsl@nl.linux.org>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Augmented AVL-tree. Original by Michael H. Buselli <cosine@cosine.org>.
|
||||
|
||||
Modified by Wessel Dankers <wsl@nl.linux.org> to add a bunch of bloat to
|
||||
the sourcecode, change the interface and squash a few bugs.
|
||||
Mail him if you find new bugs.
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef _AVL_H
|
||||
#define _AVL_H
|
||||
|
||||
/* We need either depths, counts or both (the latter being the default) */
|
||||
#if !defined(AVL_DEPTH) && !defined(AVL_COUNT)
|
||||
#define AVL_DEPTH
|
||||
#define AVL_COUNT
|
||||
#endif
|
||||
|
||||
/* User supplied function to compare two items like strcmp() does.
|
||||
* For example: cmp(a,b) will return:
|
||||
* -1 if a < b
|
||||
* 0 if a = b
|
||||
* 1 if a > b
|
||||
*/
|
||||
typedef int (*avl_compare_t)(const void *, const void *);
|
||||
|
||||
/* User supplied function to delete an item when a node is free()d.
|
||||
* If NULL, the item is not free()d.
|
||||
*/
|
||||
typedef void (*avl_freeitem_t)(void *);
|
||||
|
||||
typedef struct avl_node_t {
|
||||
struct avl_node_t *next;
|
||||
struct avl_node_t *prev;
|
||||
struct avl_node_t *parent;
|
||||
struct avl_node_t *left;
|
||||
struct avl_node_t *right;
|
||||
void *item;
|
||||
#ifdef AVL_COUNT
|
||||
unsigned int count;
|
||||
#endif
|
||||
#ifdef AVL_DEPTH
|
||||
unsigned char depth;
|
||||
#endif
|
||||
} avl_node_t;
|
||||
|
||||
typedef struct avl_tree_t {
|
||||
avl_node_t *head;
|
||||
avl_node_t *tail;
|
||||
avl_node_t *top;
|
||||
avl_compare_t cmp;
|
||||
avl_freeitem_t freeitem;
|
||||
} avl_tree_t;
|
||||
|
||||
/* Initializes a new tree for elements that will be ordered using
|
||||
* the supplied strcmp()-like function.
|
||||
* Returns the value of avltree (even if it's NULL).
|
||||
* O(1) */
|
||||
extern avl_tree_t *avl_init_tree(avl_tree_t *avltree, avl_compare_t, avl_freeitem_t);
|
||||
|
||||
/* Allocates and initializes a new tree for elements that will be
|
||||
* ordered using the supplied strcmp()-like function.
|
||||
* Returns NULL if memory could not be allocated.
|
||||
* O(1) */
|
||||
extern avl_tree_t *avl_alloc_tree(avl_compare_t, avl_freeitem_t);
|
||||
|
||||
/* Frees the entire tree efficiently. Nodes will be free()d.
|
||||
* If the tree's freeitem is not NULL it will be invoked on every item.
|
||||
* O(n) */
|
||||
extern void avl_free_tree(avl_tree_t *);
|
||||
|
||||
/* Reinitializes the tree structure for reuse. Nothing is free()d.
|
||||
* Compare and freeitem functions are left alone.
|
||||
* O(1) */
|
||||
extern void avl_clear_tree(avl_tree_t *);
|
||||
|
||||
/* Free()s all nodes in the tree but leaves the tree itself.
|
||||
* If the tree's freeitem is not NULL it will be invoked on every item.
|
||||
* O(n) */
|
||||
extern void avl_free_nodes(avl_tree_t *);
|
||||
|
||||
/* Initializes memory for use as a node. Returns NULL if avlnode is NULL.
|
||||
* O(1) */
|
||||
extern avl_node_t *avl_init_node(avl_node_t *avlnode, void *item);
|
||||
|
||||
/* Insert an item into the tree and return the new node.
|
||||
* Returns NULL and sets errno if memory for the new node could not be
|
||||
* allocated or if the node is already in the tree (EEXIST).
|
||||
* O(lg n) */
|
||||
extern avl_node_t *avl_insert(avl_tree_t *, void *item);
|
||||
|
||||
/* Insert a node into the tree and return it.
|
||||
* Returns NULL if the node is already in the tree.
|
||||
* O(lg n) */
|
||||
extern avl_node_t *avl_insert_node(avl_tree_t *, avl_node_t *);
|
||||
|
||||
/* Insert a node in an empty tree. If avlnode is NULL, the tree will be
|
||||
* cleared and ready for re-use.
|
||||
* If the tree is not empty, the old nodes are left dangling.
|
||||
* O(1) */
|
||||
extern avl_node_t *avl_insert_top(avl_tree_t *, avl_node_t *avlnode);
|
||||
|
||||
/* Insert a node before another node. Returns the new node.
|
||||
* If old is NULL, the item is appended to the tree.
|
||||
* O(lg n) */
|
||||
extern avl_node_t *avl_insert_before(avl_tree_t *, avl_node_t *old, avl_node_t *new);
|
||||
|
||||
/* Insert a node after another node. Returns the new node.
|
||||
* If old is NULL, the item is prepended to the tree.
|
||||
* O(lg n) */
|
||||
extern avl_node_t *avl_insert_after(avl_tree_t *, avl_node_t *old, avl_node_t *new);
|
||||
|
||||
/* Deletes a node from the tree. Returns immediately if the node is NULL.
|
||||
* The item will not be free()d regardless of the tree's freeitem handler.
|
||||
* This function comes in handy if you need to update the search key.
|
||||
* O(lg n) */
|
||||
extern void avl_unlink_node(avl_tree_t *, avl_node_t *);
|
||||
|
||||
/* Deletes a node from the tree. Returns immediately if the node is NULL.
|
||||
* If the tree's freeitem is not NULL, it is invoked on the item.
|
||||
* If it is, returns the item.
|
||||
* O(lg n) */
|
||||
extern void *avl_delete_node(avl_tree_t *, avl_node_t *);
|
||||
|
||||
/* Searches for an item in the tree and deletes it if found.
|
||||
* If the tree's freeitem is not NULL, it is invoked on the item.
|
||||
* If it is, returns the item.
|
||||
* O(lg n) */
|
||||
extern void *avl_delete(avl_tree_t *, const void *item);
|
||||
|
||||
/* If exactly one node is moved in memory, this will fix the pointers
|
||||
* in the tree that refer to it. It must be an exact shallow copy.
|
||||
* Returns the pointer to the old position.
|
||||
* O(1) */
|
||||
extern avl_node_t *avl_fixup_node(avl_tree_t *, avl_node_t *new);
|
||||
|
||||
/* Searches for a node with the key closest (or equal) to the given item.
|
||||
* If avlnode is not NULL, *avlnode will be set to the node found or NULL
|
||||
* if the tree is empty. Return values:
|
||||
* -1 if the returned node is smaller
|
||||
* 0 if the returned node is equal or if the tree is empty
|
||||
* 1 if the returned node is greater
|
||||
* O(lg n) */
|
||||
extern int avl_search_closest(const avl_tree_t *, const void *item, avl_node_t **avlnode);
|
||||
|
||||
/* Searches for the item in the tree and returns a matching node if found
|
||||
* or NULL if not.
|
||||
* O(lg n) */
|
||||
extern avl_node_t *avl_search(const avl_tree_t *, const void *item);
|
||||
|
||||
#ifdef AVL_COUNT
|
||||
/* Returns the number of nodes in the tree.
|
||||
* O(1) */
|
||||
extern unsigned int avl_count(const avl_tree_t *);
|
||||
|
||||
/* Searches a node by its rank in the list. Counting starts at 0.
|
||||
* Returns NULL if the index exceeds the number of nodes in the tree.
|
||||
* O(lg n) */
|
||||
extern avl_node_t *avl_at(const avl_tree_t *, unsigned int);
|
||||
|
||||
/* Returns the rank of a node in the list. Counting starts at 0.
|
||||
* O(lg n) */
|
||||
extern unsigned int avl_index(const avl_node_t *);
|
||||
#endif
|
||||
|
||||
#endif
|
@ -34,7 +34,6 @@
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <avl.h>
|
||||
#include <plist/plist.h>
|
||||
|
||||
#ifdef HAVE_LIBEVENT2
|
||||
@ -43,6 +42,7 @@
|
||||
# include "evhttp/evhttp.h"
|
||||
#endif
|
||||
|
||||
#include "avl/avl.h"
|
||||
#include "logger.h"
|
||||
#include "db.h"
|
||||
#include "filescanner.h"
|
||||
|
@ -40,8 +40,7 @@
|
||||
#include <uninorm.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <avl.h>
|
||||
|
||||
#include "avl/avl.h"
|
||||
#include "logger.h"
|
||||
#include "db.h"
|
||||
#include "conffile.h"
|
||||
|
Loading…
Reference in New Issue
Block a user