Commit c7a0a93b authored by Alexander Larsson's avatar Alexander Larsson Committed by Alexander Larsson

Import the latest EggSequence which supposedly fixes a bunch of bugs.

2006-07-25  Alexander Larsson  <alexl@redhat.com>

	* cut-n-paste-code/gsequence/gsequence.[ch]:
	Import the latest EggSequence which supposedly fixes a
	bunch of bugs.

	* src/file-manager/fm-list-model.c:
	Fix to use new function names of EggSequence
parent 798ce8e7
2006-07-25 Alexander Larsson <alexl@redhat.com>
* cut-n-paste-code/gsequence/gsequence.[ch]:
Import the latest EggSequence which supposedly fixes a
bunch of bugs.
* src/file-manager/fm-list-model.c:
Fix to use new function names of EggSequence
2006-07-25 Martin Wehner <martin.wehner@gmail.com>
* configure.in:
......
/* GLIB - Library of useful routines for C programming
* Copyright (C) 2002 Soeren Sandmann (sandmann@daimi.au.dk)
* Copyright (C) 2002, 2003, 2004, 2005 Soeren Sandmann (sandmann@daimi.au.dk)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
......@@ -23,496 +23,839 @@
typedef struct _GSequenceNode GSequenceNode;
struct _GSequence {
GSequenceNode *node; /* does not necessarily point to the root.
* You can splay it if you want it to
*/
GDestroyNotify data_destroy_notify;
struct _GSequence
{
GSequenceNode * end_node;
GDestroyNotify data_destroy_notify;
gboolean access_prohibited;
};
struct _GSequenceNode {
guint is_end : 1;
gint n_nodes : 31; /* number of nodes below this node,
* including this node
*/
GSequenceNode *parent;
struct _GSequenceNode
{
gint n_nodes;
GSequenceNode *parent;
GSequenceNode *left;
GSequenceNode *right;
GSequence *sequence;
gpointer data;
gpointer data; /* For the end node, this field points
* to the sequence
*/
};
static GSequenceNode *g_sequence_node_new (gpointer data);
static GSequenceNode *g_sequence_node_find_first (GSequenceNode *node);
static GSequenceNode *g_sequence_node_find_last (GSequenceNode *node);
static GSequenceNode *g_sequence_node_find_by_pos (GSequenceNode *node,
gint pos);
static GSequenceNode *g_sequence_node_prev (GSequenceNode *node);
static GSequenceNode *g_sequence_node_next (GSequenceNode *node);
static gint g_sequence_node_get_pos (GSequenceNode *node);
static GSequence *g_sequence_node_get_sequence (GSequenceNode *node);
static GSequenceNode *g_sequence_node_find_closest (GSequenceNode *node,
GSequenceNode *other,
GCompareDataFunc cmp,
gpointer data);
static gint g_sequence_node_get_length (GSequenceNode *node);
static void g_sequence_node_free (GSequenceNode *node,
GDestroyNotify destroy);
#if 0
static gboolean g_sequence_node_is_singleton (GSequenceNode *node);
#endif
static void g_sequence_node_split (GSequenceNode *node,
GSequenceNode **left,
GSequenceNode **right);
static void g_sequence_node_insert_before (GSequenceNode *node,
GSequenceNode *new);
static void g_sequence_node_remove (GSequenceNode *node);
static void g_sequence_node_insert_sorted (GSequenceNode *node,
GSequenceNode *new,
GCompareDataFunc cmp_func,
gpointer cmp_data);
static GSequenceNode *node_new (gpointer data);
static GSequenceNode *node_get_first (GSequenceNode *node);
static GSequenceNode *node_get_last (GSequenceNode *node);
static GSequenceNode *node_get_prev (GSequenceNode *node);
static GSequenceNode *node_get_next (GSequenceNode *node);
static gint node_get_pos (GSequenceNode *node);
static GSequenceNode *node_get_by_pos (GSequenceNode *node,
gint pos);
static GSequenceNode *node_find_closest (GSequenceNode *haystack,
GSequenceNode *needle,
GSequenceIterCompareFunc cmp,
gpointer user_data);
static gint node_get_length (GSequenceNode *node);
static void node_free (GSequenceNode *node,
GSequence *seq);
static void node_cut (GSequenceNode *split);
static void node_insert_after (GSequenceNode *node,
GSequenceNode *second);
static void node_insert_before (GSequenceNode *node,
GSequenceNode *new);
static void node_unlink (GSequenceNode *node);
static void node_insert_sorted (GSequenceNode *node,
GSequenceNode *new,
GSequenceIterCompareFunc cmp_func,
gpointer cmp_data);
static GSequence *
get_sequence (GSequenceNode *node)
{
return (GSequence *)node_get_last (node)->data;
}
static void
check_seq_access (GSequence *seq)
{
if (G_UNLIKELY (seq->access_prohibited))
{
g_warning ("Accessing a sequence while it is "
"being sorted is not allowed");
}
}
static void
check_iter_access (GSequenceIter *iter)
{
check_seq_access (get_sequence (iter));
}
static gboolean
is_end (GSequenceIter *iter)
{
GSequence *seq = get_sequence (iter);
return seq->end_node == iter;
}
/*
* Public API
*/
/* GSequence */
GSequence *
g_sequence_new (GDestroyNotify data_destroy)
g_sequence_new (GDestroyNotify data_destroy)
{
GSequence *seq = g_new (GSequence, 1);
seq->data_destroy_notify = data_destroy;
seq->node = g_sequence_node_new (NULL);
seq->node->is_end = TRUE;
seq->node->sequence = seq;
seq->end_node = node_new (seq);
seq->access_prohibited = FALSE;
return seq;
}
void
g_sequence_free (GSequence *seq)
g_sequence_free (GSequence *seq)
{
g_return_if_fail (seq != NULL);
g_sequence_node_free (seq->node, seq->data_destroy_notify);
check_seq_access (seq);
node_free (seq->end_node, seq);
g_free (seq);
}
#if 0
static void
flatten_nodes (GSequenceNode *node, GList **list)
void
g_sequence_foreach_range (GSequenceIter *begin,
GSequenceIter *end,
GFunc func,
gpointer data)
{
g_print ("flatten %p\n", node);
if (!node)
return;
else if (g_sequence_node_is_singleton (node))
*list = g_list_prepend (*list, node);
else
GSequence *seq;
GSequenceIter *iter;
g_return_if_fail (func != NULL);
g_return_if_fail (begin != NULL);
g_return_if_fail (end != NULL);
seq = get_sequence (begin);
seq->access_prohibited = TRUE;
iter = begin;
while (iter != end)
{
GSequenceNode *left;
GSequenceNode *right;
g_sequence_node_split (node, &left, &right);
flatten_nodes (left, list);
flatten_nodes (right, list);
GSequenceIter *next = node_get_next (iter);
func (iter->data, data);
iter = next;
}
seq->access_prohibited = FALSE;
}
#endif
typedef struct SortInfo SortInfo;
struct SortInfo {
GCompareDataFunc cmp;
gpointer data;
};
void
g_sequence_foreach (GSequence *seq,
GFunc func,
gpointer data)
{
GSequenceIter *begin, *end;
check_seq_access (seq);
begin = g_sequence_get_begin_iter (seq);
end = g_sequence_get_end_iter (seq);
g_sequence_foreach_range (begin, end, func, data);
}
static gint
node_compare (gconstpointer n1, gconstpointer n2, gpointer data)
GSequenceIter *
g_sequence_range_get_midpoint (GSequenceIter *begin,
GSequenceIter *end)
{
SortInfo *info = data;
const GSequenceNode *node1 = n1;
const GSequenceNode *node2 = n2;
int begin_pos, end_pos, mid_pos;
g_return_val_if_fail (begin != NULL, NULL);
g_return_val_if_fail (end != NULL, NULL);
g_return_val_if_fail (get_sequence (begin) == get_sequence (end), NULL);
begin_pos = node_get_pos (begin);
end_pos = node_get_pos (end);
g_return_val_if_fail (end_pos >= begin_pos, NULL);
mid_pos = begin_pos + (end_pos - begin_pos) / 2;
return node_get_by_pos (begin, mid_pos);
}
if (node1->is_end)
gint
g_sequence_iter_compare (GSequenceIter *a,
GSequenceIter *b)
{
gint a_pos, b_pos;
g_return_val_if_fail (a != NULL, 0);
g_return_val_if_fail (b != NULL, 0);
g_return_val_if_fail (get_sequence (a) == get_sequence (b), 0);
check_iter_access (a);
check_iter_access (b);
a_pos = node_get_pos (a);
b_pos = node_get_pos (b);
if (a_pos == b_pos)
return 0;
else if (a_pos > b_pos)
return 1;
else if (node2->is_end)
return -1;
else
return (* info->cmp) (node1->data, node2->data, info->data);
return -1;
}
void
g_sequence_append (GSequence *seq,
gpointer data)
GSequenceIter *
g_sequence_append (GSequence *seq,
gpointer data)
{
GSequenceNode *node, *last;
GSequenceNode *node;
g_return_val_if_fail (seq != NULL, NULL);
check_seq_access (seq);
node = node_new (data);
node_insert_before (seq->end_node, node);
return node;
}
g_return_if_fail (seq != NULL);
GSequenceIter *
g_sequence_prepend (GSequence *seq,
gpointer data)
{
GSequenceNode *node, *first;
g_return_val_if_fail (seq != NULL, NULL);
check_seq_access (seq);
node = node_new (data);
first = node_get_first (seq->end_node);
node_insert_before (first, node);
return node;
}
node = g_sequence_node_new (data);
node->sequence = seq;
last = g_sequence_node_find_last (seq->node);
g_sequence_node_insert_before (last, node);
GSequenceIter *
g_sequence_insert_before (GSequenceIter *iter,
gpointer data)
{
GSequenceNode *node;
g_return_val_if_fail (iter != NULL, NULL);
check_iter_access (iter);
node = node_new (data);
node_insert_before (iter, node);
return node;
}
void
g_sequence_prepend (GSequence *seq,
gpointer data)
g_sequence_remove (GSequenceIter *iter)
{
GSequenceNode *node, *second;
g_return_if_fail (seq != NULL);
GSequence *seq;
g_return_if_fail (iter != NULL);
g_return_if_fail (!is_end (iter));
node = g_sequence_node_new (data);
node->sequence = seq;
second = g_sequence_node_next (g_sequence_node_find_first (seq->node));
check_iter_access (iter);
g_sequence_node_insert_before (second, node);
seq = get_sequence (iter);
node_unlink (iter);
node_free (iter, seq);
}
void
g_sequence_insert (GSequencePtr ptr,
gpointer data)
g_sequence_remove_range (GSequenceIter *begin,
GSequenceIter *end)
{
GSequenceNode *node;
g_return_if_fail (get_sequence (begin) == get_sequence (end));
check_iter_access (begin);
check_iter_access (end);
g_return_if_fail (ptr != NULL);
g_sequence_move_range (NULL, begin, end);
}
#if 0
static void
print_node (GSequenceNode *node, int level)
{
int i;
for (i = 0; i < level; ++i)
g_print (" ");
g_print ("%p\n", node);
if (!node)
return;
print_node (node->left, level + 1);
print_node (node->right, level + 1);
}
node = g_sequence_node_new (data);
node->sequence = ptr->sequence;
static GSequenceNode *
get_root (GSequenceNode *node)
{
GSequenceNode *root;
g_sequence_node_insert_before (ptr, node);
root = node;
while (root->parent)
root = root->parent;
return root;
}
static void
g_sequence_unlink (GSequence *seq,
GSequenceNode *node)
print_tree (GSequence *seq)
{
print_node (get_root (seq->end_node), 0);
}
#endif
/**
* g_sequence_move_range:
* @dest:
* @begin:
* @end:
*
* Insert a range at the destination pointed to by ptr. The @begin and
* @end iters must point into the same sequence. It is allowed for @dest to
* point to a different sequence than the one pointed into by @begin and
* @end. If @dest is NULL, the range indicated by @begin and @end is
* removed from the sequence. If @dest iter points to a place within
* the (@begin, @end) range, the range stays put.
*
* Since: 2.12
**/
void
g_sequence_move_range (GSequenceIter *dest,
GSequenceIter *begin,
GSequenceIter *end)
{
g_assert (!node->is_end);
GSequence *src_seq;
GSequenceNode *first;
g_return_if_fail (begin != NULL);
g_return_if_fail (end != NULL);
check_iter_access (begin);
check_iter_access (end);
if (dest)
check_iter_access (dest);
src_seq = get_sequence (begin);
g_return_if_fail (src_seq == get_sequence (end));
#if 0
if (dest && get_sequence (dest) == src_seq)
{
g_return_if_fail ((g_sequence_iter_compare (dest, begin) <= 0) ||
(g_sequence_iter_compare (end, dest) <= 0));
}
#endif
seq->node = g_sequence_node_next (node);
/* Dest points to begin or end? */
if (dest == begin || dest == end)
return;
/* begin comes after end? */
if (g_sequence_iter_compare (begin, end) >= 0)
return;
/* dest points somewhere in the (begin, end) range? */
if (dest && get_sequence (dest) == src_seq &&
g_sequence_iter_compare (dest, begin) > 0 &&
g_sequence_iter_compare (dest, end) < 0)
{
return;
}
src_seq = get_sequence (begin);
first = node_get_first (begin);
node_cut (begin);
node_cut (end);
if (first != begin)
node_insert_after (node_get_last (first), end);
if (dest)
node_insert_before (dest, begin);
else
node_free (begin, src_seq);
}
g_assert (seq->node);
g_assert (seq->node != node);
typedef struct
{
GCompareDataFunc cmp_func;
gpointer cmp_data;
} SortInfo;
g_sequence_node_remove (node);
/* This function compares two iters using a normal compare
* function and user_data passed in in a SortInfo struct
*/
static gint
iter_compare (GSequenceIter *node1,
GSequenceIter *node2,
gpointer data)
{
const SortInfo *info = data;
gint retval;
if (is_end (node1))
return 1;
if (is_end (node2))
return -1;
retval = info->cmp_func (node1->data, node2->data, info->cmp_data);
/* If the nodes are different, but the user supplied compare function
* compares them equal, then force an arbitrary (but consistent) order
* on them, so that our sorts will be stable
*/
if (retval == 0 && node1 != node2)
{
if (node1 > node2)
return 1;
else
return -1;
}
return retval;
}
void
g_sequence_remove (GSequencePtr ptr)
g_sequence_sort (GSequence *seq,
GCompareDataFunc cmp_func,
gpointer cmp_data)
{
GSequence *seq;
SortInfo info = { cmp_func, cmp_data };
g_return_if_fail (ptr != NULL);
g_return_if_fail (!ptr->is_end);
check_seq_access (seq);
g_sequence_sort_iter (seq, iter_compare, &info);
}
seq = g_sequence_node_get_sequence (ptr);
g_sequence_unlink (seq, ptr);
g_sequence_node_free (ptr, seq->data_destroy_notify);
/**
* g_sequence_insert_sorted:
* @seq: a #GSequence
* @data: the data to insert
* @cmp_func: the #GCompareDataFunc used to compare elements in the queue. It is
* called with two elements of the @seq and @user_data. It should
* return 0 if the elements are equal, a negative value if the first
* element comes before the second, and a positive value if the second
* element comes before the first.
* @cmp_data: user data passed to @cmp_func.
*
* Inserts @data into @queue using @func to determine the new position.
*
* Since: 2.10
**/
GSequenceIter *
g_sequence_insert_sorted (GSequence *seq,
gpointer data,
GCompareDataFunc cmp_func,
gpointer cmp_data)
{
SortInfo info = { cmp_func, cmp_data };
g_return_val_if_fail (seq != NULL, NULL);
g_return_val_if_fail (cmp_func != NULL, NULL);
check_seq_access (seq);
return g_sequence_insert_sorted_iter (seq, data, iter_compare, &info);
}
void
g_sequence_sort (GSequence *seq,
GCompareDataFunc cmp_func,
gpointer cmp_data)
g_sequence_sort_changed (GSequenceIter *iter,
GCompareDataFunc cmp_func,
gpointer cmp_data)
{
SortInfo info = { cmp_func, cmp_data };
g_return_if_fail (!is_end (iter));
check_iter_access (iter);
g_sequence_sort_changed_iter (iter, iter_compare, &info);
}
void
g_sequence_sort_iter (GSequence *seq,
GSequenceIterCompareFunc cmp_func,
gpointer cmp_data)
{
GSequence *tmp;
GSequenceNode *begin, *end;
g_return_if_fail (seq != NULL);
g_return_if_fail (cmp_func != NULL);
begin = g_sequence_get_begin_ptr (seq);
end = g_sequence_get_end_ptr (seq);
g_sequence_remove_range (begin, end, &tmp);
check_seq_access (seq);
begin = g_sequence_get_begin_iter (seq);
end = g_sequence_get_end_iter (seq);
tmp = g_sequence_new (NULL);
g_sequence_move_range (g_sequence_get_begin_iter (tmp), begin, end);
tmp->access_prohibited = TRUE;
seq->access_prohibited = TRUE;
while (g_sequence_get_length (tmp) > 0)
{
GSequenceNode *node = g_sequence_get_begin_ptr (tmp);
g_sequence_unlink (tmp, node);
g_sequence_node_insert_sorted (seq->node, node, cmp_func, cmp_data);
GSequenceNode *node = g_sequence_get_begin_iter (tmp);
node_unlink (node);
node_insert_sorted (seq->end_node, node, cmp_func, cmp_data);
}
tmp->access_prohibited = FALSE;
seq->access_prohibited = FALSE;
g_sequence_free (tmp);
}
gpointer
g_sequence_ptr_get_data (GSequencePtr ptr)
void
g_sequence_sort_changed_iter (GSequenceIter *iter,
GSequenceIterCompareFunc iter_cmp,
gpointer cmp_data)
{
g_return_val_if_fail (ptr != NULL, NULL);
g_return_val_if_fail (!ptr->is_end, NULL);
return ptr->data;
GSequence *seq;
g_return_if_fail (!is_end (iter));
check_iter_access (iter);
seq = get_sequence (iter);
seq->access_prohibited = TRUE;
node_unlink (iter);
node_insert_sorted (seq->end_node, iter, iter_cmp, cmp_data);
seq->access_prohibited = FALSE;
}
GSequencePtr
g_sequence_insert_sorted (GSequence *seq,
gpointer data,
GCompareDataFunc cmp_func,
gpointer cmp_data)
GSequenceIter *
g_sequence_insert_sorted_iter (GSequence *seq,
gpointer data,
GSequenceIterCompareFunc iter_cmp,
gpointer cmp_data)
{
GSequenceNode *new_node = g_sequence_node_new (data);
new_node->sequence = seq;
g_sequence_node_insert_sorted (seq->node, new_node, cmp_func, cmp_data);
GSequenceNode *new_node;
check_seq_access (seq);
new_node = node_new (data);
node_insert_sorted (seq->end_node, new_node, iter_cmp, cmp_data);
return new_node;
}
void