ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Array-Heap/Heap.xs
Revision: 1.8
Committed: Tue Jul 14 23:28:10 2015 UTC (8 years, 10 months ago) by root
Branch: MAIN
CVS Tags: rel-3_2, rel-3_21
Changes since 1.7: +3 -6 lines
Log Message:
3.2

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