Skip to content

Commit b6858ae

Browse files
committed
Update qsort implementation
1 parent 02597cd commit b6858ae

File tree

1 file changed

+20
-12
lines changed

1 file changed

+20
-12
lines changed

src/stdlib/SDL_qsort.c

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848

4949
/*
5050
This code came from Gareth McCaughan, under the zlib license.
51-
Specifically this: https://www.mccaughan.org.uk/software/qsort.c-1.15
51+
Specifically this: https://www.mccaughan.org.uk/software/qsort.c-1.16
5252
5353
Everything below this comment until the HAVE_QSORT #endif was from Gareth
5454
(any minor changes will be noted inline).
@@ -97,7 +97,7 @@ Update for SDL3: we have modified this from a qsort function to qsort_r.
9797
* Gareth McCaughan
9898
*/
9999

100-
/* Copyright (c) 1998-2016 Gareth McCaughan
100+
/* Copyright (c) 1998-2021 Gareth McCaughan
101101
*
102102
* This software is provided 'as-is', without any express or implied
103103
* warranty. In no event will the authors be held liable for any
@@ -133,17 +133,23 @@ Update for SDL3: we have modified this from a qsort function to qsort_r.
133133
* (pre-insertion-sort messed up).
134134
* Disable DEBUG_QSORT by default.
135135
* Tweak comments very slightly.
136+
* 2021-02-20 v1.16 Fix bug kindly reported by Ray Gardner
137+
* (error in recursion leading to possible
138+
* stack overflow).
139+
* When checking alignment, avoid casting
140+
* pointer to possibly-smaller integer.
136141
*/
137142

138143
/* BEGIN SDL CHANGE ... commented this out with an #if 0 block. --ryan. */
139144
#if 0
140145
#include <assert.h>
146+
#include <stdint.h>
141147
#include <stdlib.h>
142148
#include <string.h>
143149

144150
#undef DEBUG_QSORT
145151

146-
static char _ID[]="<qsort.c gjm WITH CHANGES FOR SDL3 1.15 2016-03-10>";
152+
static char _ID[]="<qsort.c gjm WITH CHANGES FOR SDL3 1.16 2021-02-20>";
147153
#endif
148154
/* END SDL CHANGE ... commented this out with an #if 0 block. --ryan. */
149155

@@ -153,7 +159,8 @@ static char _ID[]="<qsort.c gjm WITH CHANGES FOR SDL3 1.15 2016-03-10>";
153159
#define WORD_BYTES sizeof(int)
154160

155161
/* How big does our stack need to be? Answer: one entry per
156-
* bit in a |size_t|.
162+
* bit in a |size_t|. (Actually, a bit less because we don't
163+
* recurse all the way down to size-1 subarrays.)
157164
*/
158165
#define STACK_SIZE (8*sizeof(size_t))
159166

@@ -192,11 +199,12 @@ typedef struct { char * first; char * last; } stack_entry;
192199
* on large datasets for locality-of-reference reasons,
193200
* but it makes the code much nastier and increases
194201
* bookkeeping overhead.
195-
* 2. We always save the shorter and get to work on the
196-
* longer. This guarantees that every time we push
197-
* an item onto the stack its size is <= 1/2 of that
198-
* of its parent; so the stack can't need more than
199-
* log_2(max-array-size) entries.
202+
* 2. We always save the longer and get to work on the
203+
* shorter. This guarantees that whenever we push
204+
* a k'th entry onto the stack we are about to get
205+
* working on something of size <= N/2^k where N is
206+
* the original array size; so the stack can't need
207+
* more than log_2(max-array-size) entries.
200208
* 3. We choose a pivot by looking at the first, last
201209
* and middle elements. We arrange them into order
202210
* because it's easy to do that in conjunction with
@@ -258,8 +266,8 @@ typedef struct { char * first; char * last; } stack_entry;
258266
if (r>=Trunc) doRight \
259267
else pop \
260268
} \
261-
else if (l<=r) { pushLeft; doRight } \
262-
else if (r>=Trunc) { pushRight; doLeft }\
269+
else if (l<=r) { pushRight; doLeft } \
270+
else if (r>=Trunc) { pushLeft; doRight }\
263271
else doLeft \
264272
}
265273

@@ -511,7 +519,7 @@ void SDL_qsort_r(void *base, size_t nmemb, size_t size,
511519
SDL_CompareCallback_r compare, void *userdata) {
512520

513521
if (nmemb<=1) return;
514-
if (((size_t)base|size)&(WORD_BYTES-1))
522+
if (((uintptr_t)base|size)&(WORD_BYTES-1))
515523
qsort_r_nonaligned(base,nmemb,size,compare,userdata);
516524
else if (size!=WORD_BYTES)
517525
qsort_r_aligned(base,nmemb,size,compare,userdata);

0 commit comments

Comments
 (0)