File: mergesort.c

package info (click to toggle)
dico 2.12-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 21,300 kB
  • sloc: ansic: 94,671; sh: 52,520; lex: 4,023; tcl: 1,439; yacc: 1,439; makefile: 1,387; python: 1,310; perl: 1,200; lisp: 489; awk: 157; pascal: 127; javascript: 71; cpp: 50; fortran: 28; asm: 21; sed: 16; xml: 8
file content (99 lines) | stat: -rw-r--r-- 2,548 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/* This file is part of GNU Dico
   Copyright (C) 2018-2024 Sergey Poznyakoff

   GNU Dico is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3, or (at your option)
   any later version.

   GNU Dico is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with GNU Dico.  If not, see <http://www.gnu.org/licenses/>. */

#include <config.h>
#include "dico.h"
#include <string.h>

static void *dico_mergesort(void *a, void *b, size_t nmemb, size_t size,
		       int (*comp)(const void *, const void *, void *),
		       void *closure);
static void merge(void *source, void *work, size_t size,
		  size_t left, size_t right, size_t end,
		  int (*comp)(const void *, const void *, void *),
		  void *closure);

int
dico_sort(void *base, size_t nmemb, size_t size,
	  int (*comp)(const void *, const void *, void *),
	  void *closure)
{
    void *tmp, *res;

    tmp = calloc(nmemb, size);
    if (!tmp)
	return -1;
    res = dico_mergesort(base, tmp, nmemb, size, comp, closure);
    if (res != base)
	memcpy(base, res, nmemb * size);
    free(tmp);
    return 0;
}

static inline size_t
min(size_t a, size_t b)
{
    return a < b ? a : b;
}

static void *
dico_mergesort(void *a, void *b, size_t nmemb, size_t size,
	       int (*comp)(const void *, const void *, void *),
	       void *closure)
{
    size_t width;

    for (width = 1; width < nmemb; width <<= 1) {
	size_t i;
	void *t;

	for (i = 0; i < nmemb; i += 2 * width) {
	    merge(a, b, size,
		  i, min(i + width, nmemb), min(i + 2 * width, nmemb),
		  comp, closure);
	}
	t = a;
	a = b;
	b = t;
    }
    return a;
}

static void
merge(void *source, void *work, size_t size,
      size_t left, size_t right, size_t end,
      int (*comp)(const void *, const void *, void *),
      void *closure)
{
    size_t i = left;
    size_t j = right;
    size_t k;
#define MEMB(b,n) ((char*)(b) + (n) * size)
#define COPY(dp,dn,sp,sn) (memcpy(MEMB(dp,dn), MEMB(sp,sn), size))

    for (k = left; k < end; k++) {
	if (i < right
	    && (j >= end || comp(MEMB(source, i),
				 MEMB(source, j),
				 closure) <= 0)) {
	    COPY(work, k, source, i);
	    i++;
	} else {
	    COPY(work, k, source, j);
	    j++;
	}
    }
}