ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Array-Heap/Heap.xs
Revision: 1.3
Committed: Sun Jul 26 04:50:02 2009 UTC (14 years, 9 months ago) by root
Branch: MAIN
Changes since 1.2: +257 -104 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 #include "EXTERN.h"
2 #include "perl.h"
3 #include "XSUB.h"
4
5 /* pre-5.10 compatibility */
6 #ifndef GV_NOTQUAL
7 # define GV_NOTQUAL 1
8 #endif
9 #ifndef gv_fetchpvs
10 # define gv_fetchpvs gv_fetchpv
11 #endif
12
13 #include "multicall.h"
14
15 /* workaround for buggy multicall API */
16 #ifndef cxinc
17 # define cxinc() Perl_cxinc (aTHX)
18 #endif
19
20 #define dCMP \
21 dMULTICALL; \
22 void *cmp_data; \
23 I32 gimme = G_SCALAR;
24
25 #define CMP_PUSH(sv) \
26 PUSH_MULTICALL (cmp_push_ (sv));\
27 cmp_data = multicall_cop;
28
29 #define CMP_POP \
30 POP_MULTICALL;
31
32 #define dCMP_CALL(data) \
33 OP *multicall_cop = (OP *)data;
34
35 static void *
36 cmp_push_ (SV *sv)
37 {
38 HV *st;
39 GV *gvp;
40 CV *cv;
41
42 cv = sv_2cv (sv, &st, &gvp, 0);
43
44 if (!cv)
45 croak ("%s: callback must be a CODE reference or another callable object", SvPV_nolen (sv));
46
47 if (!PL_firstgv) PL_firstgv = gv_fetchpvs ("a", GV_ADD | GV_NOTQUAL, SVt_PV);
48 if (!PL_secondgv) PL_secondgv = gv_fetchpvs ("b", GV_ADD | GV_NOTQUAL, SVt_PV);
49
50 SAVESPTR (GvSV (PL_firstgv));
51 SAVESPTR (GvSV (PL_secondgv));
52
53 return cv;
54 }
55
56 /*****************************************************************************/
57
58 static SV *
59 sv_first (SV *sv)
60 {
61 if (SvROK (sv) && SvTYPE (SvRV (sv)) == SVt_PVAV)
62 {
63 AV *av = (AV *)SvRV (sv);
64
65 sv = AvFILLp (av) < 0 ? &PL_sv_undef : AvARRAY (av)[0];
66 }
67
68 return sv;
69 }
70
71 static int
72 cmp_nv (SV *a, SV *b, void *cmp_data)
73 {
74 a = sv_first (a);
75 b = sv_first (b);
76
77 return SvNV (a) > SvNV (b);
78 }
79
80 static int
81 cmp_sv (SV *a, SV *b, void *cmp_data)
82 {
83 a = sv_first (a);
84 b = sv_first (b);
85
86 return sv_cmp (a, b) > 0;
87 }
88
89 static int
90 cmp_custom (SV *a, SV *b, void *cmp_data)
91 {
92 dCMP_CALL (cmp_data);
93
94 GvSV (PL_firstgv) = a;
95 GvSV (PL_secondgv) = b;
96
97 MULTICALL;
98
99 if (SvTRUE (ERRSV))
100 croak (NULL);
101
102 {
103 dSP;
104 return TOPi > 0;
105 }
106 }
107
108 /*****************************************************************************/
109
110 typedef int (*f_cmp)(SV *a, SV *b, void *cmp_data);
111
112 static AV *
113 array (SV *ref)
114 {
115 if (SvROK (ref)
116 && SvTYPE (SvRV (ref)) == SVt_PVAV
117 && !SvTIED_mg (SvRV (ref), PERL_MAGIC_tied))
118 return (AV *)SvRV (ref);
119
120 croak ("argument 'heap' must be a (non-tied) array");
121 }
122
123 #define gt(a,b) cmp ((a), (b), cmp_data)
124
125 /*****************************************************************************/
126
127 /* away from the root */
128 static void
129 downheap (AV *av, f_cmp cmp, void *cmp_data, int N, int k)
130 {
131 SV **heap = AvARRAY (av);
132 SV *he = heap [k];
133
134 for (;;)
135 {
136 int c = (k << 1) + 1;
137
138 if (c >= N)
139 break;
140
141 c += c + 1 < N && gt (heap [c], heap [c + 1])
142 ? 1 : 0;
143
144 if (!(gt (he, heap [c])))
145 break;
146
147 heap [k] = heap [c];
148
149 k = c;
150 }
151
152 heap [k] = he;
153 }
154
155 /* towards the root */
156 static void
157 upheap (AV *av, f_cmp cmp, void *cmp_data, int k)
158 {
159 SV **heap = AvARRAY (av);
160 SV *he = heap [k];
161
162 while (k)
163 {
164 int p = (k - 1) >> 1;
165
166 if (!(gt (heap [p], he)))
167 break;
168
169 heap [k] = heap [p];
170 k = p;
171 }
172
173 heap [k] = he;
174 }
175
176 /* move an element suitably so it is in a correct place */
177 static void
178 adjustheap (AV *av, f_cmp cmp, void *cmp_data, int N, int k)
179 {
180 SV **heap = AvARRAY (av);
181
182 if (k > 0 && !gt (heap [k], heap [(k - 1) >> 1]))
183 upheap (av, cmp, cmp_data, k);
184 else
185 downheap (av, cmp, cmp_data, N, k);
186 }
187
188 /*****************************************************************************/
189
190 static void
191 make_heap (AV *av, f_cmp cmp, void *cmp_data)
192 {
193 int i, len = AvFILLp (av);
194
195 /* do not use floyds algorithm, as I expect the simpler and more cache-efficient */
196 /* upheap is actually faster */
197 for (i = 0; i <= len; ++i)
198 upheap (av, cmp, cmp_data, i);
199 }
200
201 static void
202 push_heap (AV *av, f_cmp cmp, void *cmp_data, SV *elem)
203 {
204 av_push (av, newSVsv (elem));
205 upheap (av, cmp, cmp_data, AvFILLp (av));
206 }
207
208 static SV *
209 pop_heap (AV *av, f_cmp cmp, void *cmp_data)
210 {
211 int len = AvFILLp (av);
212
213 if (len < 0)
214 return &PL_sv_undef;
215 else if (len == 0)
216 return av_pop (av);
217 else
218 {
219 SV *top = av_pop (av);
220 SV *result = AvARRAY (av)[0];
221 AvARRAY (av)[0] = top;
222 downheap (av, cmp, cmp_data, len, 0);
223 return result;
224 }
225 }
226
227 static SV *
228 splice_heap (AV *av, f_cmp cmp, void *cmp_data, int idx)
229 {
230 int len = AvFILLp (av);
231
232 if (len < 0 || idx > len)
233 return &PL_sv_undef;
234 else if (len == 0 || idx == len)
235 return av_pop (av); /* the only or last element */
236 else
237 {
238 SV *top = av_pop (av);
239 SV *result = AvARRAY (av)[idx];
240 AvARRAY (av)[idx] = top;
241 adjustheap (av, cmp, cmp_data, len, idx);
242 return result;
243 }
244 }
245
246 static void
247 adjust_heap (AV *av, f_cmp cmp, void *cmp_data, int idx)
248 {
249 adjustheap (av, cmp, cmp_data, AvFILLp (av) + 1, idx);
250 }
251
252 MODULE = Array::Heap PACKAGE = Array::Heap
253
254 void
255 make_heap (SV *heap)
256 PROTOTYPE: \@
257 CODE:
258 make_heap (array (heap), cmp_nv, 0);
259
260 void
261 make_heap_lex (SV *heap)
262 PROTOTYPE: \@
263 CODE:
264 make_heap (array (heap), cmp_sv, 0);
265
266 void
267 make_heap_cmp (SV *cmp, SV *heap)
268 PROTOTYPE: &\@
269 CODE:
270 {
271 dCMP;
272 CMP_PUSH (cmp);
273 make_heap (array (heap), cmp_custom, cmp_data);
274 CMP_POP;
275 }
276
277 void
278 push_heap (SV *heap, ...)
279 PROTOTYPE: \@@
280 CODE:
281 {
282 int i;
283 for (i = 1; i < items; i++)
284 push_heap (array (heap), cmp_nv, 0, ST(i));
285 }
286
287 void
288 push_heap_lex (SV *heap, ...)
289 PROTOTYPE: \@@
290 CODE:
291 {
292 int i;
293 for (i = 1; i < items; i++)
294 push_heap (array (heap), cmp_sv, 0, ST(i));
295 }
296
297 void
298 push_heap_cmp (SV *cmp, SV *heap, ...)
299 PROTOTYPE: &\@@
300 CODE:
301 {
302 int i;
303 dCMP;
304
305 CMP_PUSH (cmp);
306 for (i = 2; i < items; i++)
307 push_heap (array (heap), cmp_custom, cmp_data, ST(i));
308 CMP_POP;
309 }
310
311 SV *
312 pop_heap (SV *heap)
313 PROTOTYPE: \@
314 CODE:
315 RETVAL = pop_heap (array (heap), cmp_nv, 0);
316 OUTPUT:
317 RETVAL
318
319 SV *
320 pop_heap_lex (SV *heap)
321 PROTOTYPE: \@
322 CODE:
323 RETVAL = pop_heap (array (heap), cmp_sv, 0);
324 OUTPUT:
325 RETVAL
326
327 SV *
328 pop_heap_cmp (SV *cmp, SV *heap)
329 PROTOTYPE: &\@
330 CODE:
331 {
332 dCMP;
333 CMP_PUSH (cmp);
334 RETVAL = pop_heap (array (heap), cmp_custom, cmp_data);
335 CMP_POP;
336 }
337 OUTPUT:
338 RETVAL
339
340 SV *
341 splice_heap (SV *heap, int idx)
342 PROTOTYPE: \@$
343 CODE:
344 RETVAL = splice_heap (array (heap), cmp_nv, 0, idx);
345 OUTPUT:
346 RETVAL
347
348 SV *
349 splice_heap_lex (SV *heap, int idx)
350 PROTOTYPE: \@$
351 CODE:
352 RETVAL = splice_heap (array (heap), cmp_sv, 0, idx);
353 OUTPUT:
354 RETVAL
355
356 SV *
357 splice_heap_cmp (SV *cmp, SV *heap, int idx)
358 PROTOTYPE: &\@$
359 CODE:
360 {
361 dCMP;
362 CMP_PUSH (cmp);
363 RETVAL = splice_heap (array (heap), cmp_custom, cmp_data, idx);
364 CMP_POP;
365 }
366 OUTPUT:
367 RETVAL
368
369 void
370 adjust_heap (SV *heap, int idx)
371 PROTOTYPE: \@$
372 CODE:
373 adjust_heap (array (heap), cmp_nv, 0, idx);
374
375 void
376 adjust_heap_lex (SV *heap, int idx)
377 PROTOTYPE: \@$
378 CODE:
379 adjust_heap (array (heap), cmp_sv, 0, idx);
380
381 void
382 adjust_heap_cmp (SV *cmp, SV *heap, int idx)
383 PROTOTYPE: &\@$
384 CODE:
385 {
386 dCMP;
387 CMP_PUSH (cmp);
388 adjust_heap (array (heap), cmp_custom, cmp_data, idx);
389 CMP_POP;
390 }
391