1
/* Copyright (C) 2006 Artifex Software, Inc.
4
This software is provided AS-IS with no warranty, either express or
7
This software is distributed under license and may not be copied, modified
8
or distributed except as expressly authorized under the terms of that
9
license. Refer to licensing information at http://www.artifex.com/
10
or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11
San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
14
/* $Id: zalg.c 8250 2007-09-25 13:31:24Z giles $ */
15
/* Operators for general-purpose algorithms. For now, only sorting. */
22
/* ========================================================================= */
25
* The "heap sort" algorithm, as implementation of the .sort operator
27
* The implementation follows Algorithm H from Donald Knuth's
28
* "The Art of Computer Programming", volume 3, section 5.2.3
31
* i. Execution time: O(n log n) in the average and worst cases.
32
* ii. The sort is not "stable" (the relative order of elements with
33
* equal keys is not necessarily preserved).
34
* iii. Status variables:
35
* - stored on the e-stack;
36
* - "l", "r", "i", "j" and "R" correspond directly to variables in
37
* Algorithm H (including the fact that indices are 1-based);
38
* - variable "K" from Algorithm H is not used here, because we don't
39
* distinguish a "key part" of the array elements;
40
* - "H" indicates the step to execute; used when resuming after executing
41
* <lt> (to execute it, we have to return to the interpreter).
42
* - "array" and "lt" are refs to the parameters; avoids using them from the
43
* o-stack after resuming, in case the predicate has odd side-efects
46
static int zsort(i_ctx_t *i_ctx_p);
47
static int zsort_continue(i_ctx_t *i_ctx_p);
48
static int zsort_cleanup(i_ctx_t *i_ctx_p);
50
/* <array> <lt> .sort <array> */
52
zsort(i_ctx_t *i_ctx_p)
57
/* Check operands for type and access */
58
/* we can sort only writable [and unpacked] arrays */
59
if (r_type(&op[-1]) == t_mixedarray || r_type(&op[-1]) == t_shortarray)
60
return_error(e_invalidaccess);
61
check_write_type(op[-1], t_array);
62
/* the predicate must be an executable array/ string/ name/ [pseudo-]operator */
63
if (!r_has_attr(&op[0], a_executable))
64
return_op_typecheck(&op[0]);
65
switch (r_btype(&op[0])) {
70
if (!r_has_attr(&op[0], a_execute))
71
return_error(e_invalidaccess);
78
return_op_typecheck(&op[0]);
81
* if array length <= 1, then nothing to sort
82
* else prepare the status variables and launch the main sorting routine zsort_continue()
90
push_mark_estack(es_other, zsort_cleanup);
91
/*H1:*/ make_int(&esp[1], N / 2 + 1); /* l */
92
make_int(&esp[2], N); /* r */
93
make_int(&esp[3], 0); /* i */
94
make_int(&esp[4], 0); /* j */
95
make_null(&esp[5]); /* R */
96
make_int(&esp[6], 2); /* H */
97
ref_assign(&esp[7], &op[0]); /* lt */
98
ref_assign(&esp[8], &op[-1]); /* the array */
100
make_op_estack(&esp[1], zsort_continue);
101
make_null(&op[0]); /* result of <lt>, not used when H = 2 */
102
return zsort_continue(i_ctx_p);
106
/* Continuation operator for .sort */
108
zsort_continue(i_ctx_t *i_ctx_p)
113
# define l (status[1].value.intval)
114
# define r (status[2].value.intval)
115
# define i (status[3].value.intval)
116
# define j (status[4].value.intval)
117
# define R (status[5])
118
# define H (status[6].value.intval)
119
# define lt (status[7])
120
# define arry (status[8])
123
Rn = arry.value.refs - 1; /* the -1 compensates for using 1-based indices */
128
ref_assign(&R, &Rn[l]);
130
ref_assign(&R, &Rn[r]);
131
ref_assign_old(&arry, &Rn[r], &Rn[1], ".sort(H2-a)");
134
ref_assign_old(&arry, &Rn[1], &R, ".sort(H2-b)");
151
ref_assign(&op[-1], &Rn[j]);
152
ref_assign(&op[0], &Rn[j + 1]);
156
/*H5_cont:*/if (!r_has_type(&op[0], t_boolean))
157
return_error(e_typecheck);
158
if (op[0].value.boolval)
162
ref_assign(&op[-1], &R);
163
ref_assign(&op[0], &Rn[j]);
166
/*H6_cont:*/if (!r_has_type(&op[0], t_boolean))
167
return_error(e_typecheck);
168
if (op[0].value.boolval) {
169
/* H7: */ ref_assign_old(&arry, &Rn[i], &Rn[j], ".sort(H7)");
172
H8: ref_assign_old(&arry, &Rn[i], &R, ".sort(H8)");
177
return_error(gs_error_unregistered); /* Must not happen. */
180
ref_assign(esp, <);
181
return o_push_estack;
191
/* No-op cleanup routine for .sort */
193
zsort_cleanup(i_ctx_t *i_ctx_p)
198
/* ------ Initialization procedure ------ */
200
const op_def zalg_op_defs[] =
203
/* Internal operators */
204
{"1%zsort_continue", zsort_continue},