File size: 10,301 Bytes
07c3cdd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
% $Header: /cvsroot/html2ps/postscript/array.ps,v 1.1 2005/12/18 07:21:36 Konstantin Exp $

% Actually, array-append and array-prepend should have names exchanged;
% nevertheless, I don't want to track down renames all over ps files, so I've decided to
% keep this as is
%
% Prepends item to array
%
% @param Item item value
% @param Array source array
% @return A copy of source array with Item prepended as a first element
%
/array-append { % => Item Array
  aload length 
  1 add
  array astore
} def

/in-array-find {      % => Array Value Pos
  2 index length 0 eq {
    pop pop pop -1
  } {
    2 index 0 get     % => Array Value Pos A0
    2 index eq {      % => Array Value Pos
      3 1 roll        % => Pos Array Value 
      pop pop         % => Pos 
    } {
      1 add           % => Array Value Pos+1
      2 index 
      array-pop-first % => Array Value Pos+1 Array'
      4 3 roll pop    % => Value Pos+1 Array' 
      3 1 roll        % => Array' Value Pos+1
      in-array-find
    } ifelse
  } ifelse
} def

/array-find {   % => Array Value
  0 in-array-find
} def

/array-insert { % => Index Value Data
  aload length  % => Index Value A1 .. AN N
  1 add         % => Index Value A1 .. AN N+1
  dup 2 add     % => Index Value A1 .. AN N+1 N+3
  dup index     % => Index Value A1 .. AN N+1 N+3 Index
  exch          % => Index Value A1 .. AN N+1 Index N+3 
  1 sub         % => Index Value A1 .. AN N+1 Index N+2 
  index         % => Index Value A1 .. AN N+1 Index Value
  exch          % => Index Value A1 .. AN N+1 Value Index 
  2 index       % => Index Value A1 .. AN N+1 Value Index N+1
  1 add         % => Index Value A1 .. AN N+1 Value Index N+2
  exch sub      % => Index Value A1 .. AN N+1 Value N-Index+2
  1             % => Index Value A1 .. AN N+1 Value N-Index+2 1
  roll          % => Index Value A1 .. AINDEX-1 Value AINDEX .. AN N+1
  array astore  % => Index Value Array
  3 1 roll      % => Array Index Value 
  pop pop
} def           % => Data'

/array-last { % => Array
  dup length  % => Array Length
  1 sub       % => Array Length-1
  get         % => Last
} def

/array-merge {                     % => A1 A2
  {                                % => A1 A2[i]
    exch array-prepend             % => A1'
  } forall                         % => A1'
} def

/array-pop-last {   % => Array
  aload length      % => A1 .. AN N
  1 sub             % => A1 .. AN N-1
  exch pop          % => A1 .. AN-1 N-1
  array astore      % => Array'
} def

/array-pop-first {  % => Array
  aload length      % => A1 .. AN N
  1 sub             % => A1 .. AN N-1
  array astore      % => A1 Array'
  exch pop          % => Array'
} def

% Appends item to array
%
% @param Item item value
% @param Array source array
% @return A copy of source array with Item appended as a last element
%
/array-prepend { % => Item Array
  aload length   % => Item Item1 .. ItemN N
  1 add          % => Item Item1 .. ItemN N+1
  dup 1 add      % => Item Item1 .. ItemN N+1 N+2
  1 index roll   % => Item1 .. ItemN N+1 Item 
  exch           % => Item1 .. ItemN Item N+1
  array astore   % => Array
} def

/array-remove { % => Array Index(ZeroBased)
  exch          % => Index Array
  aload length  % => Index A1 .. AN N
  1 sub         % => Index A1 .. AN N-1
  dup 2 add     % => Index A1 .. AN N-1 N+2
  index         % => Index A1 .. AN N-1 Index
  1 index       % => Index A1 .. AN N-1 Index N-1
  2 add         % => Index A1 .. AN N-1 Index N+1
  exch sub      % => Index A1 .. AN N-1 N-Index+1
  dup 1 sub     % => Index A1 .. AN N-1 N-Index+1 N-Index
  roll          % => Index A1 .. AINDEX-1 AINDEX+1 .. AN N-1 AINDEX 
  pop           % => Index A1 .. AINDEX-1 AINDEX+1 .. AN N-1  
  array astore  % => Index Array
  exch pop      % => Array
} def

% Basic insertions algorithm; we're working with small arrays
% and these arrays are have "good" natural order of elements, so
% more complicated algorithms are not needed here
%
/array-sort {                      % => Data GtFun
  []                               % => Data GtFun SortedData
  array-sort-rec                   % => SortedData
} def

/array-sort-rec {                  % => Data GtFun SortedData
  2 index length 0 gt {
    2 index 2 index
    array-sort-rec-select-max      % => Data GtFun SortedData Data' MaxValue
    
    5 4 roll pop                   % => GtFun SortedData Data' MaxValue
    2 index array-prepend          % => GtFun SortedData Data' SortedData'

    3 2 roll pop                   % => GtFun Data' SortedData'
    exch                           % => GtFun SortedData' Data'
    3 1 roll                       % => Data' GtFun SortedData'
    array-sort-rec
  } {
    exch pop
    exch pop                       % => SortedData
  } ifelse
} def

