File Coverage

XS.xs
Criterion Covered Total %
statement 87 123 70.7
branch 41 80 51.2
condition n/a
subroutine n/a
pod n/a
total 128 203 63.0


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