File Coverage

XS.xs
Criterion Covered Total %
statement 165 167 98.8
branch 109 120 90.8
condition n/a
subroutine n/a
pod n/a
total 274 287 95.4


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             #ifndef G_LIST
7             # define G_LIST G_ARRAY
8             #endif
9              
10             #ifdef av_push_simple
11             # define my_av_push_simple av_push_simple
12             #else
13             # define my_av_push_simple av_push
14             #endif
15              
16             static bool
17 1009           THX_keys_disjoint(pTHX_ HV *x, HV *y) {
18             HE *he;
19              
20 1009 100         if (HvTOTALKEYS(x) > HvTOTALKEYS(y)) {
21 438           HV *tmp = x;
22 438           x = y;
23 438           y = tmp;
24             }
25              
26 1009           hv_iterinit(x);
27 1889 100         while ((he = hv_iternext(x))) {
28 1885 100         if (hv_exists_ent(y, hv_iterkeysv(he), HeHASH(he)))
29 1005           return FALSE;
30             }
31 4           return TRUE;
32             }
33              
34             static bool
35 1009           THX_keys_equal(pTHX_ HV *x, HV *y) {
36             HE *he;
37              
38 1009 100         if (HvTOTALKEYS(x) != HvTOTALKEYS(y))
39 941           return FALSE;
40              
41 68           hv_iterinit(x);
42 152 100         while ((he = hv_iternext(x))) {
43 147 100         if (!hv_exists_ent(y, hv_iterkeysv(he), HeHASH(he)))
44 63           return FALSE;
45             }
46 5           return TRUE;
47             }
48              
49             static bool
50 2013           THX_keys_subset(pTHX_ HV *x, HV *y) {
51             HE *he;
52              
53 2013 100         if (HvTOTALKEYS(x) > HvTOTALKEYS(y))
54 943           return FALSE;
55              
56 1070           hv_iterinit(x);
57 2267 100         while ((he = hv_iternext(x))) {
58 2259 100         if (!hv_exists_ent(y, hv_iterkeysv(he), HeHASH(he)))
59 1062           return FALSE;
60             }
61 8           return TRUE;
62             }
63              
64             static bool
65 2010           THX_keys_proper_subset(pTHX_ HV *x, HV *y) {
66             HE *he;
67              
68 2010 100         if (HvTOTALKEYS(x) >= HvTOTALKEYS(y))
69 1066           return FALSE;
70              
71 944           hv_iterinit(x);
72 1980 100         while ((he = hv_iternext(x))) {
73 1976 100         if (!hv_exists_ent(y, hv_iterkeysv(he), HeHASH(he)))
74 940           return FALSE;
75             }
76 4           return TRUE;
77             }
78              
79             static IV
80 1000           THX_keys_union_count(pTHX_ HV *x, HV *y) {
81             HV *seen;
82             HE *he;
83             SV *key;
84              
85 1000           sv_2mortal((SV *)(seen = newHV()));
86              
87 1000           hv_iterinit(x);
88 32832 100         while ((he = hv_iternext(x))) {
89 31832           key = hv_iterkeysv(he);
90 31832 50         if (hv_exists_ent(seen, key, HeHASH(he)))
91 0           continue;
92 31832           (void)hv_store_ent(seen, key, &PL_sv_yes, HeHASH(he));
93             }
94              
95 1000           hv_iterinit(y);
96 33238 100         while ((he = hv_iternext(y))) {
97 32238           key = hv_iterkeysv(he);
98 32238 100         if (hv_exists_ent(seen, key, HeHASH(he)))
99 16112           continue;
100 16126           (void)hv_store_ent(seen, key, &PL_sv_yes, HeHASH(he));
101             }
102              
103 1000           return HvTOTALKEYS(seen);
104             }
105              
106             static IV
107 1000           THX_keys_intersection_count(pTHX_ HV *x, HV *y) {
108             HE *he;
109             SV *key;
110 1000           IV count = 0;
111              
112 1000           hv_iterinit(x);
113 32832 100         while ((he = hv_iternext(x))) {
114 31832           key = hv_iterkeysv(he);
115 31832 100         if (hv_exists_ent(y, key, HeHASH(he)))
116 16112           count++;
117             }
118 1000           return count;
119             }
120              
121             static IV
122 1000           THX_keys_difference_count(pTHX_ HV *x, HV *y) {
123             HE *he;
124             SV *key;
125 1000           IV count = 0;
126              
127 1000           hv_iterinit(x);
128 32832 100         while ((he = hv_iternext(x))) {
129 31832           key = hv_iterkeysv(he);
130 31832 100         if (!hv_exists_ent(y, key, HeHASH(he)))
131 15720           count++;
132             }
133 1000           return count;
134             }
135              
136             static IV
137 1000           THX_keys_symmetric_difference_count(pTHX_ HV *x, HV *y) {
138             HE *he;
139             SV *key;
140 1000           IV count = 0;
141              
142 1000           hv_iterinit(x);
143 32832 100         while ((he = hv_iternext(x))) {
144 31832           key = hv_iterkeysv(he);
145 31832 100         if (!hv_exists_ent(y, key, HeHASH(he)))
146 15720           count++;
147             }
148              
149 1000           hv_iterinit(y);
150 33238 100         while ((he = hv_iternext(y))) {
151 32238           key = hv_iterkeysv(he);
152 32238 100         if (!hv_exists_ent(x, key, HeHASH(he)))
153 16126           count++;
154             }
155 1000           return count;
156             }
157              
158             MODULE = Hash::Util::Set::XS PACKAGE = Hash::Util::Set::XS
159              
160             PROTOTYPES: ENABLE
161              
162             void
163             keys_union(x, y)
164             HV *x
165             HV *y
166             PROTOTYPE: \%\%
167             PREINIT:
168             HV *seen;
169             HE *he;
170             SV *key;
171             PPCODE:
172 2013 100         if(GIMME_V != G_LIST)
173 1000           XSRETURN_IV(THX_keys_union_count(aTHX_ x, y));
174              
175 1013 50         EXTEND(SP, (SSize_t)HvTOTALKEYS(x) + (SSize_t)HvTOTALKEYS(y));
    50          
