mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-10 03:16:17 +01:00
Merge branch 'wip/chergert/insertbeforelink' into 'master'
Add pre-allocated link helpers for GList and GQueue See merge request GNOME/glib!476
This commit is contained in:
commit
375fa65b24
@ -2268,6 +2268,7 @@ g_list_append
|
||||
g_list_prepend
|
||||
g_list_insert
|
||||
g_list_insert_before
|
||||
g_list_insert_before_link
|
||||
g_list_insert_sorted
|
||||
g_list_remove
|
||||
g_list_remove_link
|
||||
@ -2389,7 +2390,9 @@ g_queue_index
|
||||
g_queue_remove
|
||||
g_queue_remove_all
|
||||
g_queue_insert_before
|
||||
g_queue_insert_before_link
|
||||
g_queue_insert_after
|
||||
g_queue_insert_after_link
|
||||
g_queue_insert_sorted
|
||||
g_queue_push_head_link
|
||||
g_queue_push_tail_link
|
||||
|
68
glib/glist.c
68
glib/glist.c
@ -367,6 +367,64 @@ g_list_insert (GList *list,
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_list_insert_before_link:
|
||||
* @list: a pointer to a #GList, this must point to the top of the list
|
||||
* @sibling: (nullable): the list element before which the new element
|
||||
* is inserted or %NULL to insert at the end of the list
|
||||
* @link_: the list element to be added, which must not be part of
|
||||
* any other list
|
||||
*
|
||||
* Inserts @link_ into the list before the given position.
|
||||
*
|
||||
* Returns: the (possibly changed) start of the #GList
|
||||
*
|
||||
* Since: 2.62
|
||||
*/
|
||||
GList *
|
||||
g_list_insert_before_link (GList *list,
|
||||
GList *sibling,
|
||||
GList *link_)
|
||||
{
|
||||
g_return_val_if_fail (link_ != NULL, list);
|
||||
g_return_val_if_fail (link_->prev == NULL, list);
|
||||
g_return_val_if_fail (link_->next == NULL, list);
|
||||
|
||||
if (list == NULL)
|
||||
{
|
||||
g_return_val_if_fail (sibling == NULL, list);
|
||||
return link_;
|
||||
}
|
||||
else if (sibling != NULL)
|
||||
{
|
||||
link_->prev = sibling->prev;
|
||||
link_->next = sibling;
|
||||
sibling->prev = link_;
|
||||
if (link_->prev != NULL)
|
||||
{
|
||||
link_->prev->next = link_;
|
||||
return list;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_return_val_if_fail (sibling == list, link_);
|
||||
return link_;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GList *last;
|
||||
|
||||
for (last = list; last->next != NULL; last = last->next) {}
|
||||
|
||||
last->next = link_;
|
||||
last->next->prev = last;
|
||||
last->next->next = NULL;
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* g_list_insert_before:
|
||||
* @list: a pointer to a #GList, this must point to the top of the list
|
||||
@ -383,14 +441,14 @@ g_list_insert_before (GList *list,
|
||||
GList *sibling,
|
||||
gpointer data)
|
||||
{
|
||||
if (!list)
|
||||
if (list == NULL)
|
||||
{
|
||||
list = g_list_alloc ();
|
||||
list->data = data;
|
||||
g_return_val_if_fail (sibling == NULL, list);
|
||||
return list;
|
||||
}
|
||||
else if (sibling)
|
||||
else if (sibling != NULL)
|
||||
{
|
||||
GList *node;
|
||||
|
||||
@ -399,7 +457,7 @@ g_list_insert_before (GList *list,
|
||||
node->prev = sibling->prev;
|
||||
node->next = sibling;
|
||||
sibling->prev = node;
|
||||
if (node->prev)
|
||||
if (node->prev != NULL)
|
||||
{
|
||||
node->prev->next = node;
|
||||
return list;
|
||||
@ -414,9 +472,7 @@ g_list_insert_before (GList *list,
|
||||
{
|
||||
GList *last;
|
||||
|
||||
last = list;
|
||||
while (last->next)
|
||||
last = last->next;
|
||||
for (last = list; last->next != NULL; last = last->next) {}
|
||||
|
||||
last->next = _g_list_alloc ();
|
||||
last->next->data = data;
|
||||
|
@ -78,6 +78,10 @@ GLIB_AVAILABLE_IN_ALL
|
||||
GList* g_list_insert_before (GList *list,
|
||||
GList *sibling,
|
||||
gpointer data) G_GNUC_WARN_UNUSED_RESULT;
|
||||
GLIB_AVAILABLE_IN_2_62
|
||||
GList* g_list_insert_before_link (GList *list,
|
||||
GList *sibling,
|
||||
GList *link_) G_GNUC_WARN_UNUSED_RESULT;
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
GList* g_list_concat (GList *list1,
|
||||
GList *list2) G_GNUC_WARN_UNUSED_RESULT;
|
||||
|
@ -1047,6 +1047,44 @@ g_queue_insert_before (GQueue *queue,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* g_queue_insert_before_link:
|
||||
* @queue: a #GQueue
|
||||
* @sibling: (nullable): a #GList link that must be part of @queue, or %NULL to
|
||||
* push at the tail of the queue.
|
||||
* @link_: a #GList link to insert which must not be part of any other list.
|
||||
*
|
||||
* Inserts @link_ into @queue before @sibling.
|
||||
*
|
||||
* @sibling must be part of @queue.
|
||||
*
|
||||
* Since: 2.62
|
||||
*/
|
||||
void
|
||||
g_queue_insert_before_link (GQueue *queue,
|
||||
GList *sibling,
|
||||
GList *link_)
|
||||
{
|
||||
g_return_if_fail (queue != NULL);
|
||||
g_return_if_fail (link_ != NULL);
|
||||
g_return_if_fail (link_->prev == NULL);
|
||||
g_return_if_fail (link_->next == NULL);
|
||||
|
||||
if G_UNLIKELY (sibling == NULL)
|
||||
{
|
||||
/* We don't use g_list_insert_before_link() with a NULL sibling because it
|
||||
* would be a O(n) operation and we would need to update manually the tail
|
||||
* pointer.
|
||||
*/
|
||||
g_queue_push_tail_link (queue, link_);
|
||||
}
|
||||
else
|
||||
{
|
||||
queue->head = g_list_insert_before_link (queue->head, sibling, link_);
|
||||
queue->length++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* g_queue_insert_after:
|
||||
* @queue: a #GQueue
|
||||
@ -1074,6 +1112,35 @@ g_queue_insert_after (GQueue *queue,
|
||||
g_queue_insert_before (queue, sibling->next, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_queue_insert_after_link:
|
||||
* @queue: a #GQueue
|
||||
* @sibling: (nullable): a #GList link that must be part of @queue, or %NULL to
|
||||
* push at the head of the queue.
|
||||
* @link_: a #GList link to insert which must not be part of any other list.
|
||||
*
|
||||
* Inserts @link_ into @queue after @sibling.
|
||||
*
|
||||
* @sibling must be part of @queue.
|
||||
*
|
||||
* Since: 2.62
|
||||
*/
|
||||
void
|
||||
g_queue_insert_after_link (GQueue *queue,
|
||||
GList *sibling,
|
||||
GList *link_)
|
||||
{
|
||||
g_return_if_fail (queue != NULL);
|
||||
g_return_if_fail (link_ != NULL);
|
||||
g_return_if_fail (link_->prev == NULL);
|
||||
g_return_if_fail (link_->next == NULL);
|
||||
|
||||
if G_UNLIKELY (sibling == NULL)
|
||||
g_queue_push_head_link (queue, link_);
|
||||
else
|
||||
g_queue_insert_before_link (queue, sibling->next, link_);
|
||||
}
|
||||
|
||||
/**
|
||||
* g_queue_insert_sorted:
|
||||
* @queue: a #GQueue
|
||||
|
@ -144,10 +144,20 @@ GLIB_AVAILABLE_IN_ALL
|
||||
void g_queue_insert_before (GQueue *queue,
|
||||
GList *sibling,
|
||||
gpointer data);
|
||||
GLIB_AVAILABLE_IN_2_62
|
||||
void g_queue_insert_before_link
|
||||
(GQueue *queue,
|
||||
GList *sibling,
|
||||
GList *link_);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_queue_insert_after (GQueue *queue,
|
||||
GList *sibling,
|
||||
gpointer data);
|
||||
GLIB_AVAILABLE_IN_2_62
|
||||
void g_queue_insert_after_link
|
||||
(GQueue *queue,
|
||||
GList *sibling,
|
||||
GList *link_);
|
||||
GLIB_AVAILABLE_IN_ALL
|
||||
void g_queue_insert_sorted (GQueue *queue,
|
||||
gpointer data,
|
||||
|
@ -548,6 +548,72 @@ test_double_free (void)
|
||||
g_test_trap_assert_stderr ("*corrupted double-linked list detected*");
|
||||
}
|
||||
|
||||
static void
|
||||
test_list_insert_before_link (void)
|
||||
{
|
||||
GList a = {0};
|
||||
GList b = {0};
|
||||
GList c = {0};
|
||||
GList d = {0};
|
||||
GList e = {0};
|
||||
GList *list;
|
||||
|
||||
list = g_list_insert_before_link (NULL, NULL, &a);
|
||||
g_assert_nonnull (list);
|
||||
g_assert_true (list == &a);
|
||||
g_assert_null (a.prev);
|
||||
g_assert_null (a.next);
|
||||
g_assert_cmpint (g_list_length (list), ==, 1);
|
||||
|
||||
list = g_list_insert_before_link (list, &a, &b);
|
||||
g_assert_nonnull (list);
|
||||
g_assert_true (list == &b);
|
||||
g_assert_null (b.prev);
|
||||
g_assert_true (b.next == &a);
|
||||
g_assert_true (a.prev == &b);
|
||||
g_assert_null (a.next);
|
||||
g_assert_cmpint (g_list_length (list), ==, 2);
|
||||
|
||||
list = g_list_insert_before_link (list, &a, &c);
|
||||
g_assert_nonnull (list);
|
||||
g_assert_true (list == &b);
|
||||
g_assert_null (b.prev);
|
||||
g_assert_true (b.next == &c);
|
||||
g_assert_true (c.next == &a);
|
||||
g_assert_true (c.prev == &b);
|
||||
g_assert_true (a.prev == &c);
|
||||
g_assert_null (a.next);
|
||||
g_assert_cmpint (g_list_length (list), ==, 3);
|
||||
|
||||
list = g_list_insert_before_link (list, &b, &d);
|
||||
g_assert_nonnull (list);
|
||||
g_assert_true (list == &d);
|
||||
g_assert_null (d.prev);
|
||||
g_assert_true (b.prev == &d);
|
||||
g_assert_true (c.prev == &b);
|
||||
g_assert_true (a.prev == &c);
|
||||
g_assert_true (d.next == &b);
|
||||
g_assert_true (b.next == &c);
|
||||
g_assert_true (c.next == &a);
|
||||
g_assert_null (a.next);
|
||||
g_assert_cmpint (g_list_length (list), ==, 4);
|
||||
|
||||
list = g_list_insert_before_link (list, NULL, &e);
|
||||
g_assert_nonnull (list);
|
||||
g_assert_true (list == &d);
|
||||
g_assert_null (d.prev);
|
||||
g_assert_true (b.prev == &d);
|
||||
g_assert_true (c.prev == &b);
|
||||
g_assert_true (a.prev == &c);
|
||||
g_assert_true (d.next == &b);
|
||||
g_assert_true (b.next == &c);
|
||||
g_assert_true (c.next == &a);
|
||||
g_assert_true (a.next == &e);
|
||||
g_assert_true (e.prev == &a);
|
||||
g_assert_null (e.next);
|
||||
g_assert_cmpint (g_list_length (list), ==, 5);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
@ -562,6 +628,7 @@ main (int argc, char *argv[])
|
||||
g_test_add_func ("/list/sort", test_list_sort);
|
||||
g_test_add_func ("/list/sort-with-data", test_list_sort_with_data);
|
||||
g_test_add_func ("/list/sort/stable", test_list_sort_stable);
|
||||
g_test_add_func ("/list/insert-before-link", test_list_insert_before_link);
|
||||
g_test_add_func ("/list/insert-sorted", test_list_insert_sorted);
|
||||
g_test_add_func ("/list/insert-sorted-with-data", test_list_insert_sorted_with_data);
|
||||
g_test_add_func ("/list/reverse", test_list_reverse);
|
||||
|
@ -1117,6 +1117,40 @@ test_free_full (void)
|
||||
g_slice_free (QueueItem, three);
|
||||
}
|
||||
|
||||
static void
|
||||
test_insert_sibling_link (void)
|
||||
{
|
||||
GQueue q = G_QUEUE_INIT;
|
||||
GList a = {0};
|
||||
GList b = {0};
|
||||
GList c = {0};
|
||||
GList d = {0};
|
||||
GList e = {0};
|
||||
|
||||
g_queue_push_head_link (&q, &a);
|
||||
g_queue_insert_after_link (&q, &a, &d);
|
||||
g_queue_insert_before_link (&q, &d, &b);
|
||||
g_queue_insert_after_link (&q, &b, &c);
|
||||
g_queue_insert_after_link (&q, NULL, &e);
|
||||
|
||||
g_assert_true (q.head == &e);
|
||||
g_assert_true (q.tail == &d);
|
||||
|
||||
g_assert_null (e.prev);
|
||||
g_assert_true (e.next == &a);
|
||||
|
||||
g_assert_true (a.prev == &e);
|
||||
g_assert_true (a.next == &b);
|
||||
|
||||
g_assert_true (b.prev == &a);
|
||||
g_assert_true (b.next == &c);
|
||||
|
||||
g_assert_true (c.prev == &b);
|
||||
g_assert_true (c.next == &d);
|
||||
|
||||
g_assert_true (d.prev == &c);
|
||||
g_assert_null (d.next);
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
@ -1133,6 +1167,7 @@ int main (int argc, char *argv[])
|
||||
g_test_add_func ("/queue/clear", test_clear);
|
||||
g_test_add_func ("/queue/free-full", test_free_full);
|
||||
g_test_add_func ("/queue/clear-full", test_clear_full);
|
||||
g_test_add_func ("/queue/insert-sibling-link", test_insert_sibling_link);
|
||||
|
||||
seed = g_test_rand_int_range (0, G_MAXINT);
|
||||
path = g_strdup_printf ("/queue/random/seed:%u", seed);
|
||||
|
Loading…
Reference in New Issue
Block a user