2007-10-19 Nagappan A <anagappan@novell.com>
[mono.git] / eglib / src / sort.frag.h
index 3e9e2dde1dd6681199b81e651a0685c59f6c61da..4488fdd3d574f3970eca2159c8afafa53ae2c906 100644 (file)
@@ -1,6 +1,56 @@
-/* A "counting" merge sort that avoids recursion */
+/*
+ * sort.frag.h: Common implementation of linked-list sorting
+ *
+ * Author:
+ *   Raja R Harinath (rharinath@novell.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * (C) 2006 Novell, Inc.
+ */
 
-#define N_DIGITS (sizeof (size_t) * 8)
+/*
+ * This code requires a typedef named 'list_node' for the list node.  It
+ * is assumed that the list type is the type of a pointer to a list
+ * node, and that the node has a field named 'next' that implements to
+ * the linked list.  No additional invariant is maintained (e.g. the
+ * 'prev' pointer of a doubly-linked list node is _not_ updated).  Any
+ * invariant would require a post-processing pass to fix matters if
+ * necessary.
+ *
+ * Note: We refer to a list fragment as a "digit" because the code for
+ * maintaining the invariants of the core data structure parallels the
+ * code for incrementing the binary representation of a number.
+ */
+typedef list_node *digit;
+
+/*
+ * The maximum possible depth of the merge tree
+ *   = ceiling (log2 (maximum number of list nodes))
+ *   = ceiling (log2 (maximum possible memory size/size of each list node))
+ *   = number of bits in 'size_t' - floor (log2 (sizeof digit))
+ * Also, each "digit" is at least 2 nodes long: we can reduce the depth by 1
+ */
+
+#define FLOOR_LOG2(x) (((x)>=2) + ((x)>=4) + ((x)>=8) + ((x)>=16) + ((x)>=32) + ((x)>=64) + ((x)>=128))
+#define MAX_DIGITS ((sizeof (size_t) * 8) - FLOOR_LOG2(sizeof (list_node)) - 1)
 
 static inline digit
 add_digits (digit first, digit second, GCompareFunc func)
@@ -23,39 +73,46 @@ add_digits (digit first, digit second, GCompareFunc func)
 }
 
 static inline digit
-combine_digits (digit *digits, int max_digit, GCompareFunc func)
+combine_digits (digit *digits, digit list, int n_digits, GCompareFunc func)
 {
        int i;
-       digit list = digits [0];
-       for (i = 1; i <= max_digit; ++i)
+       for (i = 0; i < n_digits; ++i)
                list = add_digits (digits [i], list, func);
        return list;
 }
 
+/*
+ * Given: length(list) == k
+ * Invariant: digit[i] == NULL || length(digit[i]) == k * 2**i
+ */
 static inline int
-increment (digit *digits, digit list, int max_digit, GCompareFunc func)
+increment (digit *digits, digit list, int n_digits, GCompareFunc func)
 {
        int i;
-
-       if (!list)
-               return max_digit;
-
-       for (i = 0; digits [i]; i++) {
+       for (i = 0; i < n_digits && digits [i]; i++) {
                list = add_digits (digits [i], list, func);
                digits [i] = NULL;
-               if (i == N_DIGITS-1) /* Should _never_ happen, but if it does, we just devolve into quadratic ;-) */
-                       break;
        }
+       if (i == MAX_DIGITS) /* Will _never_ happen: so we can just devolve into quadratic ;-) */
+               --i;
+
+       if (i == n_digits)
+               ++n_digits;
        digits [i] = list;
-       return i > max_digit ? i : max_digit;
+       return n_digits;
 }
 
+/*
+ * A mergesort that avoids recursion.  The 'digits' array essentially
+ * captures the recursion stack.  The actual merge tree is built in a
+ * bottom-up manner.  It's "counting", since we "increment" a set of
+ * "digit"s.
+ */
 static inline digit
 do_sort (digit list, GCompareFunc func)
 {
-       int max_digit = 0;
-       digit digits [N_DIGITS]; /* 128 bytes on 32bit, 512 bytes on 64bit */
-       memset (digits, 0, sizeof digits);
+       int n_digits = 0;
+       digit digits [MAX_DIGITS]; /* ~ 128 bytes on 32bit, ~ 512 bytes on 64bit */
 
        while (list && list->next) {
                digit next = list->next;
@@ -68,14 +125,13 @@ do_sort (digit list, GCompareFunc func)
                }
                next->next = NULL;
 
-               max_digit = increment (digits, list, max_digit, func);
+               n_digits = increment (digits, list, n_digits, func);
 
                list = tail;
        }
 
-       max_digit = increment (digits, list, max_digit, func);
-
-       return combine_digits (digits, max_digit, func);
+       return combine_digits (digits, list, n_digits, func);
 }
 
-#undef N_DIGITS
+#undef MAX_DIGITS
+#undef FLOOR_LOG2