test program. covers run first/last/cleanup signal handlers, return value
[platform/upstream/glib.git] / gqueue.c
index b516b24..b15adb4 100644 (file)
--- a/gqueue.c
+++ b/gqueue.c
 /* GLIB - Library of useful routines for C programming
- * Copyright (C) 1999 Free Software Foundation, Inc.
+ * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * GQueue: Double ended queue implementation, piggy backed on GList.
+ * Copyright (C) 1998 Tim Janik
  *
  * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
+ * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2 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
- * Library General Public License for more details.
+ * Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU Library General Public
+ * 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.
  */
 
+/*
+ * MT safe
+ */
 
 #ifdef HAVE_CONFIG_H
-#  include <config.h>
+#include <config.h>
 #endif
 
-#include <glib.h>
+#include "glib.h"
 
 
+G_LOCK_DEFINE_STATIC (queue_memchunk);
+static GMemChunk   *queue_memchunk = NULL;
+static GTrashStack *free_queue_nodes = NULL;
 
-
-GQueue *
+GQueue*
 g_queue_new (void)
 {
-  GQueue *q = g_new (GQueue, 1);
+  GQueue *queue;
 
-  q->list = q->list_end = NULL;
-  q->list_size = 0;
+  G_LOCK (queue_memchunk);
+  queue = g_trash_stack_pop (&free_queue_nodes);
 
-  return q;
-}
+  if (!queue)
+    {
+      if (!queue_memchunk)
+       queue_memchunk = g_mem_chunk_new ("GLib GQueue chunk",
+                                         sizeof (GNode),
+                                         sizeof (GNode) * 128,
+                                         G_ALLOC_ONLY);
+      queue = g_chunk_new (GQueue, queue_memchunk);
+    }
+  G_UNLOCK (queue_memchunk);
+
+  queue->head = NULL;
+  queue->tail = NULL;
+  queue->length = 0;
 
+  return queue;
+}
 
 void
-g_queue_free (GQueue *q)
+g_queue_free (GQueue *queue)
 {
-  if (q)
-    {
-      if (q->list)
-        g_list_free (q->list);
-      g_free (q);
-    }
-}
+  g_return_if_fail (queue != NULL);
 
+  g_list_free (queue->head);
 
-guint
-g_queue_get_size (GQueue *q)
-{
-  return (q == NULL) ? 0 : q->list_size;
-}
+#ifdef ENABLE_GC_FRIENDLY
+  queue->head = NULL;
+  queue->tail = NULL;
+#endif /* ENABLE_GC_FRIENDLY */
 
+  G_LOCK (queue_memchunk);
+  g_trash_stack_push (&free_queue_nodes, queue);
+  G_UNLOCK (queue_memchunk);
+}
 
 void
-g_queue_push_front (GQueue *q, gpointer data)
+g_queue_push_head (GQueue  *queue,
+                  gpointer data)
 {
-  if (q)
-    {
-      q->list = g_list_prepend (q->list, data);
+  g_return_if_fail (queue != NULL);
 
-      if (q->list_end == NULL)
-        q->list_end = q->list;
+  queue->head = g_list_prepend (queue->head, data);
+  if (!queue->tail)
+    queue->tail = queue->head;
+  queue->length++;
+}
 
-      q->list_size++;
-    }
+void
+g_queue_push_head_link (GQueue *queue,
+                       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);
+
+  link->next = queue->head;
+  if (queue->head)
+    queue->head->prev = link;
+  else
+    queue->tail = link;
+  queue->head = link;
+  queue->length++;
 }
 
+void
+g_queue_push_tail (GQueue  *queue,
+                  gpointer data)
+{
+  g_return_if_fail (queue != NULL);
+
+  queue->tail = g_list_append (queue->tail, data);
+  if (queue->tail->next)
+    queue->tail = queue->tail->next;
+  else
+    queue->head = queue->tail;
+  queue->length++;
+}
 
 void
