[Proposal] GRing



Please comment on the prospects of including GRing in glib 2.0 or 2.1.
Highlights:

o GRing offers the space requirements of GList with the performance
characteristics of GQueue.  GQueue can be deprecated.

o GRing offers an API which is extremely similar to GList.

o Documentation (partially).

o Test suite.

-- 
Get self-realization at <http://sahajayoga.org> ... <http://why-compete.org> ?
  Victory to the Divine Mother!!
/* GLIB - Library of useful routines for C programming
 * Copyright (C) 2001 Joshua Nathaniel Pritikin
 *
 * 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 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.
 */

#include <glib.h>

#ifndef __G_RING_H__
#define __G_RING_H__

// G_BEGIN_DECLS

typedef struct _GRing GRing;

struct _GRing
{
  gpointer data;
  GRing *next;
  GRing *prev;
};

/* GList look-alike */
#define    g_ring_alloc()          ((GRing *) g_list_alloc())
void       g_ring_free             (GRing *ring);
void       g_ring_free_1           (GRing *ring);

GRing *    g_ring_append           (GRing *  head,
				    gpointer data);

GRing *    g_ring_prepend          (GRing *  head,
				    gpointer data);

GRing *    g_ring_insert           (GRing *  head,
				    gpointer data,
				    gint     position);

GRing *    g_ring_insert_sorted    (GRing *          head,
				    gpointer         data,
				    GCompareDataFunc func,
				    gpointer         user_data);

GRing *    g_ring_concat           (GRing *head1,
				    GRing *head2);

GRing *    g_ring_remove           (GRing *       head,
				    gconstpointer data);

GRing *    g_ring_remove_all       (GRing *       head,
				    gconstpointer data);

GRing *    g_ring_remove_link      (GRing *head,
				    GRing *ring);
GRing *    g_ring_delete_link      (GRing *head,
				    GRing *ring);
GRing *    g_ring_reverse          (GRing *head);
GRing *    g_ring_copy             (GRing *head);

GRing *    g_ring_nth              (GRing *ring,
				    guint  n);
GRing *    g_ring_nth_prev         (GRing *head,
				    guint  n);

GRing *    g_ring_find             (GRing *       head,
				    gconstpointer data);
GRing *    g_ring_find_nearby      (GRing *       head,
				    gconstpointer data);

GRing *    g_ring_find_custom        (GRing *      head,
				      GCompareFunc func,
				      gpointer     user_data);
GRing *    g_ring_find_nearby_custom (GRing *       head,
				      GCompareFunc  func,
				      gpointer      user_data);

gint       g_ring_position         (GRing *head,
				    GRing *ring);

gint       g_ring_index            (GRing *       head,
				    gconstpointer data);

#define    g_ring_first(head)      (head)
#define    g_ring_last(head)       ((head)->prev)

guint      g_ring_length           (GRing *head);

void       g_ring_foreach          (GRing ** head,
				    GFunc    func,
				    gpointer user_data);

GRing *    g_ring_sort             (GRing *      head,
				    GCompareFunc compare_func);

GRing *    g_ring_sort_with_data   (GRing *          head,
				    GCompareDataFunc compare_func,
				    gpointer         user_data);

gpointer   g_ring_nth_data         (GRing * ring,
				    guint   n);

/* GQueue look-alike */
gpointer   g_ring_pop_head         (GRing **head);
gpointer   g_ring_pop_tail         (GRing **head);


/* works for GList too :-) */
#define    g_ring_prev(head, ring) ((ring)->prev != (head)? (ring)->prev : NULL)
#define    g_ring_next(head, ring) ((ring)->next != (head)? (ring)->next : NULL)

// G_END_DECLS

#endif  /* __G_RING_H__ */
/* GLIB - Library of useful routines for C programming
 * Copyright (C) 2001 Joshua Nathaniel Pritikin and Tim Janik
 *
 * 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 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.
 */

#include "gring.h"

