File Coverage

perlsubs.c
Criterion Covered Total %
statement 202 299 67.5
branch 93 212 43.8
condition n/a
subroutine n/a
pod n/a
total 295 511 57.7


line stmt bran cond sub pod time code
1             /* Fast GF(2^m) library routines */
2             /*
3             Copyright (c) by Declan Malone 2009.
4             Licensed under the terms of the GNU General Public License and
5             the GNU Lesser (Library) General Public License.
6             */
7              
8              
9 1607           SV* mat_alloc_c(char* class, int rows, int cols, int width, int org) {
10              
11             gf2_matrix_t* Matrix;
12             SV* obj_ref;
13             SV* obj;
14            
15 1607           Matrix=malloc(sizeof (gf2_matrix_t));
16              
17 1607 50         if (Matrix == NULL) return &PL_sv_undef;
18              
19 1607           Matrix->values=malloc(rows * cols * width);
20 1607 50         if (Matrix->values == NULL) { free(Matrix); return NULL; }
21 1607           memset(Matrix->values,0,rows * cols * width);
22              
23 1607           Matrix->alloc_bits = FREE_BOTH;
24 1607           Matrix->rows = rows;
25 1607           Matrix->cols = cols;
26 1607           Matrix->width = width;
27 1607           Matrix->organisation = org;
28            
29 1607           obj_ref = newSViv(0);
30 1607           obj = newSVrv(obj_ref, class);
31              
32 1607           sv_setiv(obj,(IV)Matrix);
33 1607           SvREADONLY_on(obj);
34 1607           return obj_ref;
35             }
36              
37 1607           void mat_DESTROY (SV* Self) {
38 1607 50         gf2_matrix_t *m=(gf2_matrix_t*)SvIV(SvRV(Self));
39 1607 50         if (m->alloc_bits & 1)
40 1607           free(m->values);
41 1607 50         if (m->alloc_bits & 2)
42 1607           free(m);
43 1607           }
44              
45             /* accessor methods; get info on ROWS, COLS, etc. */
46 4124           int mat_ROWS (SV* Self) {
47 4124 50         return ((gf2_matrix_t*)SvIV(SvRV(Self)))->rows;
48             }
49              
50 14781           int mat_COLS (SV* Self) {
51 14781 50         return ((gf2_matrix_t*)SvIV(SvRV(Self)))->cols;
52             }
53              
54 5260           int mat_WIDTH (SV* Self) {
55 5260 50         return ((gf2_matrix_t*)SvIV(SvRV(Self)))->width;
56             }
57              
58 2602           int mat_ORGNUM (SV* Self) {
59 2602 50         return ((gf2_matrix_t*)SvIV(SvRV(Self)))->organisation;
60             }
61              
62 41070           gf2_u32 mat_getval(SV *Self, int row, int col) {
63 41070 50         gf2_matrix_t *m=(gf2_matrix_t*)SvIV(SvRV(Self));
64 41070           int down=gf2_matrix_offset_down(m);
65 41070           int right=gf2_matrix_offset_right(m);
66 41070           void *p=(void*)m->values + (row * down) + (col * right);
67              
68             gf2_u8 u8;
69             gf2_u16 u16;
70             gf2_u32 u32;
71              
72 41070 50         if ((row < 0) || (row >= m->rows)) {
    50          
73 0           fprintf (stderr, "Math::FastGF2::Matrix - row out of range in getval\n");
74 0           return 0;
75             }
76 41070 50         if ((col < 0) || (col >= m->cols)) {
    50          
77 0           fprintf (stderr, "Math::FastGF2::Matrix - col out of range in getval\n");
78 0           return 0;
79             }
80              
81 41070           switch (m->width) {
82             case 1:
83 36096           u8=*((gf2_u8*)p);
84 36096           return u8;
85             case 2:
86 2548           u16=*((gf2_u16*)p);
87 2548           return u16;
88             case 4:
89 2426           u32=*((gf2_u32*)p);
90 2426           return u32;
91             default:
92 0           fprintf(stderr,"Unsupported width %d in getval\n",m->width);
93 0           return 0;
94             }
95             }
96              
97 30436           gf2_u32 mat_setval(SV *Self, int row, int col, gf2_u32 val) {
98 30436 50         gf2_matrix_t *m=(gf2_matrix_t*)SvIV(SvRV(Self));
99 30436           int down=gf2_matrix_offset_down(m);
100 30436           int right=gf2_matrix_offset_right(m);
101 30436           void *p=(void*)m->values + (row * down) + (col * right);
102              
103             gf2_u8 u8;
104             gf2_u16 u16;
105             gf2_u32 u32;
106              
107 30436 50         if ((row < 0) || (row >= m->rows)) {
    50          
108 0           fprintf (stderr, "Math::FastGF2::Matrix - row out of range in setval\n");
109 0           return 0;
110             }
111              
112 30436 50         if ((col < 0) || (col >= m->cols)) {
    50          
113 0           fprintf (stderr, "Math::FastGF2::Matrix - col out of range in setval\n");
114 0           return 0;
115             }
116              
117 30436           switch (m->width) {
118             case 1:
119 26716           *((gf2_u8*)p)=(gf2_u8)val;
120 26716           break;
121             case 2:
122 1918           *((gf2_u16*)p)=(gf2_u16)val;
123 1918           break;
124             case 4:
125 1802           *((gf2_u32*)p)=(gf2_u32)val;
126 1802           break;
127             default:
128 0           fprintf(stderr,"Unsupported width %d in setval\n",m->width);
129 0           break;
130             }
131 30436           return val;
132             }
133              
134 4454           static int mat_local_byte_order (void) {
135 4454           gf2_u16 test=0x0201;
136 4454           char* first=(char*)&test;
137              
138 4454           return (int) *first;
139             }
140              
141             /* log and exponent tables for fast 8-bit multiplies */
142             /* extern const gf2_s16 *fast_gf2_log; */
143             /* extern const gf2_u8 *fast_gf2_exp; */
144              
145             /*
146             This should only be called from the Perl module code, so no checking
147             on args is done. Self, Transform and Result are expected to have
148             been already initialised and other values are expected to be sane.
149             */
150             void
151 14           mat_multiply_submatrix_c (SV *Self, SV *Transform, SV *Result,
152             int self_row, int result_row, int nrows,
153             int xform_col, int result_col, int ncols) {
154 14 50         gf2_matrix_t *self = (gf2_matrix_t*) SvIV(SvRV(Self));
155 14 50         gf2_matrix_t *xform = (gf2_matrix_t*) SvIV(SvRV(Transform));
156 14 50         gf2_matrix_t *result = (gf2_matrix_t*) SvIV(SvRV(Result));
157              
158             /* i == input == self, t == transform, o == output == result; r <- i * t */
159             /* all offsets are measured in bytes */
160 14           int idown = gf2_matrix_offset_down(self);
161 14           int iright = gf2_matrix_offset_right(self);
162 14           int tdown = gf2_matrix_offset_down(xform);
163 14           int tright = gf2_matrix_offset_right(xform);
164 14           int odown = gf2_matrix_offset_down(result);
165 14           int oright = gf2_matrix_offset_right(result);
166              
167             /*
168             Treat the most common case of width = 1 and ROWWISE/COLWISE pair
169             of matrices separately to avoid pointer arithmetic overheads
170             */
171 14 100         if ((self->width == 1) && (iright == 1) &&
    50          
    50          
172             (
173 2 50         ((tright == 1) && (odown == 1)) /* combine */
174 2 50         || ((tdown == 1) && (oright == 1)) /* split */
    0          
175             )) {
176             int r,c,v;
177             gf2_u8 u8, *u8_irp, *u8_orp, *u8_tcp, *u8_ocp, *u8_vip, *u8_vtp;
178            
179            
180 0 0         if ((tright == 1) && (odown == 1)) {
    0          
181             // fprintf(stderr, "FAST: combine\n");
182             /* (iright == tright == odown == 1) */
183 0           gf2_u8 *u8_tcp_start = xform->values + xform_col;
184 0           gf2_u8 *u8_ocp_start = result->values + oright * result_col;
185 0 0         for (r=0,
186 0           u8_irp=self->values + idown * self_row,
187 0           u8_orp=result->values + result_row;
188             r < nrows;
189 0           ++r, u8_irp += idown) {
190 0 0         for (c=0,
191 0           u8_tcp=u8_tcp_start,
192 0           u8_ocp=u8_ocp_start;
193             c < ncols;
194 0           ++c, u8_tcp ++, u8_ocp += oright) {
195 0 0         for (v=0,
196 0           u8_vip=u8_irp, u8_vtp=u8_tcp,
197 0           u8=gf2_mul8(*u8_vip,*u8_vtp);
198 0           u8_vip ++, u8_vtp += tdown,
199 0           ++v < self->cols; ) {
200 0           u8^=gf2_mul8(*u8_vip,*u8_vtp);
201             }
202 0           *(u8_ocp + r) = u8;
203             }
204             }
205             } else {
206             //fprintf(stderr, "FAST: split\n");
207             /* (iright == tdown == oright == 1) */
208 0           gf2_u8 *u8_tcp_start = xform->values + tright * xform_col;
209 0           gf2_u8 *u8_ocp_start = result->values + result_col;
210 0 0         for (r=0,
211 0           u8_irp=self->values + idown * self_row,
212 0           u8_orp=result->values + odown * result_row;
213             r < nrows;
214 0           ++r, u8_irp += idown) {
215 0 0         for (c=0,
216 0           u8_tcp=u8_tcp_start,
217 0           u8_ocp=u8_ocp_start;
218             c < ncols;
219 0           ++c, u8_tcp += tright, u8_ocp++) {
220 0 0         for (v=0,
221 0           u8_vip=u8_irp, u8_vtp=u8_tcp,
222 0           u8=gf2_mul8(*u8_vip,*u8_vtp);
223 0           u8_vip ++, u8_vtp++,
224 0           ++v < self->cols; ) {
225 0           u8^=gf2_mul8(*u8_vip,*u8_vtp);
226             }
227 0           *(u8_ocp + r * odown) = u8;
228             }
229             }
230             }
231 0           return;
232             }
233              
234             gf2_u8 u8, *u8_irp, *u8_orp, *u8_tcp, *u8_ocp, *u8_vip, *u8_vtp;
235             gf2_u16 u16, *u16_irp, *u16_orp, *u16_tcp, *u16_ocp, *u16_vip, *u16_vtp;
236             gf2_u32 u32, *u32_irp, *u32_orp, *u32_tcp, *u32_ocp, *u32_vip, *u32_vtp;
237              
238             int r,c,v;
239              
240 14           switch (self->width) {
241             case 1:
242 18 100         for (r=0,
243 2           u8_irp=self->values + idown * self_row,
244 2           u8_orp=result->values + odown * result_row;
245             r < nrows;
246 16           ++r, u8_irp += idown) {
247 144 100         for (c=0,
248 16           u8_tcp=xform->values + tright * xform_col,
249 16           u8_ocp=result->values + oright * result_col;
250             c < ncols;
251 128           ++c, u8_tcp += tright, u8_ocp += oright) {
252 1024 100         for (v=0,
253 128           u8_vip=u8_irp, u8_vtp=u8_tcp,
254 128           u8=gf2_mul8(*u8_vip,*u8_vtp);
255 1024           u8_vip += iright, u8_vtp += tdown,
256 1024           ++v < self->cols; ) {
257 896           u8^=gf2_mul8(*u8_vip,*u8_vtp);
258             }
259 128           *(u8_ocp + r * odown) = u8;
260             }
261             }
262 2           break;
263              
264             /*
265             For 16- and 32-bit words, we have to divide offset values by
266             width whenever adding them to gf2_u16 or gf2_u32 pointers since
267             C increments them to point to the next word rather than the
268             next byte. Other than that (and passing the correct width
269             parameter to gf2_mul) there's no difference between the u8 and
270             u16/u32 multiplication code
271             */
272              
273             case 2:
274 34 100         for (r=0,
275 6           u16_irp=(gf2_u16 *) (self->values + idown * self_row),
276 6           u16_orp=(gf2_u16 *) (result->values + odown * result_row);
277             r < nrows;
278 28           ++r, u16_irp +=(idown >> 1), u16_orp + (odown >> 1)) {
279 172 100         for (c=0,
280 28           u16_tcp=(gf2_u16 *) (xform->values + tright * xform_col),
281 28           u16_ocp=(gf2_u16 *) (result->values + oright * result_col);
282             c < ncols;
283 144           ++c, u16_tcp += (tright >> 1), u16_ocp += (oright >> 1)) {
284 832 100         for (v=0,
285 144           u16_vip=u16_irp, u16_vtp=u16_tcp,
286 144           u16=gf2_mul(16,*u16_vip,*u16_vtp);
287 832           u16_vip += (iright >> 1), u16_vtp += (tdown >> 1),
288 832           ++v < self->cols; ) {
289 688           u16^=gf2_mul(16,*u16_vip,*u16_vtp);
290             }
291 144           *(u16_ocp + r * (odown >> 1)) = u16;
292             }
293             }
294 6           break;
295            
296             case 4:
297 34 100         for (r=0,
298 6           u32_irp=(gf2_u32 *) (self->values + idown * self_row),
299 6           u32_orp=(gf2_u32 *) (result->values + odown * result_row);
300             r < nrows;
301 28           ++r, u32_irp +=(idown >> 2), u32_orp + (odown >> 2)) {
302 172 100         for (c=0,
303 28           u32_tcp=(gf2_u32 *) (xform->values + tright * xform_col),
304 28           u32_ocp=(gf2_u32 *) (result->values + oright * result_col);
305             c < ncols;
306 144           ++c, u32_tcp += (tright >> 2), u32_ocp += (oright >> 2)) {
307 832 100         for (v=0,
308 144           u32_vip=u32_irp, u32_vtp=u32_tcp,
309 144           u32=gf2_mul(32,*u32_vip,*u32_vtp);
310 832           u32_vip += (iright >> 2), u32_vtp += (tdown >> 2),
311 832           ++v < self->cols; ) {
312 688           u32^=gf2_mul(32,*u32_vip,*u32_vtp);
313             }
314 144           *(u32_ocp + r * (odown >> 2)) = u32;
315             }
316             }
317 6           break;
318            
319             default:
320 0           fprintf(stderr,
321             "Unsupported width %d in multiply_submatrix_c\n",self->width);
322             }
323             }
324              
325              
326             /* No error checking, so don't call directly */
327 470           int mat_values_eq_c (SV *This, SV *That) {
328 470 50         gf2_matrix_t *this = (gf2_matrix_t*) SvIV(SvRV(This));
329 470 50         gf2_matrix_t *that = (gf2_matrix_t*) SvIV(SvRV(That));
330              
331             int thisdown, thisright;
332             int thatdown, thatright;
333             int i,j;
334              
335 470           char *thisp=this->values;
336 470           char *thatp=that->values;
337              
338 470 100         if (this->organisation == that->organisation) {
339             /* compare the quick/easy way */
340 5576 100         for (i=this->rows * this->cols * this->width;
341 5576           i--;
342 5111           ++thisp, ++thatp) {
343 5321 100         if (*thisp != *thatp) return 0;
344             }
345             } else {
346             /* compare the slow/hard way */
347 5           thisdown = gf2_matrix_offset_down(this);
348 5           thisright = gf2_matrix_offset_right(this);
349 5           thatdown = gf2_matrix_offset_down(that);
350 5           thatright = gf2_matrix_offset_right(that);
351 22 100         for (i=0;
352 22           i < this-> rows;
353 17           ++i,
354 17           thisp=this->values + i * thisdown,
355 17           thatp=that->values + i * thatdown) {
356 85 100         for (j=0;
357 85           j < this-> cols;
358 67           ++j,
359 67           thisp+=thisright - this->width,
360 67           thatp+=thatright - that->width) {
361 68           switch (this -> width) {
362             case 4:
363 0 0         if (*thisp++ != *thatp++) return 0;
364 0 0         if (*thisp++ != *thatp++) return 0;
365             case 2:
366 60 50         if (*thisp++ != *thatp++) return 0;
367             case 1:
368 68 100         if (*thisp++ != *thatp++) return 0;
369             }
370             }
371             }
372             }
373 259           return 1; /* 1 == equal */
374             }
375              
376 2226           SV* mat_get_raw_values_c (SV *Self, int row, int col,
377             int words, int byteorder) {
378 2226 50         gf2_matrix_t *self = (gf2_matrix_t*) SvIV(SvRV(Self));
379 4452           char *from_start = self->values +
380 2226           gf2_matrix_offset_down(self) * row +
381 2226           gf2_matrix_offset_right(self) * col;
382             char *to_start;
383 2226           int len=self->width * words;
384 2226           SV *Str=newSVpv(from_start, len);
385 2226           int native_byteorder=mat_local_byte_order();
386             char *from, *to;
387             int i,j;
388 2226           int width=self->width;
389              
390 2226 100         if ( (width > 1) && byteorder &&
    100          
    100          
391             (native_byteorder != byteorder) ) {
392              
393 5 50         to_start=SvPV(Str,len) + width - 1;
394 19 100         for (i=width ; i-- ; --to_start, ++from_start) {
395 14           from=from_start; to=to_start;
396 32 100         for (j=words; j--; to += width, from += width) {
397 18           *to=*from;
398             }
399             ;
400             }
401             }
402             /* sv_2mortal(Str); */ /* apparently newSVpv takes care of this */
403 2226           return Str;
404             }
405              
406             // Profiling showed that getvals had a fairly high overhead for
407             // calling ROWS, COLS and WIDTH, so I'm moving some of the code into
408             // an XS routine here. This only returns a string, but unlike
409             // get_raw_values_c, it does bounds checking.
410 0           SV* mat_getvals_str (SV *Self, int row, int col,
411             int words, int byteorder) {
412 0 0         gf2_matrix_t *self = (gf2_matrix_t*) SvIV(SvRV(Self));
413              
414 0           int errors = 0;
415 0 0         if ((byteorder < 0) || (byteorder > 2)) ++errors;
    0          
416 0 0         if ((row < 0) || (row >= self->rows)) ++errors;
    0          
417 0 0         if ((col < 0) || (col >= self->cols)) ++errors;
    0          
418 0 0         if (errors) return &PL_sv_undef;
419            
420 0           char *from_start = self->values +
421 0           gf2_matrix_offset_down(self) * row +
422 0           gf2_matrix_offset_right(self) * col;
423             char *to_start;
424 0           int len=self->width * words;
425 0           SV *Str=newSVpv(from_start, len);
426 0           int native_byteorder=mat_local_byte_order();
427             char *from, *to;
428             int i,j;
429 0           int width=self->width;
430              
431 0 0         if ( (width > 1) && byteorder &&
    0          
    0          
432             (native_byteorder != byteorder) ) {
433              
434 0 0         to_start=SvPV(Str,len) + width - 1;
435 0 0         for (i=width ; i-- ; --to_start, ++from_start) {
436 0           from=from_start; to=to_start;
437 0 0         for (j=words; j--; to += width, from += width) {
438 0           *to=*from;
439             }
440             ;
441             }
442             }
443             /* sv_2mortal(Str); */ /* apparently newSVpv takes care of this */
444 0           return Str;
445             }
446              
447 2228           void mat_set_raw_values_c (SV *Self, int row, int col,
448             int words, int byteorder,
449             SV *Str) {
450              
451 2228 50         gf2_matrix_t *self = (gf2_matrix_t*) SvIV(SvRV(Self));
452 2228           int len=self->width * words;
453             char *from_start;
454 4456           char *to_start= self->values +
455 2228           gf2_matrix_offset_down(self) * row +
456 2228           gf2_matrix_offset_right(self) * col;
457 2228           int native_byteorder=mat_local_byte_order();
458             char *from, *to;
459             int i,j;
460 2228           int width=self->width;
461              
462 2234 100         if ( (width > 1) && byteorder &&
    100          
    100          
463             (native_byteorder != byteorder) ) {
464 6 50         from_start=SvPV(Str,len) + width - 1;
465 22 100         for (i=width ; i-- ; --from_start, ++to_start) {
466 16           from=from_start; to=to_start;
467 40 100         for (j=words; j--; to += width, from += width) {
468 24           *to=*from;
469             }
470             }
471             } else {
472 2222 50         from_start=SvPV(Str,len);
473 2222           memcpy(to_start, from_start, len);
474             }
475 2228           return;
476             }
477              
478 0           void mat_setvals_str (SV *Self, int row, int col,
479             SV *Str, int byteorder ) {
480              
481 0 0         gf2_matrix_t *self = (gf2_matrix_t*) SvIV(SvRV(Self));
482              
483 0           int errors = 0;
484 0 0         if ((byteorder < 0) || (byteorder > 2)) ++errors;
    0          
485 0 0         if ((row < 0) || (row >= self->rows)) ++errors;
    0          
486 0 0         if ((col < 0) || (col >= self->cols)) ++errors;
    0          
487 0 0         if (errors) return;
488              
489 0           int width=self->width;
490             int len;
491             char *from_start;
492 0           char *to_start= self->values +
493 0           gf2_matrix_offset_down(self) * row +
494 0           gf2_matrix_offset_right(self) * col;
495 0           int native_byteorder=mat_local_byte_order();
496             char *from, *to;
497             int i,j;
498              
499 0 0         if ( (width > 1) && byteorder &&
    0          
    0          
500 0           (native_byteorder != byteorder) ) {
501             int words;
502 0 0         from_start=SvPV(Str,len) + width - 1;
503 0           words = len / self->width;
504 0 0         for (i=width ; i-- ; --from_start, ++to_start) {
505 0           from=from_start; to=to_start;
506 0 0         for (j=words; j--; to += width, from += width) {
507 0           *to=*from;
508             }
509             }
510             } else {
511 0 0         from_start=SvPV(Str,len);
512 0           memcpy(to_start, from_start, len);
513             }
514 0           return;
515             }
516              
517              
518             /* new code to implement previous offset_to_rowcol */
519 12           void mat_offset_to_rowcol (SV *Self, int offset, int *row, int *col) {
520              
521 12 50         gf2_matrix_t *self = (gf2_matrix_t*) SvIV(SvRV(Self));
522 12           int width = self->width;
523 12           int cols = self->cols;
524 12           int rows = self->rows;
525              
526 12           int errors = 0;
527 12 50         if (offset % width) errors++; else offset /= width;;
528 12 50         if ((offset < 0) || (offset >= rows * cols)) errors++;
    50          
529 12 50         if (errors) {
530 0           *row = *col = &PL_sv_undef;
531 0           return;
532             }
533              
534 12 100         if (self->organisation == 1) { // ROWWISE
535 4           *row = offset / cols;
536 4           *col = offset - *row * cols;
537             } else {
538 8           *row = offset % rows;
539 8           *col = offset / rows;
540             }
541 12           return;
542             }