176              
177 1013           sv_2mortal((SV *)(seen = newHV()));
178              
179 1013           hv_iterinit(x);
180 34866 100         while ((he = hv_iternext(x))) {
181 33853           key = hv_iterkeysv(he);
182             #ifdef HV_FETCH_EMPTY_HE
183 33853           he = (HE *)hv_common(seen, key, NULL, 0, 0, HV_FETCH_LVALUE|HV_FETCH_EMPTY_HE, NULL, HeHASH(he));
184 33853 50         if (HeVAL(he))
185 0           continue;
186 33853           HeVAL(he) = &PL_sv_undef;
187             #else
188             if (hv_exists_ent(seen, key, HeHASH(he)))
189             continue;
190             (void)hv_store_ent(seen, key, &PL_sv_yes, HeHASH(he));
191             #endif
192 33853           PUSHs(key);
193             }
194              
195 1013           hv_iterinit(y);
196 35276 100         while ((he = hv_iternext(y))) {
197 34263           key = hv_iterkeysv(he);
198             #ifdef HV_FETCH_EMPTY_HE
199 34263           he = (HE *)hv_common(seen, key, NULL, 0, 0, HV_FETCH_LVALUE|HV_FETCH_EMPTY_HE, NULL, HeHASH(he));
200 34263 100         if (HeVAL(he))
201 17126           continue;
202 17137           HeVAL(he) = &PL_sv_undef;
203             #else
204             if (hv_exists_ent(seen, key, HeHASH(he)))
205             continue;
206             (void)hv_store_ent(seen, key, &PL_sv_yes, HeHASH(he));
207             #endif
208 17137           PUSHs(key);
209             }
210              
211             void
212             keys_intersection(x, y)
213             HV *x
214             HV *y
215             PROTOTYPE: \%\%
216             PREINIT:
217             HE *he;
218             SV *key;
219             PPCODE:
220 2016 100         if(GIMME_V != G_LIST)
221 1000           XSRETURN_IV(THX_keys_intersection_count(aTHX_ x, y));
222              
223 1016 100         if (HvTOTALKEYS(x) > HvTOTALKEYS(y)) {
224 440           HV *tmp = x;
225 440           x = y;
226 440           y = tmp;
227             }
228              
229 1016 50         EXTEND(SP, (SSize_t)HvTOTALKEYS(x));
    50          
230              
231 1016           hv_iterinit(x);
232 33892 100         while ((he = hv_iternext(x))) {
233 31860           key = hv_iterkeysv(he);
234 31860 100         if (hv_exists_ent(y, key, HeHASH(he)))
235 17132           PUSHs(key);
236             }
237              
238             void
239             keys_difference(x, y)
240             HV *x
241             HV *y
242             PROTOTYPE: \%\%
243             PREINIT:
244             HE *he;
245             SV *key;
246             PPCODE:
247 2009 100         if(GIMME_V != G_LIST)
248 1000           XSRETURN_IV(THX_keys_difference_count(aTHX_ x, y));
249              
250 1009 50         EXTEND(SP, (SSize_t)HvTOTALKEYS(x));
    50          
251              
252 1009           hv_iterinit(x);
253 33869 100         while ((he = hv_iternext(x))) {
254 31851           key = hv_iterkeysv(he);
255 31851 100         if (!hv_exists_ent(y, key, HeHASH(he)))
256 15730           PUSHs(key);
257             }
258              
259             void
260             keys_symmetric_difference(x, y)
261             HV *x
262             HV *y
263             PROTOTYPE: \%\%
264             PREINIT:
265             HE *he;
266             SV *key;
267             PPCODE:
268 2005 100         if(GIMME_V != G_LIST)
269 1000           XSRETURN_IV(THX_keys_symmetric_difference_count(aTHX_ x, y));
270              
271 1005 50         EXTEND(SP, (SSize_t)HvTOTALKEYS(x) + (SSize_t)HvTOTALKEYS(y));
    50          