/* Description

The #GRing structure is a doubly-linked list data structure,
very similar to #GList.

Each element in the ring contains a piece of data, together with
pointers which link to the previous and next elements in the ring.
Using these pointers it is possible to move through the ring in both
directions (unlike the Singly-Linked Lists which only allows movement
through the list in the forward direction).

Ring elements are allocated in blocks by sharing GListAllocator with #GList.
This is more efficient than allocating elements individually.

Note that most of the #GRing functions expect to be passed a pointer
to the first element of the ring. The functions which insert elements
return the new start of the ring, which may have changed.

There is no function to create a GRing. NULL is considered to be an
empty ring so you simply initialize a GRing* to NULL.

In generally, the #GRing API mimics the #GList API.  You can almost
s/list/ring/g and your code will continue to work.  Some exceptions
are g_ring_find_custom and g_ring_foreach, which take slightly
different parameters.  You must also be sure to use the g_ring_next /
g_ring_prev macros for ring traversal.

#GRing also supplies the necessary functions to replace #GQueue, which
is now deprecated.  Both g_ring_append and g_ring_prepend are O(1),
and g_ring_pop_(head|tail) offer data removal matching the style of
queues.

*/

/**
 * g_ring_free:
 * @ring: a #GRing.
 *
 * Frees all the memory used by a #GRing.
 *
 * Note: If list elements contain dynamically-allocated memory, they
 * should be freed first.
 **/
void
g_ring_free (GRing *ring)
{
  if (!ring)
    return;

  ring->prev->next = 0;   /* finesse g_list_free [HACK] */

  g_list_free ((GList*) ring);
}

/**
 * g_ring_free_1:
 * @ring: a #GRing element.
 *
 * Frees one #GRing element.  It is usually used after g_ring_remove_link().
 **/
void
g_ring_free_1 (GRing *ring)
{
  ring->next->prev = ring->prev;
  ring->prev->next = ring->next;

  g_list_free_1 ((GList*) ring);
}

static inline GRing *
_g_ring_insert (GRing *    head,
		gpointer   data)
{
  GRing *ring = g_ring_alloc ();

  ring->data = data;

  if (!head)
    {
      ring->next = ring;
      ring->prev = ring;
    }
  else
    {
      ring->next = head;
      ring->prev = head->prev;
      ring->next->prev = ring;
      ring->prev->next = ring;
    }

  return ring;
}

/**
 * g_ring_append:
 * @head: a #GRing.
 * @data: the data for the new element.
 *
 * Adds a new element on to the end of the ring.
 *
 * Return value: the new head of the #GRing.
 **/
GRing *
g_ring_append (GRing *  head,
	       gpointer data)
{
  GRing *ring;

  ring = _g_ring_insert (head, data);

  return head? head : ring;
}

/**
 * g_ring_prepend:
 * @head: a #GRing.
 * @data: the data for the new element.
 *
 * Adds a new element on to the beginning of the ring.
 *
 * Return value: the new head of the #GRing.
 **/
GRing *
g_ring_prepend (GRing *  head,
		gpointer data)
{
  return _g_ring_insert (head, data);
}

/**
 * g_ring_insert
 * @head: a #GRing.
 * @data: the data for the new element.
 * @position: the position to insert the element.  If negative or larger than
 * the length of the list then the new element is added on to the end of the
 * list.
 *
 * Inserts a new element into the list at the given position.
 *
 * Return value: the new head of the #GRing.
 **/
GRing *
g_ring_insert (GRing *  head,
	       gpointer data,
	       gint     position)
{
  GRing *ring;
  GRing *ready;

  if (position < 0)
    return g_ring_append (head, data);
  else if (position == 0)
    return g_ring_prepend (head, data);

  ring = g_ring_nth (head, position);
  if (!ring)
    return g_ring_append (head, data);

  ready = _g_ring_insert (ring, data);

  return head == ring? ready : head;
}

/**
 * g_ring_insert_sorted:
 * @head: a #GRing
 * @data: the data for the new element.
 * @func: the function to compare elements in the list.  It's return value should follow the same protocol as strcmp().
 * @user_data: user data passed to the function.
 *
 * Inserts a new element into the list using the given comparison function to
 * determine the appropriate position.
 *
 * Return value: the new head of the #GRing
 **/
