ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Array-Heap/Heap.xs
Revision: 1.5
Committed: Fri Apr 19 20:00:54 2013 UTC (11 years, 1 month ago) by root
Branch: MAIN
CVS Tags: rel-3_0
Changes since 1.4: +75 -34 lines
Log Message:
*** empty log message ***

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.5 static void
77     set_idx (SV *sv, int idx)
78     {
79     if (!SvROK (sv))
80     return;
81    
82     sv = SvRV (sv);
83    
84     if (SvTYPE (sv) != SVt_PVAV)
85     return;
86    
87     if (AvFILL ((AV *)sv) < 1 || AvARRAY ((AV *)sv)[1] == &PL_sv_undef)
88     av_store ((AV *)sv, 1, newSViv (idx));
89     else
90     {
91     sv = AvARRAY ((AV *)sv)[1];
92    
93     if (SvTYPE (sv) == SVt_IV)
94     SvIV_set (sv, idx);
95     else
96     sv_setiv (sv, idx);
97     }
98     }
99    
100     #define set_heap(idx,he) \
101     do { \
102     if (flags) \
103     set_idx (he, idx); \
104     heap [idx] = he; \
105     } while (0)
106    
107 root 1.1 static int
108 root 1.3 cmp_nv (SV *a, SV *b, void *cmp_data)
109 root 1.1 {
110 root 1.3 a = sv_first (a);
111     b = sv_first (b);
112 root 1.1
113     return SvNV (a) > SvNV (b);
114     }
115    
116     static int
117 root 1.3 cmp_sv (SV *a, SV *b, void *cmp_data)
118 root 1.1 {
119 root 1.3 a = sv_first (a);
120     b = sv_first (b);
121 root 1.1
122 root 1.3 return sv_cmp (a, b) > 0;
123 root 1.1 }
124    
125     static int
126 root 1.3 cmp_custom (SV *a, SV *b, void *cmp_data)
127 root 1.1 {
128 root 1.3 dCMP_CALL (cmp_data);
129 root 1.1
130     GvSV (PL_firstgv) = a;
131     GvSV (PL_secondgv) = b;
132    
133 root 1.3 MULTICALL;
134 root 1.1
135     if (SvTRUE (ERRSV))
136     croak (NULL);
137    
138 root 1.3 {
139     dSP;
140     return TOPi > 0;
141     }
142     }
143 root 1.1
144 root 1.3 /*****************************************************************************/
145 root 1.1
146 root 1.3 typedef int (*f_cmp)(SV *a, SV *b, void *cmp_data);
147 root 1.1
148     static AV *
149     array (SV *ref)
150     {
151 root 1.3 if (SvROK (ref)
152     && SvTYPE (SvRV (ref)) == SVt_PVAV
153     && !SvTIED_mg (SvRV (ref), PERL_MAGIC_tied))
154 root 1.1 return (AV *)SvRV (ref);
155    
156 root 1.3 croak ("argument 'heap' must be a (non-tied) array");
157 root 1.1 }
158    
159 root 1.3 #define gt(a,b) cmp ((a), (b), cmp_data)
160 root 1.1
161 root 1.3 /*****************************************************************************/
162 root 1.1
163 root 1.3 /* away from the root */
164 root 1.1 static void
165 root 1.5 downheap (AV *av, f_cmp cmp, void *cmp_data, int N, int k, int flags)
166 root 1.1 {
167 root 1.3 SV **heap = AvARRAY (av);
168     SV *he = heap [k];
169 root 1.1
170 root 1.3 for (;;)
171 root 1.1 {
172 root 1.3 int c = (k << 1) + 1;
173    
174     if (c >= N)
175     break;
176    
177     c += c + 1 < N && gt (heap [c], heap [c + 1])
178     ? 1 : 0;
179    
180     if (!(gt (he, heap [c])))
181     break;
182    
183 root 1.5 set_heap (k, heap [c]);
184 root 1.3
185     k = c;
186 root 1.1 }
187    
188 root 1.5 set_heap (k, he);
189 root 1.1 }
190    
191 root 1.3 /* towards the root */
192 root 1.1 static void
193 root 1.5 upheap (AV *av, f_cmp cmp, void *cmp_data, int k, int flags)
194 root 1.1 {
195 root 1.3 SV **heap = AvARRAY (av);
196     SV *he = heap [k];
197 root 1.1
198 root 1.3 while (k)
199 root 1.1 {
200 root 1.3 int p = (k - 1) >> 1;
201 root 1.1
202 root 1.3 if (!(gt (heap [p], he)))
203     break;
204    
205 root 1.5 set_heap (k, heap [p]);
206 root 1.3 k = p;
207 root 1.1 }
208    
209 root 1.5 set_heap (k, he);
210 root 1.3 }
211    
212     /* move an element suitably so it is in a correct place */
213     static void
214 root 1.5 adjustheap (AV *av, f_cmp cmp, void *cmp_data, int N, int k, int flags)
215 root 1.3 {
216     SV **heap = AvARRAY (av);
217 root 1.1
218 root 1.3 if (k > 0 && !gt (heap [k], heap [(k - 1) >> 1]))
219 root 1.5 upheap (av, cmp, cmp_data, k, flags);
220 root 1.3 else
221 root 1.5 downheap (av, cmp, cmp_data, N, k, flags);
222 root 1.1 }
223    
224 root 1.3 /*****************************************************************************/
225    
226 root 1.1 static void
227 root 1.5 make_heap (AV *av, f_cmp cmp, void *cmp_data, int flags)
228 root 1.1 {
229 root 1.3 int i, len = AvFILLp (av);
230 root 1.1
231 root 1.3 /* do not use floyds algorithm, as I expect the simpler and more cache-efficient */
232     /* upheap is actually faster */
233     for (i = 0; i <= len; ++i)
234 root 1.5 upheap (av, cmp, cmp_data, i, flags);
235 root 1.1 }
236    
237     static void
238 root 1.5 push_heap (AV *av, f_cmp cmp, void *cmp_data, SV **elems, int nelems, int flags)
239 root 1.1 {
240 root 1.4 int i;
241    
242     av_extend (av, AvFILLp (av) + nelems);
243    
244     /* we do it in two steps, as the perl cmp function might copy the stack */
245     for (i = 0; i < nelems; ++i)
246     AvARRAY (av)[++AvFILLp (av)] = newSVsv (elems [i]);
247    
248     for (i = 0; i < nelems; ++i)
249 root 1.5 upheap (av, cmp, cmp_data, AvFILLp (av) - i, flags);
250 root 1.1 }
251    
252     static SV *
253 root 1.5 pop_heap (AV *av, f_cmp cmp, void *cmp_data, int flags)
254 root 1.1 {
255 root 1.3 int len = AvFILLp (av);
256    
257     if (len < 0)
258 root 1.1 return &PL_sv_undef;
259 root 1.3 else if (len == 0)
260 root 1.1 return av_pop (av);
261     else
262     {
263     SV *top = av_pop (av);
264 root 1.3 SV *result = AvARRAY (av)[0];
265     AvARRAY (av)[0] = top;
266 root 1.5 downheap (av, cmp, cmp_data, len, 0, flags);
267 root 1.3 return result;
268     }
269     }
270 root 1.1
271 root 1.3 static SV *
272 root 1.5 splice_heap (AV *av, f_cmp cmp, void *cmp_data, int idx, int flags)
273 root 1.3 {
274     int len = AvFILLp (av);
275 root 1.1
276 root 1.3 if (len < 0 || idx > len)
277     return &PL_sv_undef;
278     else if (len == 0 || idx == len)
279     return av_pop (av); /* the only or last element */
280     else
281     {
282     SV *top = av_pop (av);
283     SV *result = AvARRAY (av)[idx];
284     AvARRAY (av)[idx] = top;
285 root 1.5 adjustheap (av, cmp, cmp_data, len, idx, flags);
286 root 1.1 return result;
287     }
288     }
289    
290 root 1.3 static void
291 root 1.5 adjust_heap (AV *av, f_cmp cmp, void *cmp_data, int idx, int flags)
292 root 1.3 {
293 root 1.5 adjustheap (av, cmp, cmp_data, AvFILLp (av) + 1, idx, flags);
294 root 1.3 }
295    
296 root 1.1 MODULE = Array::Heap PACKAGE = Array::Heap
297    
298     void
299 root 1.3 make_heap (SV *heap)
300 root 1.1 PROTOTYPE: \@
301 root 1.5 ALIAS:
302     make_heap_idx = 1
303 root 1.1 CODE:
304 root 1.5 make_heap (array (heap), cmp_nv, 0, ix);
305 root 1.1
306     void
307 root 1.3 make_heap_lex (SV *heap)
308 root 1.1 PROTOTYPE: \@
309     CODE:
310 root 1.5 make_heap (array (heap), cmp_sv, 0, 0);
311 root 1.1
312     void
313 root 1.3 make_heap_cmp (SV *cmp, SV *heap)
314 root 1.1 PROTOTYPE: &\@
315     CODE:
316 root 1.3 {
317     dCMP;
318     CMP_PUSH (cmp);
319 root 1.5 make_heap (array (heap), cmp_custom, cmp_data, 0);
320 root 1.3 CMP_POP;
321     }
322 root 1.1
323     void
324 root 1.3 push_heap (SV *heap, ...)
325 root 1.1 PROTOTYPE: \@@
326 root 1.5 ALIAS:
327     push_heap_idx = 1
328 root 1.1 CODE:
329 root 1.5 push_heap (array (heap), cmp_nv, 0, &(ST(1)), items - 1, ix);
330 root 1.1
331     void
332 root 1.3 push_heap_lex (SV *heap, ...)
333 root 1.1 PROTOTYPE: \@@
334     CODE:
335 root 1.5 push_heap (array (heap), cmp_sv, 0, &(ST(1)), items - 1, 0);
336 root 1.1
337     void
338 root 1.3 push_heap_cmp (SV *cmp, SV *heap, ...)
339 root 1.1 PROTOTYPE: &\@@
340     CODE:
341 root 1.3 {
342 root 1.4 SV **st_2 = &(ST(2)); /* multicall.h uses PUSHSTACK */
343 root 1.3 dCMP;
344     CMP_PUSH (cmp);
345 root 1.5 push_heap (array (heap), cmp_custom, cmp_data, st_2, items - 2, 0);
346 root 1.3 CMP_POP;
347     }
348 root 1.1
349     SV *
350 root 1.3 pop_heap (SV *heap)
351 root 1.1 PROTOTYPE: \@
352 root 1.5 ALIAS:
353     pop_heap_idx = 1
354 root 1.1 CODE:
355 root 1.5 RETVAL = pop_heap (array (heap), cmp_nv, 0, ix);
356 root 1.1 OUTPUT:
357     RETVAL
358    
359     SV *
360 root 1.3 pop_heap_lex (SV *heap)
361 root 1.1 PROTOTYPE: \@
362     CODE:
363 root 1.5 RETVAL = pop_heap (array (heap), cmp_sv, 0, 0);
364 root 1.1 OUTPUT:
365     RETVAL
366    
367     SV *
368 root 1.3 pop_heap_cmp (SV *cmp, SV *heap)
369 root 1.1 PROTOTYPE: &\@
370     CODE:
371 root 1.3 {
372     dCMP;
373     CMP_PUSH (cmp);
374 root 1.5 RETVAL = pop_heap (array (heap), cmp_custom, cmp_data, 0);
375 root 1.3 CMP_POP;
376     }
377     OUTPUT:
378     RETVAL
379    
380     SV *
381     splice_heap (SV *heap, int idx)
382     PROTOTYPE: \@$
383 root 1.5 ALIAS:
384     splice_heap_idx = 1
385 root 1.3 CODE:
386 root 1.5 RETVAL = splice_heap (array (heap), cmp_nv, 0, idx, ix);
387 root 1.3 OUTPUT:
388     RETVAL
389    
390     SV *
391     splice_heap_lex (SV *heap, int idx)
392     PROTOTYPE: \@$
393     CODE:
394 root 1.5 RETVAL = splice_heap (array (heap), cmp_sv, 0, idx, 0);
395 root 1.3 OUTPUT:
396     RETVAL
397    
398     SV *
399     splice_heap_cmp (SV *cmp, SV *heap, int idx)
400     PROTOTYPE: &\@$
401     CODE:
402     {
403     dCMP;
404     CMP_PUSH (cmp);
405 root 1.5 RETVAL = splice_heap (array (heap), cmp_custom, cmp_data, idx, 0);
406 root 1.3 CMP_POP;
407     }
408 root 1.1 OUTPUT:
409     RETVAL
410    
411 root 1.3 void
412     adjust_heap (SV *heap, int idx)
413     PROTOTYPE: \@$
414 root 1.5 ALIAS:
415     adjust_heap_idx = 1
416 root 1.3 CODE:
417 root 1.5 adjust_heap (array (heap), cmp_nv, 0, idx, ix);
418 root 1.3
419     void
420     adjust_heap_lex (SV *heap, int idx)
421     PROTOTYPE: \@$
422     CODE:
423 root 1.5 adjust_heap (array (heap), cmp_sv, 0, idx, 0);
424 root 1.3
425     void
426     adjust_heap_cmp (SV *cmp, SV *heap, int idx)
427     PROTOTYPE: &\@$
428     CODE:
429     {
430     dCMP;
431     CMP_PUSH (cmp);
432 root 1.5 adjust_heap (array (heap), cmp_custom, cmp_data, idx, 0);
433 root 1.3 CMP_POP;
434     }
435 root 1.1