File Coverage

XS.xs
Criterion Covered Total %
statement 46 69 66.6
branch 12 40 30.0
condition n/a
subroutine n/a
pod n/a
total 58 109 53.2


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
7             //#include
8             //#include
9              
10 6           inline static void shuffle_av_last_num_elements (AV *av, SSize_t len, SSize_t num) {
11              
12 6           SSize_t rand_index = 0;
13 6           SSize_t cur_index = len;
14             SV* a;
15              
16 6 50         if (SvTIED_mg((SV *)av, PERL_MAGIC_tied)) {
    0          
17             SV* b;
18              
19 0 0         while (cur_index) {
20 0           rand_index = (cur_index + 1) * Drand01(); // rand() % cur_index;
21 0           a = (SV*) *av_fetch(av, cur_index, 0);
22 0           b = (SV*) *av_fetch(av, rand_index, 0);
23 0 0         SvREFCNT_inc_simple_void(a);
24 0 0         SvREFCNT_inc_simple_void(b);
25             // if "av_store" returns NULL, the caller will have to decrement the reference count to avoid a memory leak
26 0 0         if (av_store(av, cur_index, b) == NULL)
27 0           SvREFCNT_dec(b);
28 0 0         if (av_store(av, rand_index, a) == NULL)
29 0           SvREFCNT_dec(a);
30 0           cur_index--;
31             }
32             } else {
33 6           SV **pav = AvARRAY(av);
34              
35 60 100         while (cur_index) {
36 54           rand_index = (cur_index + 1) * Drand01(); // rand() % cur_index;
37             //warn("cur_index = %i\trnd = %i\n", cur_index, rand_index);
38 54           a = (SV*) pav[rand_index];
39 54           pav[rand_index] = pav[cur_index];
40 54           pav[cur_index] = a;
41 54           cur_index--;
42             }
43             }
44 6           }
45              
46 6           inline static void shuffle_av_first_num_elements (AV *av, SSize_t len, SSize_t num) {
47              
48             /*
49             static short int is_rand_initialized = 0;
50              
51             if (is_rand_initialized == 0) {
52             srand( (unsigned int) getpid() );
53             is_rand_initialized = 1;
54             }
55             */
56              
57 6           SSize_t rand_index = 0;
58 6           SSize_t cur_index = 0;
59             SV* a;
60              
61 6           len++;
62              
63 6 50         if (SvTIED_mg((SV *)av, PERL_MAGIC_tied)) {
    0          
64             SV* b;
65              
66 0 0         while (cur_index <= num) {
67 0           rand_index = cur_index + (len - cur_index) * Drand01(); // rand() % cur_index;
68 0           a = (SV*) *av_fetch(av, cur_index, 0);
69 0           b = (SV*) *av_fetch(av, rand_index, 0);
70             // if "av_store" returns NULL, the caller will have to decrement the reference count to avoid a memory leak
71 0 0         if (av_store(av, cur_index, SvREFCNT_inc_simple(b)) == NULL)
72 0           SvREFCNT_dec(b);
73 0 0         if (av_store(av, rand_index, SvREFCNT_inc_simple(a)) == NULL)
74 0           SvREFCNT_dec(a);
75              
76 0           cur_index++;
77             }
78             } else {
79 6           SV **pav = AvARRAY(av);
80              
81 28 100         while (cur_index <= num) {
82 22           rand_index = cur_index + (len - cur_index) * Drand01(); // rand() % (len - cur_index);
83             //warn("cur_index = %i\trnd = %i\n", cur_index, rand_index);
84 22           a = (SV*) pav[rand_index];
85 22           pav[rand_index] = pav[cur_index];
86 22           pav[cur_index] = a;
87 22           cur_index++;
88             }
89             }
90 6           }
91              
92              
93             MODULE = List::Helpers::XS PACKAGE = List::Helpers::XS
94              
95             PROTOTYPES: DISABLE
96              
97             BOOT:
98             #if (PERL_VERSION >= 14)
99 1           sv_setpv((SV*)GvCV(gv_fetchpvs("List::Helpers::XS::shuffle", 0, SVt_PVCV)), "+");
100             #else
101             sv_setpv((SV*)GvCV(gv_fetchpvs("List::Helpers::XS::shuffle", 0, SVt_PVCV)), "\\@");
102             #endif
103              
104              
105             AV* random_slice (av, num)
106             AV* av
107             IV num
108             PPCODE:
109              
110 1 50         if (num < 0)
111 0           Perl_croak(pTHX_ "The slice's size can't be less than 0");
112              
113 1 50         if (num != 0) {
114              
115 1           SSize_t last_index = av_top_index(av);
116              
117 1           num -= 1;
118              
119 1 50         if (num < last_index) {
120              
121             SSize_t cur_index;
122              
123 1           shuffle_av_first_num_elements(av, last_index, num);
124              
125 1           AV *slice = av_make(num + 1, av_fetch(av, 0, 0));
126              
127 1           ST(0) = sv_2mortal(newRV_noinc( (SV *) slice )); // mXPUSHs(newRV_noinc( (SV *) slice ));
128             }
129             }
130              
131 1           XSRETURN(1);
132              
133              
134             AV* random_slice_void (av, num)
135             AV* av
136             IV num
137             PPCODE:
138              
139 5 50         if (num < 0)
140 0           Perl_croak(pTHX_ "The slice's size can't be less than 0");
141              
142 5 50         if (num == 0) {
143 0           av_fill(av, 0);
144             }
145             else {
146              
147 5           SSize_t last_index = av_top_index(av);
148              
149 5           num -= 1;
150              
151 5 50         if (num < last_index) {
152 5           shuffle_av_first_num_elements(av, last_index, num);
153 5           av_fill(av, num);
154             }
155              
156             // If "flags" equals "G_DISCARD", the element is freed and NULL is returned.
157             // But it's more slower than "av_fill"
158             // for (cur_index = last_index; cur_index > num; cur_index--)
159             // av_delete(av, cur_index, G_DISCARD); // a = av_delete(av, cur_index); SvREFCNT_dec(a)
160             // SvREFCNT_dec( av_pop(av) );
161             }
162              
163 5           XSRETURN_EMPTY;
164              
165              
166             void shuffle (av)
167             AV *av
168             PPCODE:
169 6           SSize_t len = av_top_index(av);
170             /* it's faster tahn shuffle_av_first_num_elements */
171 6           shuffle_av_last_num_elements(av, len, len);
172 6           XSRETURN_EMPTY;