~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2000 MySQL AB
2
3
   This program is free software; you can redistribute it and/or modify
4
   it under the terms of the GNU General Public License as published by
5
   the Free Software Foundation; version 2 of the License.
6
7
   This program is distributed in the hope that it will be useful,
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
   GNU General Public License for more details.
11
12
   You should have received a copy of the GNU General Public License
13
   along with this program; if not, write to the Free Software
1802.10.2 by Monty Taylor
Update all of the copyright headers to include the correct address.
14
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
1 by brian
clean slate
15
16
/*
17
  qsort implementation optimized for comparison of pointers
18
  Inspired by the qsort implementations by Douglas C. Schmidt,
19
  and Bentley & McIlroy's "Engineering a Sort Function".
20
*/
21
22
2173.2.1 by Monty Taylor
Fixes incorrect usage of include
23
#include <config.h>
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
24
2173.2.1 by Monty Taylor
Fixes incorrect usage of include
25
#include <drizzled/internal/my_sys.h>
26
#include <drizzled/internal/m_string.h>
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
27
28
namespace drizzled
29
{
30
namespace internal
31
{
32
1 by brian
clean slate
33
/* We need to use qsort with 2 different compare functions */
34
#ifdef QSORT_EXTRA_CMP_ARGUMENT
35
#define CMP(A,B) ((*cmp)(cmp_argument,(A),(B)))
36
#else
37
#define CMP(A,B) ((*cmp)((A),(B)))
38
#endif
39
40
#define SWAP(A, B, size,swap_ptrs)			\
41
do {							\
42
   if (swap_ptrs)					\
43
   {							\
2187.4.1 by Olaf van der Spek
Remove register keyword
44
     char **a = (char**) (A), **b = (char**) (B);  \
1 by brian
clean slate
45
     char *tmp = *a; *a++ = *b; *b++ = tmp;		\
46
   }							\
47
   else							\
48
   {							\
2187.4.1 by Olaf van der Spek
Remove register keyword
49
     char *a = (A), *b = (B);			\
50
     char *end= a+size;				\
1 by brian
clean slate
51
     do							\
52
     {							\
53
       char tmp = *a; *a++ = *b; *b++ = tmp;		\
54
     } while (a < end);					\
55
   }							\
56
} while (0)
57
58
/* Put the median in the middle argument */
59
#define MEDIAN(low, mid, high)				\
60
{							\
61
    if (CMP(high,low) < 0)				\
62
      SWAP(high, low, size, ptr_cmp);			\
63
    if (CMP(mid, low) < 0)				\
64
      SWAP(mid, low, size, ptr_cmp);			\
65
    else if (CMP(high, mid) < 0)			\
66
      SWAP(mid, high, size, ptr_cmp);			\
67
}
68
69
/* The following node is used to store ranges to avoid recursive calls */
70
71
typedef struct st_stack
72
{
73
  char *low,*high;
74
} stack_node;
75
76
#define PUSH(LOW,HIGH)  {stack_ptr->low = LOW; stack_ptr++->high = HIGH;}
77
#define POP(LOW,HIGH)   {LOW = (--stack_ptr)->low; HIGH = stack_ptr->high;}
78
365.2.9 by Monty Taylor
Got rid of all instances of ~0
79
/* The following stack size is enough for UINT32_MAX elements */
1 by brian
clean slate
80
#define STACK_SIZE	(8 * sizeof(unsigned long int))
81
#define THRESHOLD_FOR_INSERT_SORT 10
82
83
/****************************************************************************
84
** 'standard' quicksort with the following extensions:
85
**
86
** Can be compiled with the qsort2_cmp compare function
87
** Store ranges on stack to avoid recursion
88
** Use insert sort on small ranges
89
** Optimize for sorting of pointers (used often by MySQL)
90
** Use median comparison to find partition element
91
*****************************************************************************/
92
93
#ifdef QSORT_EXTRA_CMP_ARGUMENT
779.2.11 by Monty Taylor
General build cleanup - removed cruft, removed depreated checks.
94
void my_qsort2(void *base_ptr, size_t count, size_t size,
398.1.9 by Monty Taylor
Cleaned up stuff out of global.h.
95
                       qsort2_cmp cmp, void *cmp_argument)
1 by brian
clean slate
96
#else
779.2.11 by Monty Taylor
General build cleanup - removed cruft, removed depreated checks.
97
void my_qsort(void *base_ptr, size_t count, size_t size,
398.1.9 by Monty Taylor
Cleaned up stuff out of global.h.
98
                      qsort_cmp cmp)
1 by brian
clean slate
99
#endif
100
{
101
  char *low, *high, *pivot;
102
  stack_node stack[STACK_SIZE], *stack_ptr;
146 by Brian Aker
my_bool cleanup.
103
  bool ptr_cmp;
1 by brian
clean slate
104
  /* Handle the simple case first */
105
  /* This will also make the rest of the code simpler */
106
  if (count <= 1)
779.2.11 by Monty Taylor
General build cleanup - removed cruft, removed depreated checks.
107
    return;
1 by brian
clean slate
108
109
  low  = (char*) base_ptr;
110
  high = low+ size * (count - 1);
111
  stack_ptr = stack + 1;
1859.2.14 by Brian Aker
Add support for --with-valgrind
112
#ifdef HAVE_VALGRIND
1 by brian
clean slate
113
  /* The first element in the stack will be accessed for the last POP */
114
  stack[0].low=stack[0].high=0;
115
#endif
656.1.1 by Monty Taylor
OOOh doggie. Got rid of my_alloca.
116
  pivot = (char *) malloc(size);
1 by brian
clean slate
117
  ptr_cmp= size == sizeof(char*) && !((low - (char*) 0)& (sizeof(char*)-1));
118
119
  /* The following loop sorts elements between high and low */
120
  do
121
  {
122
    char *low_ptr, *high_ptr, *mid;
123
124
    count=((size_t) (high - low) / size)+1;
125
    /* If count is small, then an insert sort is faster than qsort */
126
    if (count < THRESHOLD_FOR_INSERT_SORT)
127
    {
128
      for (low_ptr = low + size; low_ptr <= high; low_ptr += size)
129
      {
398.1.9 by Monty Taylor
Cleaned up stuff out of global.h.
130
        char *ptr;
131
        for (ptr = low_ptr; ptr > low && CMP(ptr - size, ptr) > 0;
132
             ptr -= size)
133
          SWAP(ptr, ptr - size, size, ptr_cmp);
1 by brian
clean slate
134
      }
135
      POP(low, high);
136
      continue;
137
    }
138
139
    /* Try to find a good middle element */
140
    mid= low + size * (count >> 1);
141
    if (count > 40)				/* Must be bigger than 24 */
142
    {
143
      size_t step = size* (count / 8);
144
      MEDIAN(low, low + step, low+step*2);
145
      MEDIAN(mid - step, mid, mid+step);
146
      MEDIAN(high - 2 * step, high-step, high);
147
      /* Put best median in 'mid' */
148
      MEDIAN(low+step, mid, high-step);
149
      low_ptr  = low;
150
      high_ptr = high;
151
    }
152
    else
153
    {
154
      MEDIAN(low, mid, high);
155
      /* The low and high argument are already in sorted against 'pivot' */
156
      low_ptr  = low + size;
157
      high_ptr = high - size;
158
    }
159
    memcpy(pivot, mid, size);
160
161
    do
162
    {
163
      while (CMP(low_ptr, pivot) < 0)
398.1.9 by Monty Taylor
Cleaned up stuff out of global.h.
164
        low_ptr += size;
1 by brian
clean slate
165
      while (CMP(pivot, high_ptr) < 0)
398.1.9 by Monty Taylor
Cleaned up stuff out of global.h.
166
        high_ptr -= size;
1 by brian
clean slate
167
168
      if (low_ptr < high_ptr)
169
      {
398.1.9 by Monty Taylor
Cleaned up stuff out of global.h.
170
        SWAP(low_ptr, high_ptr, size, ptr_cmp);
171
        low_ptr += size;
172
        high_ptr -= size;
1 by brian
clean slate
173
      }
398.1.9 by Monty Taylor
Cleaned up stuff out of global.h.
174
      else
1 by brian
clean slate
175
      {
398.1.9 by Monty Taylor
Cleaned up stuff out of global.h.
176
        if (low_ptr == high_ptr)
177
        {
178
          low_ptr += size;
179
          high_ptr -= size;
180
        }
181
        break;
1 by brian
clean slate
182
      }
183
    }
184
    while (low_ptr <= high_ptr);
185
186
    /*
187
      Prepare for next iteration.
188
       Skip partitions of size 1 as these doesn't have to be sorted
189
       Push the larger partition and sort the smaller one first.
190
       This ensures that the stack is keept small.
191
    */
192
193
    if ((int) (high_ptr - low) <= 0)
194
    {
195
      if ((int) (high - low_ptr) <= 0)
196
      {
398.1.9 by Monty Taylor
Cleaned up stuff out of global.h.
197
        POP(low, high);			/* Nothing more to sort */
1 by brian
clean slate
198
      }
199
      else
398.1.9 by Monty Taylor
Cleaned up stuff out of global.h.
200
        low = low_ptr;			/* Ignore small left part. */
1 by brian
clean slate
201
    }
202
    else if ((int) (high - low_ptr) <= 0)
203
      high = high_ptr;			/* Ignore small right part. */
204
    else if ((high_ptr - low) > (high - low_ptr))
205
    {
206
      PUSH(low, high_ptr);		/* Push larger left part */
207
      low = low_ptr;
208
    }
209
    else
210
    {
211
      PUSH(low_ptr, high);		/* Push larger right part */
212
      high = high_ptr;
213
    }
214
  } while (stack_ptr > stack);
656.1.1 by Monty Taylor
OOOh doggie. Got rid of my_alloca.
215
  free(pivot);
779.2.11 by Monty Taylor
General build cleanup - removed cruft, removed depreated checks.
216
  return;
1 by brian
clean slate
217
}
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
218
219
} /* namespace internal */
220
} /* namespace drizzled */