GRing *
g_ring_insert_sorted (GRing *head,
		      gpointer data,
		      GCompareDataFunc func,
		      gpointer user_data)
{
  GRing *ring;
  gint cmp;

  g_return_val_if_fail (func, head);

  if (!head)
    {
      ring = g_ring_alloc ();

      ring->data = data;
      ring->next = ring;
      ring->prev = ring;

      return ring;
    }

  cmp = (*func) (data, head->data, user_data);

  if (cmp < 0)
    return _g_ring_insert (head, data);

  ring = head;

  while (ring->next != head && cmp > 0)
    {
      ring = ring->next;
      cmp = (*func) (data, ring->data, user_data);
    }

  if (cmp > 0)
    _g_ring_insert (ring->next, data);
  else
    _g_ring_insert (ring, data);

  return head;
}

/**
 * g_ring_concat:
 * @ring1: a #GRing
 * @ring2: the #GRing to add to the end of the first #GRing.
 *
 * Adds the second #GRing onto the end of the first #GRing.  The elements of
 * the second #GRing are not copied. They are used directly.
 *
 * Return value: the new head of the #GRing
 **/
GRing *
g_ring_concat (GRing *head1,
	       GRing *head2)
{
  GRing *tail1, *tail2;
 
  if (!head1)
    return head2;
  if (!head2)
    return head1;

  tail1 = head1->prev;
  tail2 = head2->prev;
  head1->prev = tail2;
  tail2->next = head1;
  head2->prev = tail1;
  tail1->next = head2;
 
  return head1;
}

GRing *
g_ring_remove (GRing *       head,
	       gconstpointer data)
{
  GRing *ring;

  if (!head)
    return NULL;

  for (ring = head; ring; ring = g_ring_next (head, ring))
    {
      if (ring->data != data)
	continue;

      if (ring == head)
	head = (ring == ring->next)? NULL : ring->next;

      g_ring_free_1 (ring);
      
      break;
    }
  
  return head;
}

GRing *
g_ring_remove_all (GRing *       head,
		   gconstpointer data)
{
  GRing *ring;

  if (!head)
    return NULL;

  ring = head;

  do {
    GRing *next = ring->next;

    if (ring->data == data)
      {
	if (ring == head)
	  head = (ring == ring->next)? NULL : ring->next;
	
	g_ring_free_1 (ring);
      }

    ring = next;

  } while (ring != head);
  
  return head;
}

// head == NULL is OK
//
GRing *
g_ring_remove_link (GRing *head,
		    GRing *ring)
{
  if (!ring)
    return head;

  if (ring == head)
    head = ring == ring->next? NULL : ring->next;

  ring->next->prev = ring->prev;
  ring->prev->next = ring->next;

  ring->next = ring->prev = ring;

  return head;
}

GRing *
g_ring_delete_link (GRing *head,
		    GRing *ring)
{
  head = g_ring_remove_link (head, ring);
  g_list_free_1 ((GList*) ring);
  return head;
}

GRing *
g_ring_reverse (GRing *head)
{
  GRing *last, *ring;

  if (!head || head == head->next)
    return head;

  last = head;

  do
    {
      ring = head;
      head = ring->next;
      ring->next = ring->prev;
      ring->prev = head;
    }
  while (ring->prev != last);

  return last->next;
}

GRing *
g_ring_copy (GRing *head)
{
  GRing *copy;
  GRing *ring;
  
  if (!head)
    return 0;

  copy = NULL;
  for (ring = head; ring; ring = g_ring_next (head, ring))
    {
      copy = g_ring_append (copy, ring->data);
    }

  return copy;
}

GRing *
g_ring_nth (GRing *ring,
	    guint  n)
{
  GRing *head;

  head = ring;

  while ((n-- > 0))
    {
      ring = ring->next;

      if (ring == head)
	return NULL;
    }
  
  return ring;
}

