[Xfce4-commits] <squeeze:master> Merge branch 'peter/btree' into merge
Peter de Ridder
noreply at xfce.org
Thu Dec 22 23:00:08 CET 2011
Updating branch refs/heads/master
to e012291673d37405022b2f8505d1f83463fe028c (commit)
from ce6ae3e773c0636b3f996f96d4a659e2f040a576 (commit)
commit e012291673d37405022b2f8505d1f83463fe028c
Merge: ce6ae3e 1b7de7a
Author: Peter de Ridder <peter at xfce.org>
Date: Tue Dec 20 14:13:30 2011 +0100
Merge branch 'peter/btree' into merge
commit 1b7de7a745e0ac8823f31cbc4fac3af52da0cde7
Author: Peter de Ridder <peter at xfce.org>
Date: Tue Oct 11 20:43:08 2011 +0200
Balance btree only if it helps in depth
commit 2f2c6178e58c4e3eb4e9a0bbaf39239fdd266fd8
Author: Peter de Ridder <peter at xfce.org>
Date: Sun Oct 9 20:21:03 2011 +0200
Optionally balance btree after remove
commit 1f04b35581219671f11601e0b057f0b26a636769
Author: Peter de Ridder <peter at xfce.org>
Date: Sun Oct 9 16:47:12 2011 +0200
Start supporting delete from the btree
commit f3472d91253a3016d68e2941b128a0d96f52ae00
Author: Peter de Ridder <peter at xfce.org>
Date: Tue Oct 4 21:42:13 2011 +0200
Balance the btree
btree delete isn't supported
commit d3cc31e6fb872e00eaad4291746c551435eea1c2
Author: Peter de Ridder <peter at xfce.org>
Date: Sun Oct 2 12:09:39 2011 +0200
Replaced archive iter buffer slist with a btree
The btree isn't balanced and delete isn't supported
libsqueeze/Makefile.am | 2 +-
libsqueeze/archive-iter.c | 161 ++++-------
libsqueeze/archive.c | 6 +-
libsqueeze/btree.c | 646 +++++++++++++++++++++++++++++++++++++++
libsqueeze/{slist.h => btree.h} | 50 ++--
libsqueeze/slist.c | 109 -------
6 files changed, 727 insertions(+), 247 deletions(-)
diff --git a/libsqueeze/Makefile.am b/libsqueeze/Makefile.am
index 51cc350..b7beadb 100644
--- a/libsqueeze/Makefile.am
+++ b/libsqueeze/Makefile.am
@@ -5,6 +5,7 @@ libsqueeze_2_la_SOURCES = \
archive-iter-pool.c archive-iter-pool.h \
archive-iter.c archive-iter.h \
archive-tempfs.c archive-tempfs.h \
+ btree.c btree.h \
command-queue.c command-queue.h \
command-option.c command-option.h \
internals.c internals.h \
@@ -13,7 +14,6 @@ libsqueeze_2_la_SOURCES = \
parser-context.c parser-context.h \
parser.c parser.h \
scanf-parser.c scanf-parser.h \
- slist.c slist.h \
support-reader.c support-reader.h \
support-template.c support-template.h \
support-factory.c support-factory.h
diff --git a/libsqueeze/archive-iter.c b/libsqueeze/archive-iter.c
index 6288535..0c3b5f4 100644
--- a/libsqueeze/archive-iter.c
+++ b/libsqueeze/archive-iter.c
@@ -13,7 +13,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-
#include <config.h>
#include <string.h>
#include <glib.h>
@@ -25,12 +24,12 @@
#include "libsqueeze.h"
#include "libsqueeze-view.h"
#include "support-factory.h"
-#include "slist.h"
+#include "btree.h"
#include "internals.h"
#ifndef LSQ_ENTRY_CHILD_BUFFER_SIZE
-#define LSQ_ENTRY_CHILD_BUFFER_SIZE 500
+#define LSQ_ENTRY_CHILD_BUFFER_SIZE 8000
#endif
#ifdef LSQ_ENTRY_CHILD_BUFFER_DYNAMIC_SIZE
@@ -39,10 +38,6 @@ guint buffer_flush_size = LSQ_ENTRY_CHILD_BUFFER_SIZE;
#define LSQ_ENTRY_CHILD_BUFFER_SIZE buffer_flush_size
#endif
-#ifndef LSQ_ENTRY_BUFFER_INTERVALSIZE
-#define LSQ_ENTRY_BUFFER_INTERVALSIZE 20
-#endif
-
#ifndef LSQ_MIME_DIRECTORY
#define LSQ_MIME_DIRECTORY "inode/directory"
#endif
@@ -69,8 +64,6 @@ inline static LSQArchiveEntry*
lsq_archive_entry_nth_child(const LSQArchiveEntry *, guint);
inline static void
lsq_archive_entry_flush_buffer(LSQArchiveEntry *);
-inline static void
-lsq_archive_entry_build_buffer_index(LSQArchiveEntry *);
static LSQArchiveEntry *
lsq_archive_entry_get_child(const LSQArchiveEntry *, const gchar *);
static LSQArchiveEntry *
@@ -102,8 +95,8 @@ struct _LSQArchiveEntry
gchar *content_type;
gpointer props;
LSQArchiveEntry **children;
- LSQSList *buffer;
- LSQSIndexList *buffer_index;
+ LSQBTree *buffer;
+ guint buffer_length;
};
@@ -989,7 +982,10 @@ static void
lsq_archive_entry_save_free(const LSQArchive *archive, LSQArchiveEntry *entry)
{
guint i = 0;
- LSQSList *buffer_iter = entry->buffer;
+ LSQBTree *buffer_iter;
+
+ entry->buffer = lsq_btree_flatten(entry->buffer);
+ buffer_iter = entry->buffer;
/* free the buffer */
for ( ; NULL != buffer_iter ; buffer_iter = buffer_iter->next )
@@ -999,8 +995,9 @@ lsq_archive_entry_save_free(const LSQArchive *archive, LSQArchiveEntry *entry)
else
lsq_archive_entry_save_free(archive, buffer_iter->entry);
}
- lsq_slist_free(entry->buffer);
+ lsq_btree_free(entry->buffer);
entry->buffer = NULL;
+ entry->buffer_length = 0;
/* free the sorted list */
if ( NULL != entry->children )
@@ -1026,15 +1023,19 @@ static void
lsq_archive_entry_free(const LSQArchive *archive, LSQArchiveEntry *entry)
{
guint i = 0;
- LSQSList *buffer_iter = entry->buffer;
+ LSQBTree *buffer_iter;
+
+ entry->buffer = lsq_btree_flatten(entry->buffer);
+ buffer_iter = entry->buffer;
/* free the buffer */
for ( ; NULL != buffer_iter; buffer_iter = buffer_iter->next )
{
lsq_archive_entry_free(archive, buffer_iter->entry);
}
- lsq_slist_free(entry->buffer);
+ lsq_btree_free(entry->buffer);
entry->buffer = NULL;
+ entry->buffer_length = 0;
/* free the sorted list */
if ( NULL != entry->children )
@@ -1078,7 +1079,7 @@ inline static guint
lsq_archive_entry_n_children(const LSQArchiveEntry *entry)
{
/* the first element of the array (*entry->children) contains the size of the array */
- return ((entry->children?GPOINTER_TO_UINT(*entry->children):0) + lsq_slist_length(entry->buffer));
+ return ((entry->children?GPOINTER_TO_UINT(*entry->children):0) + lsq_btree_length(entry->buffer));
}
inline static LSQArchiveEntry*
@@ -1099,7 +1100,7 @@ lsq_archive_entry_flush_buffer(LSQArchiveEntry *entry)
guint new_i = 1;
guint size;
guint n_children;
- LSQSList *buffer_iter = NULL;
+ LSQBTree *buffer_iter = NULL;
LSQArchiveEntry **children_old;
if ( NULL == entry->buffer )
@@ -1107,12 +1108,17 @@ lsq_archive_entry_flush_buffer(LSQArchiveEntry *entry)
return;
}
+ //lsq_btree_print(entry->buffer);
+
+ /* Flatten the btree so we can iterate */
+ entry->buffer = lsq_btree_flatten(entry->buffer);
+
/* the first element of the array (*entry->children) contains the size of the array */
size = entry->children?GPOINTER_TO_UINT(*entry->children):0;
n_children = size;
children_old = (LSQArchiveEntry **)entry->children;
- max_children = (n_children + lsq_slist_length(entry->buffer));
+ max_children = (n_children + lsq_btree_length(entry->buffer));
/* do all elements of the buffer */
entry->children = g_new(LSQArchiveEntry *, max_children+1);
@@ -1164,44 +1170,17 @@ lsq_archive_entry_flush_buffer(LSQArchiveEntry *entry)
*entry->children = GUINT_TO_POINTER(n_children);
/* free the buffer */
- lsq_slist_free(entry->buffer);
+ lsq_btree_free(entry->buffer);
entry->buffer = NULL;
- lsq_slist_index_free(entry->buffer_index);
- entry->buffer_index = NULL;
+ entry->buffer_length = 0;
g_free(children_old);
}
-inline static void
-lsq_archive_entry_build_buffer_index(LSQArchiveEntry *entry)
-{
- guint i = 0;
- LSQSList *buffer_iter = NULL;
- LSQSIndexList **index_iter = &entry->buffer_index;
- for ( buffer_iter = entry->buffer ; NULL != buffer_iter ; buffer_iter = buffer_iter->next )
- {
- ++i;
- if ( 0 == ( i % LSQ_ENTRY_BUFFER_INTERVALSIZE ) )
- {
- if ( NULL == *index_iter )
- {
- *index_iter = lsq_slist_index_new();
- }
-
- (*index_iter)->index = buffer_iter;
-
- index_iter = &((*index_iter)->next);
- }
- }
- lsq_slist_index_free(*index_iter);
- *index_iter = NULL;
-}
-
static LSQArchiveEntry *
lsq_archive_entry_get_child(const LSQArchiveEntry *entry, const gchar *filename)
{
- LSQSList *entry_buffer, *buffer_iter = NULL;
- LSQSIndexList *index_iter = NULL;
+ LSQBTree *buffer_iter = NULL;
/* the first element of the array (*entry->children) contains the size of the array */
guint size = entry->children?GPOINTER_TO_UINT(*entry->children):0;
guint pos = 0;
@@ -1240,37 +1219,25 @@ lsq_archive_entry_get_child(const LSQArchiveEntry *entry, const gchar *filename)
}
}
- /* find a start index into the buffer */
- entry_buffer = entry->buffer;
- for ( index_iter = entry->buffer_index; NULL != index_iter; index_iter = index_iter->next )
- {
- cmp = strcmp(filename, index_iter->index->entry->filename);
-
- if ( 0 == cmp )
- {
- g_free(_filename);
- return index_iter->index->entry;
- }
- if ( 0 > cmp )
- {
- break;
- }
- entry_buffer = index_iter->index;
- }
-
/* search the buffer */
- for ( buffer_iter = entry_buffer; NULL != buffer_iter; buffer_iter = buffer_iter->next )
+ buffer_iter = entry->buffer;
+ while ( NULL != buffer_iter )
{
+ /* archive can be NULL */
cmp = strcmp(filename, buffer_iter->entry->filename);
- if ( 0 == cmp )
+ if ( cmp < 0 )
{
- g_free(_filename);
- return buffer_iter->entry;
+ buffer_iter = buffer_iter->left;
}
- if ( 0 > cmp )
+ else if ( cmp > 0 )
{
- break;
+ buffer_iter = buffer_iter->right;
+ }
+ else
+ {
+ g_free(_filename);
+ return buffer_iter->entry;
}
}
@@ -1279,7 +1246,7 @@ lsq_archive_entry_get_child(const LSQArchiveEntry *entry, const gchar *filename)
}
static gint
-lsq_archive_entry_filename_compare(LSQArchiveEntry *a, LSQArchiveEntry *b)
+lsq_archive_entry_compare(LSQArchiveEntry *a, LSQArchiveEntry *b)
{
return strcmp(a->filename, b->filename);
}
@@ -1289,7 +1256,6 @@ lsq_archive_entry_add_child(LSQArchiveEntry *parent, const gchar *filename)
{
LSQArchiveEntry *child = lsq_archive_entry_new(filename);
const gchar *contenttype = lsq_archive_entry_get_contenttype(parent);
- guint length;
if ( ( NULL == contenttype ) || ( 0 != strcmp ( contenttype, LSQ_MIME_DIRECTORY ) ) )
{
@@ -1300,28 +1266,29 @@ lsq_archive_entry_add_child(LSQArchiveEntry *parent, const gchar *filename)
*/
}
- parent->buffer = lsq_slist_insert_sorted_single(parent->buffer, child, (GCompareFunc)lsq_archive_entry_filename_compare);
+ //g_debug("i: %s", filename);
+ parent->buffer = lsq_btree_insert_sorted_single(parent->buffer, child, (GCompareFunc)lsq_archive_entry_compare);
- /* TODO: cache the length so we doen't have to check every time? */
- length = lsq_slist_length(parent->buffer);
+ /* Cache the length so we doen't have to check every time */
+ parent->buffer_length++;
- if ( LSQ_ENTRY_CHILD_BUFFER_SIZE == length )
+ if ( LSQ_ENTRY_CHILD_BUFFER_SIZE == parent->buffer_length )
{
lsq_archive_entry_flush_buffer(parent);
}
- else if ( 0 == ( length % LSQ_ENTRY_BUFFER_INTERVALSIZE ) )
- {
- lsq_archive_entry_build_buffer_index(parent);
- }
return child;
}
+static gint
+lsq_archive_entry_filename_compare(const gchar *a_filename, LSQArchiveEntry *b)
+{
+ return strcmp(a_filename, b->filename);
+}
+
static gboolean
lsq_archive_entry_remove_child(LSQArchiveEntry *entry, const gchar *filename)
{
- LSQSList *buffer_iter = NULL, *prev_iter = NULL;
-
/* the first element of the array (*entry->children) contains the size of the array */
guint total_size, size = total_size = entry->children?GPOINTER_TO_UINT(*entry->children):0;
guint pos = 0;
@@ -1329,6 +1296,7 @@ lsq_archive_entry_remove_child(LSQArchiveEntry *entry, const gchar *filename)
gint cmp = 0;
const gchar *_pos = strchr(filename, '/');
gchar *_filename;
+ LSQArchiveEntry *found = NULL;
if ( 0 != _pos )
{
@@ -1370,31 +1338,10 @@ lsq_archive_entry_remove_child(LSQArchiveEntry *entry, const gchar *filename)
}
/* search the buffer */
- for(buffer_iter = entry->buffer; buffer_iter; buffer_iter = buffer_iter->next)
- {
- cmp = strcmp(_filename, buffer_iter->entry->filename);
-
- if ( 0 == cmp )
- {
- g_free(_filename);
- if ( NULL != prev_iter )
- {
- prev_iter->next = buffer_iter->next;
- }
- else
- {
- entry->buffer = buffer_iter->next;
- }
- g_free(buffer_iter);
- return TRUE;
- }
- if(cmp < 0)
- break;
- prev_iter = buffer_iter;
- }
+ entry->buffer = lsq_btree_remove_sorted_single(entry->buffer, _filename, (GCompareFunc)lsq_archive_entry_filename_compare, &found);
g_free(_filename);
- return FALSE;
+ return NULL != found;
}
inline static const gchar*
diff --git a/libsqueeze/archive.c b/libsqueeze/archive.c
index a2dcd7e..fdac9f4 100644
--- a/libsqueeze/archive.c
+++ b/libsqueeze/archive.c
@@ -31,16 +31,12 @@
#include "support-template.h"
#include "support-factory.h"
-#include "slist.h"
+#include "btree.h"
#include "archive-tempfs.h"
#include "command-queue.h"
#include "internals.h"
-#ifndef LSQ_ENTRY_CHILD_BUFFER_SIZE
-#define LSQ_ENTRY_CHILD_BUFFER_SIZE 500
-#endif
-
static void
lsq_archive_class_init(LSQArchiveClass *archive_class);
diff --git a/libsqueeze/btree.c b/libsqueeze/btree.c
new file mode 100644
index 0000000..5d98f0e
--- /dev/null
+++ b/libsqueeze/btree.c
@@ -0,0 +1,646 @@
+/*
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <string.h>
+#include <glib.h>
+#include <glib-object.h>
+#include <gio/gio.h>
+
+#include <libxfce4util/libxfce4util.h>
+
+#include "libsqueeze.h"
+#include "support-factory.h"
+#include "internals.h"
+#include "btree.h"
+
+#ifndef LSQ_BTREE_MAX_DEPTH
+#define LSQ_BTREE_MAX_DEPTH 20
+#endif
+
+LSQBTree *
+lsq_btree_insert_sorted_single (
+ LSQBTree *list,
+ LSQArchiveEntry *entry,
+ GCompareFunc cmp_func )
+{
+ gint cmp;
+ LSQBTree *iter;
+ LSQBTree **next = NULL;
+ LSQBTree *new_entry = NULL;
+ LSQBTree *stack[LSQ_BTREE_MAX_DEPTH];
+ guint stack_i = 0;
+ LSQArchiveEntry *swap_entry;
+ LSQBTree *swap_iter;
+ gint swap_balance;
+ gboolean short_side;
+
+ /* Check for a flat list */
+ if ( NULL != list && NULL != list->next )
+ {
+ g_critical("Cannot insert into a flattened tree");
+ return NULL;
+ }
+
+ /* Walk the btree */
+ for ( iter = list; NULL != iter; iter = *next )
+ {
+ /* archive can be NULL */
+ cmp = cmp_func( entry, iter->entry );
+
+ if ( 0 > cmp )
+ {
+ /* Go the the left */
+ next = &iter->left;
+ }
+ else if ( 0 < cmp )
+ {
+ /* Go to the right */
+ next = &iter->right;
+ }
+ else
+ {
+ /* Logic outside this routine dictates we should never find a match */
+ g_critical("THIS SHOULD NOT HAPPEN!!! (the universe has just collapsed)");
+ return NULL;
+ }
+
+ /* Keep a stack of the path we followed */
+ g_return_val_if_fail(stack_i < LSQ_BTREE_MAX_DEPTH, NULL);
+ stack[stack_i++] = iter;
+ }
+
+ /* Create a new tree element */
+ new_entry = g_new0(LSQBTree, 1);
+ new_entry->entry = entry;
+
+ /* Check it this is a new tree */
+ if ( NULL == next )
+ {
+ return new_entry;
+ }
+
+ /* Store ourself in the parent */
+ *next = new_entry;
+
+ /* Balance the tree */
+ while ( 0 < stack_i )
+ {
+ iter = stack[--stack_i];
+
+ /* Calculate new the balance for the parent */
+ if ( iter->left == new_entry )
+ {
+ short_side = iter->balance > 0;
+ --iter->balance;
+ }
+ else
+ {
+ short_side = iter->balance < 0;
+ ++iter->balance;
+ }
+
+ /* The balance in the higher parents doesn't change when the short side changed */
+ if ( FALSE != short_side )
+ {
+ break;
+ }
+
+ if ( 1 < iter->balance )
+ {
+ /* Rotate left */
+ /* The code could be easier if we would just overwrite our parent left or right value.
+ * But instead we move that data from our right to our self and use the right tree link to be placed in the tree as if it was ourself.
+ */
+ /* Letters are tree nodes, numbers are the data. This illustrates a rotate right.
+ *
+ * A:4 | A:2
+ * / \ | / \
+ * B:2 C:5 | D:1 B:4
+ * / \ | / \
+ * D:1 E:3 | E:3 C:5
+ */
+ swap_iter = iter->right;
+ swap_balance = swap_iter->balance;
+ /* Only balance if it helps */
+ if ( 0 < swap_balance )
+ {
+ /* Swap the data */
+ swap_entry = iter->entry;
+ iter->entry = swap_iter->entry;
+ swap_iter->entry = swap_entry;
+
+ /* Reformat the tree links */
+ iter->right = swap_iter->right;
+ swap_iter->right = swap_iter->left;
+ swap_iter->left = iter->left;
+ iter->left = swap_iter;
+
+ /* Fix the balance values
+ *
+ * if B > 0
+ * A = A - 1 - B
+ * else
+ * A = A - 1
+ *
+ * diff = A - 1 - B
+ * if diff < 0
+ * B = B - 1 + diff
+ * else
+ * B = B - 1
+ */
+ swap_iter->balance = iter->balance - 1;
+ if ( 0 < swap_balance )
+ {
+ swap_iter->balance -= swap_balance;
+ }
+ iter->balance = iter->balance - 1 - swap_balance;
+ if ( 0 < iter->balance )
+ {
+ iter->balance = 0;
+ }
+ iter->balance += swap_balance - 1;
+
+ /* We added a child so our depth was increased, but we also saved depth by rotation so our parents depth stays the same */
+ break;
+ }
+ }
+ else if ( -1 > iter->balance )
+ {
+ /* Rotate right */
+ /* The code could be easier if we would just overwrite our parent left or right value.
+ * But instead we move that data from our left to our self and use the left tree link to be placed in the tree as if it was ourself.
+ */
+ swap_iter = iter->left;
+ swap_balance = swap_iter->balance;
+ /* Only balance if it helps */
+ if ( 0 > swap_balance )
+ {
+ /* Swap the data */
+ swap_entry = iter->entry;
+ iter->entry = swap_iter->entry;
+ swap_iter->entry = swap_entry;
+
+ /* Reformat the tree links */
+ iter->left = swap_iter->left;
+ swap_iter->left = swap_iter->right;
+ swap_iter->right = iter->right;
+ iter->right = swap_iter;
+
+ /* Fix the balance values
+ *
+ * if B < 0
+ * A = A + 1 - B
+ * else
+ * A = A + 1
+ *
+ * diff = A + 1 - B
+ * if diff > 0
+ * B = B + 1 + diff
+ * else
+ * B = B + 1
+ */
+ swap_iter->balance = iter->balance + 1;
+ if ( 0 > swap_balance )
+ {
+ swap_iter->balance -= swap_balance;
+ }
+ iter->balance = iter->balance + 1 - swap_balance;
+ if ( 0 > iter->balance )
+ {
+ iter->balance = 0;
+ }
+ iter->balance += swap_balance + 1;
+
+ /* We added a child so our depth was increased, but we also saved depth by rotation so our parents depth stays the same */
+ break;
+ }
+ }
+
+ /* Store ourself in new_entry for the check in the next parent */
+ new_entry = iter;
+ }
+
+ return list;
+}
+
+LSQBTree *
+lsq_btree_remove_sorted_single (
+ LSQBTree *list,
+ gchar *filename,
+ GCompareFunc cmp_func,
+ LSQArchiveEntry **found )
+{
+ gint cmp;
+ LSQBTree *iter;
+ LSQBTree **next = &list;
+ LSQBTree *del_entry;
+ LSQBTree *stack[LSQ_BTREE_MAX_DEPTH];
+ guint stack_i = 0;
+ gboolean short_side;
+ LSQBTree *swap_iter;
+#ifdef BALANCE_ON_REMOVE
+ LSQArchiveEntry *swap_entry;
+ gint swap_balance;
+#endif
+
+ if ( NULL != found )
+ {
+ *found = NULL;
+ }
+
+ /* The tree is flattened */
+ if ( NULL == list || NULL != list->next )
+ {
+ for ( iter = list; NULL != iter; iter = iter->next)
+ {
+ cmp = cmp_func( filename, iter->entry );
+
+ if ( 0 == cmp )
+ {
+ if ( NULL != found )
+ {
+ *found = iter->entry;
+ }
+
+ /* remove it */
+ *next = iter->next;
+ g_free ( iter );
+ return list;
+ }
+ else if ( 0 > cmp )
+ {
+ return list;
+ }
+
+ next = &iter->next;
+ }
+ }
+ else
+ {
+ /* Walk the btree */
+ for ( iter = list; NULL != iter; iter = *next )
+ {
+ /* archive can be NULL */
+ cmp = cmp_func( filename, iter->entry );
+
+ if ( 0 > cmp )
+ {
+ /* Go the the left */
+ next = &iter->left;
+ }
+ else if ( 0 < cmp )
+ {
+ /* Go to the right */
+ next = &iter->right;
+ }
+ else
+ {
+ if ( NULL != found )
+ {
+ *found = iter->entry;
+ }
+ break;
+ }
+
+ /* Keep a stack of the path we followed */
+ g_return_val_if_fail(stack_i < LSQ_BTREE_MAX_DEPTH, NULL);
+ stack[stack_i++] = iter;
+ }
+
+ /* Not found */
+ if ( NULL == iter )
+ {
+ return list;
+ }
+
+ if ( NULL == iter->left )
+ {
+ *next = iter->right;
+ g_free ( iter );
+ }
+ else if ( NULL == iter->right )
+ {
+ *next = iter->left;
+ g_free ( iter );
+ }
+ else
+ {
+ /* Find either the most right or most left element in the tree and replace iter with it.
+ * We do this by replaceing the content of the iter, not the iter itself.
+ *
+ * We that the longest of the two paths, i the hope to be better balanced. */
+
+ /* Keep a stack of the path we followed */
+ g_return_val_if_fail(stack_i < LSQ_BTREE_MAX_DEPTH, NULL);
+ stack[stack_i++] = iter;
+
+ /* Right it the longest */
+ if ( 0 < iter->balance )
+ {
+ /* Go right */
+ for ( swap_iter = iter->right; NULL != swap_iter->left; swap_iter = *next )
+ {
+ next = &swap_iter->left;
+
+ /* Keep a stack of the path we followed */
+ g_return_val_if_fail(stack_i < LSQ_BTREE_MAX_DEPTH, NULL);
+ stack[stack_i++] = iter;
+ }
+
+ /* remove the iter from the list */
+ *next = swap_iter->right;
+
+ /* copy the iter to our current location */
+ iter->entry = swap_iter->entry;
+
+ g_free ( swap_iter );
+ }
+ else
+ {
+ /* Go left */
+ for ( swap_iter = iter->right; NULL != iter->left; iter = iter->left )
+ {
+ next = &swap_iter->right;
+
+ /* Keep a stack of the path we followed */
+ g_return_val_if_fail(stack_i < LSQ_BTREE_MAX_DEPTH, NULL);
+ stack[stack_i++] = iter;
+ }
+
+ /* remove the iter from the list */
+ *next = swap_iter->left;
+
+ /* copy the iter to our current location */
+ iter->entry = swap_iter->entry;
+
+ g_free ( swap_iter );
+ }
+ }
+
+ /* Get the new pointer for balancing */
+ del_entry = *next;
+
+ /* Balance the tree */
+ while ( 0 < stack_i )
+ {
+ iter = stack[--stack_i];
+
+ /* Calculate new the balance for the parent */
+ if ( iter->left == del_entry )
+ {
+ short_side = 0 <= iter->balance;
+ ++iter->balance;
+ }
+ else
+ {
+ short_side = 0 >= iter->balance;
+ --iter->balance;
+ }
+
+ /* The balance in the higher parents doesn't change when the short side changed */
+ if ( FALSE != short_side )
+ {
+#ifdef BALANCE_ON_REMOVE
+ if ( 1 < iter->balance )
+ {
+ /* Rotate left */
+ /* The code could be easier if we would just overwrite our parent left or right value.
+ * But instead we move that data from our right to our self and use the right tree link to be placed in the tree as if it was ourself.
+ */
+ /* Letters are tree nodes, numbers are the data. This illustrates a rotate right.
+ *
+ * A:4 | A:2
+ * / \ | / \
+ * B:2 C:5 | D:1 B:4
+ * / \ | / \
+ * D:1 E:3 | E:3 C:5
+ */
+ /* Swap the data */
+ swap_iter = iter->right;
+ swap_entry = iter->entry;
+ iter->entry = swap_iter->entry;
+ swap_iter->entry = swap_entry;
+
+ /* Reformat the tree links */
+ iter->right = swap_iter->right;
+ swap_iter->right = swap_iter->left;
+ swap_iter->left = iter->left;
+ iter->left = swap_iter;
+
+ /* Fix the balance values
+ *
+ * if B > 0
+ * A = A - 1 - B
+ * else
+ * A = A - 1
+ *
+ * diff = A - 1 - B
+ * if diff < 0
+ * B = B - 1 + diff
+ * else
+ * B = B - 1
+ */
+ swap_balance = swap_iter->balance;
+ swap_iter->balance = iter->balance - 1;
+ if ( 0 < swap_balance )
+ {
+ swap_iter->balance -= swap_balance;
+ }
+ iter->balance = iter->balance - 1 - swap_balance;
+ if ( 0 < iter->balance )
+ {
+ iter->balance = 0;
+ }
+ iter->balance += swap_balance - 1;
+
+ /* Saved depth by rotation so our parents depth also changes */
+ if ( 0 >= swap_balance )
+ {
+ break;
+ }
+ }
+ else if ( -1 > iter->balance )
+ {
+ /* Rotate right */
+ /* The code could be easier if we would just overwrite our parent left or right value.
+ * But instead we move that data from our left to our self and use the left tree link to be placed in the tree as if it was ourself.
+ */
+ /* Swap the data */
+ swap_iter = iter->left;
+ swap_entry = iter->entry;
+ iter->entry = swap_iter->entry;
+ swap_iter->entry = swap_entry;
+
+ /* Reformat the tree links */
+ iter->left = swap_iter->left;
+ swap_iter->left = swap_iter->right;
+ swap_iter->right = iter->right;
+ iter->right = swap_iter;
+
+ /* Fix the balance values
+ *
+ * if B < 0
+ * A = A + 1 - B
+ * else
+ * A = A + 1
+ *
+ * diff = A + 1 - B
+ * if diff > 0
+ * B = B + 1 + diff
+ * else
+ * B = B + 1
+ */
+ swap_balance = swap_iter->balance;
+ swap_iter->balance = iter->balance + 1;
+ if ( 0 > swap_balance )
+ {
+ swap_iter->balance -= swap_balance;
+ }
+ iter->balance = iter->balance + 1 - swap_balance;
+ if ( 0 > iter->balance )
+ {
+ iter->balance = 0;
+ }
+ iter->balance += swap_balance + 1;
+
+ /* Saved depth by rotation so our parents depth also changes */
+ if ( 0 <= swap_balance )
+ {
+ break;
+ }
+ }
+ else
+ {
+ break;
+ }
+#else
+ break;
+#endif
+ }
+
+ /* Store ourself in new_entry for the check in the next parent */
+ del_entry = iter;
+ }
+ }
+
+ return list;
+}
+
+guint
+lsq_btree_length ( LSQBTree *list )
+{
+ guint size = 0;
+ LSQBTree *iter;
+ LSQBTree *stack[LSQ_BTREE_MAX_DEPTH];
+ guint stack_i = 0;
+
+ /* The tree is flattened */
+ if ( NULL == list || NULL != list->next )
+ {
+ for ( iter = list; NULL != iter; iter = iter->next)
+ {
+ size++;
+ }
+ }
+ else
+ {
+ do
+ {
+ for ( iter = list; NULL != iter; iter = iter->left )
+ {
+ stack[stack_i++] = iter;
+ g_return_val_if_fail(stack_i < LSQ_BTREE_MAX_DEPTH, 0);
+
+ size++;
+ }
+
+ list = stack[--stack_i]->right;
+ }
+ while ( 0 != stack_i || NULL != list );
+ }
+
+ return size;
+}
+
+void
+lsq_btree_free ( LSQBTree *list )
+{
+ LSQBTree *iter, *next;
+ LSQBTree *stack[LSQ_BTREE_MAX_DEPTH];
+ guint stack_i = 0;
+
+ /* The tree is flattened */
+ if ( NULL == list || NULL != list->next )
+ {
+ for ( iter = list; NULL != iter; iter = next)
+ {
+ next = iter->next;
+ g_free( iter );
+ }
+ }
+ else
+ {
+ do
+ {
+ for ( iter = list; NULL != iter; iter = iter->left )
+ {
+ stack[stack_i++] = iter;
+ g_return_if_fail(stack_i < LSQ_BTREE_MAX_DEPTH);
+ }
+
+ list = stack[--stack_i]->right;
+
+ g_free( stack[stack_i] );
+ }
+ while ( 0 != stack_i || NULL != list );
+ }
+}
+
+LSQBTree *
+lsq_btree_flatten ( LSQBTree *list )
+{
+ LSQBTree *iter, *next = list;
+ LSQBTree **prev = &list;
+ LSQBTree *stack[LSQ_BTREE_MAX_DEPTH];
+ guint stack_i = 0;
+
+ /* The tree is flattened */
+ if ( NULL == list || NULL != list->next )
+ {
+ return list;
+ }
+
+ do
+ {
+ for ( iter = next; NULL != iter; iter = iter->left )
+ {
+ stack[stack_i++] = iter;
+ g_return_val_if_fail(stack_i < LSQ_BTREE_MAX_DEPTH, NULL);
+ }
+
+ next = stack[--stack_i];
+
+ *prev = next;
+ prev = &next->next;
+
+ next = next->right;
+ }
+ while ( 0 != stack_i || NULL != next );
+
+ return list;
+}
+
diff --git a/libsqueeze/slist.h b/libsqueeze/btree.h
similarity index 53%
rename from libsqueeze/slist.h
rename to libsqueeze/btree.h
index 4772afc..574a87b 100644
--- a/libsqueeze/slist.h
+++ b/libsqueeze/btree.h
@@ -14,39 +14,39 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#ifndef __LSQ_SLIST_H__
-#define __LSQ_SLIST_H__
+#ifndef __LSQ_BTREE_H__
+#define __LSQ_BTREE_H__
-typedef struct _LSQSList LSQSList;
+typedef struct _LSQBTree LSQBTree;
-struct _LSQSList {
- LSQArchiveEntry *entry;
- LSQSList *next;
+struct _LSQBTree {
+ LSQArchiveEntry *entry;
+ LSQBTree *next;
+ LSQBTree *left;
+ LSQBTree *right;
+ gint balance;
};
-LSQSList *
-lsq_slist_insert_sorted_single (
- LSQSList *list,
+LSQBTree *
+lsq_btree_insert_sorted_single (
+ LSQBTree *list,
LSQArchiveEntry *entry,
- GCompareFunc) G_GNUC_INTERNAL;
+ GCompareFunc ) G_GNUC_INTERNAL;
+
+LSQBTree *
+lsq_btree_remove_sorted_single (
+ LSQBTree *list,
+ gchar *filename,
+ GCompareFunc cmp_func,
+ LSQArchiveEntry **found ) G_GNUC_INTERNAL;
guint
-lsq_slist_length(LSQSList *list) G_GNUC_INTERNAL;
+lsq_btree_length ( LSQBTree *list ) G_GNUC_INTERNAL;
void
-lsq_slist_free(LSQSList *list) G_GNUC_INTERNAL;
-
-typedef struct _LSQSIndexList LSQSIndexList;
-
-struct _LSQSIndexList {
- LSQSList *index;
- LSQSIndexList *next;
-};
-
-LSQSIndexList *
-lsq_slist_index_new(void);
+lsq_btree_free ( LSQBTree *list ) G_GNUC_INTERNAL;
-void
-lsq_slist_index_free(LSQSIndexList *list);
+LSQBTree *
+lsq_btree_flatten ( LSQBTree *list ) G_GNUC_INTERNAL;
-#endif /* __LSQ_SLIST_H__ */
+#endif /* __LSQ_BTREE_H__ */
diff --git a/libsqueeze/slist.c b/libsqueeze/slist.c
deleted file mode 100644
index b15cd8a..0000000
--- a/libsqueeze/slist.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * 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 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 Library General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-#include <config.h>
-#include <string.h>
-#include <glib.h>
-#include <glib-object.h>
-#include <gio/gio.h>
-
-#include <libxfce4util/libxfce4util.h>
-
-#include "libsqueeze.h"
-#include "support-factory.h"
-#include "internals.h"
-#include "slist.h"
-
-LSQSList *
-lsq_slist_insert_sorted_single (
- LSQSList *list,
- LSQArchiveEntry *entry,
- GCompareFunc cmp_func)
-{
- gint cmp = 1;
- LSQSList *iter = list;
- LSQSList *prev_entry = NULL;
- LSQSList *new_entry = NULL;
-
- for(; iter; iter = iter->next)
- {
- /* archive can be NULL */
- cmp = cmp_func(entry, (LSQArchiveEntry*)iter->entry);
-
- if ( 0 == cmp )
- {
- g_critical("THIS SHOULD NOT HAPPEN!!! (the universe has just collapsed)");
- return NULL;
- }
- if ( 0 > cmp )
- {
- break;
- }
-
- prev_entry = iter;
- }
-
- new_entry = g_new0(LSQSList, 1);
- new_entry->next = iter;
- new_entry->entry = entry;
-
- if ( NULL == prev_entry )
- {
- return new_entry;
- }
-
- prev_entry->next = new_entry;
- return list;
-}
-
-guint
-lsq_slist_length ( LSQSList *list )
-{
- guint size = 0;
- for(; list; list = list->next)
- {
- size++;
- }
- return size;
-}
-
-void
-lsq_slist_free ( LSQSList *list )
-{
- LSQSList *next;
- for(; list; list = next)
- {
- next = list->next;
- g_free(list);
- }
-}
-
-LSQSIndexList *
-lsq_slist_index_new(void)
-{
- return g_new0(LSQSIndexList, 1);
-}
-
-void
-lsq_slist_index_free ( LSQSIndexList *list )
-{
- LSQSIndexList *next;
- for(; list; list = next)
- {
- next = list->next;
- g_free(list);
- }
-}
-
More information about the Xfce4-commits
mailing list