1/* 2 * This program is free software; you can redistribute it and/or 3 * modify it under the terms of the GNU General Public License as 4 * published by the Free Software Foundation; either version 2 of 5 * the License, or (at your option) any later version. 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 14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 15 * MA 02111-1307 USA 16 */ 17/*************************************************************************** 18 * LPRng - An Extended Print Spooler System 19 * 20 * Copyright 1988-2003, Patrick Powell, San Diego, CA 21 * papowell@lprng.com 22 * See LICENSE for conditions of use. 23 * 24 ***************************************************************************/ 25 26 static char *const _id = 27"$Id: merge.c,v 1.1.1.1 2008/10/15 03:28:27 james26_jang Exp $"; 28 29 30/*- 31 * copyright (c) 1992, 1993 32 * The Regents of the University of California. All rights reserved. 33 * 34 * This code is derived from software contributed to Berkeley by 35 * Peter McIlroy. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 3. All advertising materials mentioning features or use of this software 46 * must display the following acknowledgement: 47 * This product includes software developed by the University of 48 * California, Berkeley and its contributors. 49 * 4. Neither the name of the University nor the names of its contributors 50 * may be used to endorse or promote products derived from this software 51 * without specific prior written permission. 52 * 53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 63 * SUCH DAMAGE. 64 */ 65 66#if defined(LIBC_SCCS) && !defined(lint) 67 static char sccsid[] = "@(#)merge.c 8.2 (Berkeley) 2/14/94"; 68#endif /* LIBC_SCCS and not lint */ 69 70/* 71 * Hybrid exponential search/linear search merge sort with hybrid 72 * natural/pairwise first pass. Requires about .3% more comparisons 73 * for random data than LSMS with pairwise first pass alone. 74 * It works for objects as small as two bytes. 75 */ 76 77#define NATURAL 78#define THRESHOLD 16 /* Best choice for natural merge cut-off. */ 79 80/* #define NATURAL to get hybrid natural merge. 81 * (The default is pairwise merging.) 82 */ 83 84#include "lp.h" 85#include "merge.h" 86 87 static void 88 setup(unsigned char *list1, unsigned char *list2, size_t n, size_t size, 89 int (*cmp)(const void *, const void *, const void *), const void * arg); 90 static void 91 insertionsort(unsigned char *a, size_t n, size_t size, 92 int (*cmp)(const void *, const void *, const void *), const void * arg); 93 94#define ISIZE sizeof(int) 95#define PSIZE sizeof(unsigned char *) 96#define ICOPY_LIST(src, dst, last) \ 97 do \ 98 *(int*)dst = *(int*)src, src += ISIZE, dst += ISIZE; \ 99 while(src < last) 100#define ICOPY_ELT(src, dst, i) \ 101 do \ 102 *(int*) dst = *(int*) src, src += ISIZE, dst += ISIZE; \ 103 while (i -= ISIZE) 104 105#define CCOPY_LIST(src, dst, last) \ 106 do \ 107 *dst++ = *src++; \ 108 while (src < last) 109#define CCOPY_ELT(src, dst, i) \ 110 do \ 111 *dst++ = *src++; \ 112 while (i -= 1) 113 114/* 115 * Find the next possible pointer head. (Trickery for forcing an array 116 * to do double duty as a linked list when objects do not align with word 117 * boundaries. 118 */ 119/* Assumption: PSIZE is a power of 2. */ 120#define EVAL(p) (unsigned char **) \ 121 ((unsigned char *)0 + \ 122 (((unsigned char *)p + PSIZE - 1 - (unsigned char *) 0) & ~(PSIZE - 1))) 123 124/* 125 * We pass an additional arguement to the comparison routines. 126 * This lack of a third argument is a real defect in the qsort, etc. 127 * code 128 */ 129int 130Mergesort(void *base, size_t nmemb, size_t size, 131 int (*cmp)(const void *, const void *, const void *), const void * arg) 132{ 133 int i, sense; 134 int big, iflag; 135 unsigned char *f1, *f2, *t, *b, *tp2, *q, *l1, *l2; 136 unsigned char *list2, *list1, *p2, *p, *last, **p1; 137 138 if( nmemb < 2 ){ 139 return(0); 140 } 141 if (size < PSIZE / 2) { /* Pointers must fit into 2 * size. */ 142 errno = EINVAL; 143 return (-1); 144 } 145 146 /* 147 * XXX 148 * Stupid subtraction for the Cray. 149 */ 150 iflag = 0; 151 if (!(size % ISIZE) && !(((char *)base - (char *)0) % ISIZE)) 152 iflag = 1; 153 154 list2 = malloc_or_die( (nmemb * size + PSIZE),__FILE__,__LINE__); 155 156 list1 = base; 157 setup(list1, list2, nmemb, size, cmp, arg); 158 last = list2 + nmemb * size; 159 i = big = 0; 160 while (*EVAL(list2) != last) { 161 l2 = list1; 162 p1 = EVAL(list1); 163 for (tp2 = p2 = list2; p2 != last; p1 = EVAL(l2)) { 164 p2 = *EVAL(p2); 165 f1 = l2; 166 f2 = l1 = list1 + (p2 - list2); 167 if (p2 != last) 168 p2 = *EVAL(p2); 169 l2 = list1 + (p2 - list2); 170 while (f1 < l1 && f2 < l2) { 171 if ((*cmp)(f1, f2, arg) <= 0) { 172 q = f2; 173 b = f1, t = l1; 174 sense = -1; 175 } else { 176 q = f1; 177 b = f2, t = l2; 178 sense = 0; 179 } 180 if (!big) { /* here i = 0 */ 181/*LINEAR:*/ while ((b += size) < t && cmp(q, b, arg) >sense) 182 if (++i == 6) { 183 big = 1; 184 goto EXPONENTIAL; 185 } 186 } else { 187 EXPONENTIAL: for (i = size; ; i <<= 1) 188 if ((p = (b + i)) >= t) { 189 if ((p = t - size) > b && 190 (*cmp)(q, p, arg) <= sense) 191 t = p; 192 else 193 b = p; 194 break; 195 } else if ((*cmp)(q, p, arg) <= sense) { 196 t = p; 197 if (i == (int)size) 198 big = 0; 199 goto FASTCASE; 200 } else 201 b = p; 202/*SLOWCASE:*/ while (t > b+size) { 203 i = (((t - b) / size) >> 1) * size; 204 if ((*cmp)(q, p = b + i, arg) <= sense) 205 t = p; 206 else 207 b = p; 208 } 209 goto COPY; 210 FASTCASE: while (i > (int)size) 211 if ((*cmp)(q, 212 p = b + (i >>= 1), arg) <= sense) 213 t = p; 214 else 215 b = p; 216 COPY: b = t; 217 } 218 i = size; 219 if (q == f1) { 220 if (iflag) { 221 ICOPY_LIST(f2, tp2, b); 222 ICOPY_ELT(f1, tp2, i); 223 } else { 224 CCOPY_LIST(f2, tp2, b); 225 CCOPY_ELT(f1, tp2, i); 226 } 227 } else { 228 if (iflag) { 229 ICOPY_LIST(f1, tp2, b); 230 ICOPY_ELT(f2, tp2, i); 231 } else { 232 CCOPY_LIST(f1, tp2, b); 233 CCOPY_ELT(f2, tp2, i); 234 } 235 } 236 } 237 if (f2 < l2) { 238 if (iflag) 239 ICOPY_LIST(f2, tp2, l2); 240 else 241 CCOPY_LIST(f2, tp2, l2); 242 } else if (f1 < l1) { 243 if (iflag) 244 ICOPY_LIST(f1, tp2, l1); 245 else 246 CCOPY_LIST(f1, tp2, l1); 247 } 248 *p1 = l2; 249 } 250 tp2 = list1; /* swap list1, list2 */ 251 list1 = list2; 252 list2 = tp2; 253 last = list2 + nmemb*size; 254 } 255 if (base == list2) { 256 memmove(list2, list1, nmemb*size); 257 list2 = list1; 258 } 259 free(list2); 260 return (0); 261} 262 263#define swap(a, b) { \ 264 s = b; \ 265 i = size; \ 266 do { \ 267 tmp = *a; *a++ = *s; *s++ = tmp; \ 268 } while (--i); \ 269 a -= size; \ 270 } 271#define reverse(bot, top) { \ 272 s = top; \ 273 do { \ 274 i = size; \ 275 do { \ 276 tmp = *bot; *bot++ = *s; *s++ = tmp; \ 277 } while (--i); \ 278 s -= size2; \ 279 } while(bot < s); \ 280} 281 282/* 283 * Optional hybrid natural/pairwise first pass. Eats up list1 in runs of 284 * increasing order, list2 in a corresponding linked list. Checks for runs 285 * when THRESHOLD/2 pairs compare with same sense. (Only used when NATURAL 286 * is defined. Otherwise simple pairwise merging is used.) 287 */ 288 static void 289 setup(unsigned char *list1, unsigned char *list2, size_t n, size_t size, 290 int (*cmp)(const void *, const void *, const void *), const void * arg) 291{ 292 int i, length, size2, tmp, sense; 293 unsigned char *f1, *f2, *s, *l2, *last, *p2; 294 295 size2 = size*2; 296 if (n <= 5) { 297 insertionsort(list1, n, size, cmp, arg); 298 *EVAL(list2) = (unsigned char*) list2 + n*size; 299 return; 300 } 301 /* 302 * Avoid running pointers out of bounds; limit n to evens 303 * for simplicity. 304 */ 305 i = 4 + (n & 1); 306 insertionsort(list1 + (n - i) * size, i, size, cmp, arg); 307 last = list1 + size * (n - i); 308 *EVAL(list2 + (last - list1)) = list2 + n * size; 309 310#ifdef NATURAL 311 p2 = list2; 312 f1 = list1; 313 sense = (cmp(f1, f1 + size, arg) > 0); 314 for (; f1 < last; sense = !sense) { 315 length = 2; 316 /* Find pairs with same sense. */ 317 for (f2 = f1 + size2; f2 < last; f2 += size2) { 318 if ((cmp(f2, f2+ size, arg) > 0) != sense) 319 break; 320 length += 2; 321 } 322 if (length < THRESHOLD) { /* Pairwise merge */ 323 do { 324 p2 = *EVAL(p2) = f1 + size2 - list1 + list2; 325 if (sense > 0) 326 swap (f1, f1 + size); 327 } while ((f1 += size2) < f2); 328 } else { /* Natural merge */ 329 l2 = f2; 330 for (f2 = f1 + size2; f2 < l2; f2 += size2) { 331 if ((cmp(f2-size, f2, arg) > 0) != sense) { 332 p2 = *EVAL(p2) = f2 - list1 + list2; 333 if (sense > 0) 334 reverse(f1, f2-size); 335 f1 = f2; 336 } 337 } 338 if (sense > 0) 339 reverse (f1, f2-size); 340 f1 = f2; 341 if (f2 < last || cmp(f2 - size, f2, arg) > 0) 342 p2 = *EVAL(p2) = f2 - list1 + list2; 343 else 344 p2 = *EVAL(p2) = list2 + n*size; 345 } 346 } 347#else /* pairwise merge only. */ 348 for (f1 = list1, p2 = list2; f1 < last; f1 += size2) { 349 p2 = *EVAL(p2) = p2 + size2; 350 if (cmp (f1, f1 + size, arg) > 0) 351 swap(f1, f1 + size); 352 } 353#endif /* NATURAL */ 354} 355 356/* 357 * This is to avoid out-of-bounds addresses in sorting the 358 * last 4 elements. 359 */ 360 static void 361 insertionsort(unsigned char *a, size_t n, size_t size, 362 int (*cmp)(const void *, const void *, const void *), const void * arg) 363{ 364 unsigned char *ai, *s, *t, *u, tmp; 365 int i; 366 367 for (ai = a+size; --n >= 1; ai += size) 368 for (t = ai; t > a; t -= size) { 369 u = t - size; 370 if (cmp(u, t, arg) <= 0) 371 break; 372 swap(u, t); 373 } 374} 375