Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/psi/zalg.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2021 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, for further information.
14
*/
15
16
17
/* Operators for general-purpose algorithms. For now, only sorting. */
18
#include "ghost.h"
19
#include "gserrors.h"
20
#include "oper.h"
21
#include "store.h"
22
#include "estack.h"
23
24
/* ========================================================================= */
25
26
/*
27
 * The "heap sort" algorithm, as implementation of the .sort operator
28
 *
29
 * The implementation follows Algorithm H from Donald Knuth's
30
 * "The Art of Computer Programming", volume 3, section 5.2.3
31
 *
32
 * Notes:
33
 * i.   Execution time: O(n log n) in the average and worst cases.
34
 * ii.  The sort is not "stable" (the relative order of elements with
35
 *  equal keys is not necessarily preserved).
36
 * iii. Status variables:
37
 *  - stored on the e-stack;
38
 *  - "l", "r", "i", "j" and "R" correspond directly to variables in
39
 *    Algorithm H (including the fact that indices are 1-based);
40
 *  - variable "K" from Algorithm H is not used here, because we don't
41
 *    distinguish a "key part" of the array elements;
42
 *  - "H" indicates the step to execute; used when resuming after executing
43
 *    <lt> (to execute it, we have to return to the interpreter).
44
 *  - "array" and "lt" are refs to the parameters; avoids using them from the
45
 *    o-stack after resuming, in case the predicate has odd side-efects
46
 */