GRing *
g_ring_nth_prev (GRing *ring,
		 guint  n)
{
  GRing *head;

  head = ring;

  while ((n-- > 0))
    {
      ring = ring->prev;

      if (ring == head)
	return NULL;
    }
  
  return ring;
}

GRing *
g_ring_find (GRing *       head,
	     gconstpointer data)
{
  GRing *ring;

  for (ring = head; ring; ring = g_ring_next (head, ring))
    {
      if (ring->data == data)
	return ring;
    }

  return NULL;
}

GRing *
g_ring_find_nearby (GRing *       head,
		    gconstpointer data)
{
  GRing *fwd, *bck;

  if (!head)
    return NULL;

  if (head->data == data)
    return head;

  if (head->next == head)
    return NULL;

  fwd = head->next;
  bck = head->prev;

  while (1)
    {
      if (fwd->data == data)
	return fwd;

      if (fwd == bck)
	return NULL;
      
      if (bck->data == data)
	return bck;
      
      fwd = fwd->next;
      
      if (fwd == bck)
	return NULL;
      
      bck = bck->prev;
    }

  return NULL;
}

/**
 * g_ring_find_custom:
 * @head: a #GRing
 * @func: the function to call for each link.  It should return 0 when the desired link is found.
 * @user_data: user data passed to the function.
 *
 * Finds an link in a #GRing using a supplied function to test for the desired element.
 * It iterates over the list, calling the given function which should return 0 when the
 * desired element is found. The function takes two gpointer arguments, the #GRing
 * link's data and the given user data.
 *
 * Return value: the found #GRing or NULL
 **/
GRing *
g_ring_find_custom (GRing *      head,
		    GCompareFunc func,
		    gpointer     user_data)
{
  GRing *ring;

  g_return_val_if_fail (func != NULL, NULL);

  if (!head)
    return NULL;

  for (ring = head; ring; ring = g_ring_next (head, ring))
    {
      if (! (*func) (ring->data, user_data))
	return ring;
    }
  
  return NULL;
}

GRing *
g_ring_find_nearby_custom (GRing *       head,
			   GCompareFunc  func,
			   gpointer      user_data)
{
  GRing *fwd, *bck;

  g_return_val_if_fail (func != NULL, NULL);

  if (!head)
    return NULL;

  if (! (*func) (head->data, user_data))
    return head;

  if (head->next == head)
    return NULL;

  fwd = head->next;
  bck = head->prev;

  while (1)
    {
      if (! (*func) (fwd->data, user_data))
	return fwd;

      if (fwd == bck)
	return NULL;
      
      if (! (*func) (bck->data, user_data))
	return bck;
      
      fwd = fwd->next;
      
      if (fwd == bck)
	return NULL;
      
      bck = bck->prev;
    }

  return NULL;
}

/**
 * g_ring_position:
 * @head: a #GRing.
 * @ring: an element in the #GRing.
 *
 * Gets the position of the given element in the #GRing (starting from 0).
 *
 * Return value: the position of the element in the #GRing or
 * -1 if the element is not found.
 **/
gint
g_ring_position (GRing *head,
		 GRing *ring)
{
  GRing *iter;
  gint ix=0;

  for (iter = head; iter; iter = g_ring_next (head, iter))
    {
      if (iter == ring) return ix;
      ++ix;
    }

  return -1;
}

/**
 * g_ring_index:
 * @head: a #GRing.
 * @data: the data to find.
 *
 * Gets the position of the element containing the given data (starting from 0).
 *
 * Return value: the index of the element containing the data or
 * -1 if the data is not found.
 **/
gint
g_ring_index (GRing *       head,
	      gconstpointer data)
{
  GRing *iter;
  gint ix=0;

  for (iter = head; iter; iter = g_ring_next (head, iter))
    {
      if (iter->data == data) return ix;
      ++ix;
    }

  return -1;
}

/**
 * g_ring_length:
 * @head: a #GRing
 *
 * Gets the number of links in the ring by traversing the whole ring.
 *
 * Return value: the number of links in the ring
 **/
