File Coverage

XS.xs
Criterion Covered Total %
statement 95 101 94.0
branch 84 220 38.1
condition n/a
subroutine n/a
pod n/a
total 179 321 55.7


line stmt bran cond sub pod time code
1             #define PERL_NO_GET_CONTEXT
2             #include "EXTERN.h"
3             #include "perl.h"
4             #include "XSUB.h"
5              
6             #include "ppport.h"
7              
8             #define iParent(i) (((i)-1) / 2)
9             #define iLeftChild(i) ((2*(i)) + 1)
10             #define iRightChild(i) ((2*(i)) + 2)
11              
12             #define OUT_OF_ORDER(a,tmpsv,child_is_magic,parent_is_magic,child,parent,is_min) \
13             ( ( ( (child_is_magic) || (parent_is_magic) ) \
14             ? (((tmpsv) = amagic_call((a)[(child)], (a)[(parent)], is_min & 2 ? sgt_amg : gt_amg, 0)) && SvTRUE((tmpsv))) \
15             : ( ((is_min & 2) ? Perl_sv_cmp(aTHX_ (a)[(child)], a[(parent)]) \
16             : Perl_do_ncmp(aTHX_ (a)[(child)], a[(parent)])) > 0) )\
17             ? !(is_min & 1) : (is_min & 1) )
18              
19              
20 8           I32 sift_up(pTHX_ SV **a, ssize_t start, ssize_t end, I32 is_min) {
21             /*start represents the limit of how far up the heap to sift.
22             end is the node to sift up. */
23 8           ssize_t child = end;
24 8           SV *tmpsv = NULL;
25             I32 child_is_magic;
26 8           I32 swapped = 0;
27 8 50         SvGETMAGIC(a[child]);
    0          
28 8 50         child_is_magic= SvAMAGIC(a[child]);
    0          
    0          
29              
30 22 100         while (child > start) {
31 18           ssize_t parent = iParent(child);
32             I32 parent_is_magic;
33 18 50         SvGETMAGIC(a[parent]);
    0          
34 18 50         parent_is_magic= SvAMAGIC(a[parent]);
    0          
    0          
35 18 50         if ( OUT_OF_ORDER(a,tmpsv,child_is_magic,parent_is_magic,child,parent,is_min) ) {
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    100          
    100          
36 14           SV *swap_tmp= a[parent];
37 14           a[parent]= a[child];
38 14           a[child]= swap_tmp;
39              
40 14           child = parent; /* repeat to continue sifting up the parent now */
41 14           child_is_magic= parent_is_magic;
42 14           swapped++;
43             }
44             else {
45 4           return swapped;
46             }
47             }
48 4           return swapped;
49             }
50              
51             /*Repair the heap whose root element is at index 'start', assuming the heaps rooted at its children are valid*/
52 75468           I32 sift_down(pTHX_ SV **a, ssize_t start, ssize_t end, I32 is_min) {
53 75468           ssize_t root = start;
54 75468 100         I32 root_is_magic = SvAMAGIC(a[root]);
    50          
    50          
55 75468           I32 swapped = 0;
56              
57 186397 100         while (iLeftChild(root) <= end) { /* While the root has at least one child */
58 140476           ssize_t child = iLeftChild(root); /* Left child of root */
59 140476 100         I32 child_is_magic = SvAMAGIC(a[child]);
    50          
    50          
60 140476           ssize_t swap = root; /* Keeps track of child to swap with */
61 140476           I32 swap_is_magic = root_is_magic;
62 140476           SV *tmpsv = NULL;
63              
64             /* if the root is smaller than the left child
65             * then the swap is with the left child */
66 140476 100         if ( OUT_OF_ORDER(a,tmpsv,child_is_magic,swap_is_magic,child,swap,is_min) ) {
    50          
    50          
    50          
    50          
    50          
    0          
    50          
    0          
    0          
    50          
    50          
    50          
    100          
    50          
    100          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    100          
    100          
67 94481           swap = child;
68 94481           swap_is_magic = child_is_magic;
69             }
70             /* if there is a right child and the right child is larger than the root or the left child
71             * then the swap is with the right child */
72 140476 100         if (child+1 <= end) {
73 139860 100         child_is_magic = SvAMAGIC(a[child+1]);
    50          
    50          
74 139860 100         if ( OUT_OF_ORDER(a,tmpsv,child_is_magic,swap_is_magic,child+1,swap,is_min) ) {
    50          
    50          
    50          
    50          
    50          
    0          
    50          
    0          
    0          
    50          
    50          
    50          
    100          
    50          
    100          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    50          
    100          
    100          
75 55056           swap = child + 1;
76 55056           swap_is_magic = child_is_magic;
77             }
78             }
79             /* check if we need to swap or if this tree is in heap-order */
80 140476 100         if (swap == root) {
81             /* The root is larger than both children, and as we assume the heaps rooted at the children are valid
82             * then we know we can stop. */
83 29547           return swapped;
84             } else {
85             /* swap the root with the largest child */
86 110929           SV *tmp= a[root];
87 110929           a[root]= a[swap];
88 110929           a[swap]= tmp;
89             /* continue sifting down the child by setting the root to the chosen child
90             * effectively we sink down the tree towards the leafs */
91 110929           root = swap;
92 110929           root_is_magic = swap_is_magic;
93 110929           swapped++;
94             }
95             }
96 45921           return swapped;
97             }
98              
99             /* this is O(N log N) */
100 0           void heapify_with_sift_up(pTHX_ SV **a, ssize_t count, I32 is_min) {
101 0           ssize_t end = 1; /* end is assigned the index of the first (left) child of the root */
102              
103 0 0         while (end < count) {
104             /*sift up the node at index end to the proper place such that all nodes above
105             the end index are in heap order */
106 0           (void)sift_up(aTHX_ a, 0, end, is_min);
107 0           end++;
108             }
109             /* after sifting up the last node all nodes are in heap order */
110 0           }
111              
112             /* this is O(N) */
113 310           void heapify_with_sift_down(pTHX_ SV **a, ssize_t count, I32 is_min) {
114             /*start is assigned the index in 'a' of the last parent node
115             the last element in a 0-based array is at index count-1; find the parent of that element */
116 310           ssize_t start = iParent(count-1);
117              
118 75470 100         while (start >= 0) {
119             /* sift down the node at index 'start' to the proper place such that all nodes below
120             the start index are in heap order */
121 75160           (void)sift_down(aTHX_ a, start, count - 1, is_min);
122             /* go to the next parent node */
123 75160           start--;
124             }
125             /* after sifting down the root all nodes/elements are in heap order */
126 310           }
127              
128             #define FORCE_SCALAR(fakeop) \
129             STMT_START { \
130             SAVEOP(); \
131             Copy(PL_op, &fakeop, 1, OP); \
132             fakeop.op_flags = OPf_WANT_SCALAR; \
133             PL_op = &fakeop; \
134             } STMT_END
135              
136             MODULE = Algorithm::Heapify::XS PACKAGE = Algorithm::Heapify::XS
137              
138             void
139             max_heapify(av)
140             AV *av
141             PROTOTYPE: \@
142             ALIAS:
143             max_heapify = 0
144             min_heapify = 1
145             maxstr_heapify = 2
146             minstr_heapify = 3
147             PREINIT:
148             OP fakeop;
149             I32 count;
150             PPCODE:
151 310           FORCE_SCALAR(fakeop);
152 310           count = av_top_index(av)+1;
153 310 50         if ( count ) {
154 310           heapify_with_sift_down(aTHX_ AvARRAY(av),count,ix);
155 310           ST(0)= AvARRAY(av)[0];
156 310           XSRETURN(1);
157             }
158             else {
159 310           XSRETURN(0);
160             }
161              
162             void
163             max_heap_shift(av)
164             AV *av
165             PROTOTYPE: \@
166             ALIAS:
167             max_heap_shift = 0
168             min_heap_shift = 1
169             maxstr_heap_shift = 2
170             minstr_heap_shift = 3
171             PREINIT:
172             OP fakeop;
173             I32 top;
174             I32 count;
175             PPCODE:
176 324           FORCE_SCALAR(fakeop);
177 324           top= av_top_index(av);
178 324           count= top+1;
179 324 50         if (count) {
180 324           SV *tmp= AvARRAY(av)[0];
181 324           AvARRAY(av)[0]= AvARRAY(av)[top];
182 324           AvARRAY(av)[top]= tmp;
183 324           ST(0)= av_pop(av);
184 324 100         if (count > 2)
185 304           sift_down(aTHX_ AvARRAY(av),0,top-1,ix);
186 324           XSRETURN(1);
187             }
188             else {
189 324           XSRETURN(0);
190             }
191              
192             void
193             max_heap_push(av,sv)
194             AV *av
195             SV *sv
196             PROTOTYPE: \@$
197             ALIAS:
198             max_heap_push = 0
199             min_heap_push = 1
200             maxstr_heap_push = 2
201             minstr_heap_push = 3
202             PREINIT:
203             OP fakeop;
204             I32 top;
205             I32 count;
206             PPCODE:
207 4           FORCE_SCALAR(fakeop);
208 4           av_push(av,newSVsv(sv));
209 4           top= av_top_index(av);
210 4           count= top+1;
211 4           sift_up(aTHX_ AvARRAY(av),0,top,ix);
212 4           ST(0)= AvARRAY(av)[0];
213 4           XSRETURN(1);
214              
215             void
216             max_heap_adjust_top(av)
217             AV *av
218             PROTOTYPE: \@
219             ALIAS:
220             max_heap_adjust_top = 0
221             min_heap_adjust_top = 1
222             maxstr_heap_adjust_top = 2
223             minstr_heap_adjust_top = 3
224             PREINIT:
225             OP fakeop;
226             I32 top;
227             I32 count;
228             PPCODE:
229 2           FORCE_SCALAR(fakeop);
230 2           top= av_top_index(av);
231 2           count= top+1;
232 2 50         if ( count ) {
233 2           (void)sift_down(aTHX_ AvARRAY(av),0,top,ix);
234 2           ST(0)= AvARRAY(av)[0];
235 2           XSRETURN(1);
236             } else {
237 2           XSRETURN(0);
238             }
239              
240             void
241             max_heap_adjust_item(av,idx=0)
242             AV *av
243             I32 idx;
244             PROTOTYPE: \@;$
245             ALIAS:
246             max_heap_adjust_item = 0
247             min_heap_adjust_item = 1
248             maxstr_heap_adjust_item = 2
249             minstr_heap_adjust_item = 3
250             PREINIT:
251             OP fakeop;
252             I32 top;
253             I32 count;
254             PPCODE:
255 4           FORCE_SCALAR(fakeop);
256 4           top= av_top_index(av);
257 4           count= top+1;
258 4 50         if ( idx < count ) {
259 4 50         if (!idx || !sift_up(aTHX_ AvARRAY(av),0,idx,ix))
    100          
260 2           (void)sift_down(aTHX_ AvARRAY(av),idx,top,ix);
261 4           ST(0)= AvARRAY(av)[0];
262 4           XSRETURN(1);
263             } else {
264 4           XSRETURN(0);
265             }
266