Coverage Report

Created: 2025-06-10 06:58

/src/ghostpdl/psi/zalg.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2023 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.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, 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
10.3k
{
56
10.3k
    os_ptr op = osp;
57
10.3k
    uint N;
58
59
10.3k
    check_op(2);
60
    /* Check operands for type and access */
61
    /* we can sort only writable [and unpacked] arrays */
62
10.3k
    if (r_type(&op[-1]) == t_mixedarray || r_type(&op[-1]) == t_shortarray)
63
0
        return_error(gs_error_invalidaccess);
64
10.3k
    check_write_type(op[-1], t_array);
65
    /* the predicate must be an executable array/ string/ name/ [pseudo-]operator */
66
10.3k
    if (!r_has_attr(&op[0], a_executable))
67
10.3k
        return_op_typecheck(&op[0]);
68
10.3k
    switch (r_btype(&op[0])) {
69
0
        case t_array:
70
0
        case t_mixedarray:
71
10.3k
        case t_shortarray:
72
10.3k
        case t_string:
73
10.3k
            if (!r_has_attr(&op[0], a_execute))
74
0
                return_error(gs_error_invalidaccess);
75
10.3k
            break;
76
10.3k
        case t_name:
77
0
        case t_operator:
78
0
        case t_oparray:
79
0
            break;
80
0
        default:
81
0
            return_op_typecheck(&op[0]);
82
10.3k
    }
83
    /*
84
     * if array length <= 1, then nothing to sort
85
     * else prepare the status variables and launch the main sorting routine zsort_continue()
86
     */
87
10.3k
    N = r_size(&op[-1]);
88
10.3k
    if (N <= 1) {
89
0
        pop(1);
90
0
        return 0;
91
10.3k
    } else {
92
10.3k
        check_estack(11);
93
10.3k
        push_mark_estack(es_other, zsort_cleanup);
94
10.3k
/*H1:*/ make_int(&esp[1], N / 2 + 1); /* l */
95
10.3k
        make_int(&esp[2], N);       /* r */
96
10.3k
        make_int(&esp[3], 0);       /* i */
97
10.3k
        make_int(&esp[4], 0);       /* j */
98
10.3k
        make_null(&esp[5]);        /* R */
99
10.3k
        make_int(&esp[6], 2);       /* H */
100
10.3k
        ref_assign(&esp[7], &op[0]);  /* lt */
101
10.3k
        ref_assign(&esp[8], &op[-1]); /* the array */
102
10.3k
        esp += 8;
103
10.3k
        make_op_estack(&esp[1], zsort_continue);
104
10.3k
        make_null(&op[0]);   /* result of <lt>, not used when H = 2 */
105
10.3k
        return zsort_continue(i_ctx_p);
106
10.3k
    }
107
10.3k
}
108
109
/* Continuation operator for .sort */
110
static int
111
zsort_continue(i_ctx_t *i_ctx_p)
112
7.15M
{
113
7.15M
    os_ptr op = osp;
114
7.15M
    ref *status;
115
7.15M
    ref *Rn;
116
7.15M
#   define l  (status[1].value.intval)
117
9.52M
#   define r  (status[2].value.intval)
118
7.15M
#   define i  (status[3].value.intval)
119
19.5M
#   define j  (status[4].value.intval)
120
7.15M
#   define R  (status[5])
121
14.2M
#   define H  (status[6].value.intval)
122
7.15M
#   define lt (status[7])
123
7.15M
#   define arry (status[8])
124
125
7.15M
    status = esp - 8;
126
7.15M
    Rn = arry.value.refs - 1; /* the -1 compensates for using 1-based indices */
127
7.15M
    switch (H) {
128
3.59M
        case 6:
129
3.59M
            /*H6_cont:*/if (!r_has_type(&op[0], t_boolean)) {
130
0
                esp -= 9;
131
0
                return_error(gs_error_typecheck);
132
0
            }
133
3.59M
            if (op[0].value.boolval) {
134
3.29M
/* H7: */       ref_assign_old(&arry, &Rn[i], &Rn[j], ".sort(H7)");
135
3.29M
                goto H4;
136
3.29M
            }
137
1.12M
            do {
138
1.12M
/* H8: */       ref_assign_old(&arry, &Rn[i], &R, ".sort(H8)");
139
                /* fallthrough */
140
1.13M
        case 2:
141
1.13M
/* H2: */       if (l > 1) {
142
381k
                    l--;
143
381k
                    ref_assign(&R, &Rn[l]);
144
752k
                } else {
145
752k
                    ref_assign(&R, &Rn[r]);
146
752k
                    ref_assign_old(&arry, &Rn[r], &Rn[1], ".sort(H2-a)");
147
752k
                    r--;
148
752k
                    if (r <= 1) {
149
10.3k
                        ref_assign_old(&arry, &Rn[1], &R, ".sort(H2-b)");
150
10.3k
                        esp -= 9;
151
10.3k
                        pop(1);
152
10.3k
                        return o_pop_estack;
153
10.3k
                    }
154
752k
                }
155
1.12M
/* H3: */       j = l;
156
4.42M
H4:             i = j;
157
4.42M
                j <<= 1;
158
4.42M
            } while (j > r);
159
3.59M
            if (j == r)
160
51.5k
                goto H6;
161
3.54M
/* H5: */   H = 5;
162
3.54M
            push(1);
163
3.54M
            ref_assign(&op[-1], &Rn[j]);
164
3.54M
            ref_assign(&op[0], &Rn[j + 1]);
165
3.54M
            break;
166
3.54M
        case 5:
167
3.54M
/*H5_cont:*/if (!r_has_type(&op[0], t_boolean))
168
0
                return_error(gs_error_typecheck);
169
3.54M
            if (op[0].value.boolval)
170
1.60M
                j++;
171
3.59M
H6:         H = 6;
172
3.59M
            push(1);
173
3.59M
            ref_assign(&op[-1], &R);
174
3.59M
            ref_assign(&op[0], &Rn[j]);
175
3.59M
            break;
176
0
        default:
177
0
            pop(1);
178
0
            esp -= 9;
179
0
            return_error(gs_error_unregistered); /* Must not happen. */
180
7.15M
    }
181
7.14M
    esp += 2;
182
7.14M
    ref_assign(esp, &lt);
183
7.14M
    return o_push_estack;
184
7.15M
#undef l
185
7.15M
#undef r
186
7.15M
#undef i
187
7.15M
#undef j
188
7.15M
#undef R
189
7.15M
#undef H
190
7.15M
#undef lt
191
7.15M
}
192
193
/* No-op cleanup routine for .sort */
194
static int
195
zsort_cleanup(i_ctx_t *i_ctx_p)
196
0
{
197
0
    return 0;
198
0
}
199
200
/* ------ Initialization procedure ------ */
201
202
const op_def zalg_op_defs[] =
203
{
204
    {"2.sort", zsort},
205
                /* Internal operators */
206
    {"1%zsort_continue", zsort_continue},
207
    op_def_end(0)
208
};