Coverage Report

Created: 2025-06-10 06:56

/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
1.78k
{
56
1.78k
    os_ptr op = osp;
57
1.78k
    uint N;
58
59
1.78k
    check_op(2);
60
    /* Check operands for type and access */
61
    /* we can sort only writable [and unpacked] arrays */
62
1.78k
    if (r_type(&op[-1]) == t_mixedarray || r_type(&op[-1]) == t_shortarray)
63
0
        return_error(gs_error_invalidaccess);
64
1.78k
    check_write_type(op[-1], t_array);
65
    /* the predicate must be an executable array/ string/ name/ [pseudo-]operator */
66
1.78k
    if (!r_has_attr(&op[0], a_executable))
67
1.78k
        return_op_typecheck(&op[0]);
68
1.78k
    switch (r_btype(&op[0])) {
69
0
        case t_array:
70
0
        case t_mixedarray:
71
1.78k
        case t_shortarray:
72
1.78k
        case t_string:
73
1.78k
            if (!r_has_attr(&op[0], a_execute))
74
0
                return_error(gs_error_invalidaccess);
75
1.78k
            break;
76
1.78k
        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
1.78k
    }
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
1.78k
    N = r_size(&op[-1]);
88
1.78k
    if (N <= 1) {
89
0
        pop(1);
90
0
        return 0;
91
1.78k
    } else {
92
1.78k
        check_estack(11);
93
1.78k
        push_mark_estack(es_other, zsort_cleanup);
94
1.78k
/*H1:*/ make_int(&esp[1], N / 2 + 1); /* l */
95
1.78k
        make_int(&esp[2], N);       /* r */
96
1.78k
        make_int(&esp[3], 0);       /* i */
97
1.78k
        make_int(&esp[4], 0);       /* j */
98
1.78k
        make_null(&esp[5]);        /* R */
99
1.78k
        make_int(&esp[6], 2);       /* H */
100
1.78k
        ref_assign(&esp[7], &op[0]);  /* lt */
101
1.78k
        ref_assign(&esp[8], &op[-1]); /* the array */
102
1.78k
        esp += 8;
103
1.78k
        make_op_estack(&esp[1], zsort_continue);
104
1.78k
        make_null(&op[0]);   /* result of <lt>, not used when H = 2 */
105
1.78k
        return zsort_continue(i_ctx_p);
106
1.78k
    }
107
1.78k
}
108
109
/* Continuation operator for .sort */
110
static int
111
zsort_continue(i_ctx_t *i_ctx_p)
112
1.23M
{
113
1.23M
    os_ptr op = osp;
114
1.23M
    ref *status;
115
1.23M
    ref *Rn;
116
1.23M
#   define l  (status[1].value.intval)
117
1.64M
#   define r  (status[2].value.intval)
118
1.23M
#   define i  (status[3].value.intval)
119
3.39M
#   define j  (status[4].value.intval)
120
1.23M
#   define R  (status[5])
121
2.47M
#   define H  (status[6].value.intval)
122
1.23M
#   define lt (status[7])
123
1.23M
#   define arry (status[8])
124
125
1.23M
    status = esp - 8;
126
1.23M
    Rn = arry.value.refs - 1; /* the -1 compensates for using 1-based indices */
127
1.23M
    switch (H) {
128
622k
        case 6:
129
622k
            /*H6_cont:*/if (!r_has_type(&op[0], t_boolean)) {
130
0
                esp -= 9;
131
0
                return_error(gs_error_typecheck);
132
0
            }
133
622k
            if (op[0].value.boolval) {
134
570k
/* H7: */       ref_assign_old(&arry, &Rn[i], &Rn[j], ".sort(H7)");
135
570k
                goto H4;
136
570k
            }
137
194k
            do {
138
194k
/* H8: */       ref_assign_old(&arry, &Rn[i], &R, ".sort(H8)");
139
                /* fallthrough */
140
196k
        case 2:
141
196k
/* H2: */       if (l > 1) {
142
66.0k
                    l--;
143
66.0k
                    ref_assign(&R, &Rn[l]);
144
130k
                } else {
145
130k
                    ref_assign(&R, &Rn[r]);
146
130k
                    ref_assign_old(&arry, &Rn[r], &Rn[1], ".sort(H2-a)");
147
130k
                    r--;
148
130k
                    if (r <= 1) {
149
1.78k
                        ref_assign_old(&arry, &Rn[1], &R, ".sort(H2-b)");
150
1.78k
                        esp -= 9;
151
1.78k
                        pop(1);
152
1.78k
                        return o_pop_estack;
153
1.78k
                    }
154
130k
                }
155
194k
/* H3: */       j = l;
156
765k
H4:             i = j;
157
765k
                j <<= 1;
158
765k
            } while (j > r);
159
622k
            if (j == r)
160
8.92k
                goto H6;
161
613k
/* H5: */   H = 5;
162
613k
            push(1);
163
613k
            ref_assign(&op[-1], &Rn[j]);
164
613k
            ref_assign(&op[0], &Rn[j + 1]);
165
613k
            break;
166
613k
        case 5:
167
613k
/*H5_cont:*/if (!r_has_type(&op[0], t_boolean))
168
0
                return_error(gs_error_typecheck);
169
613k
            if (op[0].value.boolval)
170
278k
                j++;
171
622k
H6:         H = 6;
172
622k
            push(1);
173
622k
            ref_assign(&op[-1], &R);
174
622k
            ref_assign(&op[0], &Rn[j]);
175
622k
            break;
176
0
        default:
177
0
            pop(1);
178
0
            esp -= 9;
179
0
            return_error(gs_error_unregistered); /* Must not happen. */
180
1.23M
    }
181
1.23M
    esp += 2;
182
1.23M
    ref_assign(esp, &lt);
183
1.23M
    return o_push_estack;
184
1.23M
#undef l
185
1.23M
#undef r
186
1.23M
#undef i
187
1.23M
#undef j
188
1.23M
#undef R
189
1.23M
#undef H
190
1.23M
#undef lt
191
1.23M
}
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
};