diff --git a/ChangeLog b/ChangeLog index 25d3b3a64..3ab24ca3d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2005-01-13 Matthias Clasen + + * glib/gqsort.c: Sync to glibc. (#133994, Morten Welinder, + patch by Kjartan Maraas) + 2005-01-11 Owen Taylor * configure.in: Add gmodule-export-2.0.pc to AC_CONFIG_FILES. diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 25d3b3a64..3ab24ca3d 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,8 @@ +2005-01-13 Matthias Clasen + + * glib/gqsort.c: Sync to glibc. (#133994, Morten Welinder, + patch by Kjartan Maraas) + 2005-01-11 Owen Taylor * configure.in: Add gmodule-export-2.0.pc to AC_CONFIG_FILES. diff --git a/ChangeLog.pre-2-12 b/ChangeLog.pre-2-12 index 25d3b3a64..3ab24ca3d 100644 --- a/ChangeLog.pre-2-12 +++ b/ChangeLog.pre-2-12 @@ -1,3 +1,8 @@ +2005-01-13 Matthias Clasen + + * glib/gqsort.c: Sync to glibc. (#133994, Morten Welinder, + patch by Kjartan Maraas) + 2005-01-11 Owen Taylor * configure.in: Add gmodule-export-2.0.pc to AC_CONFIG_FILES. diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 25d3b3a64..3ab24ca3d 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,8 @@ +2005-01-13 Matthias Clasen + + * glib/gqsort.c: Sync to glibc. (#133994, Morten Welinder, + patch by Kjartan Maraas) + 2005-01-11 Owen Taylor * configure.in: Add gmodule-export-2.0.pc to AC_CONFIG_FILES. diff --git a/glib/gqsort.c b/glib/gqsort.c index ac45e8b59..bee523b40 100644 --- a/glib/gqsort.c +++ b/glib/gqsort.c @@ -1,5 +1,5 @@ /* GLIB - Library of useful routines for C programming - * Copyright (C) 1991, 1992, 1996, 1997 Free Software Foundation, Inc. + * Copyright (C) 1991, 1992, 1996, 1997,1999,2004 Free Software Foundation, Inc. * Copyright (C) 2000 Eazel, Inc. * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * @@ -34,12 +34,14 @@ #include "config.h" +#include +#include +#include #include #include "galias.h" #include "glib.h" - /* Byte-wise swap two items of size SIZE. */ #define SWAP(a, b, size) \ do \ @@ -60,42 +62,45 @@ /* Stack node declarations used to store unfulfilled partition obligations. */ typedef struct -{ - char *lo; - char *hi; -} -stack_node; + { + char *lo; + char *hi; + } stack_node; /* The next 4 #defines implement a very fast in-line stack abstraction. */ -#define STACK_SIZE (8 * sizeof(unsigned long int)) +/* The stack needs log (total_elements) entries (we could even subtract + log(MAX_THRESH)). Since total_elements has type size_t, we get as + upper bound for log (total_elements): + bits per byte (CHAR_BIT) * sizeof(size_t). */ +#define STACK_SIZE (CHAR_BIT * sizeof(size_t)) #define PUSH(low, high) ((void) ((top->lo = (low)), (top->hi = (high)), ++top)) #define POP(low, high) ((void) (--top, (low = top->lo), (high = top->hi))) #define STACK_NOT_EMPTY (stack < top) /* Order size using quicksort. This implementation incorporates - * four optimizations discussed in Sedgewick: - * - * 1. Non-recursive, using an explicit stack of pointer that store the next - * array partition to sort. To save time, this maximum amount of space - * required to store an array of MAX_INT is allocated on the stack. Assuming - * a 32-bit integer, this needs only 32 * sizeof(stack_node) == 136 bits. - * Pretty cheap, actually. - * - * 2. Chose the pivot element using a median-of-three decision tree. This - * reduces the probability of selecting a bad pivot value and eliminates - * certain * extraneous comparisons. - * - * 3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving insertion - * sort to order the MAX_THRESH items within each partition. This is a big - * win, since insertion sort is faster for small, mostly sorted array - * segments. - * - * 4. The larger of the two sub-partitions is always pushed onto the stack - * first, with the algorithm then concentrating on the smaller partition. - * This *guarantees* no more than log (n) stack size is needed (actually O(1) - * in this case)! - */ + four optimizations discussed in Sedgewick: + + 1. Non-recursive, using an explicit stack of pointer that store the + next array partition to sort. To save time, this maximum amount + of space required to store an array of SIZE_MAX is allocated on the + stack. Assuming a 32-bit (64 bit) integer for size_t, this needs + only 32 * sizeof(stack_node) == 256 bytes (for 64 bit: 1024 bytes). + Pretty cheap, actually. + + 2. Chose the pivot element using a median-of-three decision tree. + This reduces the probability of selecting a bad pivot value and + eliminates certain extraneous comparisons. + + 3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving + insertion sort to order the MAX_THRESH items within each partition. + This is a big win, since insertion sort is faster for small, mostly + sorted array segments. + + 4. The larger of the two sub-partitions is always pushed onto the + stack first, with the algorithm then concentrating on the + smaller partition. This *guarantees* no more than log (total_elems) + stack size is needed (actually O(1) in this case)! */ /** * g_qsort_with_data: @@ -118,10 +123,6 @@ g_qsort_with_data (gconstpointer pbase, { register char *base_ptr = (char *) pbase; - /* Allocating SIZE bytes for a pivot buffer facilitates a better - * algorithm below since we can do comparisons directly on the pivot. - */ - char *pivot_buffer = (char *) g_alloca (size); const size_t max_thresh = MAX_THRESH * size; g_return_if_fail (total_elems >= 0); @@ -129,27 +130,28 @@ g_qsort_with_data (gconstpointer pbase, g_return_if_fail (compare_func != NULL); if (total_elems == 0) + /* Avoid lossage with unsigned arithmetic below. */ return; if (total_elems > MAX_THRESH) { char *lo = base_ptr; char *hi = &lo[size * (total_elems - 1)]; - /* Largest size needed for 32-bit int!!! */ stack_node stack[STACK_SIZE]; - stack_node *top = stack + 1; + stack_node *top = stack; + + PUSH (NULL, NULL); while (STACK_NOT_EMPTY) - { - char *left_ptr; - char *right_ptr; - - char *pivot = pivot_buffer; + { + char *left_ptr; + char *right_ptr; /* Select median value from among LO, MID, and HI. Rearrange - * LO and HI so the three values are sorted. This lowers the - * probability of picking a pathological pivot value and - * skips a comparison for both the LEFT_PTR and RIGHT_PTR. */ + LO and HI so the three values are sorted. This lowers the + probability of picking a pathological pivot value and + skips a comparison for both the LEFT_PTR and RIGHT_PTR in + the while loops. */ char *mid = lo + size * ((hi - lo) / size >> 1); @@ -162,30 +164,28 @@ g_qsort_with_data (gconstpointer pbase, if ((*compare_func) ((void *) mid, (void *) lo, user_data) < 0) SWAP (mid, lo, size); jump_over:; - memcpy (pivot, mid, size); - pivot = pivot_buffer; - left_ptr = lo + size; + left_ptr = lo + size; right_ptr = hi - size; /* Here's the famous ``collapse the walls'' section of quicksort. - * Gotta like those tight inner loops! They are the main reason - * that this algorithm runs much faster than others. */ + Gotta like those tight inner loops! They are the main reason + that this algorithm runs much faster than others. */ do { - while ((*compare_func) - ((void *) left_ptr, (void *) pivot, - user_data) < 0) + while ((*compare_func) ((void *) left_ptr, (void *) mid, user_data) < 0) left_ptr += size; - while ((*compare_func) - ((void *) pivot, (void *) right_ptr, - user_data) < 0) + while ((*compare_func) ((void *) mid, (void *) right_ptr, user_data) < 0) right_ptr -= size; if (left_ptr < right_ptr) { SWAP (left_ptr, right_ptr, size); + if (mid == left_ptr) + mid = right_ptr; + else if (mid == right_ptr) + mid = left_ptr; left_ptr += size; right_ptr -= size; } @@ -198,60 +198,59 @@ g_qsort_with_data (gconstpointer pbase, } while (left_ptr <= right_ptr); - /* Set up pointers for next iteration. First determine whether - * left and right partitions are below the threshold size. If so, - * ignore one or both. Otherwise, push the larger partition's - * bounds on the stack and continue sorting the smaller one. */ + /* Set up pointers for next iteration. First determine whether + left and right partitions are below the threshold size. If so, + ignore one or both. Otherwise, push the larger partition's + bounds on the stack and continue sorting the smaller one. */ - if ((size_t) (right_ptr - lo) <= max_thresh) - { - if ((size_t) (hi - left_ptr) <= max_thresh) + if ((size_t) (right_ptr - lo) <= max_thresh) + { + if ((size_t) (hi - left_ptr) <= max_thresh) /* Ignore both small partitions. */ - POP (lo, hi); - else + POP (lo, hi); + else /* Ignore small left partition. */ - lo = left_ptr; - } - else if ((size_t) (hi - left_ptr) <= max_thresh) - /* Ignore small right partition. */ - hi = right_ptr; - else if ((right_ptr - lo) > (hi - left_ptr)) - { - /* Push larger left partition indices. */ - PUSH (lo, right_ptr); - lo = left_ptr; - - } - else - { - /* Push larger right partition indices. */ - PUSH (left_ptr, hi); - hi = right_ptr; - } - } + lo = left_ptr; + } + else if ((size_t) (hi - left_ptr) <= max_thresh) + /* Ignore small right partition. */ + hi = right_ptr; + else if ((right_ptr - lo) > (hi - left_ptr)) + { + /* Push larger left partition indices. */ + PUSH (lo, right_ptr); + lo = left_ptr; + } + else + { + /* Push larger right partition indices. */ + PUSH (left_ptr, hi); + hi = right_ptr; + } + } } /* Once the BASE_PTR array is partially sorted by quicksort the rest - * is completely sorted using insertion sort, since this is efficient - * for partitions below MAX_THRESH size. BASE_PTR points to the beginning - * of the array to sort, and END_PTR points at the very last element in - * the array (*not* one beyond it!). */ + is completely sorted using insertion sort, since this is efficient + for partitions below MAX_THRESH size. BASE_PTR points to the beginning + of the array to sort, and END_PTR points at the very last element in + the array (*not* one beyond it!). */ + +#define min(x, y) ((x) < (y) ? (x) : (y)) { char *const end_ptr = &base_ptr[size * (total_elems - 1)]; char *tmp_ptr = base_ptr; - char *thresh = MIN (end_ptr, base_ptr + max_thresh); + char *thresh = min(end_ptr, base_ptr + max_thresh); register char *run_ptr; /* Find smallest element in first threshold and place it at the - * array's beginning. This is the smallest array element, - * and the operation speeds up insertion sort's inner loop. */ + array's beginning. This is the smallest array element, + and the operation speeds up insertion sort's inner loop. */ - for (run_ptr = tmp_ptr + size; run_ptr <= thresh; - run_ptr += - size) if ((*compare_func) ((void *) run_ptr, (void *) tmp_ptr, - user_data) < 0) - tmp_ptr = run_ptr; + for (run_ptr = tmp_ptr + size; run_ptr <= thresh; run_ptr += size) + if ((*compare_func) ((void *) run_ptr, (void *) tmp_ptr, user_data) < 0) + tmp_ptr = run_ptr; if (tmp_ptr != base_ptr) SWAP (tmp_ptr, base_ptr, size); @@ -262,28 +261,25 @@ g_qsort_with_data (gconstpointer pbase, while ((run_ptr += size) <= end_ptr) { tmp_ptr = run_ptr - size; - while ((*compare_func) - ((void *) run_ptr, (void *) tmp_ptr, - user_data) < 0) + while ((*compare_func) ((void *) run_ptr, (void *) tmp_ptr, user_data) < 0) tmp_ptr -= size; tmp_ptr += size; - if (tmp_ptr != run_ptr) - { - char *trav; + if (tmp_ptr != run_ptr) + { + char *trav; trav = run_ptr + size; while (--trav >= run_ptr) - { - char c = *trav; - char *hi, *lo; + { + char c = *trav; + char *hi, *lo; - for (hi = lo = trav; - (lo -= size) >= tmp_ptr; hi = lo) - *hi = *lo; - *hi = c; - } - } + for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo) + *hi = *lo; + *hi = c; + } + } } } }