File Coverage

src/xs/compare.cc
Criterion Covered Total %
statement 56 56 100.0
branch 102 154 66.2
condition n/a
subroutine n/a
pod n/a
total 158 210 75.2


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