Hi everyone Here is my first piece of perl source code hacking. As predicted, it was trivial, requiring modifications to only nine files in the 5.7.1 source: opcode.pl hv.c pp.c toke.c intrpvar.h mg.c av.c keywords.h embed.pl The attached patch defines a pointer-to-sv stash where the perl operations "defined" and "exists" store a copy of whatever they were determining the definedness or existence of; also a new operator, C<it> which provides (read-only) access to the stash. This has two goals. 1: now your perl code can look more like your pseudocode, in case you ever write things like exists ${$_}{$_[0]} and return it; in your design notebooks. 2: improve performance by avoiding redundant data structure descents. Your mileage may vary. If you don't use the shortcut, and your programs use exists and defined heavily, there will be a slight performance hit. Instructions: Obtain and untar the 5.7.1 source, and save the patch file that is attached to this e-mail. Apply it something like this: cd perl-5.7.1 && patch -p1 < ../perl-5.7.1_it.patch Proceed with the compilation as normal. Example of use: ./perl -le '%r = (aa..bb);print it;print $r{ag}; print it; defined 5; print it' should print : ah 5 Thanks are due: Brian Warnock selected the discussion from perl6-language to include in his summary of the perl 6 lists, on June 4. Michael Schwern reluctantly admitted that he could imagine using the "it" operator. Simon Cozens helpfully suggested which files to edit, even though he does not approve of the concept implemented by the patch. -- David Nicol 816.235.1187 Signature closed for repaving, please have a nice weekend.
--- perl-5.7.1/av.c Mon Mar 5 20:04:21 2001 +++ perl-5.7.1_it/av.c Fri Jun 8 22:28:46 2001 @@ -819,4 +819,46 @@ } + +/* +=for apidoc av_exists_setit + + av_exists, and also sets the "it" stash + +=cut +*/ +bool +Perl_av_exists_setit(pTHX_ AV *av, I32 key) +{ + if (!av) + return FALSE; + if (key < 0) { + key += AvFILL(av) + 1; + if (key < 0) + return FALSE; + } + if (SvRMAGICAL(av)) { + if (mg_find((SV*)av,'P') || mg_find((SV*)av,'D')) { + SV *sv = sv_newmortal(); + MAGIC *mg; + + mg_copy((SV*)av, sv, 0, key); + mg = mg_find(sv, 'p'); + if (mg) { + magic_existspack(sv, mg); + return SvTRUE(sv); + } + } + } + if (key <= AvFILLp(av) && AvARRAY(av)[key] != &PL_sv_undef + && AvARRAY(av)[key]) + { + PL_it_pointer = AvARRAY(av)[key]; + return TRUE; + } + else + return FALSE; +} + + /* AVHV: Support for treating arrays as if they were hashes. The * first element of the array should be a hash reference that maps @@ -904,4 +946,16 @@ return av_exists(av, avhv_index_sv(HeVAL(he))); +} +bool +Perl_avhv_exists_ent_setit(pTHX_ AV *av, SV *keysv, U32 hash) +{ + HV *keys = avhv_keys(av); + HE *he; + + he = hv_fetch_ent(keys, keysv, FALSE, hash); + if (!he || !SvOK(HeVAL(he))) + return FALSE; + + return av_exists_setit(av, avhv_index_sv(HeVAL(he))); } --- perl-5.7.1/opcode.pl Mon Mar 5 20:06:13 2001 +++ perl-5.7.1_it/opcode.pl Fri Jun 8 13:37:49 2001 @@ -849,2 +849,6 @@ setstate set statement info ck_null s; method_named method with known name ck_null d$ + +# the "it" hack +it it ck_null s0 + --- perl-5.7.1/hv.c Fri Mar 9 08:59:40 2001 +++ perl-5.7.1_it/hv.c Fri Jun 8 22:27:30 2001 @@ -922,5 +922,96 @@ bool is_utf8; char *keysave; + + if (!hv) + return 0; + + if (SvRMAGICAL(hv)) { + if (mg_find((SV*)hv,'P')) { + SV* svret = sv_newmortal(); + sv = sv_newmortal(); + keysv = sv_2mortal(newSVsv(keysv)); + mg_copy((SV*)hv, sv, (char*)keysv, HEf_SVKEY); + magic_existspack(svret, mg_find(sv, 'p')); + return SvTRUE(svret); + } +#ifdef ENV_IS_CASELESS + else if (mg_find((SV*)hv,'E')) { + key = SvPV(keysv, klen); + keysv = sv_2mortal(newSVpvn(key,klen)); + (void)strupr(SvPVX(keysv)); + hash = 0; + } +#endif + } + + xhv = (XPVHV*)SvANY(hv); +#ifndef DYNAMIC_ENV_FETCH + if (!xhv->xhv_array) + return 0; +#endif + + keysave = key = SvPV(keysv, klen); + is_utf8 = (SvUTF8(keysv) != 0); + if (is_utf8 && !(PL_hints & HINT_UTF8_DISTINCT)) + key = (char*)bytes_from_utf8((U8*)key, &klen, &is_utf8); + if (!hash) + PERL_HASH(hash, key, klen); + +#ifdef DYNAMIC_ENV_FETCH + if (!xhv->xhv_array) entry = Null(HE*); + else +#endif + entry = ((HE**)xhv->xhv_array)[hash & (I32) xhv->xhv_max]; + for (; entry; entry = HeNEXT(entry)) { + if (HeHASH(entry) != hash) /* strings can't be equal */ + continue; + if (HeKLEN(entry) != klen) + continue; + if (HeKEY(entry) != key && memNE(HeKEY(entry),key,klen)) /* is this it? */ + continue; + if (HeKUTF8(entry) != (char)is_utf8) + continue; + if (key != keysave) + Safefree(key); + return TRUE; + } +#ifdef DYNAMIC_ENV_FETCH /* is it out there? */ + if (HvNAME(hv) && strEQ(HvNAME(hv), ENV_HV_NAME)) { + unsigned long len; + char *env = PerlEnv_ENVgetenv_len(key,&len); + if (env) { + sv = newSVpvn(env,len); + SvTAINTED_on(sv); + (void)hv_store_ent(hv,keysv,sv,hash); + return TRUE; + } + } +#endif + if (key != keysave) + Safefree(key); + return FALSE; +} + + + +/* +=for apidoc hv_exists_ent_setit + +just like hv_exists_ent, but sets the "it" stash too. +=cut +*/ +bool +Perl_hv_exists_ent_setit(pTHX_ HV *hv, SV *keysv, U32 hash) +{ + register XPVHV* xhv; + register char *key; + STRLEN klen; + register HE *entry; + SV *sv; + bool is_utf8; + char *keysave; + + if (!hv) return 0; @@ -974,4 +1065,5 @@ if (key != keysave) Safefree(key); + PL_it_pointer = entry->hent_val; return TRUE; } --- perl-5.7.1/pp.c Thu Apr 5 17:15:53 2001 +++ perl-5.7.1_it/pp.c Fri Jun 8 21:31:46 2001 @@ -778,4 +778,5 @@ sv = POPs; + PL_it_pointer = sv; if (!sv || !SvANY(sv)) RETPUSHNO; @@ -3517,8 +3518,10 @@ HV *hv; + PL_it_pointer = &PL_sv_undef; if (PL_op->op_private & OPpEXISTS_SUB) { GV *gv; CV *cv; SV *sv = POPs; + PL_it_pointer = sv; cv = sv_2cv(sv, &hv, &gv, FALSE); if (cv) @@ -3531,13 +3534,13 @@ hv = (HV*)POPs; if (SvTYPE(hv) == SVt_PVHV) { - if (hv_exists_ent(hv, tmpsv, 0)) + if (hv_exists_ent_setit(hv, tmpsv, 0)) RETPUSHYES; } else if (SvTYPE(hv) == SVt_PVAV) { if (PL_op->op_flags & OPf_SPECIAL) { /* array element */ - if (av_exists((AV*)hv, SvIV(tmpsv))) + if (av_exists_setit((AV*)hv, SvIV(tmpsv))) RETPUSHYES; } - else if (avhv_exists_ent((AV*)hv, tmpsv, 0)) /* pseudo-hash element */ + else if (avhv_exists_ent_setit((AV*)hv, tmpsv, 0)) /* pseudo-hash element */ RETPUSHYES; } @@ -3924,4 +3927,11 @@ SP = ORIGMARK; PUSHi( AvFILL(ary) + 1 ); + RETURN; +} + +PP(pp_it) +{ + dSP; + PUSHs(PL_it_pointer); RETURN; } --- perl-5.7.1/toke.c Sat Mar 31 23:43:59 2001 +++ perl-5.7.1_it/toke.c Fri Jun 8 13:18:18 2001 @@ -5108,4 +5108,7 @@ UNI(OP_TIED); + case KEY_it: + FUN0(OP_IT); + case KEY_time: FUN0(OP_TIME); @@ -5479,4 +5482,5 @@ case 2: if (strEQ(d,"if")) return KEY_if; + if (strEQ(d,"it")) return -KEY_it; break; case 3: --- perl-5.7.1/intrpvar.h Mon Mar 5 20:05:19 2001 +++ perl-5.7.1_it/intrpvar.h Fri Jun 8 21:39:35 2001 @@ -468,4 +468,5 @@ PERLVARI(Isig_pending, int,0) /* Number if highest signal pending */ +PERLVARI(Iit_pointer, SV *,0) /* stash for "it" */ /* New variables must be added to the very end for binary compatibility. --- perl-5.7.1/mg.c Fri Mar 30 23:26:20 2001 +++ perl-5.7.1_it/mg.c Fri Jun 8 18:07:43 2001 @@ -1292,4 +1292,5 @@ Perl_magic_existspack(pTHX_ SV *sv, MAGIC *mg) { + PL_it_pointer = sv; /* dln */ return magic_methpack(sv,mg,"EXISTS"); } --- perl-5.7.1/keywords.h Thu Apr 5 12:48:10 2001 +++ perl-5.7.1_it/keywords.h Fri Jun 8 13:32:54 2001 @@ -252,2 +252,3 @@ #define KEY_xor 251 #define KEY_y 252 +#define KEY_it 253 --- perl-5.7.1/embed.pl Fri Apr 6 08:19:51 2001 +++ perl-5.7.1_it/embed.pl Fri Jun 8 18:12:47 2001 @@ -1402,4 +1402,5 @@ Ap |SV* |avhv_delete_ent|AV *ar|SV* keysv|I32 flags|U32 hash Ap |bool |avhv_exists_ent|AV *ar|SV* keysv|U32 hash +Ap |bool |avhv_exists_ent_setit|AV *ar|SV* keysv|U32 hash Ap |SV** |avhv_fetch_ent |AV *ar|SV* keysv|I32 lval|U32 hash Ap |SV** |avhv_store_ent |AV *ar|SV* keysv|SV* val|U32 hash @@ -1410,4 +1411,5 @@ Apd |SV* |av_delete |AV* ar|I32 key|I32 flags Apd |bool |av_exists |AV* ar|I32 key +Apd |bool |av_exists_setit |AV* ar|I32 key Apd |void |av_extend |AV* ar|I32 key p |AV* |av_fake |I32 size|SV** svp @@ -1591,4 +1593,5 @@ Apd |bool |hv_exists |HV* tb|const char* key|I32 klen Apd |bool |hv_exists_ent |HV* tb|SV* key|U32 hash +Apd |bool |hv_exists_ent_setit |HV* tb|SV* key|U32 hash Apd |SV** |hv_fetch |HV* tb|const char* key|I32 klen|I32 lval Apd |HE* |hv_fetch_ent |HV* tb|SV* key|I32 lval|U32 hash