SV *e = TOPs; /* e is for 'expression' */
SV *d = TOPm1s; /* d is for 'default', as in PL_defgv */
- SV *This, *Other; /* 'This' (and Other to match) to play with C++ */
- REGEXP *this_regex, *other_regex;
-
-# define NOT_EMPTY_PROTO(cv) (!SvPOK(cv) || SvCUR(cv) == 0)
-
-# define SM_REF(type) ( \
- (SvROK(d) && (SvTYPE(This = SvRV(d)) == SVt_##type) && (Other = e)) \
- || (SvROK(e) && (SvTYPE(This = SvRV(e)) == SVt_##type) && (Other = d)))
-
-# define SM_CV_NEP /* Find a code ref without an empty prototype */ \
- ((SvROK(d) && (SvTYPE(This = SvRV(d)) == SVt_PVCV) \
- && NOT_EMPTY_PROTO(This) && (Other = e)) \
- || (SvROK(e) && (SvTYPE(This = SvRV(e)) == SVt_PVCV) \
- && NOT_EMPTY_PROTO(This) && (Other = d)))
-
-# define SM_REGEX ( \
- (SvROK(d) && (SvTYPE(This = SvRV(d)) == SVt_REGEXP) \
- && (this_regex = (REGEXP*) This) \
- && (Other = e)) \
- || \
- (SvROK(e) && (SvTYPE(This = SvRV(e)) == SVt_REGEXP) \
- && (this_regex = (REGEXP*) This) \
- && (Other = d)) )
-
-
-# define SM_OBJECT ( \
- (sv_isobject(d) && (SvTYPE(SvRV(d)) != SVt_REGEXP)) \
- || \
- (sv_isobject(e) && (SvTYPE(SvRV(e)) != SVt_REGEXP)) ) \
-
-# define SM_OTHER_REF(type) \
- (SvROK(Other) && SvTYPE(SvRV(Other)) == SVt_##type)
-
-# define SM_OTHER_REGEX (SvROK(Other) \
- && (SvTYPE(SvRV(Other)) == SVt_REGEXP) \
- && (other_regex = (REGEXP*) SvRV(Other)))
-
# define SM_SEEN_THIS(sv) hv_exists_ent(seen_this, \
sv_2mortal(newSViv(PTR2IV(sv))), 0)
# define SM_SEEN_OTHER(sv) hv_exists_ent(seen_other, \
sv_2mortal(newSViv(PTR2IV(sv))), 0)
- tryAMAGICbinSET(smart, 0);
-
+ if (SvAMAGIC(d) || SvAMAGIC(e)) {
+ SV * const tmpsv = amagic_call(d, e, smart_amg, 0);
+ if (tmpsv) {
+ SPAGAIN;
+ (void)POPs;
+ SETs(tmpsv);
+ RETURN;
+ }
+ }
+
SP -= 2; /* Pop the values */
/* Take care only to invoke mg_get() once for each argument.
if (SvGMAGICAL(e))
e = sv_mortalcopy(e);
- if (SM_OBJECT) {
- if (!SvOK(d) || !SvOK(e))
+ /* ~~ undef */
+ if (!SvOK(e)) {
+ if (SvOK(d))
RETPUSHNO;
else
- Perl_croak(aTHX_ "Smart matching a non-overloaded object breaks encapsulation");
+ RETPUSHYES;
}
- if (SM_CV_NEP) {
+ if ((sv_isobject(d) && (SvTYPE(SvRV(d)) != SVt_REGEXP))
+ || (sv_isobject(e) && (SvTYPE(SvRV(e)) != SVt_REGEXP)))
+ Perl_croak(aTHX_ "Smart matching a non-overloaded object breaks encapsulation");
+
+ /* ~~ sub */
+ if (SvROK(e) && SvTYPE(SvRV(e)) == SVt_PVCV) {
I32 c;
-
- if ( SM_OTHER_REF(PVCV) && NOT_EMPTY_PROTO(SvRV(Other)) )
- {
- if (This == SvRV(Other))
+ if (SvROK(d) && SvTYPE(SvRV(d)) == SVt_PVHV) {
+ /* Test sub truth for each key */
+ HE *he;
+ bool andedresults = TRUE;
+ HV *hv = (HV*) SvRV(d);
+ I32 numkeys = hv_iterinit(hv);
+ if (numkeys == 0)
+ RETPUSHYES;
+ while ( (he = hv_iternext(hv)) ) {
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+ PUSHs(hv_iterkeysv(he));
+ PUTBACK;
+ c = call_sv(e, G_SCALAR);
+ SPAGAIN;
+ if (c == 0)
+ andedresults = FALSE;
+ else
+ andedresults = SvTRUEx(POPs) && andedresults;
+ FREETMPS;
+ LEAVE;
+ }
+ if (andedresults)
RETPUSHYES;
else
RETPUSHNO;
}
-
- ENTER;
- SAVETMPS;
- PUSHMARK(SP);
- PUSHs(Other);
- PUTBACK;
- c = call_sv(This, G_SCALAR);
- SPAGAIN;
- if (c == 0)
- PUSHs(&PL_sv_no);
- else if (SvTEMP(TOPs))
- SvREFCNT_inc_void(TOPs);
- FREETMPS;
- LEAVE;
- RETURN;
+ else if (SvROK(d) && SvTYPE(SvRV(d)) == SVt_PVAV) {
+ /* Test sub truth for each element */
+ I32 i;
+ bool andedresults = TRUE;
+ AV *av = (AV*) SvRV(d);
+ const I32 len = av_len(av);
+ if (len == -1)
+ RETPUSHYES;
+ for (i = 0; i <= len; ++i) {
+ SV * const * const svp = av_fetch(av, i, FALSE);
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+ if (svp)
+ PUSHs(*svp);
+ PUTBACK;
+ c = call_sv(e, G_SCALAR);
+ SPAGAIN;
+ if (c == 0)
+ andedresults = FALSE;
+ else
+ andedresults = SvTRUEx(POPs) && andedresults;
+ FREETMPS;
+ LEAVE;
+ }
+ if (andedresults)
+ RETPUSHYES;
+ else
+ RETPUSHNO;
+ }
+ else {
+ ENTER;
+ SAVETMPS;
+ PUSHMARK(SP);
+ PUSHs(d);
+ PUTBACK;
+ c = call_sv(e, G_SCALAR);
+ SPAGAIN;
+ if (c == 0)
+ PUSHs(&PL_sv_no);
+ else if (SvTEMP(TOPs))
+ SvREFCNT_inc_void(TOPs);
+ FREETMPS;
+ LEAVE;
+ RETURN;
+ }
}
- else if (SM_REF(PVHV)) {
- if (SM_OTHER_REF(PVHV)) {
+ /* ~~ %hash */
+ else if (SvROK(e) && SvTYPE(SvRV(e)) == SVt_PVHV) {
+ if (!SvOK(d)) {
+ RETPUSHNO;
+ }
+ else if (SvROK(d) && SvTYPE(SvRV(d)) == SVt_PVHV) {
/* Check that the key-sets are identical */
HE *he;
- HV *other_hv = MUTABLE_HV(SvRV(Other));
+ HV *other_hv = MUTABLE_HV(SvRV(d));
bool tied = FALSE;
bool other_tied = FALSE;
U32 this_key_count = 0,
other_key_count = 0;
+ HV *hv = MUTABLE_HV(SvRV(e));
/* Tied hashes don't know how many keys they have. */
- if (SvTIED_mg(This, PERL_MAGIC_tied)) {
+ if (SvTIED_mg((SV*)hv, PERL_MAGIC_tied)) {
tied = TRUE;
}
else if (SvTIED_mg((const SV *)other_hv, PERL_MAGIC_tied)) {
HV * const temp = other_hv;
- other_hv = MUTABLE_HV(This);
- This = MUTABLE_SV(temp);
+ other_hv = hv;
+ hv = temp;
tied = TRUE;
}
if (SvTIED_mg((const SV *)other_hv, PERL_MAGIC_tied))
other_tied = TRUE;
- if (!tied && HvUSEDKEYS((const HV *) This) != HvUSEDKEYS(other_hv))
+ if (!tied && HvUSEDKEYS((const HV *) hv) != HvUSEDKEYS(other_hv))
RETPUSHNO;
/* The hashes have the same number of keys, so it suffices
to check that one is a subset of the other. */
- (void) hv_iterinit(MUTABLE_HV(This));
- while ( (he = hv_iternext(MUTABLE_HV(This))) ) {
+ (void) hv_iterinit(hv);
+ while ( (he = hv_iternext(hv)) ) {
I32 key_len;
char * const key = hv_iterkey(he, &key_len);
++ this_key_count;
if(!hv_exists(other_hv, key, key_len)) {
- (void) hv_iterinit(MUTABLE_HV(This)); /* reset iterator */
+ (void) hv_iterinit(hv); /* reset iterator */
RETPUSHNO;
}
}
else
RETPUSHYES;
}
- else if (SM_OTHER_REF(PVAV)) {
- AV * const other_av = MUTABLE_AV(SvRV(Other));
+ else if (SvROK(d) && SvTYPE(SvRV(d)) == SVt_PVAV) {
+ AV * const other_av = MUTABLE_AV(SvRV(d));
const I32 other_len = av_len(other_av) + 1;
I32 i;
+ HV *hv = MUTABLE_HV(SvRV(e));
for (i = 0; i < other_len; ++i) {
SV ** const svp = av_fetch(other_av, i, FALSE);
if (svp) { /* ??? When can this not happen? */
key = SvPV(*svp, key_len);
- if (hv_exists(MUTABLE_HV(This), key, key_len))
+ if (hv_exists(hv, key, key_len))
RETPUSHYES;
}
}
RETPUSHNO;
}
- else if (SM_OTHER_REGEX) {
- PMOP * const matcher = make_matcher(other_regex);
+ else if (SvROK(d) && SvTYPE(SvRV(d)) == SVt_REGEXP) {
+ PMOP * const matcher = make_matcher((REGEXP*) SvRV(d));
HE *he;
+ HV *hv = MUTABLE_HV(SvRV(e));
- (void) hv_iterinit(MUTABLE_HV(This));
- while ( (he = hv_iternext(MUTABLE_HV(This))) ) {
+ (void) hv_iterinit(hv);
+ while ( (he = hv_iternext(hv)) ) {
if (matcher_matches_sv(matcher, hv_iterkeysv(he))) {
- (void) hv_iterinit(MUTABLE_HV(This));
+ (void) hv_iterinit(hv);
destroy_matcher(matcher);
RETPUSHYES;
}
RETPUSHNO;
}
else {
- if (hv_exists_ent(MUTABLE_HV(This), Other, 0))
+ if (hv_exists_ent(MUTABLE_HV(SvRV(e)), d, 0))
RETPUSHYES;
else
RETPUSHNO;
}
}
- else if (SM_REF(PVAV)) {
- if (SM_OTHER_REF(PVAV)) {
- AV *other_av = MUTABLE_AV(SvRV(Other));
- if (av_len(MUTABLE_AV(This)) != av_len(other_av))
+ /* ~~ @array */
+ else if (SvROK(e) && SvTYPE(SvRV(e)) == SVt_PVAV) {
+ if (SvROK(d) && SvTYPE(SvRV(d)) == SVt_PVHV) {
+ AV * const other_av = MUTABLE_AV(SvRV(e));
+ const I32 other_len = av_len(other_av) + 1;
+ I32 i;
+
+ for (i = 0; i < other_len; ++i) {
+ SV ** const svp = av_fetch(other_av, i, FALSE);
+ char *key;
+ STRLEN key_len;
+
+ if (svp) { /* ??? When can this not happen? */
+ key = SvPV(*svp, key_len);
+ if (hv_exists(MUTABLE_HV(SvRV(d)), key, key_len))
+ RETPUSHYES;
+ }
+ }
+ RETPUSHNO;
+ }
+ if (SvROK(d) && SvTYPE(SvRV(d)) == SVt_PVAV) {
+ AV *other_av = MUTABLE_AV(SvRV(d));
+ if (av_len(MUTABLE_AV(SvRV(e))) != av_len(other_av))
RETPUSHNO;
else {
I32 i;
(void) sv_2mortal(MUTABLE_SV(seen_other));
}
for(i = 0; i <= other_len; ++i) {
- SV * const * const this_elem = av_fetch(MUTABLE_AV(This), i, FALSE);
+ SV * const * const this_elem = av_fetch(MUTABLE_AV(SvRV(e)), i, FALSE);
SV * const * const other_elem = av_fetch(other_av, i, FALSE);
if (!this_elem || !other_elem) {
(void)hv_store_ent(seen_other,
sv_2mortal(newSViv(PTR2IV(*other_elem))),
&PL_sv_undef, 0);
- PUSHs(*this_elem);
PUSHs(*other_elem);
+ PUSHs(*this_elem);
PUTBACK;
(void) do_smartmatch(seen_this, seen_other);
RETPUSHYES;
}
}
- else if (SM_OTHER_REGEX) {
- PMOP * const matcher = make_matcher(other_regex);
- const I32 this_len = av_len(MUTABLE_AV(This));
+ else if (SvROK(d) && SvTYPE(SvRV(d)) == SVt_REGEXP) {
+ PMOP * const matcher = make_matcher((REGEXP*) SvRV(d));
+ const I32 this_len = av_len(MUTABLE_AV(SvRV(e)));
I32 i;
for(i = 0; i <= this_len; ++i) {
- SV * const * const svp = av_fetch(MUTABLE_AV(This), i, FALSE);
+ SV * const * const svp = av_fetch(MUTABLE_AV(SvRV(e)), i, FALSE);
if (svp && matcher_matches_sv(matcher, *svp)) {
destroy_matcher(matcher);
RETPUSHYES;
destroy_matcher(matcher);
RETPUSHNO;
}
- else if (SvIOK(Other) || SvNOK(Other)) {
+ else if (SvNIOK(d)) {
I32 i;
- for(i = 0; i <= AvFILL(MUTABLE_AV(This)); ++i) {
- SV * const * const svp = av_fetch(MUTABLE_AV(This), i, FALSE);
+ for(i = 0; i <= AvFILL(MUTABLE_AV(SvRV(e))); ++i) {
+ SV * const * const svp = av_fetch(MUTABLE_AV(SvRV(e)), i, FALSE);
if (!svp)
continue;
- PUSHs(Other);
+ PUSHs(d);
PUSHs(*svp);
PUTBACK;
if (CopHINTS_get(PL_curcop) & HINT_INTEGER)
}
RETPUSHNO;
}
- else if (SvPOK(Other)) {
- const I32 this_len = av_len(MUTABLE_AV(This));
+ else if (SvPOK(d)) {
+ const I32 this_len = av_len(MUTABLE_AV(SvRV(e)));
I32 i;
for(i = 0; i <= this_len; ++i) {
- SV * const * const svp = av_fetch(MUTABLE_AV(This), i, FALSE);
+ SV * const * const svp = av_fetch(MUTABLE_AV(SvRV(e)), i, FALSE);
if (!svp)
continue;
- PUSHs(Other);
+ PUSHs(d);
PUSHs(*svp);
PUTBACK;
(void) pp_seq();
RETPUSHNO;
}
}
- else if (!SvOK(d) || !SvOK(e)) {
- if (!SvOK(d) && !SvOK(e))
- RETPUSHYES;
- else
- RETPUSHNO;
- }
- else if (SM_REGEX) {
- PMOP * const matcher = make_matcher(this_regex);
+ /* ~~ qr// */
+ else if (SvROK(e) && SvTYPE(SvRV(e)) == SVt_REGEXP) {
+ PMOP * const matcher = make_matcher((REGEXP*) SvRV(e));
PUTBACK;
- PUSHs(matcher_matches_sv(matcher, Other)
+ PUSHs(matcher_matches_sv(matcher, d)
? &PL_sv_yes
: &PL_sv_no);
destroy_matcher(matcher);
RETURN;
}
- else if (SM_REF(PVCV)) {
- I32 c;
- /* This must be a null-prototyped sub, because we
- already checked for the other kind. */
-
- ENTER;
- SAVETMPS;
- PUSHMARK(SP);
- PUTBACK;
- c = call_sv(This, G_SCALAR);
- SPAGAIN;
- if (c == 0)
- PUSHs(&PL_sv_undef);
- else if (SvTEMP(TOPs))
- SvREFCNT_inc_void(TOPs);
-
- if (SM_OTHER_REF(PVCV)) {
- /* This one has to be null-proto'd too.
- Call both of 'em, and compare the results */
- PUSHMARK(SP);
- c = call_sv(SvRV(Other), G_SCALAR);
- SPAGAIN;
- if (c == 0)
- PUSHs(&PL_sv_undef);
- else if (SvTEMP(TOPs))
- SvREFCNT_inc_void(TOPs);
- FREETMPS;
- LEAVE;
- PUTBACK;
- return pp_eq();
- }
-
- FREETMPS;
- LEAVE;
- RETURN;
- }
- else if ( ((SvIOK(d) || SvNOK(d)) && (This = d) && (Other = e))
- || ((SvIOK(e) || SvNOK(e)) && (This = e) && (Other = d)) )
- {
- if (SvPOK(Other) && !looks_like_number(Other)) {
- /* String comparison */
- PUSHs(d); PUSHs(e);
- PUTBACK;
- return pp_seq();
- }
- /* Otherwise, numeric comparison */
+ /* ~~ X..Y TODO */
+ /* ~~ scalar */
+ else if (SvNIOK(e) || (SvPOK(e) && looks_like_number(e) && SvNIOK(d))) {
+ /* numeric comparison */
PUSHs(d); PUSHs(e);
PUTBACK;
if (CopHINTS_get(PL_curcop) & HINT_INTEGER)