ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Array-Heap/Heap.xs
Revision: 1.4
Committed: Sun Jul 26 05:25:18 2009 UTC (14 years, 9 months ago) by root
Branch: MAIN
CVS Tags: rel-2_0
Changes since 1.3: +20 -17 lines
Log Message:
2.0

File Contents

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