r3926 - in trunk: . sfi sfi/tests



Author: timj
Date: 2006-10-03 11:28:27 -0400 (Tue, 03 Oct 2006)
New Revision: 3926

Added:
   trunk/sfi/sfiring.c
   trunk/sfi/sfiring.h
   trunk/sfi/tests/
   trunk/sfi/tests/Makefile.am
   trunk/sfi/tests/dummy.cc
   trunk/sfi/tests/ring.c
Modified:
   trunk/configure.in
   trunk/sfi/ChangeLog
   trunk/sfi/Makefile.am
   trunk/sfi/sfi.h
   trunk/sfi/sficomport.h
   trunk/sfi/sficomwire.h
   trunk/sfi/sfifilecrawler.h
   trunk/sfi/sfiglue.h
   trunk/sfi/sfiprimitives.c
   trunk/sfi/sfiprimitives.h
   trunk/sfi/sfistore.h
   trunk/sfi/sfitime.c
   trunk/sfi/sfitypes.h
Log:
Tue Oct  3 17:21:08 2006  Tim Janik  <timj gtk org>

        * sfiring.h, sfiring.c: moved BirnetRing here, renamed to Sfi.

        * sfiprimitives.h, sfiprimitives.c: removed obsolete Ring code.

        * tests/ring.c: test SfiRing thoroughly.
        moved here from birnet/tests/ring.cc, renamed to use SfiRing.

        * tests/Makefile.am:
        * Makefile.am: build and integrate sfi/tests/.




Modified: trunk/configure.in
===================================================================
--- trunk/configure.in	2006-10-03 11:19:35 UTC (rev 3925)
+++ trunk/configure.in	2006-10-03 15:28:27 UTC (rev 3926)
@@ -597,6 +597,7 @@
 birnet/Makefile
 birnet/tests/Makefile
 sfi/Makefile
+sfi/tests/Makefile
 bse/bseconfig.h
 bse/Makefile
 bse/icons/Makefile

Modified: trunk/sfi/ChangeLog
===================================================================
--- trunk/sfi/ChangeLog	2006-10-03 11:19:35 UTC (rev 3925)
+++ trunk/sfi/ChangeLog	2006-10-03 15:28:27 UTC (rev 3926)
@@ -1,3 +1,15 @@
+Tue Oct  3 17:21:08 2006  Tim Janik  <timj gtk org>
+
+	* sfiring.h, sfiring.c: moved BirnetRing here, renamed to Sfi.
+
+	* sfiprimitives.h, sfiprimitives.c: removed obsolete Ring code.
+
+	* tests/ring.c: test SfiRing thoroughly.
+	moved here from birnet/tests/ring.cc, renamed to use SfiRing.
+
+	* tests/Makefile.am:
+	* Makefile.am: build and integrate sfi/tests/.
+
 Fri Jul  7 02:10:42 2006  Tim Janik  <timj gtk org>
 
 	* sfifilecrawler.[hc]: removed sfi_file_check() and sfi_file_equals() 

Modified: trunk/sfi/Makefile.am
===================================================================
--- trunk/sfi/Makefile.am	2006-10-03 11:19:35 UTC (rev 3925)
+++ trunk/sfi/Makefile.am	2006-10-03 15:28:27 UTC (rev 3926)
@@ -4,6 +4,7 @@
 ## GNU Lesser General Public License version 2 or any later version.
 include $(top_srcdir)/Makefile.decl
 
+SUBDIRS   = . tests
 INCLUDES += -I$(top_srcdir) -I$(top_builddir) $(SFI_CFLAGS)
 DEFS     += -DG_LOG_DOMAIN=\"SFI\" -DG_DISABLE_CONST_RETURNS
 
@@ -13,7 +14,7 @@
 	sfivmarshal.h	sfiglue.h	sfigluecodec.h	sfiglueproxy.h	\
 	sfinote.h	sfiparams.h	sfiprimitives.h	sfiserial.h	\
 	sfitime.h	sfitypes.h	sfivalues.h	sfiustore.h	\