guint
g_ring_length (GRing *head)
{
  GRing *ring;
  guint length;
 
  if (!head)
    return 0;

  ring = head;
  length = 0;

  do
    {
      ++length;
      ring = ring->next;
    }
  while (ring != head);
 
  return length;
}

/**
 * g_ring_foreach:
 * @head: a pointer to a #GRing.
 * @func: the function to call with each ring's data
 * @user_data: user data to pass to the function
 *
 * Calls a function for each element of a #GRing.
 *
 * It is permissible to modify the ring during traversal.  However, you
 * must carefully check your code against the implementation of g_ring_foreach.
 * Modifications may cause elements to be skipped or visited twice.
 * The safest approach is to do any modifications outside of the
 * g_ring_foreach callback.
 *
 **/
void
g_ring_foreach (GRing ** head,
		GFunc    func,
		gpointer user_data)
{
  GRing *ring = *head;

  if (!ring)
    return;

  do
    {
      GRing *next = ring->next;
      (*func) (ring->data, user_data);
      ring = next;
    }
  while (ring != *head);
}

GRing     *g_ring_sort             (GRing *head, GCompareFunc compare_func)
{
  g_error("not implemented");
}

GRing     *g_ring_sort_with_data   (GRing           *head,
				    GCompareDataFunc compare_func,
				    gpointer         user_data)
{
  g_error ("not implemented");
}

/**
 * g_ring_nth_data:
 * @head: a #GRing.
 * @n: the position of the element.
 *
 * Gets the data of the element at the given position.
 *
 * Return value: the element's data or NULL if the position is off the end
 * of the #GRing.
 **/
gpointer
g_ring_nth_data (GRing *head,
		 guint  n)
{
  GRing *ring;

  ring = head;

  while ((n-- > 0))
    {
      ring = ring->next;

      if (ring == head)
	return NULL;
    }
  
  return ring->data;
}

gpointer
g_ring_pop_head (GRing **head)
{
  gpointer data;
 
  g_return_val_if_fail (head != NULL, NULL);
 
  if (!*head)
    return NULL;

  data = (*head)->data;
  *head = g_ring_delete_link (*head, *head);
 
  return data;
}

gpointer
g_ring_pop_tail (GRing **head)
{
  gpointer data;
 
  g_return_val_if_fail (head != NULL, NULL);
 
  if (!*head)
    return NULL;

  data = (*head)->prev->data;
  *head = g_ring_delete_link (*head, (*head)->prev);
 
  return data;
}

/* GLIB - Library of useful routines for C programming
 * Copyright (C) 2001 Joshua Nathaniel Pritikin
 *
 * 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 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.
 */

#undef G_LOG_DOMAIN

#ifdef GLIB_COMPILATION
#undef GLIB_COMPILATION
#endif

#include <stdlib.h>
#include <stdio.h>
#include "gring.h"