272              
273 1005           hv_iterinit(x);
274 33850 100         while ((he = hv_iternext(x))) {
275 31840           key = hv_iterkeysv(he);
276 31840 100         if (!hv_exists_ent(y, key, HeHASH(he)))
277 15723           PUSHs(key);
278             }
279              
280 1005           hv_iterinit(y);
281 34259 100         while ((he = hv_iternext(y))) {
282 32249           key = hv_iterkeysv(he);
283 32249 100         if (!hv_exists_ent(x, key, HeHASH(he)))
284 16132           PUSHs(key);
285             }
286              
287             bool
288             keys_disjoint(x, y)
289             HV *x
290             HV *y
291             PROTOTYPE: \%\%
292             CODE:
293 1009           RETVAL = THX_keys_disjoint(aTHX_ x, y);
294             OUTPUT:
295             RETVAL
296              
297             bool
298             keys_equal(x, y)
299             HV *x
300             HV *y
301             PROTOTYPE: \%\%
302             CODE:
303 1009           RETVAL = THX_keys_equal(aTHX_ x, y);
304             OUTPUT:
305             RETVAL
306              
307             bool
308             keys_subset(x, y)
309             HV *x
310             HV *y
311             PROTOTYPE: \%\%
312             CODE:
313 1007           RETVAL = THX_keys_subset(aTHX_ x, y);
314             OUTPUT:
315             RETVAL
316              
317             bool
318             keys_proper_subset(x, y)
319             HV *x
320             HV *y
321             PROTOTYPE: \%\%
322             CODE:
323 1005           RETVAL = THX_keys_proper_subset(aTHX_ x, y);
324             OUTPUT:
325             RETVAL
326              
327             bool
328             keys_superset(x, y)
329             HV *x
330             HV *y
331             PROTOTYPE: \%\%
332             CODE:
333 1006           RETVAL = THX_keys_subset(aTHX_ y, x);
334             OUTPUT:
335             RETVAL
336              
337             bool
338             keys_proper_superset(x, y)
339             HV *x
340             HV *y
341             PROTOTYPE: \%\%
342             CODE:
343 1005           RETVAL = THX_keys_proper_subset(aTHX_ y, x);
344             OUTPUT:
345             RETVAL
346              
347             void
348             keys_any(x, ...)
349             HV *x
350             PROTOTYPE: \%@
351             PREINIT:
352             I32 i;
353             PPCODE:
354 1925 100         for (i = 1; i < items; i++) {
355 1827 100         if (hv_exists_ent(x, ST(i), 0))
356 915           XSRETURN_YES;
357             }
358 98           XSRETURN_NO;
359              
360             void
361             keys_all(x, ...)
362             HV *x
363             PROTOTYPE: \%@
364             PREINIT:
365             I32 i;
366             PPCODE:
367 1911 100         for (i = 1; i < items; i++) {
368 1803 100         if (!hv_exists_ent(x, ST(i), 0))
369 904           XSRETURN_NO;
370             }
371 108           XSRETURN_YES;
372              
373             void
374             keys_none(x, ...)
375             HV *x
376             PROTOTYPE: \%@
377             PREINIT:
378             I32 i;
379             PPCODE:
380 1925 100         for (i = 1; i < items; i++) {
381 1825 100         if (hv_exists_ent(x, ST(i), 0))
382 910           XSRETURN_NO;
383             }
384 100           XSRETURN_YES;
385              
386             void
387             keys_partition(x, y)
388             HV *x
389             HV *y
390             PROTOTYPE: \%\%
391             PREINIT:
392             AV *only_x, *both, *only_y;
393             HE *he;
394             SV *key;
395             PPCODE:
396              
397 1004           sv_2mortal((SV *)(only_x = newAV()));
398 1004           sv_2mortal((SV *)(both = newAV()));
399 1004           sv_2mortal((SV *)(only_y = newAV()));
400              
401 1004           hv_iterinit(x);
402 32843 100         while ((he = hv_iternext(x))) {
403 31839           key = hv_iterkeysv(he);
404 31839 100         if (hv_exists_ent(y, key, HeHASH(he)))
405 16116           my_av_push_simple(both, SvREFCNT_inc(key));
406             else
407 15723           my_av_push_simple(only_x, SvREFCNT_inc(key));
408             }
409              
410 1004           hv_iterinit(y);
411 34253 100         while ((he = hv_iternext(y))) {
412 32245           key = hv_iterkeysv(he);
413 32245 100         if (!hv_exists_ent(x, key, HeHASH(he)))
414 16129           my_av_push_simple(only_y, SvREFCNT_inc(key));
415             }
416            
417 1004 50         EXTEND(SP, 3);
418 1004           PUSHs(sv_2mortal(newRV_inc((SV *)only_x)));
419 1004           PUSHs(sv_2mortal(newRV_inc((SV *)both)));
420 1004           PUSHs(sv_2mortal(newRV_inc((SV *)only_y)));
421