X-Git-Url: https://perl5.git.perl.org/perl5.git/blobdiff_plain/6d822dc4045278fb03135b2683bac92dba061369..8c18259e23fd9d5fd07b5221a1df53c2111ce455:/av.c diff --git a/av.c b/av.c index 3146f25..1b54065 100644 --- a/av.c +++ b/av.c @@ -1,6 +1,7 @@ /* av.c * - * Copyright (c) 1991-2002, Larry Wall + * Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + * 2000, 2001, 2002, 2003, 2004, 2005 by Larry Wall and others * * You may distribute under the terms of either the GNU General Public * License or the Artistic License, as specified in the README file. @@ -24,7 +25,6 @@ void Perl_av_reify(pTHX_ AV *av) { I32 key; - SV* sv; if (AvREAL(av)) return; @@ -36,7 +36,7 @@ Perl_av_reify(pTHX_ AV *av) while (key > AvFILLp(av) + 1) AvARRAY(av)[--key] = &PL_sv_undef; while (key) { - sv = AvARRAY(av)[--key]; + SV * const sv = AvARRAY(av)[--key]; assert(sv); if (sv != &PL_sv_undef) (void)SvREFCNT_inc(sv); @@ -87,7 +87,7 @@ Perl_av_extend(pTHX_ AV *av, I32 key) tmp = AvARRAY(av) - AvALLOC(av); Move(AvARRAY(av), AvALLOC(av), AvFILLp(av)+1, SV*); AvMAX(av) += tmp; - SvPVX(av) = (char*)AvALLOC(av); + SvPV_set(av, (char*)AvALLOC(av)); if (AvREAL(av)) { while (tmp) ary[--tmp] = &PL_sv_undef; @@ -99,13 +99,18 @@ Perl_av_extend(pTHX_ AV *av, I32 key) } } else { +#ifdef PERL_MALLOC_WRAP + static const char oom_array_extend[] = + "Out of memory during array extend"; /* Duplicated in pp_hot.c */ +#endif + if (AvALLOC(av)) { #if !defined(STRANGE_MALLOC) && !defined(MYMALLOC) MEM_SIZE bytes; IV itmp; #endif -#if defined(MYMALLOC) && !defined(LEAKTEST) +#ifdef MYMALLOC newmax = malloced_size((void*)AvALLOC(av))/sizeof(SV*) - 1; if (key <= newmax) @@ -113,6 +118,7 @@ Perl_av_extend(pTHX_ AV *av, I32 key) #endif newmax = key + AvMAX(av) / 5; resize: + MEM_WRAP_CHECK_1(newmax+1, SV*, oom_array_extend); #if defined(STRANGE_MALLOC) || defined(MYMALLOC) Renew(AvALLOC(av),newmax+1, SV*); #else @@ -126,7 +132,7 @@ Perl_av_extend(pTHX_ AV *av, I32 key) assert(itmp > newmax); newmax = itmp - 1; assert(newmax >= AvMAX(av)); - New(2,ary, newmax+1, SV*); + Newx(ary, newmax+1, SV*); Copy(AvALLOC(av), ary, AvMAX(av)+1, SV*); if (AvMAX(av) > 64) offer_nice_chunk(AvALLOC(av), (AvMAX(av)+1) * sizeof(SV*)); @@ -134,7 +140,7 @@ Perl_av_extend(pTHX_ AV *av, I32 key) Safefree(AvALLOC(av)); AvALLOC(av) = ary; #endif -#if defined(MYMALLOC) && !defined(LEAKTEST) +#ifdef MYMALLOC resized: #endif ary = AvALLOC(av) + AvMAX(av) + 1; @@ -147,7 +153,8 @@ Perl_av_extend(pTHX_ AV *av, I32 key) } else { newmax = key < 3 ? 3 : key; - New(2,AvALLOC(av), newmax+1, SV*); + MEM_WRAP_CHECK_1(newmax+1, SV*, oom_array_extend); + Newx(AvALLOC(av), newmax+1, SV*); ary = AvALLOC(av) + 1; tmp = newmax; AvALLOC(av)[0] = &PL_sv_undef; /* For the stacks */ @@ -157,7 +164,7 @@ Perl_av_extend(pTHX_ AV *av, I32 key) ary[--tmp] = &PL_sv_undef; } - SvPVX(av) = (char*)AvALLOC(av); + SvPV_set(av, (char*)AvALLOC(av)); AvMAX(av) = newmax; } } @@ -184,23 +191,44 @@ Perl_av_fetch(pTHX_ register AV *av, I32 key, I32 lval) if (!av) return 0; + if (SvRMAGICAL(av)) { + const MAGIC * const tied_magic = mg_find((SV*)av, PERL_MAGIC_tied); + if (tied_magic || mg_find((SV*)av, PERL_MAGIC_regdata)) { + U32 adjust_index = 1; + + if (tied_magic && key < 0) { + /* Handle negative array indices 20020222 MJD */ + SV **negative_indices_glob = + hv_fetch(SvSTASH(SvRV(SvTIED_obj((SV *)av, + tied_magic))), + NEGATIVE_INDICES_VAR, 16, 0); + + if (negative_indices_glob + && SvTRUE(GvSV(*negative_indices_glob))) + adjust_index = 0; + } + + if (key < 0 && adjust_index) { + key += AvFILL(av) + 1; + if (key < 0) + return 0; + } + + sv = sv_newmortal(); + sv_upgrade(sv, SVt_PVLV); + mg_copy((SV*)av, sv, 0, key); + LvTYPE(sv) = 't'; + LvTARG(sv) = sv; /* fake (SV**) */ + return &(LvTARG(sv)); + } + } + if (key < 0) { key += AvFILL(av) + 1; if (key < 0) return 0; } - if (SvRMAGICAL(av)) { - if (mg_find((SV*)av, PERL_MAGIC_tied) || - mg_find((SV*)av, PERL_MAGIC_regdata)) - { - sv = sv_newmortal(); - mg_copy((SV*)av, sv, 0, key); - PL_av_fetch_sv = sv; - return &PL_av_fetch_sv; - } - } - if (key > AvFILLp(av)) { if (!lval) return 0; @@ -251,6 +279,33 @@ Perl_av_store(pTHX_ register AV *av, I32 key, SV *val) if (!val) val = &PL_sv_undef; + if (SvRMAGICAL(av)) { + const MAGIC * const tied_magic = mg_find((SV*)av, PERL_MAGIC_tied); + if (tied_magic) { + /* Handle negative array indices 20020222 MJD */ + if (key < 0) { + unsigned adjust_index = 1; + SV **negative_indices_glob = + hv_fetch(SvSTASH(SvRV(SvTIED_obj((SV *)av, + tied_magic))), + NEGATIVE_INDICES_VAR, 16, 0); + if (negative_indices_glob + && SvTRUE(GvSV(*negative_indices_glob))) + adjust_index = 0; + if (adjust_index) { + key += AvFILL(av) + 1; + if (key < 0) + return 0; + } + } + if (val != &PL_sv_undef) { + mg_copy((SV*)av, val, 0, key); + } + return 0; + } + } + + if (key < 0) { key += AvFILL(av) + 1; if (key < 0) @@ -260,15 +315,6 @@ Perl_av_store(pTHX_ register AV *av, I32 key, SV *val) if (SvREADONLY(av) && key >= AvFILL(av)) Perl_croak(aTHX_ PL_no_modify); - if (SvRMAGICAL(av)) { - if (mg_find((SV*)av, PERL_MAGIC_tied)) { - if (val != &PL_sv_undef) { - mg_copy((SV*)av, val, 0, key); - } - return 0; - } - } - if (!AvREAL(av) && AvREIFY(av)) av_reify(av); if (key > AvMAX(av)) @@ -312,9 +358,9 @@ Perl_newAV(pTHX) av = (AV*)NEWSV(3,0); sv_upgrade((SV *)av, SVt_PVAV); - AvREAL_on(av); + /* sv_upgrade does AvREAL_only() */ AvALLOC(av) = 0; - SvPVX(av) = 0; + SvPV_set(av, (char*)0); AvMAX(av) = AvFILLp(av) = -1; return av; } @@ -333,16 +379,16 @@ AV * Perl_av_make(pTHX_ register I32 size, register SV **strp) { register AV *av; - register I32 i; - register SV** ary; av = (AV*)NEWSV(8,0); sv_upgrade((SV *) av,SVt_PVAV); - AvFLAGS(av) = AVf_REAL; - if (size) { /* `defined' was returning undef for size==0 anyway. */ - New(4,ary,size,SV*); + /* sv_upgrade does AvREAL_only() */ + if (size) { /* "defined" was returning undef for size==0 anyway. */ + register SV** ary; + register I32 i; + Newx(ary,size,SV*); AvALLOC(av) = ary; - SvPVX(av) = (char*)ary; + SvPV_set(av, (char*)ary); AvFILLp(av) = size - 1; AvMAX(av) = size - 1; for (i = 0; i < size; i++) { @@ -363,11 +409,11 @@ Perl_av_fake(pTHX_ register I32 size, register SV **strp) av = (AV*)NEWSV(9,0); sv_upgrade((SV *)av, SVt_PVAV); - New(4,ary,size+1,SV*); + Newx(ary,size+1,SV*); AvALLOC(av) = ary; Copy(strp,ary,size,SV*); - AvFLAGS(av) = AVf_REIFY; - SvPVX(av) = (char*)ary; + AvREIFY_only(av); + SvPV_set(av, (char*)ary); AvFILLp(av) = size - 1; AvMAX(av) = size - 1; while (size--) { @@ -391,7 +437,6 @@ void Perl_av_clear(pTHX_ register AV *av) { register I32 key; - SV** ary; #ifdef DEBUGGING if (SvREFCNT(av) == 0 && ckWARN_d(WARN_DEBUGGING)) { @@ -400,7 +445,6 @@ Perl_av_clear(pTHX_ register AV *av) #endif if (!av) return; - /*SUPPRESS 560*/ if (SvREADONLY(av)) Perl_croak(aTHX_ PL_no_modify); @@ -413,16 +457,19 @@ Perl_av_clear(pTHX_ register AV *av) return; if (AvREAL(av)) { - ary = AvARRAY(av); + SV** ary = AvARRAY(av); key = AvFILLp(av) + 1; while (key) { - SvREFCNT_dec(ary[--key]); + SV * sv = ary[--key]; + /* undef the slot before freeing the value, because a + * destructor might try to modify this arrray */ ary[key] = &PL_sv_undef; + SvREFCNT_dec(sv); } } if ((key = AvARRAY(av) - AvALLOC(av))) { AvMAX(av) += key; - SvPVX(av) = (char*)AvALLOC(av); + SvPV_set(av, (char*)AvALLOC(av)); } AvFILLp(av) = -1; @@ -439,29 +486,24 @@ Undefines the array. Frees the memory used by the array itself. void Perl_av_undef(pTHX_ register AV *av) { - register I32 key; - if (!av) return; - /*SUPPRESS 560*/ /* Give any tie a chance to cleanup first */ if (SvTIED_mg((SV*)av, PERL_MAGIC_tied)) av_fill(av, -1); /* mg_clear() ? */ if (AvREAL(av)) { - key = AvFILLp(av) + 1; + register I32 key = AvFILLp(av) + 1; while (key) SvREFCNT_dec(AvARRAY(av)[--key]); } Safefree(AvALLOC(av)); AvALLOC(av) = 0; - SvPVX(av) = 0; + SvPV_set(av, (char*)0); AvMAX(av) = AvFILLp(av) = -1; - if (AvARYLEN(av)) { - SvREFCNT_dec(AvARYLEN(av)); - AvARYLEN(av) = 0; - } + /* It's in magic - it must already be gone. */ + assert (!AvARYLEN(av)); } /* @@ -476,6 +518,7 @@ to accommodate the addition. void Perl_av_push(pTHX_ register AV *av, SV *val) { + dVAR; MAGIC *mg; if (!av) return; @@ -511,6 +554,7 @@ is empty. SV * Perl_av_pop(pTHX_ register AV *av) { + dVAR; SV *retval; MAGIC* mg; @@ -556,10 +600,9 @@ must then use C to assign values to these new elements. void Perl_av_unshift(pTHX_ register AV *av, register I32 num) { + dVAR; register I32 i; - register SV **ary; MAGIC* mg; - I32 slide; if (!av) return; @@ -595,9 +638,11 @@ Perl_av_unshift(pTHX_ register AV *av, register I32 num) AvMAX(av) += i; AvFILLp(av) += i; - SvPVX(av) = (char*)(AvARRAY(av) - i); + SvPV_set(av, (char*)(AvARRAY(av) - i)); } if (num) { + register SV **ary; + I32 slide; i = AvFILLp(av); /* Create extra elements */ slide = i > 0 ? i : 0; @@ -612,7 +657,7 @@ Perl_av_unshift(pTHX_ register AV *av, register I32 num) /* Make extra elements into a buffer */ AvMAX(av) -= slide; AvFILLp(av) -= slide; - SvPVX(av) = (char*)(AvARRAY(av) + slide); + SvPV_set(av, (char*)(AvARRAY(av) + slide)); } } @@ -627,6 +672,7 @@ Shifts an SV off the beginning of the array. SV * Perl_av_shift(pTHX_ register AV *av) { + dVAR; SV *retval; MAGIC* mg; @@ -655,7 +701,7 @@ Perl_av_shift(pTHX_ register AV *av) retval = *AvARRAY(av); if (AvREAL(av)) *AvARRAY(av) = &PL_sv_undef; - SvPVX(av) = (char*)(AvARRAY(av) + 1); + SvPV_set(av, (char*)(AvARRAY(av) + 1)); AvMAX(av)--; AvFILLp(av)--; if (SvSMAGICAL(av)) @@ -673,7 +719,7 @@ empty. */ I32 -Perl_av_len(pTHX_ register AV *av) +Perl_av_len(pTHX_ const register AV *av) { return AvFILL(av); } @@ -689,6 +735,7 @@ Perl's C<$#array = $fill;>. void Perl_av_fill(pTHX_ register AV *av, I32 fill) { + dVAR; MAGIC *mg; if (!av) Perl_croak(aTHX_ "panic: null array"); @@ -737,7 +784,8 @@ Perl_av_fill(pTHX_ register AV *av, I32 fill) =for apidoc av_delete Deletes the element indexed by C from the array. Returns the -deleted element. C is currently ignored. +deleted element. If C equals C, the element is freed +and null is returned. =cut */ @@ -750,29 +798,53 @@ Perl_av_delete(pTHX_ AV *av, I32 key, I32 flags) return Nullsv; if (SvREADONLY(av)) Perl_croak(aTHX_ PL_no_modify); + + if (SvRMAGICAL(av)) { + const MAGIC * const tied_magic = mg_find((SV*)av, PERL_MAGIC_tied); + if ((tied_magic || mg_find((SV*)av, PERL_MAGIC_regdata))) { + /* Handle negative array indices 20020222 MJD */ + SV **svp; + if (key < 0) { + unsigned adjust_index = 1; + if (tied_magic) { + SV **negative_indices_glob = + hv_fetch(SvSTASH(SvRV(SvTIED_obj((SV *)av, + tied_magic))), + NEGATIVE_INDICES_VAR, 16, 0); + if (negative_indices_glob + && SvTRUE(GvSV(*negative_indices_glob))) + adjust_index = 0; + } + if (adjust_index) { + key += AvFILL(av) + 1; + if (key < 0) + return Nullsv; + } + } + svp = av_fetch(av, key, TRUE); + if (svp) { + sv = *svp; + mg_clear(sv); + if (mg_find(sv, PERL_MAGIC_tiedelem)) { + sv_unmagic(sv, PERL_MAGIC_tiedelem); /* No longer an element */ + return sv; + } + return Nullsv; + } + } + } + if (key < 0) { key += AvFILL(av) + 1; if (key < 0) return Nullsv; } - if (SvRMAGICAL(av)) { - SV **svp; - if ((mg_find((SV*)av, PERL_MAGIC_tied) || - mg_find((SV*)av, PERL_MAGIC_regdata)) - && (svp = av_fetch(av, key, TRUE))) - { - sv = *svp; - mg_clear(sv); - if (mg_find(sv, PERL_MAGIC_tiedelem)) { - sv_unmagic(sv, PERL_MAGIC_tiedelem); /* No longer an element */ - return sv; - } - return Nullsv; /* element cannot be deleted */ - } - } + if (key > AvFILLp(av)) return Nullsv; else { + if (!AvREAL(av) && AvREIFY(av)) + av_reify(av); sv = AvARRAY(av)[key]; if (key == AvFILLp(av)) { AvARRAY(av)[key] = &PL_sv_undef; @@ -789,6 +861,8 @@ Perl_av_delete(pTHX_ AV *av, I32 key, I32 flags) SvREFCNT_dec(sv); sv = Nullsv; } + else if (AvREAL(av)) + sv = sv_2mortal(sv); return sv; } @@ -807,26 +881,48 @@ Perl_av_exists(pTHX_ AV *av, I32 key) { if (!av) return FALSE; + + + if (SvRMAGICAL(av)) { + const MAGIC * const tied_magic = mg_find((SV*)av, PERL_MAGIC_tied); + if (tied_magic || mg_find((SV*)av, PERL_MAGIC_regdata)) { + SV *sv = sv_newmortal(); + MAGIC *mg; + /* Handle negative array indices 20020222 MJD */ + if (key < 0) { + unsigned adjust_index = 1; + if (tied_magic) { + SV **negative_indices_glob = + hv_fetch(SvSTASH(SvRV(SvTIED_obj((SV *)av, + tied_magic))), + NEGATIVE_INDICES_VAR, 16, 0); + if (negative_indices_glob + && SvTRUE(GvSV(*negative_indices_glob))) + adjust_index = 0; + } + if (adjust_index) { + key += AvFILL(av) + 1; + if (key < 0) + return FALSE; + } + } + + mg_copy((SV*)av, sv, 0, key); + mg = mg_find(sv, PERL_MAGIC_tiedelem); + if (mg) { + magic_existspack(sv, mg); + return (bool)SvTRUE(sv); + } + + } + } + if (key < 0) { key += AvFILL(av) + 1; if (key < 0) return FALSE; } - if (SvRMAGICAL(av)) { - if (mg_find((SV*)av, PERL_MAGIC_tied) || - mg_find((SV*)av, PERL_MAGIC_regdata)) - { - SV *sv = sv_newmortal(); - MAGIC *mg; - mg_copy((SV*)av, sv, 0, key); - mg = mg_find(sv, PERL_MAGIC_tiedelem); - if (mg) { - magic_existspack(sv, mg); - return (bool)SvTRUE(sv); - } - } - } if (key <= AvFILLp(av) && AvARRAY(av)[key] != &PL_sv_undef && AvARRAY(av)[key]) { @@ -835,3 +931,31 @@ Perl_av_exists(pTHX_ AV *av, I32 key) else return FALSE; } + +SV ** +Perl_av_arylen_p(pTHX_ AV *av) { + dVAR; + MAGIC *mg = mg_find((SV*)av, PERL_MAGIC_arylen_p); + + if (!mg) { + mg = sv_magicext((SV*)av, 0, PERL_MAGIC_arylen_p, &PL_vtbl_arylen_p, + 0, 0); + + if (!mg) { + Perl_die(aTHX_ "panic: av_arylen_p"); + } + /* sv_magicext won't set this for us because we pass in a NULL obj */ + mg->mg_flags |= MGf_REFCOUNTED; + } + return &(mg->mg_obj); +} + +/* + * Local variables: + * c-indentation-style: bsd + * c-basic-offset: 4 + * indent-tabs-mode: t + * End: + * + * ex: set ts=8 sts=4 sw=4 noet: + */