#define	TEST(cond)	G_STMT_START { gboolean failed = !(cond); \
if (failed) \
  g_print ("\n(%s:%d) failed for: %s\n", __FILE__, __LINE__, ( # cond )); \
else \
  g_print ("."); fflush (stdout); \
} G_STMT_END

void walk_signature(gpointer list, GString *sig)   // GList or GRing
{
  GList *elem;

  g_string_assign(sig, "");

  for (elem=list; elem; elem = g_ring_next(list, elem))
    g_string_append(sig, elem->data);
}

gboolean match_list(GRing *rhead, GList *lhead)
{
  static GString *sig1=0;
  static GString *sig2=0;

  if (!sig1) {
    sig1 = g_string_new(0);
    sig2 = g_string_new(0);
  }

  walk_signature(rhead, sig1);
  walk_signature(lhead, sig2);

  //g_print("%s =? %s\n", sig1->str, sig2->str);

  return strcmp(sig1->str, sig2->str) == 0;
}

gint
_str_compare(const gchar *s1, const gchar *s2)
{ return strcmp(s1,s2); }

gint
_elem_compare(gpointer d1, gpointer d2)
{ return d1 - d2; }

void
_sum (gchar *data, gint *sum)
{
  *sum += atoi(data);
}

#define NUM_TDATA 36
static char *tdata[NUM_TDATA] = {
  "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
  "a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
  "k", "l", "m", "n", "o", "p", "q", "r", "s", "t",
  "u", "v", "w", "x", "y", "z"
};

int main() {
  GRing *ring=0;
  GList *list=0;
  GRing *ring1;
  GList *list1;
  gint xx;
  gint tx;
  gint sum1, sum2;

  for (xx=0; xx < 5; xx++) {
    ring = g_ring_append(ring, tdata[xx]);
    list = g_list_append(list, tdata[xx]);
  }

  for (xx=0; xx < 6; xx++) {
    GRing *rx;
    GList *lx;

    rx = g_ring_nth (ring, xx);
    lx = g_list_nth (list, xx);
    TEST((rx==0 && lx==0) || rx->data == lx->data);

    rx = g_ring_nth_prev (g_ring_last(ring), xx);
    lx = g_list_nth_prev (g_list_last(list), xx);
    TEST((rx==0 && lx==0) || rx->data == lx->data);
  }

  TEST(match_list(ring, list));
  
  g_ring_free(ring);
  g_list_free(list);
  ring = NULL;
  list = NULL;

  for (xx=0; xx < 5; xx++) {
    ring = g_ring_prepend(ring, tdata[xx]);
    list = g_list_prepend(list, tdata[xx]);
  }

  TEST(match_list(ring, list));
  
  TEST (g_ring_find_nearby (ring, NULL) == NULL);

  for (ring1=ring; ring1; ring1 = g_ring_next (ring, ring1)) {
    TEST (g_ring_find_nearby (ring, ring1->data) == ring1);
  }

  ring = g_ring_prepend(ring, tdata[6]);
  list = g_list_prepend(list, tdata[6]);

  for (ring1=ring; ring1; ring1 = g_ring_next (ring, ring1)) {
    TEST (g_ring_find_nearby (ring, ring1->data) == ring1);
  }

  ring = g_ring_remove(ring, tdata[2]);
  list = g_list_remove(list, tdata[2]);
  ring = g_ring_remove(ring, tdata[8]);
  list = g_list_remove(list, tdata[8]);

  TEST(match_list(ring, list));

  ring = g_ring_remove_link(ring, NULL);
  list = g_list_remove_link(list, NULL);

  ring1 = ring;
  list1 = list;
  ring = g_ring_remove_link(ring, ring1);
  list = g_list_remove_link(list, list1);
  ring = g_ring_remove_link(ring, ring1);
  list = g_list_remove_link(list, list1);
  g_ring_free_1(ring1);
  g_list_free_1(list1);
  
  TEST(match_list(ring, list));

  g_ring_free(ring);
  g_list_free(list);
  ring = NULL;
  list = NULL;

  tx=0;
  for (xx=0; xx < 2; xx++) {
    ring = g_ring_insert(ring, tdata[tx], -1);
    list = g_list_insert(list, tdata[tx++], -1);

    ring = g_ring_insert(ring, tdata[tx], 0);
    list = g_list_insert(list, tdata[tx++], 0);
    
    ring = g_ring_insert(ring, tdata[tx], 1);
    list = g_list_insert(list, tdata[tx++], 1);

    ring = g_ring_insert(ring, tdata[tx], 2);
    list = g_list_insert(list, tdata[tx++], 2);

    ring = g_ring_insert(ring, tdata[tx], 100);
    list = g_list_insert(list, tdata[tx++], 100);
  }
  
  TEST(match_list(ring, list));
  
  g_ring_free(ring);
  g_list_free(list);
  ring = NULL;
  list = NULL;

  ring = g_ring_insert_sorted (ring, tdata[4], (GCompareDataFunc) _str_compare, NULL);
  list = g_list_insert_sorted (list, tdata[4], (GCompareFunc) _str_compare);

  ring = g_ring_insert_sorted (ring, tdata[5], (GCompareDataFunc) _str_compare, NULL);
  list = g_list_insert_sorted (list, tdata[5], (GCompareFunc) _str_compare);

  ring = g_ring_insert_sorted (ring, tdata[3], (GCompareDataFunc) _str_compare, NULL);
  list = g_list_insert_sorted (list, tdata[3], (GCompareFunc) _str_compare);

  ring = g_ring_insert_sorted (ring, tdata[5], (GCompareDataFunc) _str_compare, NULL);
  list = g_list_insert_sorted (list, tdata[5], (GCompareFunc) _str_compare);

  ring = g_ring_insert_sorted (ring, tdata[6], (GCompareDataFunc) _str_compare, NULL);
  list = g_list_insert_sorted (list, tdata[6], (GCompareFunc) _str_compare);

  ring = g_ring_insert_sorted (ring, tdata[8], (GCompareDataFunc) _str_compare, NULL);
  list = g_list_insert_sorted (list, tdata[8], (GCompareFunc) _str_compare);

  ring = g_ring_insert_sorted (ring, tdata[7], (GCompareDataFunc) _str_compare, NULL);
  list = g_list_insert_sorted (list, tdata[7], (GCompareFunc) _str_compare);

  sum1 = sum2 = 0;
  g_ring_foreach(&ring, (GFunc) _sum, &sum1);
  g_list_foreach(list, (GFunc) _sum, &sum2);
  TEST (sum1 == sum2);

  TEST (match_list(ring, list));
  
  TEST (g_ring_find (ring, tdata[20]) == NULL);
  TEST (g_list_find (list, tdata[20]) == NULL);

  TEST (g_ring_find (ring, tdata[7])->data == tdata[7]);
  TEST (g_list_find (list, tdata[7])->data == tdata[7]);

  // API difference XXX
  TEST (g_ring_find_custom (ring, (GCompareFunc) _elem_compare, tdata[20]) == NULL);
  TEST (g_list_find_custom (list, tdata[20], (GCompareFunc) _elem_compare) == NULL);

  TEST (g_ring_find_custom (ring, (GCompareFunc) _elem_compare, tdata[7])->data == tdata[7]);
  TEST (g_list_find_custom (list, tdata[7], (GCompareFunc) _elem_compare)->data == tdata[7]);

  TEST (g_ring_index (ring, tdata[7]) ==
	g_list_index (list, tdata[7]));
  TEST (g_ring_index (ring, tdata[20]) ==
	g_list_index (list, tdata[20]));

  TEST (g_ring_position (ring, ring->prev) ==
	g_list_position (list, g_list_last(list)));
  TEST (g_ring_position (ring, 0) ==
	g_list_position (list, 0));

  TEST (g_ring_length (ring) ==
	g_list_length (list));
  TEST (g_ring_length (0) ==
	g_list_length (0));

  ring = g_ring_reverse (ring);
  list = g_list_reverse (list);

  TEST(match_list(ring, list));

  ring = g_ring_reverse (ring);
  list = g_list_reverse (list);

  ring1 = NULL;
  list1 = NULL;
  ring1 = g_ring_append (ring1, tdata[10]);
  list1 = g_list_append (list1, tdata[10]);
  ring1 = g_ring_append (ring1, tdata[11]);
  list1 = g_list_append (list1, tdata[11]);

  ring = g_ring_concat (ring, ring1);
  list = g_list_concat (list, list1);

  TEST(match_list(ring, list));

  ring1 = g_ring_copy (ring);

  TEST(match_list(ring, ring1));

  g_ring_free (ring1);

  ring = g_ring_remove_all (ring, tdata[5]);
  list = g_list_remove_all (list, tdata[5]);

  TEST(match_list(ring, list));

  ring = g_ring_delete_link (ring, ring);
  list = g_list_delete_link (list, list);

  TEST(match_list(ring, list));

  while (ring)
    ring = g_ring_delete_link (ring, ring);
  while (list)
    list = g_list_delete_link (list, list);

  g_print("\n");

  return 0;
}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]