47
48
static int zsort(i_ctx_t *i_ctx_p);
49
static int zsort_continue(i_ctx_t *i_ctx_p);
50
static int zsort_cleanup(i_ctx_t *i_ctx_p);
51
52
/* <array> <lt> .sort <array> */
53
static int
54
zsort(i_ctx_t *i_ctx_p)
55
89.2k
{
56
89.2k
    os_ptr op = osp;
57
89.2k
    uint N;
58
59
    /* Check operands for type and access */
60
    /* we can sort only writable [and unpacked] arrays */
61
89.2k
    if (r_type(&op[-1]) == t_mixedarray || r_type(&op[-1]) == t_shortarray)
62
0
        return_error(gs_error_invalidaccess);
63
89.2k
    check_write_type(op[-1], t_array);
64
    /* the predicate must be an executable array/ string/ name/ [pseudo-]operator */
65
89.2k
    if (!r_has_attr(&op[0], a_executable))
66
89.2k
        return_op_typecheck(&op[0]);
67
89.2k
    switch (r_btype(&op[0])) {
68
0
        case t_array:
69
0
        case t_mixedarray:
70
89.2k
        case t_shortarray:
71
89.2k
        case t_string:
72
89.2k
            if (!r_has_attr(&op[0], a_execute))
73
0
                return_error(gs_error_invalidaccess);
74
89.2k
            break;
75
89.2k
        case t_name:
76
0
        case t_operator:
77
0
        case t_oparray:
78
0
            break;
79
0
        default:
80
0
            return_op_typecheck(&op[0]);
81
89.2k
    }
82
    /*
83
     * if array length <= 1, then nothing to sort
84
     * else prepare the status variables and launch the main sorting routine zsort_continue()
85
     */
86
89.2k
    N = r_size(&op[-1]);
87
89.2k
    if (N <= 1) {
88
0
        pop(1);
89
0
        return 0;
90
89.2k
    } else {
91
89.2k
        check_estack(11);
92
89.2k
        push_mark_estack(es_other, zsort_cleanup);
93
89.2k
/*H1:*/ make_int(&esp[1], N / 2 + 1); /* l */
94
89.2k
        make_int(&esp[2], N);       /* r */
95
89.2k
        make_int(&esp[3], 0);       /* i */
96
89.2k
        make_int(&esp[4], 0);       /* j */
97
89.2k
        make_null(&esp[5]);        /* R */
98
89.2k
        make_int(&esp[6], 2);       /* H */
99
89.2k
        ref_assign(&esp[7], &op[0]);  /* lt */
100
89.2k
        ref_assign(&esp[8], &op[-1]); /* the array */
101
89.2k
        esp += 8;
102
89.2k
        make_op_estack(&esp[1], zsort_continue);
103
89.2k
        make_null(&op[0]);   /* result of <lt>, not used when H = 2 */
104
89.2k
        return zsort_continue(i_ctx_p);
105
89.2k
    }
106
89.2k
}
107
108
/* Continuation operator for .sort */
109
static int
110
zsort_continue(i_ctx_t *i_ctx_p)
111
49.8M
{
112
49.8M
    os_ptr op = osp;
113
49.8M
    ref *status;
114
49.8M
    ref *Rn;
115
49.8M
#   define l  (status[1].value.intval)
116
67.0M
#   define r  (status[2].value.intval)
117
49.8M
#   define i  (status[3].value.intval)
118
138M
#   define j  (status[4].value.intval)
119
49.8M
#   define R  (status[5])
120
99.6M
#   define H  (status[6].value.intval)
121
49.8M
#   define lt (status[7])
122
49.8M
#   define arry (status[8])
123
124
49.8M
    status = esp - 8;
125
49.8M
    Rn = arry.value.refs - 1; /* the -1 compensates for using 1-based indices */
126
49.8M
    switch (H) {
127
25.0M
        case 6:
128
25.0M
            /*H6_cont:*/if (!r_has_type(&op[0], t_boolean)) {
129
0
                esp -= 9;
130
0
                return_error(gs_error_typecheck);
131
0
            }
132
25.0M
            if (op[0].value.boolval) {
133
22.6M
/* H7: */       ref_assign_old(&arry, &Rn[i], &Rn[j], ".sort(H7)");
134
22.6M
                goto H4;
135
22.6M
            }
136
8.21M
            do {
137
8.21M
/* H8: */       ref_assign_old(&arry, &Rn[i], &R, ".sort(H8)");
138
                /* fallthrough */
139
8.30M
        case 2:
140
8.30M
/* H2: */       if (l > 1) {
141
2.76M
                    l--;
142
2.76M
                    ref_assign(&R, &Rn[l]);
143
5.53M
                } else {
144
5.53M
                    ref_assign(&R, &Rn[r]);
145
5.53M
                    ref_assign_old(&arry, &Rn[r], &Rn[1], ".sort(H2-a)");
146
5.53M
                    r--;
147
5.53M
                    if (r <= 1) {
148
89.2k
                        ref_assign_old(&arry, &Rn[1], &R, ".sort(H2-b)");
149
89.2k
                        esp -= 9;
150
89.2k
                        pop(1);
151
89.2k
                        return o_pop_estack;
152
89.2k
                    }
153
5.53M
                }
154
/* H3: */       j = l;
155
30.8M
H4:             i = j;
156
30.8M
                j <<= 1;
157
30.8M
            } while (j > r);
158
25.0M
            if (j == r)
159
357k
                goto H6;
160
/* H5: */   H = 5;
161
24.7M
            push(1);
162
24.7M
            ref_assign(&op[-1], &Rn[j]);
163
24.7M
            ref_assign(&op[0], &Rn[j + 1]);
164
24.7M
            break;
165
24.7M
        case 5:
166
24.7M
/*H5_cont:*/if (!r_has_type(&op[0], t_boolean))
167
0
                return_error(gs_error_typecheck);
168
24.7M
            if (op[0].value.boolval)
169
12.1M
                j++;
170
25.0M
H6:         H = 6;
171
25.0M
            push(1);
172
25.0M
            ref_assign(&op[-1], &R);
173
25.0M
            ref_assign(&op[0], &Rn[j]);
174
25.0M
            break;
175
0
        default:
176
0
            pop(1);
177
0
            esp -= 9;
178
0
            return_error(gs_error_unregistered); /* Must not happen. */
179
49.8M
    }
180
49.8M
    esp += 2;
181
49.8M
    ref_assign(esp, &lt);
182
49.8M
    return o_push_estack;
183
49.8M
#undef l
184
49.8M
#undef r
185
49.8M
#undef i
186
49.8M
#undef j
187
49.8M
#undef R
188
49.8M
#undef H
189
49.8M
#undef lt
190
49.8M
}
191
192
/* No-op cleanup routine for .sort */
193
static int
194
zsort_cleanup(i_ctx_t *i_ctx_p)
195
0
{
196
0
    return 0;
197
0
}
198
199
/* ------ Initialization procedure ------ */
200
201
const op_def zalg_op_defs[] =
202
{
203
    {"2.sort", zsort},
204
                /* Internal operators */
205
    {"1%zsort_continue", zsort_continue},
206
    op_def_end(0)
207
};