File Coverage

src/xs/lib/cmp.cc
Criterion Covered Total %
statement 60 61 98.3
branch 107 160 66.8
condition n/a
subroutine n/a
pod n/a
total 167 221 75.5


line stmt bran cond sub pod time code
1             #include
2             #include
3              
4             namespace xs { namespace lib {
5              
6 604           static inline bool _elem_cmp (pTHX_ SV* f, SV* s) {
7 604 100         if (f == s) return true;
8              
9 111 100         if (SvROK(f) | SvROK(s)) { /* unroll references */
10 123 100         while (SvROK(f) & SvROK(s)) {
11 78           SV* fval = SvRV(f);
12 78           SV* sval = SvRV(s);
13 78 100         if (SvOBJECT(fval) ^ SvOBJECT(sval)) return false;
14 76 100         if (SvOBJECT(fval)) {
15 12 100         if (fval == sval) return true;
16 11 100         if (SvSTASH(fval) != SvSTASH(sval)) return false;
17 9 100         if (HvAMAGIC(SvSTASH(fval))) { // class has operator overloadings
18 4           SV* const tmpsv = amagic_call(f, s, eq_amg, 0);
19 9 100         if (tmpsv) return SvTRUE(tmpsv); // class has '==' operator overloading
    50          
    50          
    0          
    50          
    0          
    0          
    50          
    50          
    50          
    100          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
20             // otherwise compare object's data structure as it wasn't blessed at all.
21             }
22             }
23 70           f = fval;
24 70           s = sval;
25             }
26 45 100         if (SvROK(f) | SvROK(s)) return false; /* asymmetric references */
27 41 100         if (f == s) return true;
28             }
29              
30 97           switch (SvTYPE(f)) {
31             case SVt_IV:
32             case SVt_NV:
33             case SVt_PV:
34             case SVt_PVIV:
35             case SVt_PVNV:
36             case SVt_NULL:
37             case SVt_PVMG:
38 63 100         if (SvOK(f) && SvOK(s)) { // both are not undefs
    50          
    50          
    100          
    50          
    50          
39 57 50         if (SvTYPE(s) > SVt_PVMG) return false; // wrong type
40 57 100         if (SvPOK(f) | SvPOK(s)) return strEQ(SvPV_nolen(f), SvPV_nolen(s)); // both strings
    100          
    100          
41 44 100         if (SvNOK(f) | SvNOK(s)) return SvNV(f) == SvNV(s); // natural values
    100          
    100          
42 40           return SvIVX(f) == SvIVX(s); // compare as integers
43             }
44 6 100         return !(SvOK(f) || SvOK(s));
    50          
    50          
    100          
    50          
    50          
45             case SVt_PVHV:
46 19 50         return SvTYPE(s) == SVt_PVHV && hv_compare(aTHX_ (HV*)f, (HV*)s);
    100          
47             case SVt_PVAV:
48 9 50         return SvTYPE(s) == SVt_PVAV && av_compare(aTHX_ (AV*)f, (AV*)s);
    100          
49             case SVt_PVIO:
50 1 50         return SvTYPE(s) == SVt_PVIO && PerlIO_fileno(IoIFP(f)) == PerlIO_fileno(IoIFP(s));
    50          
51             case SVt_REGEXP:
52 3 50         return SvTYPE(s) == SVt_REGEXP && strEQ(SvPV_nolen(f), SvPV_nolen(s));
    50          
    50          
    100          
53             case SVt_PVCV:
54             case SVt_PVGV:
55 2           return false; /* already checked by pointers equality */
56             default:
57 0           return false;
58             }
59             }
60              
61 57           bool sv_compare (pTHX_ SV* f, SV* s) {
62 57 50         if ((bool)f ^ (bool)s) return false;
63 57           return _elem_cmp(aTHX_ f, s); // _elem_cmp cannot receive NULLs except for when both are NULLs
64             }
65              
66 19           bool hv_compare (pTHX_ HV* f, HV* s) {
67 19 50         if (f == s) return true;
68 19 50         if (!f || !s) return false;
    50          
69 19 50         if (HvUSEDKEYS(f) != HvUSEDKEYS(s)) return false;
    50          
    100          
70              
71 18           HE** farr = HvARRAY(f);
72 18 100         if (!farr) return true; // both are empty
73 17           STRLEN fmax = HvMAX(f);
74 17           bool res = true;
75              
76 130 100         for (STRLEN i = 0; res && i <= fmax; ++i) {
    100          
77             const HE* entry;
78 144 100         for (entry = farr[i]; res && entry; entry = HeNEXT(entry)) {
    100          
79 31           const HEK* hek = HeKEY_hek(entry);
80 31           SV** sref = hv_fetchhek(s, hek, 0);
81 31 100         if (!sref) return false;
82 29           res = _elem_cmp(aTHX_ HeVAL(entry), *sref);
83             }
84             }
85              
86 15           return res;
87             }
88              
89 9           bool av_compare (pTHX_ AV* f, AV* s) {
90 9 50         if (f == s) return true;
91 9 50         if (!f || !s) return true;
    50          
92              
93 9           SSize_t lasti = AvFILLp(f);
94 9 50         if (lasti != AvFILLp(s)) return false;
95 9           SV** fl = AvARRAY(f);
96 9           SV** sl = AvARRAY(s);
97              
98 9           bool res = true;
99 527 100         while (res && lasti-- >= 0) {
    100          
    100          
100 519 100         if ((bool)*fl ^ (bool)*sl) return false; // one is null while another is not.
101 518           res = _elem_cmp(aTHX_ *fl++, *sl++);
102             }
103 8           return res;
104             }
105              
106 44 50         }}
    50