-g_queue_push_back (GQueue *q, gpointer data)
+g_queue_push_tail_link (GQueue *queue,
+                       GList  *link)
 {
-  if (q)
+  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);
+
+  link->prev = queue->tail;
+  if (queue->tail)
+    queue->tail->next = link;
+  else
+    queue->head = link;
+  queue->tail = link;
+  queue->length++;
+}
+
+gpointer
+g_queue_pop_head (GQueue *queue)
+{
+  g_return_val_if_fail (queue != NULL, NULL);
+
+  if (queue->head)
     {
-      q->list_end = g_list_append (q->list_end, data);
+      GList *node = queue->head;
+      gpointer data = node->data;
 
-      if (! q->list)
-        q->list = q->list_end;
+      queue->head = node->next;
+      if (queue->head)
+       queue->head->prev = NULL;
       else
-        q->list_end = q->list_end->next;
+       queue->tail = NULL;
+      g_list_free_1 (node);
+      queue->length--;
 
-      q->list_size++;
+      return data;
     }
-}
 
+  return NULL;
+}
 
-gpointer
-g_queue_pop_front (GQueue *q)
+GList*
+g_queue_pop_head_link (GQueue *queue)
 {
-  gpointer data = NULL;
+  g_return_val_if_fail (queue != NULL, NULL);
 
-  if ((q) && (q->list))
+  if (queue->head)
     {
-      GList *node;
-
-      node = q->list;
-      data = node->data;
+      GList *node = queue->head;
 
-      if (! node->next)
-        {
-          q->list = q->list_end = NULL;
-          q->list_size = 0;
-        }
+      queue->head = node->next;
+      if (queue->head)
+       {
+         queue->head->prev = NULL;
+         node->next = NULL;
+       }
       else
-        {
-          q->list = node->next;
-          q->list->prev = NULL;
-          q->list_size--;
-        }
+       queue->tail = NULL;
+      queue->length--;
 
-      g_list_free_1 (node);
+      return node;
     }
 
-  return data;
+  return NULL;
 }
 
-
 gpointer
-g_queue_pop_back (GQueue *q)
+g_queue_pop_tail (GQueue *queue)
 {
-  gpointer data = NULL;
+  g_return_val_if_fail (queue != NULL, NULL);
 
-  if ((q) && (q->list))
+  if (queue->tail)
     {
-      GList *node;
+      GList *node = queue->tail;
+      gpointer data = node->data;
 
-      node = q->list_end;
-      data = node->data;
+      queue->tail = node->prev;
+      if (queue->tail)
+       queue->tail->next = NULL;
+      else
+       queue->head = NULL;
+      queue->length--;
+      g_list_free_1 (node);
 
-      if (! node->prev)
+      return data;
+    }
+  
+  return NULL;
+}
+
+GList*
+g_queue_pop_tail_link (GQueue *queue)
+{
+  g_return_val_if_fail (queue != NULL, NULL);
+  
+  if (queue->tail)
+    {
+      GList *node = queue->tail;
+      
+      queue->tail = node->prev;
+      if (queue->tail)
        {
-          q->list = q->list_end = NULL;
-          q->list_size = 0;
-        }
+         queue->tail->next = NULL;
+         node->prev = NULL;
+       }
       else
-       {
-          q->list_end = node->prev;
-          q->list_end->next = NULL;
-          q->list_size--;
-        }
-
-      g_list_free_1 (node);
+       queue->head = NULL;
+      queue->length--;
+      
+      return node;
     }
+  
+  return NULL;
+}
+
+gboolean
+g_queue_is_empty (GQueue *queue)
+{
+  g_return_val_if_fail (queue != NULL, TRUE);
+
+  return queue->head == NULL;
+}
+
+gpointer
+g_queue_peek_head (GQueue *queue)
+{
+  g_return_val_if_fail (queue != NULL, NULL);
 
-  return data;
+  return queue->head ? queue->head->data : NULL;
 }
 
+gpointer
+g_queue_peek_tail (GQueue *queue)
+{
+  g_return_val_if_fail (queue != NULL, NULL);
 
+  return queue->tail ? queue->tail->data : NULL;
+}