Coverage Report

Created: 2025-06-10 07:15

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