Added silc_list_sort, sorts SilcList using Gnome Sort algorithm
authorPekka Riikonen <priikone@silcnet.org>
Sat, 28 Jun 2008 13:57:45 +0000 (16:57 +0300)
committerPekka Riikonen <priikone@silcnet.org>
Sat, 28 Jun 2008 13:57:45 +0000 (16:57 +0300)
lib/silcutil/silclist.h
lib/silcutil/tests/test_silclist.c

index 52454c30d7f1dd2b2ec1ab575d6d46a7b7520a2e..7336c5e183c3e1e4835d6d709a4af5b69a6a5d0f 100644 (file)
@@ -394,4 +394,64 @@ void *__silc_list_pop(SilcList *list)
   return head;
 }
 
+/****f* silcutil/silc_list_sort
+ *
+ * SYNOPSIS
+ *
+ *    void silc_list_sort(SilcList *list,
+ *                        int (*compare)(void *entry1, void *entry2,
+ *                                       void *context), void *context);
+ *
+ * DESCRIPTION
+ *
+ *    Sort the list.  The `compare' function will be called with `context'
+ *    to do comparison between the entries.  The `compare' must return
+ *    less than, equal to, or greater than zero if the first argument is
+ *    considered to be respectively less than, equal to, or greater than
+ *    the second.  The entries are then sorted in ascending order.
+ *
+ * NOTES
+ *
+ *    The list must be initialized with silc_list_init_prev for sorting
+ *    to work.
+ *
+ ***/
+#define silc_list_sort(x, comp, ctx) __silc_list_sort(&(x), comp, ctx)
+static inline
+void __silc_list_sort(SilcList *list,
+                     int (*compare)(void *entry1, void *entry2,
+                                    void *context), void *context)
+{
+  void *c_cur, *c_prev;
+
+  SILC_ASSERT(list->prev_set);
+  if (!list->prev_set)
+    return;
+
+  if (silc_list_count(*list) < 2)
+    return;
+
+  /* Gnome sort */
+  silc_list_start(*list);
+  c_prev = silc_list_get(*list);
+  while ((c_cur = silc_list_get(*list))) {
+    if (compare(c_prev, c_cur, context) > 0) {
+      list->current = *__silc_list_prev(*list, c_prev);
+      silc_list_del(*list, c_prev);
+      silc_list_insert(*list, c_cur, c_prev);
+
+      if (list->current) {
+        c_prev = list->current;
+        list->current = c_cur;
+        continue;
+      }
+      list->current = c_cur;
+      silc_list_get(*list);
+    }
+    c_prev = c_cur;
+  }
+
+  list->current = NULL;
+}
+
 #endif /* SILCLIST_H */
index 70c1cb0eb167fc98b756c51cfb65f02f2f55cf58..86de91e78a5c79e2a3afe4dcf17113e26142fcd2 100644 (file)
@@ -8,11 +8,21 @@ struct foo {
   struct foo *prev;
 };
 
+static int compare(void *e1, void *e2, void *context)
+{
+  struct foo *ee1 = e1, *ee2 = e2;
+  SILC_LOG_DEBUG(("entry %d, %p, next=%p, prev=%p", ee1->i, ee1, ee1->next,
+                  ee1->prev));
+  SILC_LOG_DEBUG(("> entry %d, %p, next=%p, prev=%p", ee2->i, ee2, ee2->next,
+                  ee2->prev));
+  return ee1->i - ee2->i;
+}
+
 int main(int argc, char **argv)
 {
   SilcBool success = FALSE;
   SilcList list;
-  struct foo *f, *f1, *f2, *f3, *f4;
+  struct foo *f, *f1, *f2, *f3, *f4, *f5, *f6, *f7;
 
   if (argc > 1 && !strcmp(argv[1], "-d")) {
     silc_log_debug(TRUE);
@@ -37,6 +47,18 @@ int main(int argc, char **argv)
   if (!f4)
     goto err;
   f4->i = 4;
+  f5 = silc_calloc(1, sizeof(*f4));
+  if (!f5)
+    goto err;
+  f5->i = 5;
+  f6 = silc_calloc(1, sizeof(*f4));
+  if (!f6)
+    goto err;
+  f6->i = 6;
+  f7 = silc_calloc(1, sizeof(*f4));
+  if (!f7)
+    goto err;
+  f7->i = 7;
 
   SILC_LOG_DEBUG(("Add one entry"));
   silc_list_add(list, f1);
@@ -162,6 +184,31 @@ int main(int argc, char **argv)
   if (silc_list_count(list))
     goto err;
 
+  /* Sort */
+  silc_list_init_prev(list, struct foo, next, prev);
+  silc_list_add(list, f2);
+  silc_list_add(list, f7);
+  silc_list_add(list, f4);
+  silc_list_add(list, f6);
+  silc_list_add(list, f5);
+  silc_list_add(list, f1);
+  silc_list_add(list, f3);
+
+  SILC_LOG_DEBUG(("Unsorted list"));
+  silc_list_start(list);
+  while ((f = silc_list_get(list)) != SILC_LIST_END)
+    SILC_LOG_DEBUG(("entry %d, %p, next=%p, prev=%p", f->i, f, f->next,
+                  f->prev));
+
+  SILC_LOG_DEBUG(("Sorting"));  
+  silc_list_sort(list, compare, NULL);
+
+  SILC_LOG_DEBUG(("Sorted list"));
+  silc_list_start(list);
+  while ((f = silc_list_get(list)) != SILC_LIST_END)
+    SILC_LOG_DEBUG(("entry %d, %p, next=%p, prev=%p", f->i, f, f->next,
+                  f->prev));
+
   success = TRUE;
 
  err: