File: rtn_tbl_sort.c

package info (click to toggle)
fis-gtm 6.2-000-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 30,784 kB
  • ctags: 42,554
  • sloc: ansic: 358,483; asm: 4,847; csh: 4,574; sh: 2,261; awk: 200; makefile: 86; sed: 13
file content (164 lines) | stat: -rw-r--r-- 4,388 bytes parent folder | download
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/****************************************************************
 *								*
 *	Copyright 2004, 2011 Fidelity Information Services, Inc	*
 *								*
 *	This source code contains the intellectual property	*
 *	of its copyright holder(s), and is made available	*
 *	under a license.  If you do not know the terms of	*
 *	the license, please stop and do not read further.	*
 *								*
 ****************************************************************/

/* NOTE: The rtn_tbl_qsort below uses exactly the same quick sort algorithm used in stpg_sort() and gvcst_kill_sort() */

#include "mdef.h"
#include <rtnhdr.h>
#include "obj_file.h"		/* for RNAMB_PREF_LEN */
#include "objlangdefs.h"	/* for EGPS$S_NAME */
#include "min_max.h"		/* MIDENT_CMP needs MIN */

#define S_CUTOFF		15

void rtn_tbl_qsort(rtn_tabent *start, rtn_tabent *end);

void rtn_tbl_sort(rtn_tabent *rtab_base, rtn_tabent *rtab_end)
{
	rtn_tabent	*start, *end;

	for (start = rtab_base; start < rtab_end; start = end)
	{ /* Since the table is already sorted by the VMS linker based on the first 26 characters of rt_name,
	     we only need to sort those routines with longer than 26 char names. However, if the routine name
	     starts with 26 all z's, it may not have been sorted. So, to avoid special cases, each iteration
	     of this loop needs to find a contiguous segment of routines of more than 25 chars and invoke
	     the quicksort on that segment. */
		for (; start < rtab_end && start->rt_name.len < RNAME_SORTED_LEN; start++)
			;
		for (end = start; end < rtab_end && end->rt_name.len >= RNAME_SORTED_LEN; end++)
			;
		if (start < end)
		{
			if (end < rtab_end)
				rtn_tbl_qsort(start, end - 1);
			else
				rtn_tbl_qsort(start, end);
		}
	}
}

/* Sorts a segment of contiguous routine table entries using the value of each rt_name.addr field as the key.
 * The algorithm is a modified QuickSort algorithm which assumes that top+1 has a greater key value than
 * any element in the segment. */
void rtn_tbl_qsort(rtn_tabent *base, rtn_tabent *top)
{
	/* Since a pair of pointers are pushed at each level, the stack space of 64 is sufficient
	 * upto a table size of 2**32 elements */
	rtn_tabent	*stack[64], **sp;
	rtn_tabent	v, t;
	rtn_tabent	*l, *r;
	rtn_tabent	*ix, *jx, *kx;
	mident		*tval;
	int		cmp;

	sp = &stack[0];
	l = base;
	r = top;
	for (;;)
	{
		if (r - l < S_CUTOFF)
		{
			for (ix  = l + 1;  ix <= r;  ix++)
			{
				for (jx = ix, t = *ix, tval = &t.rt_name; 1 < jx; jx--)
				{
					MIDENT_CMP(&(jx - 1)->rt_name, tval, cmp);
					if (0 >= cmp)
						break;
					*jx = *(jx - 1);
				}
				if (ix != jx)
					*jx = t;
			}
			if (sp <= stack)
				break;
			else
			{	/* Pop the anchors of a subtable that were pushed earlier and begin a new sort */
				l = *--sp;
				r = *--sp;
			}
		} else
		{
			ix = l;
			jx = r;
			kx = l + ((int)(r - l) / 2); /* pivotal key */
			/* Find the best possible pivotal key among ix, jx and kx (sorta median of those) */
			MIDENT_CMP(&ix->rt_name, &jx->rt_name, cmp);
			if (0 < cmp)
			{
				MIDENT_CMP(&jx->rt_name, &kx->rt_name, cmp);
				if (0 < cmp)
					kx = jx;
				else
				{
					MIDENT_CMP(&ix->rt_name, &kx->rt_name, cmp);
					if (0 >= cmp)
						kx = ix;
					/* else "kx" is already the right choice */
				}
			} else
			{
				MIDENT_CMP(&jx->rt_name, &kx->rt_name, cmp);
				if (0 > cmp)
					kx = jx;
				else
				{
					MIDENT_CMP(&ix->rt_name, &kx->rt_name, cmp);
					if (0 < cmp)
						kx = ix;
					/* else "kx" is already the right choice */
				}
			}
			/* Partition the table into two subtables based on the pivotal */
			v = *kx;
			*kx = *jx;
			*jx = v;
			tval = &v.rt_name;
			ix--;
			do
			{
				do
				{
					ix++;
					MIDENT_CMP(&ix->rt_name, tval, cmp);
				} while (cmp < 0);
				do
				{
					jx--;
					MIDENT_CMP(&jx->rt_name, tval, cmp);
				} while (cmp > 0);
				t = *ix;
				*ix = *jx;
				*jx = t;
			} while (jx > ix);
			*jx = *ix;
			*ix = *r;
			*r = t;

			/* Ensure there are at least two more slots available in the stack for the pushes below */
			assert((sp - &stack[0]) + 2 < (SIZEOF(stack)/SIZEOF(stack[0])));
			/* Push the anchors of the large subtable into the stack and begin a new sort on the smaller subtable */
			if (ix - l > r - ix)
			{
				*sp++ = ix - 1;
				*sp++ = l;
				l = ix + 1;
			}
			else
			{
				*sp++ = r;
				*sp++ = ix + 1;
				r = ix - 1;
			}
		}
	}
	return;
}