-	sficxx.hh			sfimemory.h	sficomport.h	\
+	sficxx.hh	sfiring.h	sfimemory.h	sficomport.h	\
 	sfi.h								\
 )
 sfi_all_sources = $(strip \
@@ -22,7 +23,7 @@
 	sfivmarshal.c	sfiglue.c	sfigluecodec.c	sfiglueproxy.c	\
 	sfinote.c	sfiparams.c	sfiprimitives.c	sfiserial.c	\
 	sfitime.c	sfitypes.c	sfivalues.c	sfiustore.c	\
-	sficxx.cc			sfimemory.c	sficomport.c	\
+	sficxx.cc	sfiring.c	sfimemory.c	sficomport.c	\
 	$(conditional_toyprof_sources)	\
 )
 sfi_extra_sources = $(strip \

Modified: trunk/sfi/sfi.h
===================================================================
--- trunk/sfi/sfi.h	2006-10-03 11:19:35 UTC (rev 3925)
+++ trunk/sfi/sfi.h	2006-10-03 15:28:27 UTC (rev 3926)
@@ -29,6 +29,7 @@
 #include <sfi/sfinote.h>
 #include <sfi/sfiparams.h>
 #include <sfi/sfiprimitives.h>
+#include <sfi/sfiring.h>
 /* #include <sfi/sfisclock.h> */
 #include <sfi/sfiserial.h>
 /* no bin-compat: #include <sfi/sfistore.h> */

Modified: trunk/sfi/sficomport.h
===================================================================
--- trunk/sfi/sficomport.h	2006-10-03 11:19:35 UTC (rev 3925)
+++ trunk/sfi/sficomport.h	2006-10-03 15:28:27 UTC (rev 3926)
@@ -20,6 +20,7 @@
 #define __SFI_COM_PORT_H__
 
 #include <sfi/sfitypes.h>
+#include <sfi/sfiring.h>
 
 G_BEGIN_DECLS
 

Modified: trunk/sfi/sficomwire.h
===================================================================
--- trunk/sfi/sficomwire.h	2006-10-03 11:19:35 UTC (rev 3925)
+++ trunk/sfi/sficomwire.h	2006-10-03 15:28:27 UTC (rev 3926)
@@ -20,6 +20,7 @@
 #define __SFI_COM_WIRE_H__
 
 #include <sfi/sfitypes.h>
+#include <sfi/sfiring.h>
 
 #ifdef __cplusplus
 extern "C" {

Modified: trunk/sfi/sfifilecrawler.h
===================================================================
--- trunk/sfi/sfifilecrawler.h	2006-10-03 11:19:35 UTC (rev 3925)
+++ trunk/sfi/sfifilecrawler.h	2006-10-03 15:28:27 UTC (rev 3926)
@@ -20,6 +20,7 @@
 #define __SFI_FILE_CRAWLER_H__
 
 #include <sfi/sfitypes.h>
+#include <sfi/sfiring.h>
 
 G_BEGIN_DECLS
 

Modified: trunk/sfi/sfiglue.h
===================================================================
--- trunk/sfi/sfiglue.h	2006-10-03 11:19:35 UTC (rev 3925)
+++ trunk/sfi/sfiglue.h	2006-10-03 15:28:27 UTC (rev 3926)
@@ -20,6 +20,7 @@
 #define __SFI_GLUE_H__
 
 #include <sfi/sfiprimitives.h>
+#include <sfi/sfiring.h>
 #include <sfi/sfiparams.h>
 
 G_BEGIN_DECLS

Modified: trunk/sfi/sfiprimitives.c
===================================================================
--- trunk/sfi/sfiprimitives.c	2006-10-03 11:19:35 UTC (rev 3925)
+++ trunk/sfi/sfiprimitives.c	2006-10-03 15:28:27 UTC (rev 3926)
@@ -1311,996 +1311,3 @@
     return sfi_value_get_proxy (v);
   return 0;
 }
-
-
-/* --- basic comparisons --- */
-gint
-sfi_pointer_cmp (gconstpointer   value1,
-                 gconstpointer   value2,
-                 gpointer        dummy)
-{
-  const char *p1 = value1;
-  const char *p2 = value2;
-  return p1 < p2 ? -1 : p1 != p2;
-}
-
-
-/* --- ring (circular-list) --- */
-static inline SfiRing*
-sfi_ring_prepend_link_i (SfiRing *head,
-			 SfiRing *ring)
-{
-  if (!head)
-    {
-      ring->prev = ring;
-      ring->next = ring;
-    }
-  else
-    {
-      ring->prev = head->prev;
-      ring->next = head;
-      head->prev->next = ring;
-      head->prev = ring;
-    }
-  return ring;
-}
-
-static inline SfiRing*
-sfi_ring_prepend_i (SfiRing *head,
-		    gpointer data)
-{
-  SfiRing *ring = sfi_new_struct (SfiRing, 1);
-  
-  ring->data = data;
-  return sfi_ring_prepend_link_i (head, ring);
-}
-
-static inline SfiRing*
-sfi_ring_append_link_i (SfiRing *head,
-			SfiRing *ring)
-{
-  sfi_ring_prepend_link_i (head, ring);
-  return head ? head : ring;
-}
-
-SfiRing*
-sfi_ring_prepend (SfiRing  *head,
-		  gpointer data)
-{
-  return sfi_ring_prepend_i (head, data);
-}
-
-SfiRing*
-sfi_ring_prepend_uniq (SfiRing  *head,
-		       gpointer data)
-{
-  SfiRing *ring;
-  for (ring = head; ring; ring = sfi_ring_walk (ring, head))
-    if (ring->data == data)
-      return head;
-  return sfi_ring_prepend_i (head, data);
-}
-
-SfiRing*
-sfi_ring_append (SfiRing *head,
-		 gpointer data)
-{
-  SfiRing *ring = sfi_ring_prepend_i (head, data);
-  return head ? head : ring;
-}
-
-SfiRing*
-sfi_ring_append_uniq (SfiRing *head,
-                      gpointer data)
-{
-  SfiRing *ring;
-  for (ring = head; ring; ring = sfi_ring_walk (ring, head))
-    if (ring->data == data)
-      return head;
-  ring = sfi_ring_prepend_i (head, data);
-  return head ? head : ring;
-}
-
-SfiRing*
-sfi_ring_insert_before (SfiRing        *head,
-                        SfiRing        *sibling,
-                        gpointer        data)
-{
-  if (!sibling)
-    return sfi_ring_append (head, data);
-  SfiRing *node = sfi_ring_prepend (sibling, data);
-  return sibling == head ? node : head;
-}
-
-SfiRing*
-sfi_ring_insert (SfiRing *head,
-                 gpointer data,
-                 gint     position)
-{
-  if (position < 0)
-    return sfi_ring_append (head, data);
-  else if (position == 0)
-    return sfi_ring_prepend (head, data);
-  SfiRing *node = sfi_ring_nth (head, position);
-  if (node)
-    return sfi_ring_insert_before (head, node, data);
-  else
-    return sfi_ring_append (head, data);
-}
-
-gint
-sfi_ring_position (const SfiRing  *head,
-                   const SfiRing  *node)
-{
-  guint i = 0;
-  const SfiRing *ring;
-  for (ring = head; ring; ring = sfi_ring_walk (ring, head), i++)
-    if (ring == node)
-      return i;
-  return -1;
-}
-
-gint
-sfi_ring_index (const SfiRing *head,
-                gconstpointer  data)
-{
-  guint i = 0;
-  const SfiRing *ring;
-  for (ring = head; ring; ring = sfi_ring_walk (ring, head), i++)
-    if (ring->data == data)
-      return i;
-  return -1;
-}
-
-SfiRing*
-sfi_ring_copy (const SfiRing *head)
-{
-  const SfiRing *walk;
-  SfiRing *dest = NULL;
-  for (walk = head; walk; walk = sfi_ring_walk (walk, head))
-    dest = sfi_ring_append (dest, walk->data);
-  return dest;
-}
-
-SfiRing*
-sfi_ring_copy_deep (const SfiRing  *head,
-		    SfiRingDataFunc copy,
-		    gpointer        func_data)
-{
-  const SfiRing *walk;
-  SfiRing *dest = NULL;
-  for (walk = head; walk; walk = sfi_ring_walk (walk, head))
-    dest = sfi_ring_append (dest, copy (walk->data, func_data));
-  return dest;
-}
-
-SfiRing*
-sfi_ring_copy_rest (const SfiRing *ring,
-                    const SfiRing *head)
-{
-  const SfiRing *walk;
-  SfiRing *dest = NULL;
-  for (walk = ring; walk; walk = sfi_ring_walk (walk, head))
-    dest = sfi_ring_append (dest, walk->data);
-  return dest;
-}
-
-SfiRing*
-sfi_ring_concat (SfiRing *head1,
-		 SfiRing *head2)
-{
-  SfiRing *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;
-}
-
-/**
- * @param head1	a non-empty ring
- * @param head2	a ring node different from @a head1 contained in @a head1
- * @param returns	@a head2 for convenience
- *
- * Split a ring into two parts, starting the second ring with @a head2.
- * @a head2 must therefore be non-NULL and must be contained in the ring
- * formed by @a head1.
- */
-SfiRing*
-sfi_ring_split (SfiRing *head1,
-		SfiRing *head2)
-{
-  SfiRing *tail1, *tail2;
-
-  g_return_val_if_fail (head1 != NULL, NULL);
-  g_return_val_if_fail (head2 != NULL, NULL);
-  g_return_val_if_fail (head1 != head2, NULL);
-
-  tail1 = head2->prev;
-  tail2 = head1->prev;
-  head2->prev = tail2;
-  tail2->next = head2;
-  head1->prev = tail1;
-  tail1->next = head1;
-  return head2;
-}
-
-static inline SfiRing*
-sfi_ring_unlink_node_dangling (SfiRing *head,
-                               SfiRing *node)
-{
-  g_assert (head && node);
-  /* special case one item ring */
-  if (head->prev == head)
-    return NULL;
-  /* unlink */
-  node->next->prev = node->prev;
-  node->prev->next = node->next;
-  if (head == node)
-    head = node->next;
-  /* node->prev and node->next are dangling now */
-  return head;
-}
-
-SfiRing*
-sfi_ring_remove_node (SfiRing *head,
-		      SfiRing *node)
-{
-  if (!head)
-    g_return_val_if_fail (head == NULL && node == NULL, NULL);
-  if (!head || !node)
-    return NULL;
-  
-  /* special case one item ring */
-  if (head->prev == head)
-    {
-      g_return_val_if_fail (node == head, head);
-      
-      sfi_delete_struct (SfiRing, node);
-      return NULL;
-    }
-  g_return_val_if_fail (node != node->next, head); /* node can't be a one item ring here */
-  
-  node->next->prev = node->prev;
-  node->prev->next = node->next;
-  if (head == node)
-    head = node->next;
-  sfi_delete_struct (SfiRing, node);
-  
-  return head;
-}
-
-SfiRing*
-sfi_ring_reverse (SfiRing *head)
-{
-  if (head)
-    {
-      SfiRing *ring = head = head->prev;
-      do
-	{
-	  SfiRing *tmp = ring;
-	  ring = tmp->next;
-	  tmp->next = tmp->prev;
-	  tmp->prev = ring;
-	}
-      while (ring != head);
-    }
-  return head;
-}
-
-SfiRing*
-sfi_ring_remove (SfiRing *head,
-		 gpointer data)
-{
-  SfiRing *walk;
-
-  if (!head)
-    return NULL;
-  
-  /* make tail data removal an O(1) operation */
-  if (head->prev->data == data)
-    return sfi_ring_remove_node (head, head->prev);
-  
-  for (walk = head; walk; walk = sfi_ring_walk (walk, head))
-    if (walk->data == data)
-      return sfi_ring_remove_node (head, walk);
-  
-  /* g_warning (G_STRLOC ": couldn't find data item (%p) to remove from ring (%p)", data, head); */
-  
-  return head;
-}
-
-guint
-sfi_ring_length (const SfiRing *head)
-{
-  const SfiRing *ring;
-  guint i = 0;
-  
-  for (ring = head; ring; ring = sfi_ring_walk (ring, head))
-    i++;
-
-  return i;
-}
-
-gint    /* essentially compute length(ring) - test_length, clamped to -1..+1 */
-sfi_ring_cmp_length (const SfiRing *head,
-                     guint          test_length)
-{
-  const SfiRing *ring = head;
-
-  while (test_length && ring)
-    {
-      test_length--;
-      ring = sfi_ring_walk (ring, head);
-    }
-
-  return test_length > 0 ? -1 : ring != NULL;
-}
-
-SfiRing*
-sfi_ring_find (const SfiRing*head,
-	       gconstpointer data)
-{
-  const SfiRing *ring;
-  for (ring = head; ring; ring = sfi_ring_walk (ring, head))
-    if (ring->data == (gpointer) data)
-      return (SfiRing*) ring;
-  return NULL;
-}
-
-SfiRing*
-sfi_ring_nth (const SfiRing *head,
-	      guint          n)
-{
-  const SfiRing *ring = head;
-  while (n-- && ring)
-    ring = sfi_ring_walk (ring, head);
-  return (SfiRing*) ring;
-}
-
-gpointer
-sfi_ring_nth_data (const SfiRing *head,
-		   guint          n)
-{
-  const SfiRing *ring = head;
-
-  while (n-- && ring)
-    ring = sfi_ring_walk (ring, head);
-
-  return ring ? ring->data : NULL;
-}
-
-void
-sfi_ring_free_deep (SfiRing        *head,
-		    GDestroyNotify  data_destroy)
-{
-  while (head)
-    {
-      gpointer data = sfi_ring_pop_head (&head);
-      data_destroy (data);
-      data = sfi_ring_pop_head (&head);
-    }
-}
-
-void
-sfi_ring_free (SfiRing *head)
-{
-  if (head)
-    {
-      head->prev->next = NULL;
-      _sfi_free_node_list (head, sizeof (*head));
-    }
-}
-
-gpointer
-sfi_ring_pop_head (SfiRing **head_p)
-{
-  gpointer data;
-  
-  g_return_val_if_fail (head_p != NULL, NULL);
-  
-  if (!*head_p)
-    return NULL;
-  data = (*head_p)->data;
-  *head_p = sfi_ring_remove_node (*head_p, *head_p);
-  
-  return data;
-}
-
-gpointer
-sfi_ring_pop_tail (SfiRing **head_p)
-{
-  gpointer data;
-  
-  g_return_val_if_fail (head_p != NULL, NULL);
-  
-  if (!*head_p)
-    return NULL;
-  data = (*head_p)->prev->data;
-  *head_p = sfi_ring_remove_node (*head_p, (*head_p)->prev);
-  
-  return data;
-}
-
-SfiRing*
-sfi_ring_from_list (GList *list)
-{
-  SfiRing *ring = NULL;
-  for (; list; list = list->next)
-    ring = sfi_ring_append (ring, list->data);
-  return ring;
-}
-
-SfiRing*
-sfi_ring_from_list_and_free (GList *list)
-{
-  SfiRing *ring = NULL;
-  GList *free_list = list;
-  for (; list; list = list->next)
-    ring = sfi_ring_append (ring, list->data);
-  g_list_free (free_list);
-  return ring;
-}
-
-SfiRing*
-sfi_ring_from_slist (GSList *slist)
-{
-  SfiRing *ring = NULL;
-  for (; slist; slist = slist->next)
-    ring = sfi_ring_append (ring, slist->data);
-  return ring;
-}
-
-SfiRing*
-sfi_ring_from_slist_and_free (GSList *slist)
-{
-  SfiRing *ring = NULL;
-  GSList *free_slist = slist;
-  for (; slist; slist = slist->next)
-    ring = sfi_ring_append (ring, slist->data);
-  g_slist_free (free_slist);
-  return ring;
-}
-
-SfiRing*
-sfi_ring_insert_sorted (SfiRing	      *head,
-			gpointer       insertion_data,
-                        SfiCompareFunc cmp,
-                        gpointer       cmp_data)
-{
-  g_return_val_if_fail (cmp != NULL, head);
-  if (!head)
-    return sfi_ring_prepend (head, insertion_data);
-
-  /* implement stable sorting by inserting insertion_data *after* equal nodes */
-
-  if (cmp (insertion_data, head->data, cmp_data) >= 0)  /* insert after head */
-    {
-      SfiRing *tmp, *tail = head->prev;
-      
-      /* make appending an O(1) operation */
-      if (head == tail || cmp (insertion_data, tail->data, cmp_data) >= 0)
-	return sfi_ring_append (head, insertion_data);
-
-      /* walk forward while data >= tmp (skipping equal nodes) */
-      for (tmp = head->next; tmp != tail; tmp = tmp->next)
-	if (cmp (insertion_data, tmp->data, cmp_data) < 0)
-	  break;
-
-      /* insert before sibling which is greater than insertion_data */
-      sfi_ring_prepend (tmp, insertion_data); /* keep current head */
-      return head;
-    }
-  else /* cmp < 0 */
-    return sfi_ring_prepend (head, insertion_data);
-}
-
-SfiRing*
-sfi_ring_merge_sorted (SfiRing        *head1,
-		       SfiRing        *head2,
-                       SfiCompareFunc  cmp,
-                       gpointer        data)
-{
-  /* implement stable sorting by inserting head2 members *after* equal nodes from head1 */
-
-  if (head1 && head2)
-    {
-      SfiRing *tail1 = head1->prev;
-      SfiRing *tail2 = head2->prev;
-      SfiRing *tmp, *ring = NULL;
-      /* NULL terminate rings */
-      tail1->next = NULL;
-      tail2->next = NULL;
-      while (head1 && head2)
-	{
-	  gint c = cmp (head1->data, head2->data, data);
-	  if (c <= 0)
-	    {
-	      tmp = head1;
-	      head1 = head1->next;
-	    }
-	  else
-	    {
-	      tmp = head2;
-	      head2 = head2->next;
-	    }
-	  ring = sfi_ring_append_link_i (ring, tmp);
-	}
-      /* reform valid rings, concat sorted rest */
-      if (head1)
-	{
-	  tail1->next = head1;
-	  head1->prev = tail1;
-	  return sfi_ring_concat (ring, head1);
-	}
-      if (head2)
-	{
-	  tail2->next = head2;
-	  head2->prev = tail2;
-	  return sfi_ring_concat (ring, head2);
-	}
-      return ring;
-    }
-  else
-    return sfi_ring_concat (head1, head2);
-}
-
-SfiRing*
-sfi_ring_sort (SfiRing        *head,
-               SfiCompareFunc  cmp,
-               gpointer        data)
-{
-  g_return_val_if_fail (cmp != NULL, head);
-
-  /* stable sorting guaranteed by sfi_ring_merge_sorted() */
-
-  if (head && head->next != head)
-    {
-      SfiRing *ring, *tmp, *tail = head->prev;
-      /* find middle node to get log2 recursion depth */
-      ring = tmp = head->next;
-      while (tmp != tail && tmp->next != tail)
-	{
-	  ring = ring->next;
-	  tmp = tmp->next->next;
-	}
-      sfi_ring_split (head, ring);
-      return sfi_ring_merge_sorted (sfi_ring_sort (head, cmp, data),
-				    sfi_ring_sort (ring, cmp, data),
-				    cmp, data);
-    }
-  return head;
-}
-
-SfiRing* /* eliminates duplicate nodes */
-sfi_ring_uniq (SfiRing        *sorted_ring1,
-               SfiCompareFunc  cmp,
-               gpointer        data)
-{
-  /* always preserves the first of a sublist of consequtive equal elements */
-  SfiRing *r1 = sorted_ring1;
-  SfiRing *r2 = NULL;
-  if (r1)
-    {
-      SfiRing *last = r1;
-      r1 = sfi_ring_unlink_node_dangling (r1, last);
-      r2 = last->next = last->prev = last; /* form new ring */
-      while (r1)
-        {
-          SfiRing *node = r1;
-          r1 = sfi_ring_unlink_node_dangling (r1, node);
-          if (cmp (last->data, node->data, data))
-            {
-              last = node;
-              r2 = sfi_ring_append_link_i (r2, last);
-            }
-          else
-            sfi_delete_struct (SfiRing, node);
-        }
-    }
-  return r2;
-}
-
-SfiRing* /* eliminates duplicate nodes */
-sfi_ring_uniq_free_deep (SfiRing        *sorted_ring1,
-                         SfiCompareFunc  cmp,
-                         gpointer        data,
-                         GDestroyNotify  data_destroy)
-{
-  /* always preserves the first of a sublist of consequtive equal elements */
-  if (!data_destroy)
-    return sfi_ring_uniq (sorted_ring1, cmp, data);
-  SfiRing *r1 = sorted_ring1;
-  SfiRing *r2 = NULL;
-  if (r1)
-    {
-      SfiRing *last = r1;
-      r1 = sfi_ring_unlink_node_dangling (r1, last);
-      r2 = last->next = last->prev = last; /* form new ring */
-      while (r1)
-        {
-          SfiRing *node = r1;
-          r1 = sfi_ring_unlink_node_dangling (r1, node);
-          if (cmp (last->data, node->data, data))
-            {
-              last = node;
-              r2 = sfi_ring_append_link_i (r2, last);
-            }
-          else
-            {
-              data_destroy (node->data);
-              sfi_delete_struct (SfiRing, node);
-            }
-        }
-    }
-  return r2;
-}
-
-SfiRing* /* eliminates duplicate nodes */
-sfi_ring_copy_deep_uniq (const SfiRing  *sorted_ring1,
-                         SfiRingDataFunc copy,
-                         gpointer        copy_data,
-                         SfiCompareFunc  cmp,
-                         gpointer        cmp_data)
-{
-  /* always preserves the first of a sublist of consequtive equal elements */
-  if (!copy)
-    return sfi_ring_copy_uniq (sorted_ring1, cmp, cmp_data);
-  const SfiRing *r1 = sorted_ring1;
-  SfiRing *r2 = NULL;
-  if (r1)
-    {
-      gpointer last_data = r1->data;
-      r2 = sfi_ring_append (r2, copy (last_data, copy_data));
-      for (r1 = sfi_ring_walk (r1, sorted_ring1); r1; r1 = sfi_ring_walk (r1, sorted_ring1))
-        if (cmp (last_data, r1->data, cmp_data))
-          {
-            last_data = r1->data;
-            r2 = sfi_ring_append (r2, copy (last_data, copy_data));
-          }
-    }
-  return r2;
-}
-
-SfiRing* /* eliminates duplicate nodes */
-sfi_ring_copy_uniq (const SfiRing  *sorted_ring1,
-                    SfiCompareFunc  cmp,
-                    gpointer        data)
-{
-  /* always preserves the first of a sublist of consequtive equal elements */
-  const SfiRing *r1 = sorted_ring1;
-  SfiRing *r2 = NULL;
-  if (r1)
-    {
-      gpointer last_data = r1->data;
-      r2 = sfi_ring_append (r2, last_data);
-      for (r1 = sfi_ring_walk (r1, sorted_ring1); r1; r1 = sfi_ring_walk (r1, sorted_ring1))
-        if (cmp (last_data, r1->data, data))
-          {
-            last_data = r1->data;
-            r2 = sfi_ring_append (r2, last_data);
-          }
-    }
-  return r2;
-}
-
-SfiRing* /* merges rings without dups */
-sfi_ring_union (const SfiRing  *sorted_set1,
-                const SfiRing  *sorted_set2,
-                SfiCompareFunc  cmp,
-                gpointer        data)
-{
-  /* for two equal elements from both sets, the element from sorted_set1 is picked, the one from sorted_set2 discarded */
-  const SfiRing *r1 = sorted_set1, *r2 = sorted_set2;
-  SfiRing *d = NULL;
-  while (r1 && r2)
-    {
-      gint c = cmp (r1->data, r2->data, data);
-      if (c < 0)
-        {
-          d = sfi_ring_append (d, r1->data);
-          r1 = sfi_ring_walk (r1, sorted_set1);
-        }
-      else if (c > 0)
-        {
-          d = sfi_ring_append (d, r2->data);
-          r2 = sfi_ring_walk (r2, sorted_set2);
-        }
-      else
-        {
-          d = sfi_ring_append (d, r1->data);
-          r1 = sfi_ring_walk (r1, sorted_set1);
-          r2 = sfi_ring_walk (r2, sorted_set2);
-        }
-    }
-  return sfi_ring_concat (d, sfi_ring_copy_rest (r1 ? r1 : r2, r1 ? sorted_set1 : sorted_set2));
-}
-
-SfiRing* /* returns nodes contained in both rings */
-sfi_ring_intersection (const SfiRing  *sorted_set1,
-                       const SfiRing  *sorted_set2,
-                       SfiCompareFunc  cmp,
-                       gpointer        data)
-{
-  /* for two equal elements from both sets, only elements from sorted_set1 are picked */
-  const SfiRing *r1 = sorted_set1, *r2 = sorted_set2;
-  SfiRing *d = NULL;
-  while (r1 && r2)
-    {
-      gint c = cmp (r1->data, r2->data, data);
-      if (c < 0)
-        r1 = sfi_ring_walk (r1, sorted_set1);
-      else if (c > 0)
-        r2 = sfi_ring_walk (r2, sorted_set2);
-      else
-        {
-          d = sfi_ring_append (d, r1->data);
-          r1 = sfi_ring_walk (r1, sorted_set1);
-          r2 = sfi_ring_walk (r2, sorted_set2);
-        }
-    }
-  return d;
-}
-
-SfiRing* /* produces set1 without the elements of set2 */
-sfi_ring_difference (const SfiRing  *sorted_set1,
-                     const SfiRing  *sorted_set2,
-                     SfiCompareFunc  cmp,
-                     gpointer        data)
-{
-  const SfiRing *r1 = sorted_set1, *r2 = sorted_set2;
-  SfiRing *d = NULL;
-  while (r1 && r2)
-    {
-      gint c = cmp (r1->data, r2->data, data);
-      if (c < 0)
-        {
-          d = sfi_ring_append (d, r1->data);
-          r1 = sfi_ring_walk (r1, sorted_set1);
-        }
-      else if (c > 0)
-        r2 = sfi_ring_walk (r2, sorted_set2);
-      else
-        {
-          r1 = sfi_ring_walk (r1, sorted_set1);
-          r2 = sfi_ring_walk (r2, sorted_set2);
-        }
-    }
-  return sfi_ring_concat (d, sfi_ring_copy_rest (r1, sorted_set1));
-}
-
-SfiRing* /* prduces difference (set1, set2) + difference (set2, set1) */
-sfi_ring_symmetric_difference (const SfiRing  *sorted_set1,
-                               const SfiRing  *sorted_set2,
-                               SfiCompareFunc  cmp,
-                               gpointer        data)
-{
-  const SfiRing *r1 = sorted_set1, *r2 = sorted_set2;
-  SfiRing *d = NULL;
-  while (r1 && r2)
-    {
-      gint c = cmp (r1->data, r2->data, data);
-      if (c < 0)
-        {
-          d = sfi_ring_append (d, r1->data);
-          r1 = sfi_ring_walk (r1, sorted_set1);
-        }
-      else if (c > 0)
-        {
-          d = sfi_ring_append (d, r2->data);
-          r2 = sfi_ring_walk (r2, sorted_set2);
-        }
-      else
-        {
-          r1 = sfi_ring_walk (r1, sorted_set1);
-          r2 = sfi_ring_walk (r2, sorted_set2);
-        }
-    }
-  return sfi_ring_concat (d, sfi_ring_copy_rest (r1 ? r1 : r2, r1 ? sorted_set1 : sorted_set2));
-}
-
-static inline int
-pointerloccmp (const void *pp1,
-               const void *pp2)
-{
-  const gpointer *p1 = pp1;
-  const gpointer *p2 = pp2;
-  return *p1 < *p2 ? -1 : *p1 != *p2;
-}
-
-static inline gboolean
-ring_reorder_lookup (guint          n_items,
-                     gpointer      *items,
-                     gpointer       key,
-                     guint         *indexp)
-{
-  guint offset = 0, n = n_items;
-  while (offset < n)
-    {
-      guint i = (offset + n) >> 1;
-      gint cmp = key < items[i] ? -1 : key != items[i];
-      if (cmp < 0)
-        n = i;
-      else if (cmp > 0)
-        offset = i + 1;
-      else /* match */
-        {
-          *indexp = i;
-          return TRUE;
-        }
-    }
-  return FALSE;
-}
-
-SfiRing* /* reproduce all elements from unordered_ring in the order new_ring_order */
-sfi_ring_reorder (SfiRing        *unordered_ring,
-                  const SfiRing  *new_ring_order)
-{
-  if (!unordered_ring || !new_ring_order)
-    return unordered_ring;
-  const SfiRing *ring;
-
-  /* construct a sorted array for faster lookups */
-  gpointer *items = NULL;
-  guint i, n_items = 0, n_alloced = 0;
-  for (ring = unordered_ring; ring; ring = sfi_ring_walk (ring, unordered_ring))
-    {
-      i = n_items++;
-      if (n_items > n_alloced)
-        {
-          n_alloced = sfi_alloc_upper_power2 (MAX (n_items, 32));
-          items = g_renew (gpointer, items, n_alloced);
-        }
-      items[i] = ring->data;
-    }
-  sfi_ring_free (unordered_ring);
-  unordered_ring = NULL;
-  qsort (items, n_items, sizeof (items[0]), pointerloccmp);
-
-  /* collapse duplicates */
-  guint j = 0, *counts = g_new0 (guint, n_items);
-  for (i = 0; i < n_items; i++)
-    if (items[j] != items[i])
-      {
-        if (++j != i)
-          items[j] = items[i];
-        counts[j] = 1;
-      }
-    else /* catch dups */
-      counts[j]++;
-  n_items = j + 1;      /* shrink to number of different items */
-
-  /* pick unordered_ring members in the order given by new_ring_order */
-  for (ring = new_ring_order; ring; ring = sfi_ring_walk (ring, new_ring_order))
-    if (ring_reorder_lookup (n_items, items, ring->data, &i) && counts[i])
-      {
-        counts[i]--;
-        unordered_ring = sfi_ring_append (unordered_ring, ring->data);
-      }
-
-  /* append left-over members from sorted_ring */
-  for (i = 0; i < n_items; i++)
-    while (counts[i]--)
-      unordered_ring = sfi_ring_append (unordered_ring, items[i]);
-
-  g_free (items);
-  g_free (counts);
-  return unordered_ring;
-}
-
-gboolean
-sfi_ring_includes (const SfiRing  *sorted_super_set,
-                   const SfiRing  *sorted_sub_set,
-                   SfiCompareFunc  cmp,
-                   gpointer        data)
-{
-  const SfiRing *r1 = sorted_super_set, *r2 = sorted_sub_set;
-  while (r1 && r2)
-    {
-      gint c = cmp (r1->data, r2->data, data);
-      if (c > 0)
-        return FALSE;
-      else if (c == 0)
-        r2 = sfi_ring_walk (r2, sorted_sub_set);
-      r1 = sfi_ring_walk (r1, sorted_super_set);
-    }
-  return !r2;
-}
-
-gboolean
-sfi_ring_equals (const SfiRing  *sorted_ring1,
-                 const SfiRing  *sorted_ring2,
-                 SfiCompareFunc  cmp,
-                 gpointer        data)
-{
-  const SfiRing *r1 = sorted_ring1, *r2 = sorted_ring2;
-  while (r1 && r2)
-    {
-      if (cmp (r1->data, r2->data, data))
-        return FALSE;
-      r1 = sfi_ring_walk (r1, sorted_ring1);
-      r2 = sfi_ring_walk (r2, sorted_ring2);
-    }
-  return r1 == r2; /* both need to be NULL */
-}
-
-gboolean
-sfi_ring_mismatch (SfiRing       **sorted_ring1_p,
-                   SfiRing       **sorted_ring2_p,
-                   SfiCompareFunc  cmp,
-                   gpointer        data)
-{
-  SfiRing *head1 = *sorted_ring1_p, *head2 = *sorted_ring2_p;
-  SfiRing *r1 = head1, *r2 = head2;
-  while (r1 && r2)
-    {
-      if (cmp (r1->data, r2->data, data))
-        goto mismatch;
-      r1 = sfi_ring_walk (r1, head1);
-      r2 = sfi_ring_walk (r2, head2);
-    }
-  if (r1 == r2) /* both are NULL */
-    return FALSE;
- mismatch:
-  *sorted_ring1_p = r1;
-  *sorted_ring2_p = r2;
-  return TRUE;
-}
-
-SfiRing*
-sfi_ring_min_node (const SfiRing  *head,
-                   SfiCompareFunc  cmp,
-                   gpointer        data)
-{
-  const SfiRing *ring = head, *last = NULL;
-  if (ring)
-    {
-      last = ring;
-      for (ring = sfi_ring_walk (ring, head); ring; ring = sfi_ring_walk (ring, head))
-        if (cmp (last->data, ring->data, data) > 0)
-          last = ring;
-    }
-  return (SfiRing*) last;
-}
-
-SfiRing*
-sfi_ring_max_node (const SfiRing  *head,
-                   SfiCompareFunc  cmp,
-                   gpointer        data)
-{
-  const SfiRing *ring = head, *last = NULL;
-  if (ring)
-    {
-      last = ring;
-      for (ring = sfi_ring_walk (ring, head); ring; ring = sfi_ring_walk (ring, head))
-        if (cmp (last->data, ring->data, data) < 0)
-          last = ring;
-    }
-  return (SfiRing*) last;
-}
-
-gpointer
-sfi_ring_min (const SfiRing  *head,
-              SfiCompareFunc  cmp,
-              gpointer        data)
-{
-  SfiRing *ring = sfi_ring_min_node (head, cmp, data);
-  return ring ? ring->data : NULL;
-}
-
-gpointer
-sfi_ring_max (const SfiRing  *head,
-              SfiCompareFunc  cmp,
-              gpointer        data)
-{
-  SfiRing *ring = sfi_ring_max_node (head, cmp, data);
-  return ring ? ring->data : NULL;
-}

Modified: trunk/sfi/sfiprimitives.h
===================================================================
--- trunk/sfi/sfiprimitives.h	2006-10-03 11:19:35 UTC (rev 3925)
+++ trunk/sfi/sfiprimitives.h	2006-10-03 15:28:27 UTC (rev 3926)
@@ -246,155 +246,6 @@
 SfiProxy     sfi_rec_get_proxy	(SfiRec		*rec,
 				 const gchar	*field_name);
 
-
-/* --- basic comparisons --- */
-typedef gint (*SfiCompareFunc)          (gconstpointer   value1,
-                                         gconstpointer   value2,
-                                         gpointer        data);
-gint     sfi_pointer_cmp                (gconstpointer   value1,
-                                         gconstpointer   value2,
-                                         gpointer        dummy);
-
-
-/* --- ring (circular-list) --- */
-typedef gpointer (*SfiRingDataFunc)	(gpointer	 data,
-					 gpointer	 func_data);
-struct _SfiRing		// FIXME: move SfiRing into its own object file
-{
-  gpointer  data;
-  SfiRing  *next;
-  SfiRing  *prev;
-};
-SfiRing*        sfi_ring_prepend        (SfiRing        *head,
-                                         gpointer        data);
-SfiRing*        sfi_ring_prepend_uniq   (SfiRing        *head,
-                                         gpointer        data);
-SfiRing*        sfi_ring_append         (SfiRing        *head,
-                                         gpointer        data);
-SfiRing*        sfi_ring_append_uniq    (SfiRing        *head,
-                                         gpointer        data);
-SfiRing*        sfi_ring_insert         (SfiRing        *head,
-                                         gpointer        data,
-                                         gint            position);
-SfiRing*        sfi_ring_insert_before  (SfiRing        *head,
-                                         SfiRing        *sibling,
-                                         gpointer        data);
-gint            sfi_ring_position       (const SfiRing  *head,
-                                         const SfiRing  *node);
-gint            sfi_ring_index          (const SfiRing  *head,
-                                         gconstpointer   data);
-SfiRing*        sfi_ring_nth            (const SfiRing  *head,
-                                         guint           n);
-gpointer        sfi_ring_nth_data       (const SfiRing  *head,
-                                         guint           n);
-SfiRing*        sfi_ring_find           (const SfiRing  *head,
-                                         gconstpointer   data);
-SfiRing*        sfi_ring_remove_node    (SfiRing        *head,
-                                         SfiRing        *node);
-SfiRing*        sfi_ring_remove         (SfiRing        *head,
-                                         gpointer        data);
-guint           sfi_ring_length         (const SfiRing  *head);
-gint            sfi_ring_cmp_length     (const SfiRing  *head,
-                                         guint           test_length);
-SfiRing*        sfi_ring_copy           (const SfiRing  *head);
-SfiRing*        sfi_ring_copy_deep      (const SfiRing  *head,
-                                         SfiRingDataFunc copy,
-                                         gpointer        func_data);
-SfiRing*        sfi_ring_copy_rest      (const SfiRing  *ring,
-                                         const SfiRing  *head);
-SfiRing*        sfi_ring_concat         (SfiRing        *head1,
-                                         SfiRing        *head2);
-SfiRing*        sfi_ring_split          (SfiRing        *head1,
-                                         SfiRing        *head2);
-SfiRing*        sfi_ring_reverse        (SfiRing        *head);
-gpointer        sfi_ring_pop_head       (SfiRing       **head);
-gpointer        sfi_ring_pop_tail       (SfiRing       **head);
-#define         sfi_ring_push_head      sfi_ring_prepend
-#define         sfi_ring_push_tail      sfi_ring_append
-void            sfi_ring_free           (SfiRing        *head);
-void            sfi_ring_free_deep      (SfiRing        *head,
-                                         GDestroyNotify  data_destroy);
-#define sfi_ring_tail(head)             ((head) ? (head)->prev : NULL)
-#define sfi_ring_walk(node,head_bound)  ((node)->next != (head_bound) ? (node)->next : NULL)
-#define sfi_ring_next                   sfi_ring_walk
-
-SfiRing* sfi_ring_from_list             (GList          *list);
-SfiRing* sfi_ring_from_list_and_free    (GList          *list);
-SfiRing* sfi_ring_from_slist            (GSList         *slist);
-SfiRing* sfi_ring_from_slist_and_free   (GSList         *slist);
-
-/* ring-modifying cmp-based operations */
-SfiRing* sfi_ring_insert_sorted         (SfiRing        *head,
-                                         gpointer        insertion_data,
-                                         SfiCompareFunc  cmp,
-                                         gpointer        cmp_data);
-SfiRing* sfi_ring_merge_sorted          (SfiRing        *head1,
-                                         SfiRing        *head2,
-                                         SfiCompareFunc  cmp,
-                                         gpointer        data);
-SfiRing* sfi_ring_sort                  (SfiRing        *head,
-                                         SfiCompareFunc  cmp,
-                                         gpointer        data);
-SfiRing* sfi_ring_uniq                  (SfiRing        *sorted_ring1,
-                                         SfiCompareFunc  cmp,
-                                         gpointer        data);
-SfiRing* sfi_ring_uniq_free_deep        (SfiRing        *sorted_ring1,
-                                         SfiCompareFunc  cmp,
-                                         gpointer        data,
-                                         GDestroyNotify  data_destroy);
-SfiRing* sfi_ring_reorder               (SfiRing        *unordered_ring,
-                                         const SfiRing  *new_ring_order);
-/* ring-copying cmp-based operations */
-SfiRing* sfi_ring_copy_deep_uniq        (const SfiRing  *sorted_ring1,
-                                         SfiRingDataFunc copy,
-                                         gpointer        copy_data,
-                                         SfiCompareFunc  cmp,
-                                         gpointer        cmp_data);
-SfiRing* sfi_ring_copy_uniq             (const SfiRing  *sorted_ring1,
-                                         SfiCompareFunc  cmp,
-                                         gpointer        data);
-SfiRing* sfi_ring_union                 (const SfiRing  *sorted_set1,
-                                         const SfiRing  *sorted_set2,
-                                         SfiCompareFunc  cmp,
-                                         gpointer        data);
-SfiRing* sfi_ring_intersection          (const SfiRing  *sorted_set1,
-                                         const SfiRing  *sorted_set2,
-                                         SfiCompareFunc  cmp,
-                                         gpointer        data);
-SfiRing* sfi_ring_difference            (const SfiRing  *sorted_set1,
-                                         const SfiRing  *sorted_set2,
-                                         SfiCompareFunc  cmp,
-                                         gpointer        data);
-SfiRing* sfi_ring_symmetric_difference  (const SfiRing  *sorted_set1,
-                                         const SfiRing  *sorted_set2,
-                                         SfiCompareFunc  cmp,
-                                         gpointer        data);
-/* const-result cmp-based operations */
-gboolean sfi_ring_includes              (const SfiRing  *sorted_super_set,
-                                         const SfiRing  *sorted_sub_set,
-                                         SfiCompareFunc  cmp,
-                                         gpointer        data);
-gboolean sfi_ring_mismatch              (SfiRing       **sorted_ring1_p,
-                                         SfiRing       **sorted_ring2_p,
-                                         SfiCompareFunc  cmp,
-                                         gpointer        data);
-gboolean sfi_ring_equals                (const SfiRing  *sorted_set1,
-                                         const SfiRing  *sorted_set2,
-                                         SfiCompareFunc  cmp,
-                                         gpointer        data);
-SfiRing* sfi_ring_min_node              (const SfiRing  *head,
-                                         SfiCompareFunc  cmp,
-                                         gpointer        data);
-SfiRing* sfi_ring_max_node              (const SfiRing  *head,
-                                         SfiCompareFunc  cmp,
-                                         gpointer        data);
-gpointer sfi_ring_min                   (const SfiRing  *head,
-                                         SfiCompareFunc  cmp,
-                                         gpointer        data);
-gpointer sfi_ring_max                   (const SfiRing  *head,
-                                         SfiCompareFunc  cmp,
-                                         gpointer        data);
-
 G_END_DECLS
 
 #endif /* __SFI_PRIMITIVES_H__ */

Copied: trunk/sfi/sfiring.c (from rev 3925, trunk/birnet/birnetring.c)
===================================================================
--- trunk/birnet/birnetring.c	2006-10-03 11:19:35 UTC (rev 3925)
+++ trunk/sfi/sfiring.c	2006-10-03 15:28:27 UTC (rev 3926)
@@ -0,0 +1,1175 @@
+/* SfiRing
+ * Copyright (C) 2002-2006 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 "sfiring.h"
+#include "sfimemory.h"
+#include <stdlib.h>
+#include <string.h>
+
+#define HAVE_GSLICE     GLIB_CHECK_VERSION (2, 9, 7)
+
+/* --- memory handling --- */
+static inline SfiRing*
+node_alloc (void)
+{
+#if HAVE_GSLICE
+  return g_slice_new (SfiRing);
+#else
+  return (SfiRing*) g_list_alloc();
+#endif
+}
+
+static inline void
+node_free (SfiRing *node)
+{
+#if HAVE_GSLICE
+  g_slice_free (SfiRing, node);
+#else
+  g_list_free_1 ((GList*) node);
+#endif
+}
+
+static inline void
+free_node_list (SfiRing *start)
+{
+  /* NULL terminated list of ->next pointers */
+#if HAVE_GSLICE
+  g_slice_free_chain (SfiRing, start, next);
+#else
+  g_list_free ((GList*) start);
+#endif
+}
+
+/* --- basic comparisons --- */
+gint
+sfi_pointer_cmp (gconstpointer   value1,
+                 gconstpointer   value2,
+                 gpointer        dummy)
+{
+  const char *p1 = value1;
+  const char *p2 = value2;
+  return p1 < p2 ? -1 : p1 != p2;
+}
+
+
+/* --- ring (circular-list) --- */
+static inline SfiRing*
+sfi_ring_prepend_link_i (SfiRing *head,
+                         SfiRing *ring)
+{
+  if (!head)
+    {
+      ring->prev = ring;
+      ring->next = ring;
+    }
+  else
+    {
+      ring->prev = head->prev;
+      ring->next = head;
+      head->prev->next = ring;
+      head->prev = ring;
+    }
+  return ring;
+}
+
+static inline SfiRing*
+sfi_ring_prepend_i (SfiRing *head,
+                    gpointer data)
+{
+  SfiRing *ring = node_alloc();
+  
+  ring->data = data;
+  return sfi_ring_prepend_link_i (head, ring);
+}
+
+static inline SfiRing*
+sfi_ring_append_link_i (SfiRing *head,
+                        SfiRing *ring)
+{
+  sfi_ring_prepend_link_i (head, ring);
+  return head ? head : ring;
+}
+
+SfiRing*
+sfi_ring_prepend (SfiRing  *head,
+                  gpointer data)
+{
+  return sfi_ring_prepend_i (head, data);
+}
+
+SfiRing*
+sfi_ring_prepend_uniq (SfiRing  *head,
+                       gpointer data)
+{
+  SfiRing *ring;
+  for (ring = head; ring; ring = sfi_ring_walk (ring, head))
+    if (ring->data == data)
+      return head;
+  return sfi_ring_prepend_i (head, data);
+}
+
+SfiRing*
+sfi_ring_append (SfiRing *head,
+                 gpointer data)
+{
+  SfiRing *ring = sfi_ring_prepend_i (head, data);
+  return head ? head : ring;
+}
+
+SfiRing*
+sfi_ring_append_uniq (SfiRing *head,
+                      gpointer data)
+{
+  SfiRing *ring;
+  for (ring = head; ring; ring = sfi_ring_walk (ring, head))
+    if (ring->data == data)
+      return head;
+  ring = sfi_ring_prepend_i (head, data);
+  return head ? head : ring;
+}
+
+SfiRing*
+sfi_ring_insert_before (SfiRing        *head,
+                        SfiRing        *sibling,
+                        gpointer        data)
+{
+  if (!sibling)
+    return sfi_ring_append (head, data);
+  SfiRing *node = sfi_ring_prepend (sibling, data);
+  return sibling == head ? node : head;
+}
+
+SfiRing*
+sfi_ring_insert (SfiRing *head,
+                 gpointer data,
+                 gint     position)
+{
+  if (position < 0)
+    return sfi_ring_append (head, data);
+  else if (position == 0)
+    return sfi_ring_prepend (head, data);
+  SfiRing *node = sfi_ring_nth (head, position);
+  if (node)
+    return sfi_ring_insert_before (head, node, data);
+  else
+    return sfi_ring_append (head, data);
+}
+
+gint
+sfi_ring_position (const SfiRing  *head,
+                   const SfiRing  *node)
+{
+  guint i = 0;
+  const SfiRing *ring;
+  for (ring = head; ring; ring = sfi_ring_walk (ring, head), i++)
+    if (ring == node)
+      return i;
+  return -1;
+}
+
+gint
+sfi_ring_index (const SfiRing *head,
+                gconstpointer  data)
+{
+  guint i = 0;
+  const SfiRing *ring;
+  for (ring = head; ring; ring = sfi_ring_walk (ring, head), i++)
+    if (ring->data == data)
+      return i;
+  return -1;
+}
+
+SfiRing*
+sfi_ring_copy (const SfiRing *head)
+{
+  const SfiRing *walk;
+  SfiRing *dest = NULL;
+  for (walk = head; walk; walk = sfi_ring_walk (walk, head))
+    dest = sfi_ring_append (dest, walk->data);
+  return dest;
+}
+
+SfiRing*
+sfi_ring_copy_deep (const SfiRing  *head,
+                    SfiRingDataFunc copy,
+                    gpointer        func_data)
+{
+  const SfiRing *walk;
+  SfiRing *dest = NULL;
+  for (walk = head; walk; walk = sfi_ring_walk (walk, head))
+    dest = sfi_ring_append (dest, copy (walk->data, func_data));
+  return dest;
+}
+
+SfiRing*
+sfi_ring_copy_rest (const SfiRing *ring,
+                    const SfiRing *head)
+{
+  const SfiRing *walk;
+  SfiRing *dest = NULL;
+  for (walk = ring; walk; walk = sfi_ring_walk (walk, head))
+    dest = sfi_ring_append (dest, walk->data);
+  return dest;
+}
+
+SfiRing*
+sfi_ring_concat (SfiRing *head1,
+                 SfiRing *head2)
+{
+  SfiRing *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;
+}
+
+/**
+ * @param head1	a non-empty ring
+ * @param head2	a ring node different from @a head1 contained in @a head1
+ * @param returns	@a head2 for convenience
+ *
+ * Split a ring into two parts, starting the second ring with @a head2.
+ * @a head2 must therefore be non-NULL and must be contained in the ring
+ * formed by @a head1.
+ */
+SfiRing*
+sfi_ring_split (SfiRing *head1,
+                SfiRing *head2)
+{
+  SfiRing *tail1, *tail2;
+  
+  g_return_val_if_fail (head1 != NULL, NULL);
+  g_return_val_if_fail (head2 != NULL, NULL);
+  g_return_val_if_fail (head1 != head2, NULL);
+  
+  tail1 = head2->prev;
+  tail2 = head1->prev;
+  head2->prev = tail2;
+  tail2->next = head2;
+  head1->prev = tail1;
+  tail1->next = head1;
+  return head2;
+}
+
+static inline SfiRing*
+sfi_ring_unlink_node_dangling (SfiRing *head,
+                               SfiRing *node)
+{
+  g_assert (head && node);
+  /* special case one item ring */
+  if (head->prev == head)
+    return NULL;
+  /* unlink */
+  node->next->prev = node->prev;
+  node->prev->next = node->next;
+  if (head == node)
+    head = node->next;
+  /* node->prev and node->next are dangling now */
+  return head;
+}
+
+SfiRing*
+sfi_ring_remove_node (SfiRing *head,
+                      SfiRing *node)
+{
+  if (!head)
+    g_return_val_if_fail (head == NULL && node == NULL, NULL);
+  if (!head || !node)
+    return NULL;
+  
+  /* special case one item ring */
+  if (head->prev == head)
+    {
+      g_return_val_if_fail (node == head, head);
+      
+      node_free (node);
+      return NULL;
+    }
+  g_return_val_if_fail (node != node->next, head); /* node can't be a one item ring here */
+  
+  node->next->prev = node->prev;
+  node->prev->next = node->next;
+  if (head == node)
+    head = node->next;
+  node_free (node);
+  
+  return head;
+}
+
+SfiRing*
+sfi_ring_reverse (SfiRing *head)
+{
+  if (head)
+    {
+      SfiRing *ring = head = head->prev;
+      do
+	{
+	  SfiRing *tmp = ring;
+	  ring = tmp->next;
+	  tmp->next = tmp->prev;
+	  tmp->prev = ring;
+	}
+      while (ring != head);
+    }
+  return head;
+}
+
+SfiRing*
+sfi_ring_remove (SfiRing *head,
+                 gpointer data)
+{
+  SfiRing *walk;
+  
+  if (!head)
+    return NULL;
+  
+  /* make tail data removal an O(1) operation */
+  if (head->prev->data == data)
+    return sfi_ring_remove_node (head, head->prev);
+  
+  for (walk = head; walk; walk = sfi_ring_walk (walk, head))
+    if (walk->data == data)
+      return sfi_ring_remove_node (head, walk);
+  
+  /* g_warning (G_STRLOC ": couldn't find data item (%p) to remove from ring (%p)", data, head); */
+  
+  return head;
+}
+
+guint
+sfi_ring_length (const SfiRing *head)
+{
+  const SfiRing *ring;
+  guint i = 0;
+  
+  for (ring = head; ring; ring = sfi_ring_walk (ring, head))
+    i++;
+  
+  return i;
+}
+
+gint    /* essentially compute length(ring) - test_length, clamped to -1..+1 */
+sfi_ring_cmp_length (const SfiRing *head,
+                     guint          test_length)
+{
+  const SfiRing *ring = head;
+  
+  while (test_length && ring)
+    {
+      test_length--;
+      ring = sfi_ring_walk (ring, head);
+    }
+  
+  return test_length > 0 ? -1 : ring != NULL;
+}
+
+SfiRing*
+sfi_ring_find (const SfiRing *head,
+               gconstpointer  data)
+{
+  const SfiRing *ring;
+  for (ring = head; ring; ring = sfi_ring_walk (ring, head))
+    if (ring->data == (gpointer) data)
+      return (SfiRing*) ring;
+  return NULL;
+}
+
+SfiRing*
+sfi_ring_nth (const SfiRing *head,
+              guint          n)
+{
+  const SfiRing *ring = head;
+  while (n-- && ring)
+    ring = sfi_ring_walk (ring, head);
+  return (SfiRing*) ring;
+}
+
+gpointer
+sfi_ring_nth_data (const SfiRing *head,
+                   guint          n)
+{
+  const SfiRing *ring = head;
+  
+  while (n-- && ring)
+    ring = sfi_ring_walk (ring, head);
+  
+  return ring ? ring->data : NULL;
+}
+
+void
+sfi_ring_free_deep (SfiRing        *head,
+                    GDestroyNotify  data_destroy)
+{
+  while (head)
+    {
+      gpointer data = sfi_ring_pop_head (&head);
+      data_destroy (data);
+      data = sfi_ring_pop_head (&head);
+    }
+}
+
+void
+sfi_ring_free (SfiRing *head)
+{
+  if (head)
+    {
+      head->prev->next = NULL;
+      free_node_list (head);
+    }
+}
+
+gpointer
+sfi_ring_pop_head (SfiRing **head_p)
+{
+  gpointer data;
+  
+  g_return_val_if_fail (head_p != NULL, NULL);
+  
+  if (!*head_p)
+    return NULL;
+  data = (*head_p)->data;
+  *head_p = sfi_ring_remove_node (*head_p, *head_p);
+  
+  return data;
+}
+
+gpointer
+sfi_ring_pop_tail (SfiRing **head_p)
+{
+  gpointer data;
+  
+  g_return_val_if_fail (head_p != NULL, NULL);
+  
+  if (!*head_p)
+    return NULL;
+  data = (*head_p)->prev->data;
+  *head_p = sfi_ring_remove_node (*head_p, (*head_p)->prev);
+  
+  return data;
+}
+
+SfiRing*
+sfi_ring_from_list (GList *list)
+{
+  SfiRing *ring = NULL;
+  for (; list; list = list->next)
+    ring = sfi_ring_append (ring, list->data);
+  return ring;
+}
+
+SfiRing*
+sfi_ring_from_list_and_free (GList *list)
+{
+  SfiRing *ring = NULL;
+  GList *free_list = list;
+  for (; list; list = list->next)
+    ring = sfi_ring_append (ring, list->data);
+  g_list_free (free_list);
+  return ring;
+}
+
+SfiRing*
+sfi_ring_from_slist (GSList *slist)
+{
+  SfiRing *ring = NULL;
+  for (; slist; slist = slist->next)
+    ring = sfi_ring_append (ring, slist->data);
+  return ring;
+}
+
+SfiRing*
+sfi_ring_from_slist_and_free (GSList *slist)
+{
+  SfiRing *ring = NULL;
+  GSList *free_slist = slist;
+  for (; slist; slist = slist->next)
+    ring = sfi_ring_append (ring, slist->data);
+  g_slist_free (free_slist);
+  return ring;
+}
+
+SfiRing*
+sfi_ring_insert_sorted (SfiRing	      *head,
+                        gpointer       insertion_data,
+                        SfiCompareFunc cmp,
+                        gpointer       cmp_data)
+{
+  g_return_val_if_fail (cmp != NULL, head);
+  if (!head)
+    return sfi_ring_prepend (head, insertion_data);
+  
+  /* implement stable sorting by inserting insertion_data *after* equal nodes */
+  
+  if (cmp (insertion_data, head->data, cmp_data) >= 0)  /* insert after head */
+    {
+      SfiRing *tmp, *tail = head->prev;
+      
+      /* make appending an O(1) operation */
+      if (head == tail || cmp (insertion_data, tail->data, cmp_data) >= 0)
+	return sfi_ring_append (head, insertion_data);
+      
+      /* walk forward while data >= tmp (skipping equal nodes) */
+      for (tmp = head->next; tmp != tail; tmp = tmp->next)
+	if (cmp (insertion_data, tmp->data, cmp_data) < 0)
+	  break;
+      
+      /* insert before sibling which is greater than insertion_data */
+      sfi_ring_prepend (tmp, insertion_data); /* keep current head */
+      return head;
+    }
+  else /* cmp < 0 */
+    return sfi_ring_prepend (head, insertion_data);
+}
+
+SfiRing*
+sfi_ring_merge_sorted (SfiRing        *head1,
+                       SfiRing        *head2,
+                       SfiCompareFunc  cmp,
+                       gpointer        data)
+{
+  /* implement stable sorting by inserting head2 members *after* equal nodes from head1 */
+  
+  if (head1 && head2)
+    {
+      SfiRing *tail1 = head1->prev;
+      SfiRing *tail2 = head2->prev;
+      SfiRing *tmp, *ring = NULL;
+      /* NULL terminate rings */
+      tail1->next = NULL;
+      tail2->next = NULL;
+      while (head1 && head2)
+	{
+	  gint c = cmp (head1->data, head2->data, data);
+	  if (c <= 0)
+	    {
+	      tmp = head1;
+	      head1 = head1->next;
+	    }
+	  else
+	    {
+	      tmp = head2;
+	      head2 = head2->next;
+	    }
+	  ring = sfi_ring_append_link_i (ring, tmp);
+	}
+      /* reform valid rings, concat sorted rest */
+      if (head1)
+	{
+	  tail1->next = head1;
+	  head1->prev = tail1;
+	  return sfi_ring_concat (ring, head1);
+	}
+      if (head2)
+	{
+	  tail2->next = head2;
+	  head2->prev = tail2;
+	  return sfi_ring_concat (ring, head2);
+	}
+      return ring;
+    }
+  else
+    return sfi_ring_concat (head1, head2);
+}
+
+SfiRing*
+sfi_ring_sort (SfiRing        *head,
+               SfiCompareFunc  cmp,
+               gpointer        data)
+{
+  g_return_val_if_fail (cmp != NULL, head);
+  
+  /* stable sorting guaranteed by sfi_ring_merge_sorted() */
+  
+  if (head && head->next != head)
+    {
+      SfiRing *ring, *tmp, *tail = head->prev;
+      /* find middle node to get log2 recursion depth */
+      ring = tmp = head->next;
+      while (tmp != tail && tmp->next != tail)
+	{
+	  ring = ring->next;
+	  tmp = tmp->next->next;
+	}
+      sfi_ring_split (head, ring);
+      return sfi_ring_merge_sorted (sfi_ring_sort (head, cmp, data),
+                                    sfi_ring_sort (ring, cmp, data),
+                                    cmp, data);
+    }
+  return head;
+}
+
+SfiRing* /* eliminates duplicate nodes */
+sfi_ring_uniq (SfiRing        *sorted_ring1,
+               SfiCompareFunc  cmp,
+               gpointer        data)
+{
+  /* always preserves the first of a sublist of consequtive equal elements */
+  SfiRing *r1 = sorted_ring1;
+  SfiRing *r2 = NULL;
+  if (r1)
+    {
+      SfiRing *last = r1;
+      r1 = sfi_ring_unlink_node_dangling (r1, last);
+      r2 = last->next = last->prev = last; /* form new ring */
+      while (r1)
+        {
+          SfiRing *node = r1;
+          r1 = sfi_ring_unlink_node_dangling (r1, node);
+          if (cmp (last->data, node->data, data))
+            {
+              last = node;
+              r2 = sfi_ring_append_link_i (r2, last);
+            }
+          else
+            node_free (node);
+        }
+    }
+  return r2;
+}
+
+SfiRing* /* eliminates duplicate nodes */
+sfi_ring_uniq_free_deep (SfiRing        *sorted_ring1,
+                         SfiCompareFunc  cmp,
+                         gpointer        data,
+                         GDestroyNotify  data_destroy)
+{
+  /* always preserves the first of a sublist of consequtive equal elements */
+  if (!data_destroy)
+    return sfi_ring_uniq (sorted_ring1, cmp, data);
+  SfiRing *r1 = sorted_ring1;
+  SfiRing *r2 = NULL;
+  if (r1)
+    {
+      SfiRing *last = r1;
+      r1 = sfi_ring_unlink_node_dangling (r1, last);
+      r2 = last->next = last->prev = last; /* form new ring */
+      while (r1)
+        {
+          SfiRing *node = r1;
+          r1 = sfi_ring_unlink_node_dangling (r1, node);
+          if (cmp (last->data, node->data, data))
+            {
+              last = node;
+              r2 = sfi_ring_append_link_i (r2, last);
+            }
+          else
+            {
+              data_destroy (node->data);
+              node_free (node);
+            }
+        }
+    }
+  return r2;
+}
+
+SfiRing* /* eliminates duplicate nodes */
+sfi_ring_copy_deep_uniq (const SfiRing  *sorted_ring1,
+                         SfiRingDataFunc copy,
+                         gpointer        copy_data,
+                         SfiCompareFunc  cmp,
+                         gpointer        cmp_data)
+{
+  /* always preserves the first of a sublist of consequtive equal elements */
+  if (!copy)
+    return sfi_ring_copy_uniq (sorted_ring1, cmp, cmp_data);
+  const SfiRing *r1 = sorted_ring1;
+  SfiRing *r2 = NULL;
+  if (r1)
+    {
+      gpointer last_data = r1->data;
+      r2 = sfi_ring_append (r2, copy (last_data, copy_data));
+      for (r1 = sfi_ring_walk (r1, sorted_ring1); r1; r1 = sfi_ring_walk (r1, sorted_ring1))
+        if (cmp (last_data, r1->data, cmp_data))
+          {
+            last_data = r1->data;
+            r2 = sfi_ring_append (r2, copy (last_data, copy_data));
+          }
+    }
+  return r2;
+}
+
+SfiRing* /* eliminates duplicate nodes */
+sfi_ring_copy_uniq (const SfiRing  *sorted_ring1,
+                    SfiCompareFunc  cmp,
+                    gpointer        data)
+{
+  /* always preserves the first of a sublist of consequtive equal elements */
+  const SfiRing *r1 = sorted_ring1;
+  SfiRing *r2 = NULL;
+  if (r1)
+    {
+      gpointer last_data = r1->data;
+      r2 = sfi_ring_append (r2, last_data);
+      for (r1 = sfi_ring_walk (r1, sorted_ring1); r1; r1 = sfi_ring_walk (r1, sorted_ring1))
+        if (cmp (last_data, r1->data, data))
+          {
+            last_data = r1->data;
+            r2 = sfi_ring_append (r2, last_data);
+          }
+    }
+  return r2;
+}
+
+/**
+ * @param sorted_set1   Sorted ring 1
+ * @param sorted_set2   Sorted ring 2
+ * @param cmp           Compare function for node data
+ * @param data          Data argument passed into the cmp() function
+ * @return              Newly created (or empty) ring
+ *
+ * Return a newly created ring that contains all data items from @a sorted_set1
+ * and @a sorted_set2, omitting duplicates.
+ * Items are considered equal according to the cmp() function.
+ * For two equal items contained in both sets, the data pointer from
+ * @a sorted_set1 will be added to the resulting set.
+ * In mathematical terms, the returned ring is the union (sorted_set1, sorted_set2).
+ * The complexity is O(MAX (length (sorted_set1), length (sorted_set2))).
+ */
+SfiRing* /* merges rings without dups */
+sfi_ring_union (const SfiRing  *sorted_set1,
+                const SfiRing  *sorted_set2,
+                SfiCompareFunc  cmp,
+                gpointer           data)
+{
+  /* for two equal elements from both sets, the element from sorted_set1 is picked, the one from sorted_set2 ignored */
+  const SfiRing *r1 = sorted_set1, *r2 = sorted_set2;
+  SfiRing *d = NULL;
+  while (r1 && r2)
+    {
+      gint c = cmp (r1->data, r2->data, data);
+      if (c < 0)
+        {
+          d = sfi_ring_append (d, r1->data);
+          r1 = sfi_ring_walk (r1, sorted_set1);
+        }
+      else if (c > 0)
+        {
+          d = sfi_ring_append (d, r2->data);
+          r2 = sfi_ring_walk (r2, sorted_set2);
+        }
+      else
+        {
+          d = sfi_ring_append (d, r1->data);
+          r1 = sfi_ring_walk (r1, sorted_set1);
+          r2 = sfi_ring_walk (r2, sorted_set2);
+        }
+    }
+  return sfi_ring_concat (d, sfi_ring_copy_rest (r1 ? r1 : r2, r1 ? sorted_set1 : sorted_set2));
+}
+
+/**
+ * @param sorted_set1   Sorted ring 1
+ * @param sorted_set2   Sorted ring 2
+ * @param cmp           Compare function for node data
+ * @param data          Data argument passed into the cmp() function
+ * @return              Newly created (or empty) ring
+ *
+ * Return a newly created ring that contains all data items which are contained
+ * in both sets, @a sorted_set1 and @a sorted_set2.
+ * Items are considered equal according to the cmp() function.
+ * For two equal items contained in both sets, the data pointer from
+ * @a sorted_set1 will be added to the resulting set.
+ * In mathematical terms, the returned ring is the intersection (sorted_set1, sorted_set2).
+ * The complexity is O(MAX (length (sorted_set1), length (sorted_set2))).
+ */
+SfiRing* /* returns nodes contained in both rings */
+sfi_ring_intersection (const SfiRing  *sorted_set1,
+                       const SfiRing  *sorted_set2,
+                       SfiCompareFunc  cmp,
+                       gpointer        data)
+{
+  /* for two equal elements from both sets, only elements from sorted_set1 are picked */
+  const SfiRing *r1 = sorted_set1, *r2 = sorted_set2;
+  SfiRing *d = NULL;
+  while (r1 && r2)
+    {
+      gint c = cmp (r1->data, r2->data, data);
+      if (c < 0)
+        r1 = sfi_ring_walk (r1, sorted_set1);
+      else if (c > 0)
+        r2 = sfi_ring_walk (r2, sorted_set2);
+      else
+        {
+          d = sfi_ring_append (d, r1->data);
+          r1 = sfi_ring_walk (r1, sorted_set1);
+          r2 = sfi_ring_walk (r2, sorted_set2);
+        }
+    }
+  return d;
+}
+
+/**
+ * @param sorted_set1   Sorted ring 1
+ * @param sorted_set2   Sorted ring 2
+ * @param cmp           Compare function for node data
+ * @param data          Data argument passed into the cmp() function
+ * @return              Newly created (or empty) ring
+ *
+ * Collect and return all data items from @a sorted_set1 which are not contained in
+ * @a sorted_set2, according to the cmp() function.
+ * In mathematical terms, the returned ring is the difference (sorted_set1, sorted_set2).
+ * The complexity is O(MAX (length (sorted_set1), length (sorted_set2))).
+ */
+SfiRing*
+sfi_ring_difference (const SfiRing  *sorted_set1,
+                     const SfiRing  *sorted_set2,
+                     SfiCompareFunc  cmp,
+                     gpointer        data)
+{
+  const SfiRing *r1 = sorted_set1, *r2 = sorted_set2;
+  SfiRing *d = NULL;
+  while (r1 && r2)
+    {
+      gint c = cmp (r1->data, r2->data, data);
+      if (c < 0)
+        {
+          d = sfi_ring_append (d, r1->data);
+          r1 = sfi_ring_walk (r1, sorted_set1);
+        }
+      else if (c > 0)
+        r2 = sfi_ring_walk (r2, sorted_set2);
+      else
+        {
+          r1 = sfi_ring_walk (r1, sorted_set1);
+          r2 = sfi_ring_walk (r2, sorted_set2);
+        }
+    }
+  return sfi_ring_concat (d, sfi_ring_copy_rest (r1, sorted_set1));
+}
+
+/**
+ * @param sorted_set1   Sorted ring 1
+ * @param sorted_set2   Sorted ring 2
+ * @param cmp           Compare function for node data
+ * @param data          Data argument passed into the cmp() function
+ * @return              Newly created (or empty) ring
+ *
+ * Collect and return all data items from @a sorted_set1 which are not contained in
+ * @a sorted_set2, and all data items from @a sorted_set2 which are not contained in
+ * @a sorted_set1, according to the cmp() function.
+ * In mathematical terms, the returned ring is the union (difference (sorted_set1, sorted_set2)
+ * + difference (sorted_set2, sorted_set1)).
+ * The complexity is O(MAX (length (sorted_set1), length (sorted_set2))).
+ */
+SfiRing*
+sfi_ring_symmetric_difference (const SfiRing  *sorted_set1,
+                               const SfiRing  *sorted_set2,
+                               SfiCompareFunc  cmp,
+                               gpointer        data)
+{
+  const SfiRing *r1 = sorted_set1, *r2 = sorted_set2;
+  SfiRing *d = NULL;
+  while (r1 && r2)
+    {
+      gint c = cmp (r1->data, r2->data, data);
+      if (c < 0)
+        {
+          d = sfi_ring_append (d, r1->data);
+          r1 = sfi_ring_walk (r1, sorted_set1);
+        }
+      else if (c > 0)
+        {
+          d = sfi_ring_append (d, r2->data);
+          r2 = sfi_ring_walk (r2, sorted_set2);
+        }
+      else
+        {
+          r1 = sfi_ring_walk (r1, sorted_set1);
+          r2 = sfi_ring_walk (r2, sorted_set2);
+        }
+    }
+  return sfi_ring_concat (d, sfi_ring_copy_rest (r1 ? r1 : r2, r1 ? sorted_set1 : sorted_set2));
+}
+
+static inline int
+pointerloccmp (const void *pp1,
+               const void *pp2)
+{
+  const gpointer *p1 = pp1;
+  const gpointer *p2 = pp2;
+  return *p1 < *p2 ? -1 : *p1 != *p2;
+}
+
+static inline gboolean
+ring_reorder_lookup (guint          n_items,
+                     gpointer      *items,
+                     gpointer       key,
+                     guint         *indexp)
+{
+  guint offset = 0, n = n_items;
+  while (offset < n)
+    {
+      guint i = (offset + n) >> 1;
+      gint cmp = key < items[i] ? -1 : key != items[i];
+      if (cmp < 0)
+        n = i;
+      else if (cmp > 0)
+        offset = i + 1;
+      else /* match */
+        {
+          *indexp = i;
+          return TRUE;
+        }
+    }
+  return FALSE;
+}
+
+/**
+ * @param unordered_ring        Unsorted ring
+ * @param new_ring_order        Ring with arbitrary order
+ * @return                      Reordered version of @a unordered_ring
+ *
+ * Reorders the data pointers of @a unordered_ring according to the order
+ * as given by @a new_ring_order.
+ * The complexity involves roughly 3 * length(unordered_ring) + qsort(unordered_ring) + length(new_ring_order) * bsearch(unordered_ring)),
+ * i.e. it is at worst O(length(unordered_ring) * log (length(unordered_ring)) * length(new_ring_order)).
+ */
+SfiRing* /* reproduce all elements from unordered_ring in the order new_ring_order */
+sfi_ring_reorder (SfiRing        *unordered_ring,
+                  const SfiRing  *new_ring_order)
+{
+  if (!unordered_ring || !new_ring_order)
+    return unordered_ring;
+  const SfiRing *ring;
+  
+  /* construct a sorted array for faster lookups; O(length(unordered_ring)) */
+  gpointer *items = NULL;
+  guint i, n_items = 0, n_alloced = 0;
+  for (ring = unordered_ring; ring; ring = sfi_ring_walk (ring, unordered_ring))
+    {
+      i = n_items++;
+      if (n_items > n_alloced)
+        {
+          n_alloced = sfi_alloc_upper_power2 (MAX (n_items, 32));
+          items = g_renew (gpointer, items, n_alloced);
+        }
+      items[i] = ring->data;
+    }
+  sfi_ring_free (unordered_ring);
+  unordered_ring = NULL;
+  qsort (items, n_items, sizeof (items[0]), pointerloccmp);
+  
+  /* collapse duplicates; O(length(unordered_ring)) */
+  guint j = 0, *counts = g_new0 (guint, n_items);
+  for (i = 0; i < n_items; i++)
+    if (items[j] != items[i])
+      {
+        if (++j != i)
+          items[j] = items[i];
+        counts[j] = 1;
+      }
+    else /* catch dups */
+      counts[j]++;
+  n_items = j + 1;      /* shrink to number of different items */
+  
+  /* pick unordered_ring members in the order given by new_ring_order;
+   * O(length(new_ring_order) * O(bsearch(unordered_ring)))
+   */
+  for (ring = new_ring_order; ring; ring = sfi_ring_walk (ring, new_ring_order))
+    if (ring_reorder_lookup (n_items, items, ring->data, &i) && counts[i])
+      {
+        counts[i]--;
+        unordered_ring = sfi_ring_append (unordered_ring, ring->data);
+      }
+  
+  /* append left-over members from sorted_ring; O(length(unordered_ring)) */
+  for (i = 0; i < n_items; i++)
+    while (counts[i]--)
+      unordered_ring = sfi_ring_append (unordered_ring, items[i]);
+  
+  g_free (items);
+  g_free (counts);
+  return unordered_ring;
+}
+
+gboolean
+sfi_ring_includes (const SfiRing  *sorted_super_set,
+                   const SfiRing  *sorted_sub_set,
+                   SfiCompareFunc  cmp,
+                   gpointer        data)
+{
+  const SfiRing *r1 = sorted_super_set, *r2 = sorted_sub_set;
+  while (r1 && r2)
+    {
+      gint c = cmp (r1->data, r2->data, data);
+      if (c > 0)
+        return FALSE;
+      else if (c == 0)
+        r2 = sfi_ring_walk (r2, sorted_sub_set);
+      // FIXME: misses backtracking to find "abc" in "aabc"
+      r1 = sfi_ring_walk (r1, sorted_super_set);
+    }
+  return !r2;
+}
+
+/**
+ * @param sorted_ring1  Sorted ring 1
+ * @param sorted_ring2  Sorted ring 2
+ * @param cmp           Compare function for node data
+ * @param data          Data argument passed into the cmp() function
+ * @return              TRUE for equal rings, FALSE otherwise
+ *
+ * Compare two rings according to the cmp() function. Return FALSE as
+ * soon as a mismatch is found, returns TRUE for rings which are equal according to cmp().
+ * The complexity is at most O(MIN (length (sorted_ring1), length (sorted_ring2))).
+ */
+gboolean
+sfi_ring_equals (const SfiRing  *sorted_ring1,
+                 const SfiRing  *sorted_ring2,
+                 SfiCompareFunc  cmp,
+                 gpointer        data)
+{
+  const SfiRing *r1 = sorted_ring1, *r2 = sorted_ring2;
+  while (r1 && r2)
+    {
+      if (cmp (r1->data, r2->data, data))
+        return FALSE;
+      r1 = sfi_ring_walk (r1, sorted_ring1);
+      r2 = sfi_ring_walk (r2, sorted_ring2);
+    }
+  return r1 == r2; /* both need to be NULL */
+}
+
+/**
+ * @param sorted_ring1_p        Pointer to sorted ring 1
+ * @param sorted_ring2_p        Pointer to sorted ring 2
+ * @param cmp                   Compare function for node data
+ * @param data                  Data argument passed into the cmp() function
+ * @return                      TRUE for mismatching rings, FALSE otherwise
+ *
+ * Compare two rings according to the cmp() function. For mismatching rings,
+ * @a sorted_ring1_p and @a sorted_ring2_p are set to point to the mismatching nodes.
+ * The complexity is at most O(MIN (length (sorted_ring1), length (sorted_ring2))).
+ */
+gboolean
+sfi_ring_mismatch (SfiRing       **sorted_ring1_p,
+                   SfiRing       **sorted_ring2_p,
+                   SfiCompareFunc  cmp,
+                   gpointer        data)
+{
+  SfiRing *head1 = *sorted_ring1_p, *head2 = *sorted_ring2_p;
+  SfiRing *r1 = head1, *r2 = head2;
+  while (r1 && r2)
+    {
+      if (cmp (r1->data, r2->data, data))
+        goto mismatch;
+      r1 = sfi_ring_walk (r1, head1);
+      r2 = sfi_ring_walk (r2, head2);
+    }
+  if (r1 == r2) /* both are NULL */
+    return FALSE;
+ mismatch:
+  *sorted_ring1_p = r1;
+  *sorted_ring2_p = r2;
+  return TRUE;
+}
+
+/**
+ * @param head  Head node of a ring or NULL for an empty ring
+ * @param cmp   Compare function for node data
+ * @param data  Data argument passed into the cmp() function
+ * @return      Node with minimum data argument or NULL for empty rings
+ *
+ * Find and return the node holding the minimum data pointer of a ring, measured by evaluating cmp().
+ * The complexity is O(length (head)).
+ */
+SfiRing*
+sfi_ring_min_node (const SfiRing  *head,
+                   SfiCompareFunc  cmp,
+                   gpointer        data)
+{
+  const SfiRing *ring = head, *last = NULL;
+  if (ring)
+    {
+      last = ring;
+      for (ring = sfi_ring_walk (ring, head); ring; ring = sfi_ring_walk (ring, head))
+        if (cmp (last->data, ring->data, data) > 0)
+          last = ring;
+    }
+  return (SfiRing*) last;
+}
+
+/**
+ * @param head  Head node of a ring or NULL for an empty ring
+ * @param cmp   Compare function for node data
+ * @param data  Data argument passed into the cmp() function
+ * @return      Node with maximum data argument or NULL for empty rings
+ *
+ * Find and return the node holding the maximum data pointer of a ring, measured by evaluating cmp().
+ * The complexity is O(length (head)).
+ */
+SfiRing*
+sfi_ring_max_node (const SfiRing  *head,
+                   SfiCompareFunc  cmp,
+                   gpointer        data)
+{
+  const SfiRing *ring = head, *last = NULL;
+  if (ring)
+    {
+      last = ring;
+      for (ring = sfi_ring_walk (ring, head); ring; ring = sfi_ring_walk (ring, head))
+        if (cmp (last->data, ring->data, data) < 0)
+          last = ring;
+    }
+  return (SfiRing*) last;
+}
+
+/**
+ * @param head  Head node of a ring or NULL for an empty ring
+ * @param cmp   Compare function for node data
+ * @param data  Data argument passed into the cmp() function
+ * @return      Minimum data argument or NULL for empty rings
+ *
+ * Find and return the minimum data pointer of a ring, measured by evaluating cmp().
+ * The complexity is O(length (head)).
+ */
+gpointer
+sfi_ring_min (const SfiRing  *head,
+              SfiCompareFunc  cmp,
+              gpointer        data)
+{
+  SfiRing *ring = sfi_ring_min_node (head, cmp, data);
+  return ring ? ring->data : NULL;
+}
+
+/**
+ * @param head  Head node of a ring or NULL for an empty ring
+ * @param cmp   Compare function for node data
+ * @param data  Data argument passed into the cmp() function
+ * @return      Maximum data argument or NULL for empty rings
+ *
+ * Find and return the maximum data pointer of a ring, measured by evaluating cmp().
+ * The complexity is O(length (head)).
+ */
+gpointer
+sfi_ring_max (const SfiRing  *head,
+              SfiCompareFunc  cmp,
+              gpointer        data)
+{
+  SfiRing *ring = sfi_ring_max_node (head, cmp, data);
+  return ring ? ring->data : NULL;
+}

Copied: trunk/sfi/sfiring.h (from rev 3925, trunk/birnet/birnetring.h)
===================================================================
--- trunk/birnet/birnetring.h	2006-10-03 11:19:35 UTC (rev 3925)
+++ trunk/sfi/sfiring.h	2006-10-03 15:28:27 UTC (rev 3926)
@@ -0,0 +1,181 @@
+/* SfiRing
+ * Copyright (C) 2002-2006 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.
+ */
+#ifndef __SFI_RING_H__
+#define __SFI_RING_H__
+
+#include <sfi/sfitypes.h>
+
+G_BEGIN_DECLS;
+
+
+/* --- basic comparisons --- */
+typedef gint (*SfiCompareFunc)		(gconstpointer   value1,
+					 gconstpointer   value2,
+					 gpointer        data);
+gint     sfi_pointer_cmp             	(gconstpointer   value1,
+					 gconstpointer   value2,
+					 gpointer        dummy);
+
+
+/* --- ring (circular-list) --- */
+typedef gpointer (*SfiRingDataFunc)	(gpointer	 data,
+					 gpointer	 func_data);
+typedef struct SfiRing SfiRing;
+struct SfiRing
+{
+  gpointer  data;
+  SfiRing  *next;
+  SfiRing  *prev;
+};
+SfiRing* sfi_ring_prepend               (SfiRing             *head,
+                                         gpointer             data);
+SfiRing* sfi_ring_prepend_uniq          (SfiRing             *head,
+                                         gpointer             data);
+SfiRing* sfi_ring_append                (SfiRing             *head,
+                                         gpointer             data);
+SfiRing* sfi_ring_append_uniq           (SfiRing             *head,
+                                         gpointer             data);
+SfiRing* sfi_ring_insert                (SfiRing             *head,
+                                         gpointer             data,
+                                         gint                 position);
+SfiRing* sfi_ring_insert_before         (SfiRing             *head,
+                                         SfiRing             *sibling,
+                                         gpointer             data);
+gint        sfi_ring_position           (const SfiRing       *head,
+					 const SfiRing       *node);
+gint        sfi_ring_index              (const SfiRing       *head,
+					 gconstpointer        data);
+SfiRing* sfi_ring_nth                	(const SfiRing       *head,
+					 guint                n);
+gpointer    sfi_ring_nth_data           (const SfiRing       *head,
+					 guint                n);
+SfiRing* sfi_ring_find               	(const SfiRing       *head,
+					 gconstpointer        data);
+SfiRing* sfi_ring_remove_node        	(SfiRing             *head,
+					 SfiRing             *node);
+SfiRing* sfi_ring_remove             	(SfiRing             *head,
+					 gpointer             data);
+guint       sfi_ring_length             (const SfiRing       *head);
+gint        sfi_ring_cmp_length         (const SfiRing       *head,
+					 guint                test_length);
+SfiRing* sfi_ring_copy               	(const SfiRing       *head);
+SfiRing* sfi_ring_copy_deep          	(const SfiRing       *head,
+					 SfiRingDataFunc      copy,
+					 gpointer             func_data);
+SfiRing* sfi_ring_copy_rest          	(const SfiRing       *ring,
+					 const SfiRing       *head);
+SfiRing* sfi_ring_concat             	(SfiRing             *head1,
+					 SfiRing             *head2);
+SfiRing* sfi_ring_split              	(SfiRing             *head1,
+					 SfiRing             *head2);
+SfiRing* sfi_ring_reverse            	(SfiRing             *head);
+gpointer    sfi_ring_pop_head           (SfiRing             **head);
+gpointer    sfi_ring_pop_tail           (SfiRing             **head);
+#define     sfi_ring_push_head        sfi_ring_prepend
+#define     sfi_ring_push_tail        sfi_ring_append
+void        sfi_ring_free               (SfiRing             *head);
+void        sfi_ring_free_deep          (SfiRing             *head,
+					 GDestroyNotify          data_destroy);
+
+SfiRing* sfi_ring_from_list           	(GList       	*list);
+SfiRing* sfi_ring_from_list_and_free	(GList          *list);
+SfiRing* sfi_ring_from_slist            (GSList         *slist);
+SfiRing* sfi_ring_from_slist_and_free	(GSList         *slist);
+#define     sfi_ring_tail(head)            	((head) ? (head)->prev : NULL)
+#define     sfi_ring_walk(node,head_bound) 	((node)->next != (head_bound) ? (node)->next : NULL)
+#define     sfi_ring_next(node,head_bound)  	 sfi_ring_walk (node, head_bound)
+
+
+/* ring-modifying cmp-based operations */
+SfiRing* sfi_ring_insert_sorted		(SfiRing        	*head,
+					 gpointer       	 insertion_data,
+					 SfiCompareFunc 	 cmp,
+					 gpointer       	 cmp_data);
+SfiRing* sfi_ring_merge_sorted       	(SfiRing        	*head1,
+					 SfiRing        	*head2,
+					 SfiCompareFunc 	 cmp,
+                                         gpointer       	 data);
+SfiRing* sfi_ring_sort               	(SfiRing        	*head,
+                                         SfiCompareFunc 	 cmp,
+                                         gpointer       	 data);
+SfiRing* sfi_ring_uniq               	(SfiRing        	*sorted_ring1,
+                                         SfiCompareFunc 	 cmp,
+                                         gpointer       	 data);
+SfiRing* sfi_ring_uniq_free_deep     	(SfiRing        	*sorted_ring1,
+                                         SfiCompareFunc 	 cmp,
+                                         gpointer       	 data,
+                                         GDestroyNotify 	 data_destroy);
+SfiRing* sfi_ring_reorder            	(SfiRing        	*unordered_ring,
+					 const SfiRing  	*new_ring_order);
+/* ring-copying cmp-based operations */
+SfiRing* sfi_ring_copy_deep_uniq	(const SfiRing  	*sorted_ring1,
+                                         SfiRingDataFunc	 copy,
+                                         gpointer       	 copy_data,
+                                         SfiCompareFunc 	 cmp,
+                                         gpointer       	 cmp_data);
+SfiRing* sfi_ring_copy_uniq   		(const SfiRing  	*sorted_ring1,
+                                         SfiCompareFunc 	 cmp,
+                                         gpointer       	 data);
+SfiRing* sfi_ring_union              	(const SfiRing  	*sorted_set1,
+                                         const SfiRing  	*sorted_set2,
+                                         SfiCompareFunc 	 cmp,
+                                         gpointer       	 data);
+SfiRing* sfi_ring_intersection       	(const SfiRing  	*sorted_set1,
+                                         const SfiRing  	*sorted_set2,
+                                         SfiCompareFunc 	 cmp,
+                                         gpointer       	 data);
+SfiRing* sfi_ring_difference    	(const SfiRing  	*sorted_set1,
+                                         const SfiRing  	*sorted_set2,
+                                         SfiCompareFunc 	 cmp,
+                                         gpointer       	 data);
+SfiRing* sfi_ring_symmetric_difference  (const SfiRing  	*sorted_set1,
+					 const SfiRing  	*sorted_set2,
+					 SfiCompareFunc 	 cmp,
+					 gpointer       	 data);
+/* const-result cmp-based operations */
+gboolean    sfi_ring_includes      	(const SfiRing  	*sorted_super_set,
+                                         const SfiRing  	*sorted_sub_set,
+                                         SfiCompareFunc 	 cmp,
+                                         gpointer       	 data);
+gboolean    sfi_ring_mismatch      	(SfiRing               **sorted_ring1_p,
+                                         SfiRing               **sorted_ring2_p,
+                                         SfiCompareFunc 	 cmp,
+                                         gpointer       	 data);
+gboolean    sfi_ring_equals      	(const SfiRing  	*sorted_set1,
+                                         const SfiRing  	*sorted_set2,
+                                         SfiCompareFunc 	 cmp,
+                                         gpointer       	 data);
+SfiRing* sfi_ring_min_node    		(const SfiRing  	*head,
+                                         SfiCompareFunc 	 cmp,
+                                         gpointer       	 data);
+SfiRing* sfi_ring_max_node    		(const SfiRing  	*head,
+                                         SfiCompareFunc 	 cmp,
+                                         gpointer       	 data);
+gpointer    sfi_ring_min            	(const SfiRing  	*head,
+                                         SfiCompareFunc 	 cmp,
+                                         gpointer       	 data);
+gpointer    sfi_ring_max           	(const SfiRing  	*head,
+                                         SfiCompareFunc 	 cmp,
+                                         gpointer       	 data);
+
+G_END_DECLS;
+
+#endif /* __SFI_RING_H__ */
+
+/* vim:set ts=8 sts=2 sw=2: */

Modified: trunk/sfi/sfistore.h
===================================================================
--- trunk/sfi/sfistore.h	2006-10-03 11:19:35 UTC (rev 3925)
+++ trunk/sfi/sfistore.h	2006-10-03 15:28:27 UTC (rev 3926)
@@ -20,6 +20,7 @@
 #define __SFI_STORE_H__
 
 #include <sfi/sfivalues.h>
+#include <sfi/sfiring.h>
 
 G_BEGIN_DECLS
 

Modified: trunk/sfi/sfitime.c
===================================================================
--- trunk/sfi/sfitime.c	2006-10-03 11:19:35 UTC (rev 3925)
+++ trunk/sfi/sfitime.c	2006-10-03 15:28:27 UTC (rev 3926)
@@ -18,6 +18,7 @@
  */
 #include "topconfig.h"
 #include "sfitime.h"
+#include "sfiring.h"
 #include "sfiprimitives.h"
 #include <sys/time.h>
 #include <string.h>

Modified: trunk/sfi/sfitypes.h
===================================================================
--- trunk/sfi/sfitypes.h	2006-10-03 11:19:35 UTC (rev 3925)
+++ trunk/sfi/sfitypes.h	2006-10-03 15:28:27 UTC (rev 3926)
@@ -55,7 +55,6 @@
 typedef struct _SfiSeq		SfiSeq;
 typedef struct _SfiRec		SfiRec;
 typedef GType /* pointer */	SfiProxy;
-typedef struct _SfiRing		SfiRing;
 typedef struct {
   guint        n_fields;
   GParamSpec **fields;

Added: trunk/sfi/tests/Makefile.am
===================================================================
--- trunk/sfi/tests/Makefile.am	2006-10-03 11:19:35 UTC (rev 3925)
+++ trunk/sfi/tests/Makefile.am	2006-10-03 15:28:27 UTC (rev 3926)
@@ -0,0 +1,17 @@
+# Birnet
+# Copyright (C) 2006 Tim Janik
+#
+## GNU Lesser General Public License version 2 or any later version.
+include $(top_srcdir)/Makefile.decl
+
+INCLUDES       += -I$(top_srcdir) -I$(top_builddir) -I. $(SFI_CFLAGS)
+DEFS	       += -DG_LOG_DOMAIN='"$(basename $(@F))"' -DPARANOID # -DG_DISABLE_CONST_RETURNS
+
+TESTS 		 =
+noinst_PROGRAMS  = $(TESTS)
+progs_ldadd 	 = $(top_builddir)/birnet/libbirnet.o $(top_builddir)/sfi/libsfi.o $(SFI_LIBS) -lm
+
+# ring
+TESTS       += ring
+ring_SOURCES = ring.c dummy.cc
+ring_LDADD   = $(progs_ldadd)

Copied: trunk/sfi/tests/dummy.cc (from rev 3925, trunk/sfi/dummy.cc)

Copied: trunk/sfi/tests/ring.c (from rev 3925, trunk/birnet/tests/ring.cc)
===================================================================
--- trunk/birnet/tests/ring.cc	2006-10-03 11:19:35 UTC (rev 3925)
+++ trunk/sfi/tests/ring.c	2006-10-03 15:28:27 UTC (rev 3926)
@@ -0,0 +1,232 @@
+/* Birnet
+ * Copyright (C) 2006 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.
+ */
+// #define TEST_VERBOSE
+#include <birnet/birnettests.h>
+#include <sfi/sfi.h>
+
+static void
+print_ring_ints (SfiRing *ring)
+{
+  g_print ("SfiRing(%p): {", ring);
+  SfiRing *node;
+  for (node = ring; node; node = sfi_ring_walk (node, ring))
+    g_print (" %d,", (ptrdiff_t) node->data);
+  g_print (" };");
+}
+
+static void
+print_rings_side_by_side (SfiRing *ring1,
+                          SfiRing *ring2)
+{
+  SfiRing *r1 = ring1, *r2 = ring2;
+  g_printerr ("\nRing=%p Ring=%p\n", r1, r2);
+  while (r1 || r2)
+    {
+      if (r1 && r2)
+        g_printerr ("  %10p  %10p\n", r1->data, r2->data);
+      else if (r1)
+        g_printerr ("  %10p\n", r1->data);
+      else
+        g_printerr ("              %10p\n", r2->data);
+      if (r1)
+        r1 = sfi_ring_walk (r1, ring1);
+      if (r2)
+        r2 = sfi_ring_walk (r2, ring2);
+    }
+}
+
+static void
+test_sfi_ring (void)
+{
+  TSTART ("RingBasics");
+  (void) print_ring_ints;
+
+  SfiRing *r1 = NULL, *r2 = NULL, *d = NULL;
+
+  r1= sfi_ring_append (r1, (void*) 3);
+  r1= sfi_ring_append (r1, (void*) 7);
+  r1= sfi_ring_append (r1, (void*) 8);
+  r1= sfi_ring_append (r1, (void*) 13);
+  r1= sfi_ring_append (r1, (void*) 18);
+  TASSERT (sfi_ring_length (r1) == 5);
+  TASSERT (sfi_ring_equals (r1, r1, sfi_pointer_cmp, NULL));
+
+  d = sfi_ring_append (d, (void*) 13);
+  d = sfi_ring_append (d, (void*) 7);
+  d = sfi_ring_append (d, (void*) 18);
+  d = sfi_ring_append (d, (void*) 3);
+  d = sfi_ring_append (d, (void*) 8);
+  TASSERT (sfi_ring_equals (d, d, sfi_pointer_cmp, NULL));
+  TASSERT (sfi_ring_min (d, sfi_pointer_cmp, NULL) == (void*) 3);
+  TASSERT (sfi_ring_max (d, sfi_pointer_cmp, NULL) == (void*) 18);
+
+  TASSERT (sfi_ring_equals (r1, d, sfi_pointer_cmp, NULL) == FALSE);
+  d = sfi_ring_sort (d, sfi_pointer_cmp, NULL);
+  TASSERT (sfi_ring_equals (r1, d, sfi_pointer_cmp, NULL));
+  TASSERT (sfi_ring_includes (r1, d, sfi_pointer_cmp, NULL));
+  TASSERT (sfi_ring_includes (d, r1, sfi_pointer_cmp, NULL));
+  sfi_ring_free (d);
+
+  r2 = sfi_ring_append (r2, (void*) 4);
+  r2 = sfi_ring_append (r2, (void*) 7);
+  r2 = sfi_ring_append (r2, (void*) 13);
+  TASSERT (sfi_ring_length (r2) == 3);
+  d = sfi_ring_sort (sfi_ring_copy (r2), sfi_pointer_cmp, NULL);
+  TASSERT (sfi_ring_equals (r2, d, sfi_pointer_cmp, NULL));
+  TASSERT (sfi_ring_equals (r1, r2, sfi_pointer_cmp, NULL) == FALSE);
+  TASSERT (sfi_ring_includes (r1, r2, sfi_pointer_cmp, NULL) == FALSE);
+  sfi_ring_free (d);
+
+  TDONE ();
+  TSTART ("RingMath");
+
+  d = sfi_ring_difference (r1, r2, sfi_pointer_cmp, NULL);
+  TASSERT (sfi_ring_pop_head (&d) == (void*) 3);
+  TASSERT (sfi_ring_pop_head (&d) == (void*) 8);
+  TASSERT (sfi_ring_pop_head (&d) == (void*) 18);
+  TASSERT (d == NULL);
+
+  d = sfi_ring_symmetric_difference (r1, r2, sfi_pointer_cmp, NULL);
+  TASSERT (sfi_ring_pop_head (&d) == (void*) 3);
+  TASSERT (sfi_ring_pop_head (&d) == (void*) 4);
+  TASSERT (sfi_ring_pop_head (&d) == (void*) 8);
+  TASSERT (sfi_ring_pop_head (&d) == (void*) 18);
+  TASSERT (d == NULL);
+
+  SfiRing *t1 = sfi_ring_symmetric_difference (r1, r2, sfi_pointer_cmp, NULL);
+  SfiRing *t2 = sfi_ring_intersection (r1, r2, sfi_pointer_cmp, NULL);
+  d = sfi_ring_intersection (t1, t2, sfi_pointer_cmp, NULL);
+  TASSERT (d == NULL);
+  d = sfi_ring_union (t1, t2, sfi_pointer_cmp, NULL);
+  TASSERT (sfi_ring_includes (d, t1, sfi_pointer_cmp, NULL));
+  TASSERT (sfi_ring_includes (d, t2, sfi_pointer_cmp, NULL));
+  sfi_ring_free (t1);
+  sfi_ring_free (t2);
+  TASSERT (sfi_ring_includes (d, r1, sfi_pointer_cmp, NULL));
+  TASSERT (sfi_ring_includes (d, r2, sfi_pointer_cmp, NULL));
+
+  d = sfi_ring_union (r1, r2, sfi_pointer_cmp, NULL);
+  TASSERT (sfi_ring_length (d) == 6);
+  t1 = r1, t2 = d;
+  sfi_ring_mismatch (&t1, &t2, sfi_pointer_cmp, NULL);
+  TASSERT (t1->data == (void*) 7);
+  TASSERT (t2->data == (void*) 4);
+  t2 = sfi_ring_concat (sfi_ring_copy (r1), sfi_ring_copy (r2));
+  TASSERT (sfi_ring_length (t2) == 8);
+  t2 = sfi_ring_sort (t2, sfi_pointer_cmp, NULL);
+  TASSERT (sfi_ring_length (t2) == 8);
+  t1 = sfi_ring_copy_uniq (t2, sfi_pointer_cmp, NULL);
+  TASSERT (sfi_ring_length (t1) == 6);
+  TASSERT (sfi_ring_equals (d, t1, sfi_pointer_cmp, NULL));
+  sfi_ring_free (t1);
+  t1 = sfi_ring_uniq (t2, sfi_pointer_cmp, NULL);
+  TASSERT (sfi_ring_length (t1) == 6);
+  TASSERT (sfi_ring_equals (d, t1, sfi_pointer_cmp, NULL));
+  sfi_ring_free (t1);
+  sfi_ring_free (d);
+
+  sfi_ring_free (r1);
+  sfi_ring_free (r2);
+
+  TDONE ();
+  TSTART ("RingReorder");
+
+  r1 = NULL;
+  r1 = sfi_ring_append (r1, (void*) 5);
+  r1 = sfi_ring_append (r1, (void*) 7);
+  r1 = sfi_ring_append (r1, (void*) 4);
+  r1 = sfi_ring_append (r1, (void*) 8);
+  r1 = sfi_ring_append (r1, (void*) 1);
+  r2 = sfi_ring_sort (sfi_ring_copy (r1), sfi_pointer_cmp, NULL);
+  t1 = sfi_ring_reorder (sfi_ring_copy (r2), r1);
+  if (0)
+    print_rings_side_by_side (t1, r1);
+  TASSERT (sfi_ring_equals (t1, r1, sfi_pointer_cmp, NULL));
+  sfi_ring_free (t1);
+  r2 = sfi_ring_remove (r2, (void*) 4);
+  r2 = sfi_ring_append (r2, (void*) 9);
+  t1 = sfi_ring_reorder (sfi_ring_copy (r2), r1);
+  r1 = sfi_ring_remove (r1, (void*) 4);
+  r1 = sfi_ring_append (r1, (void*) 9);
+  if (0)
+    print_rings_side_by_side (t1, r1);
+  TASSERT (sfi_ring_equals (t1, r1, sfi_pointer_cmp, NULL));
+  sfi_ring_free (r1);
+  sfi_ring_free (r2);
+  sfi_ring_free (t1);
+  r1 = NULL;
+  r2 = NULL;
+  r1 = sfi_ring_append (r1, (void*) 0x75);
+  r1 = sfi_ring_append (r1, (void*) 0x4c);
+  r1 = sfi_ring_append (r1, (void*) 0x5e);
+  r2 = sfi_ring_append (r2, (void*) 0x4c);
+  r2 = sfi_ring_append (r2, (void*) 0x5e);
+  r2 = sfi_ring_append (r2, (void*) 0x68);
+  r2 = sfi_ring_append (r2, (void*) 0x68);
+  r2 = sfi_ring_reorder (r2, r1);
+  if (0)
+    print_rings_side_by_side (r2, r1);
+  TASSERT (sfi_ring_pop_head (&r2) == (void*) 0x4c);
+  TASSERT (sfi_ring_pop_head (&r2) == (void*) 0x5e);
+  TASSERT (sfi_ring_pop_head (&r2) == (void*) 0x68);
+  TASSERT (sfi_ring_pop_head (&r2) == (void*) 0x68);
+  TASSERT (r2 == NULL);
+  sfi_ring_free (r1);
+
+  r1 = NULL;
+  r1 = sfi_ring_append (r1, (void*) 0x11);
+  r1 = sfi_ring_append (r1, (void*) 0x16);
+  r1 = sfi_ring_append (r1, (void*) 0x15);
+  r1 = sfi_ring_append (r1, (void*) 0x14);
+  r1 = sfi_ring_append (r1, (void*) 0x13);
+  r1 = sfi_ring_append (r1, (void*) 0x12);
+  r1 = sfi_ring_append (r1, (void*) 0x03);
+  r1 = sfi_ring_append (r1, (void*) 0x02);
+  r1 = sfi_ring_append (r1, (void*) 0x01);
+  r2 = NULL;
+  r2 = sfi_ring_append (r2, (void*) 0x16);
+  r2 = sfi_ring_append (r2, (void*) 0x15);
+  r2 = sfi_ring_append (r2, (void*) 0x14);
+  r2 = sfi_ring_append (r2, (void*) 0x13);
+  r2 = sfi_ring_append (r2, (void*) 0x12);
+  r2 = sfi_ring_append (r2, (void*) 0x11);
+  r2 = sfi_ring_append (r2, (void*) 0x01);
+  r2 = sfi_ring_append (r2, (void*) 0x02);
+  r2 = sfi_ring_append (r2, (void*) 0x03);
+  r1 = sfi_ring_reorder (r1, r2);
+  TASSERT (sfi_ring_equals (r1, r2, sfi_pointer_cmp, NULL));
+  sfi_ring_free (r1);
+  sfi_ring_free (r2);
+
+  TDONE ();
+}
+
+
+int
+main (int   argc,
+      char *argv[])
+{
+  birnet_init_test (&argc, &argv);
+
+  test_sfi_ring();
+
+  return 0;
+}
+
+/* vim:set ts=8 sts=2 sw=2: */




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