File Coverage

XS.xs
Criterion Covered Total %
statement 108 123 87.8
branch 61 78 78.2
condition n/a
subroutine n/a
pod n/a
total 169 201 84.0


line stmt bran cond sub pod time code
1             #include "EXTERN.h"
2             #include "perl.h"
3             #include "XSUB.h"
4              
5             struct LK {
6             struct LK *link;
7             IV i;
8             IV j;
9             struct LK *next;
10             };
11             struct LA {
12             struct LK **arr;
13             IV max;
14             IV alloc;
15             };
16             struct TA {
17             IV *arr;
18             IV max;
19             IV alloc;
20             };
21             struct CTX {
22             struct TA thresh;
23             struct LA links;
24             struct LA avail;
25             struct LK *current;
26             };
27              
28             inline
29 11400114           static IV *ta_push(struct TA *a)
30             {
31 11400114           a->max++;
32 11400114 50         if (a->max == a->alloc) {
33 0           IV *new = malloc(2 * a->alloc * sizeof *new);
34 0           memcpy(new, a->arr, a->max * sizeof *new);
35 0           free(a->arr);
36 0           a->arr = new;
37 0           a->alloc *= 2;
38             }
39 11400114           return &a->arr[a->max];
40             }
41              
42             inline
43 11400125           static struct LK **la_push(struct LA *a)
44             {
45 11400125           a->max++;
46 11400125 50         if (a->max == a->alloc) {
47 0           struct LK **new = malloc(2 * a->alloc * sizeof *new);
48 0           memcpy(new, a->arr, a->max * sizeof *new);
49 0           free(a->arr);
50 0           a->arr = new;
51 0           a->alloc *= 2;
52             }
53 11400125           return &a->arr[a->max];
54             }
55              
56              
57             #define PREP_LINKS(cur,N) do { \
58             struct LK *e = (cur), *end = (cur) + ((N)-1); \
59             while (e < end) { \
60             e->next = e + 1; \
61             ++e; \
62             } \
63             end->next = NULL; \
64             } while(0)
65              
66              
67             inline
68 145501455           static struct LK *make_link(struct CTX *ctx, struct LK *lk, IV i, IV j)
69             {
70 145501455           struct LK *new = ctx->current;
71 145501455           new->link = lk;
72 145501455           new->i = i;
73 145501455           new->j = j;
74 145501455 100         if (new->next) {
75 145501446           ctx->current = new->next;
76 145501446           return new;
77             }
78 9           ctx->current = malloc(ctx->avail.alloc * sizeof *ctx->current);
79 900 100         PREP_LINKS(ctx->current, ctx->avail.alloc);
80 9           *la_push(&ctx->avail) = ctx->current;
81 9           new->next = ctx->current;
82 9           return new;
83             }
84              
85              
86             inline
87 2           static IV lcs_DESTROY(SV *sv)
88             {
89 2           struct CTX *ctx = (struct CTX *)SvIVX(SvRV(sv));
90 2 50         if (ctx == NULL)
91 0           return 0;
92 2 50         if (ctx->thresh.alloc)
93 2           free(ctx->thresh.arr);
94 2 50         if (ctx->links.alloc)
95 2           free(ctx->links.arr);
96 2 50         if (ctx->avail.alloc) {
97 13 100         while (ctx->avail.max >= 0)
98 11           free(ctx->avail.arr[ctx->avail.max--]);
99 2           free(ctx->avail.arr);
100             }
101              
102 2           free(ctx);
103 2           return 1;
104             }
105              
106             inline
107 2           static SV *lcs_new(char *class)
108             {
109 2           struct CTX *ctx = malloc(sizeof *ctx);
110             struct LK *end;
111              
112 2           ctx->thresh.arr = malloc(100 * sizeof *ctx->thresh.arr);
113 2           ctx->thresh.alloc = 100;
114 2           ctx->thresh.max = -1;
115              
116 2           ctx->links.arr = malloc(100 * sizeof *ctx->links.arr);
117 2           ctx->links.alloc = 100;
118 2           ctx->links.max = -1;
119              
120 2           ctx->avail.arr = malloc(100 * sizeof *ctx->links.arr);
121 2           ctx->avail.alloc = 100;
122 2           ctx->avail.max = -1;
123              
124 2           ctx->current = malloc(100 * sizeof *ctx->current);
125 200 100         PREP_LINKS(ctx->current, 100);
126 2           *la_push(&ctx->avail) = ctx->current;
127              
128 2           return sv_setref_pv(newSV(0),class,ctx);
129             }
130              
131             inline
132 148201482           static int rnlw(struct TA *a, const IV aValue, IV high)
133             {
134             /* literal C translation of Algorithm::Diff::_replaceNextLargestWith */
135 148201482           IV low = 0;
136 148201482 100         if (high <= 0)
137 30100301           high = a->max;
138 148201482 100         if (high == -1 || aValue > a->arr[a->max]) {
    100          
139 11400114           *ta_push(a) = aValue;
140 11400114           return high + 1;
141             }
142 680006800 100         while (low <= high) {
143 566305663           IV idx = (low + high) / 2;
144 566305663           IV found = a->arr[idx];
145 566305663 100         if (aValue == found)
146 23100231           return -1;
147 543205432 100         else if (aValue > found)
148 363503635           low = idx + 1;
149             else
150 179701797           high = idx - 1;
151             }
152 113701137           a->arr[low] = aValue;
153 113701137           return low;
154             }
155              
156              
157             MODULE = Algorithm::LCS::XS PACKAGE = Algorithm::LCS::XS PREFIX = lcs_
158             PROTOTYPES: DISABLED
159              
160             SV *lcs_new(char *class)
161              
162             IV lcs_DESTROY(SV *sv)
163              
164             void lcs__core_loop(obj, a, a_min, a_max, h)
165             SV *obj
166             AV *a
167             IV a_min
168             IV a_max
169             HV *h
170              
171             PREINIT:
172 300003           struct CTX *ctx = (struct CTX *)SvIVX(SvRV(obj));
173             IV i, j;
174              
175             PPCODE:
176 300003           ctx->links.max = ctx->thresh.max = -1;
177 300003           ctx->current = *ctx->avail.arr;
178              
179 17700177 100         for (i = a_min; i <= a_max; ++i) {
180 17400174           SV *line = *av_fetch(a, i, 0);
181             STRLEN klen;
182 17400174 50         char *key = SvPVbyte(line, klen);
183 17400174           SV **lines = hv_fetch(h, key, klen, 0);
184              
185 17400174 50         if (lines != NULL) {
186 17400174           register IV k = 0, idx;
187 17400174           AV *matches = (AV *)SvRV(*lines); /* line_map() value */
188              
189 186001860 100         for (idx = av_len(matches); idx >= 0; --idx) {
190             /* We know (via sub line_map) "matches" holds
191             * valid SvIV's, in increasing order, so we can use
192             * (quicker) SvIVX instead of (safer) SvIV here.
193             */
194 168601686           j = SvIVX(*av_fetch(matches, idx, 0));
195              
196 168601686 100         if (k > 0 && ctx->thresh.arr[k] > j &&
    50          
    100          
197 138501385           ctx->thresh.arr[k-1] < j) {
198 20400204           ctx->thresh.arr[k] = j;
199             }
200             else
201 148201482           k = rnlw(&ctx->thresh, j, k);
202              
203 168601686 100         if (k >= 0) {
204 145501455 100         struct LK *lk = make_link(ctx, (k>0) ?
205 142101421           ctx->links.arr[k-1] :
206             NULL, i, j);
207 145501455 100         if (ctx->links.max < k) {
208 11400114           *la_push(&ctx->links) = lk;
209             }
210             else
211 134101341           ctx->links.arr[k] = lk;
212             }
213             }
214             }
215             }
216              
217 300003 50         if (ctx->thresh.max >= 0) {
218             struct LK *lk;
219 300003 100         if (GIMME_V == G_ARRAY) {
    100          
220             SV **start, **end;
221 200003           XSprePUSH;
222 200003           start = SP+1;
223 7600117 100         for (lk = ctx->links.arr[ctx->thresh.max]; lk; lk = lk->link) {
224             AV *arr;
225             /* only count transitions */
226 7400114 100         if (lk->link && lk->link->i == lk->i)
    50          
227 0           continue;
228 7400114           arr = newAV();
229 7400114           av_push(arr, newSViv(lk->i));
230 7400114           av_push(arr, newSViv(lk->j));
231 7400114 50         XPUSHs(sv_2mortal(newRV_noinc((SV *)arr)));
232             }
233             /* reverse the stack */
234 200003           end = SP;
235 3800059 100         while (start < end) {
236 3600056           SV *tmp = *start;
237 3600056           *start++ = *end;
238 3600056           *end-- = tmp;
239             }
240             }
241             else {
242 100000           j = 0;
243 4100000 100         for (lk = ctx->links.arr[ctx->thresh.max]; lk; lk = lk->link) {
244 4000000 100         if (lk->link && lk->link->i == lk->i)
    50          
245 0           continue;
246 4000000           ++j;
247             }
248 300003           XSRETURN_IV(j);
249             }
250             }
251 0 0         else if (GIMME_V == G_SCALAR)
    0          
252 0           XSRETURN_IV(0);