/array-sort-rec-select-max {       % => Data GtFun
  1 index 0 get                    % => Data GtFun E0
  0 1                              % => Data GtFun EMax EMaxIndex ECurIndex
  array-sort-rec-select-max-rec    % => Data GtFun EMax EMaxIndex 
  
% remove element found from source array
  3 index exch array-remove        % => Data GtFun EMax Data'
  
  4 2 roll pop pop                 % => EMax Data
  exch                             % => Data EMax
} def

/array-sort-rec-select-max-rec {   % => Data GtFun EMax EMaxIndex ECurIndex
% Check if we're out of source array bounds
  4 index length 1 index gt {      % => Data GtFun EMax EMaxIndex ECurIndex
    4 index 1 index get            % => Data GtFun EMax EMaxIndex ECurIndex ECur
    3 index                        % => Data GtFun EMax EMaxIndex ECurIndex ECur EMax
    5 index exec                   % => Data GtFun EMax EMaxIndex ECurIndex ECur>EMax
    {                              % => Data GtFun EMax EMaxIndex  ECurIndex
      exch pop dup                 % => Data GtFun EMax EMaxIndex' ECurIndex
      4 index 1 index get          % => Data GtFun EMax EMaxIndex' ECurIndex EMax'
      4 3 roll pop                 % => Data GtFun EMaxIndex' ECurIndex EMax'
      3 1 roll                     % => Data GtFun EMax' EMaxIndex' ECurIndex
    } if                           % => Data GtFun EMax' EMaxIndex' ECurIndex
    1 add
    array-sort-rec-select-max-rec
  } {
    pop
  } ifelse
} def                              % => Data GtFun EMax EMaxIndex

/expand-to {    % => Size Array
% if array have no elements - return immediately 
  dup length 0 eq {
    []                             % => Size Array Flags []
  } {
    dup sum       % => Size Array ASize
    dup 0 gt {    % => Size Array ASize
      dup         % => Size Array ASize ASize
      3 index lt  % => Size Array ASize
      {           % => Size Array ASize
        2 index   % => Size Array ASize Size
        exch div  % => Size Array Size/ASize
        map-scale % => Size Array'
        exch pop  % => Array'
      } {         % => Size Array ASize
        pop exch  % => Array Size
        pop       % => Array
      } ifelse    % => Array
    } {           % => Size Array ASize
% No content found in some colspan columns
      pop                           % => Size Array
      array-pop-first               
      array-append                  % => Array
    } ifelse
  } ifelse
} def

/expand-to-with-flags {            % => Size Array Flags
% if array have no elements - return immediately 
  1 index length 0 eq {
    []                             % => Size Array Flags []
  } {
% Never decrease exising values
    1 index sum                    % => Size Array Flags ASum
    3 index                        % => Size Array Flags ASum Size
    gt {
      1 index                      % => Size Array Flags Expanded
    } {                            % => Size Array Flags
% Subtract non-modifiable values from target value
      2 copy {
        dup not { pop } { pop pop 0 } ifelse
      } zip-with
      sum                          % => Size  Array Flags Non-modSum
      4 3 roll exch sub 3 1 roll   % => Size' Array Flags
% Check if there's any expandable columns
      2 copy {                   
        dup { pop } { pop pop 0 } ifelse
      } zip-with
      sum                          % => Size Array Flags ModSum

      dup 0 eq {                   % => Size Array Flags ModSum
        pop                        % => Size Array Flags 
        1 index                    % => Size Array Flags Array
        0 get 3 index add          % => Size Array Flags A0'
        2 index exch
        0 exch put                 % => Size Array Flags
        1 index
      } {                          % => Size Array Flags ModSum
% Calculate scale koeff
        3 index exch div           % => Size Array Flags Koeff
% Apply scale koeff
        0 1 4 index length 1 sub { % => Size Array Flags Koeff I
          2 index 1 index get {
            3 index
            1 index get            % => Size Array Flags Koeff I A[i]
            2 index mul            % => Size Array Flags Koeff I A[i]*Koeff
            4 index exch
            2 index exch put       % => Size Array Flags Koeff I 
          } if
          pop
        } for                      % => Size Array Flags Koeff
        pop                        % => Size Array Flags
        1 index 
      } ifelse                     % => Size Array Flags Expanded
    } ifelse
  } ifelse                         % => Size Array Flags Expanded
  
  exch pop
  exch pop
  exch pop
} def

/in-reduce {     % => A1 .. AN N Fun StartValue
  2 index 0 gt {
    4 3 roll     % => A1 .. AN-1 N Fun StartValue AN 
    2 index exec % => A1 .. AN-1 N Fun (StartValue Fun AN)
    3 2 roll     % => A1 .. AN-1 Fun (StartValue Fun AN) N
    1 sub        % => A1 .. AN-1 Fun (StartValue Fun AN) N-1
    3 1 roll     % => A1 .. AN-1 N-1 Fun (StartValue Fun AN)
    in-reduce
  } {            % => N Fun Value
    3 1 roll     % => Value N Fun 
    pop pop      % => Value
  } ifelse
} def

/reduce {                          % => Fun StartValue Array 
  aload length                     % => Fun StartValue A1 .. AN N
  dup 3 add                        % => Fun StartValue A1 .. AN N N+3 
  1 index 1 add                    % => Fun StartValue A1 .. AN N N+3 N+1
  roll                             % => A1 .. AN N Fun StartValue
  in-reduce 
} def

/sum {     % => Array
  {add} 0  % => Array {add} 0
  3 2 roll % => {add} 0 Array 
  reduce   % => Sum
} def