/* av.c
*
- * Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- * 2000, 2001, 2002, 2003, 2004, 2005, 2006, by Larry Wall and others
+ * Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+ * 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 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.
*/
/*
- * "...for the Entwives desired order, and plenty, and peace (by which they
- * meant that things should remain where they had set them)." --Treebeard
+ * '...for the Entwives desired order, and plenty, and peace (by which they
+ * meant that things should remain where they had set them).' --Treebeard
+ *
+ * [p.476 of _The Lord of the Rings_, III/iv: "Treebeard"]
*/
/*
dVAR;
I32 key;
- assert(av);
+ PERL_ARGS_ASSERT_AV_REIFY;
+ assert(SvTYPE(av) == SVt_PVAV);
if (AvREAL(av))
return;
#ifdef DEBUGGING
- if (SvTIED_mg((SV*)av, PERL_MAGIC_tied) && ckWARN_d(WARN_DEBUGGING))
- Perl_warner(aTHX_ packWARN(WARN_DEBUGGING), "av_reify called on tied array");
+ if (SvTIED_mg((const SV *)av, PERL_MAGIC_tied))
+ Perl_ck_warner_d(aTHX_ packWARN(WARN_DEBUGGING), "av_reify called on tied array");
#endif
key = AvMAX(av) + 1;
while (key > AvFILLp(av) + 1)
dVAR;
MAGIC *mg;
- assert(av);
+ PERL_ARGS_ASSERT_AV_EXTEND;
+ assert(SvTYPE(av) == SVt_PVAV);
- mg = SvTIED_mg((SV*)av, PERL_MAGIC_tied);
+ mg = SvTIED_mg((const SV *)av, PERL_MAGIC_tied);
if (mg) {
- dSP;
- ENTER;
- SAVETMPS;
- PUSHSTACKi(PERLSI_MAGIC);
- PUSHMARK(SP);
- EXTEND(SP,2);
- PUSHs(SvTIED_obj((SV*)av, mg));
- PUSHs(sv_2mortal(newSViv(key+1)));
- PUTBACK;
- call_method("EXTEND", G_SCALAR|G_DISCARD);
- POPSTACK;
- FREETMPS;
- LEAVE;
+ SV *arg1 = sv_newmortal();
+ sv_setiv(arg1, (IV)(key + 1));
+ Perl_magic_methcall(aTHX_ MUTABLE_SV(av), mg, SV_CONST(EXTEND), G_DISCARD, 1,
+ arg1);
return;
}
- if (key > AvMAX(av)) {
+ av_extend_guts(av,key,&AvMAX(av),&AvALLOC(av),&AvARRAY(av));
+}
+
+/* The guts of av_extend. *Not* for general use! */
+void
+Perl_av_extend_guts(pTHX_ AV *av, I32 key, SSize_t *maxp, SV ***allocp,
+ SV ***arrayp)
+{
+ dVAR;
+
+ PERL_ARGS_ASSERT_AV_EXTEND_GUTS;
+
+ if (key > *maxp) {
SV** ary;
I32 tmp;
I32 newmax;
- if (AvALLOC(av) != AvARRAY(av)) {
- ary = AvALLOC(av) + AvFILLp(av) + 1;
- tmp = AvARRAY(av) - AvALLOC(av);
- Move(AvARRAY(av), AvALLOC(av), AvFILLp(av)+1, SV*);
- AvMAX(av) += tmp;
- SvPV_set(av, (char*)AvALLOC(av));
+ if (av && *allocp != *arrayp) {
+ ary = *allocp + AvFILLp(av) + 1;
+ tmp = *arrayp - *allocp;
+ Move(*arrayp, *allocp, AvFILLp(av)+1, SV*);
+ *maxp += tmp;
+ *arrayp = *allocp;
if (AvREAL(av)) {
while (tmp)
ary[--tmp] = &PL_sv_undef;
}
- if (key > AvMAX(av) - 10) {
- newmax = key + AvMAX(av);
+ if (key > *maxp - 10) {
+ newmax = key + *maxp;
goto resize;
}
}
"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
-
-#ifdef MYMALLOC
- newmax = malloced_size((void*)AvALLOC(av))/sizeof(SV*) - 1;
+ if (*allocp) {
+
+#ifdef Perl_safesysmalloc_size
+ /* Whilst it would be quite possible to move this logic around
+ (as I did in the SV code), so as to set AvMAX(av) early,
+ based on calling Perl_safesysmalloc_size() immediately after
+ allocation, I'm not convinced that it is a great idea here.
+ In an array we have to loop round setting everything to
+ &PL_sv_undef, which means writing to memory, potentially lots
+ of it, whereas for the SV buffer case we don't touch the
+ "bonus" memory. So there there is no cost in telling the
+ world about it, whereas here we have to do work before we can
+ tell the world about it, and that work involves writing to
+ memory that might never be read. So, I feel, better to keep
+ the current lazy system of only writing to it if our caller
+ has a need for more space. NWC */
+ newmax = Perl_safesysmalloc_size((void*)*allocp) /
+ sizeof(const SV *) - 1;
if (key <= newmax)
goto resized;
#endif
- newmax = key + AvMAX(av) / 5;
+ newmax = key + *maxp / 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
- bytes = (newmax + 1) * sizeof(SV*);
-#define MALLOC_OVERHEAD 16
- itmp = MALLOC_OVERHEAD;
- while ((MEM_SIZE)(itmp - MALLOC_OVERHEAD) < bytes)
- itmp += itmp;
- itmp -= MALLOC_OVERHEAD;
- itmp /= sizeof(SV*);
- assert(itmp > newmax);
- newmax = itmp - 1;
- assert(newmax >= AvMAX(av));
- 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*));
- else
- Safefree(AvALLOC(av));
- AvALLOC(av) = ary;
-#endif
-#ifdef MYMALLOC
+ Renew(*allocp,newmax+1, SV*);
+#ifdef Perl_safesysmalloc_size
resized:
#endif
- ary = AvALLOC(av) + AvMAX(av) + 1;
- tmp = newmax - AvMAX(av);
+ ary = *allocp + *maxp + 1;
+ tmp = newmax - *maxp;
if (av == PL_curstack) { /* Oops, grew stack (via av_store()?) */
- PL_stack_sp = AvALLOC(av) + (PL_stack_sp - PL_stack_base);
- PL_stack_base = AvALLOC(av);
+ PL_stack_sp = *allocp + (PL_stack_sp - PL_stack_base);
+ PL_stack_base = *allocp;
PL_stack_max = PL_stack_base + newmax;
}
}
else {
newmax = key < 3 ? 3 : key;
MEM_WRAP_CHECK_1(newmax+1, SV*, oom_array_extend);
- Newx(AvALLOC(av), newmax+1, SV*);
- ary = AvALLOC(av) + 1;
+ Newx(*allocp, newmax+1, SV*);
+ ary = *allocp + 1;
tmp = newmax;
- AvALLOC(av)[0] = &PL_sv_undef; /* For the stacks */
+ *allocp[0] = &PL_sv_undef; /* For the stacks */
}
- if (AvREAL(av)) {
+ if (av && AvREAL(av)) {
while (tmp)
ary[--tmp] = &PL_sv_undef;
}
- SvPV_set(av, (char*)AvALLOC(av));
- AvMAX(av) = newmax;
+ *arrayp = *allocp;
+ *maxp = newmax;
}
}
}
=for apidoc av_fetch
Returns the SV at the specified index in the array. The C<key> is the
-index. If C<lval> is set then the fetch will be part of a store. Check
-that the return value is non-null before dereferencing it to a C<SV*>.
+index. If lval is true, you are guaranteed to get a real SV back (in case
+it wasn't real before), which you can then modify. Check that the return
+value is non-null before dereferencing it to a C<SV*>.
See L<perlguts/"Understanding the Magic of Tied Hashes and Arrays"> for
more information on how to use this function on tied arrays.
+The rough perl equivalent is C<$myarray[$idx]>.
+
=cut
*/
+static bool
+S_adjust_index(pTHX_ AV *av, const MAGIC *mg, I32 *keyp)
+{
+ bool adjust_index = 1;
+ if (mg) {
+ /* Handle negative array indices 20020222 MJD */
+ SV * const ref = SvTIED_obj(MUTABLE_SV(av), mg);
+ SvGETMAGIC(ref);
+ if (SvROK(ref) && SvOBJECT(SvRV(ref))) {
+ SV * const * const negative_indices_glob =
+ hv_fetchs(SvSTASH(SvRV(ref)), NEGATIVE_INDICES_VAR, 0);
+
+ if (negative_indices_glob && SvTRUE(GvSV(*negative_indices_glob)))
+ adjust_index = 0;
+ }
+ }
+
+ if (adjust_index) {
+ *keyp += AvFILL(av) + 1;
+ if (*keyp < 0)
+ return FALSE;
+ }
+ return TRUE;
+}
+
SV**
-Perl_av_fetch(pTHX_ register AV *av, I32 key, I32 lval)
+Perl_av_fetch(pTHX_ AV *av, I32 key, I32 lval)
{
dVAR;
- assert(av);
+ PERL_ARGS_ASSERT_AV_FETCH;
+ assert(SvTYPE(av) == SVt_PVAV);
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)) {
+ const MAGIC * const tied_magic
+ = mg_find((const SV *)av, PERL_MAGIC_tied);
+ if (tied_magic || mg_find((const SV *)av, PERL_MAGIC_regdata)) {
SV *sv;
if (key < 0) {
- I32 adjust_index = 1;
- if (tied_magic) {
- /* Handle negative array indices 20020222 MJD */
- SV * const * const 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)
+ if (!S_adjust_index(aTHX_ av, tied_magic, &key))
return NULL;
- }
}
sv = sv_newmortal();
sv_upgrade(sv, SVt_PVLV);
- mg_copy((SV*)av, sv, 0, key);
+ mg_copy(MUTABLE_SV(av), sv, 0, key);
+ if (!tied_magic) /* for regdata, force leavesub to make copies */
+ SvTEMP_off(sv);
LvTYPE(sv) = 't';
LvTARG(sv) = sv; /* fake (SV**) */
return &(LvTARG(sv));
return NULL;
}
- if (key > AvFILLp(av)) {
- if (!lval)
- return NULL;
- return av_store(av,key,newSV(0));
- }
- if (AvARRAY(av)[key] == &PL_sv_undef) {
- emptyness:
- if (lval)
- return av_store(av,key,newSV(0));
- return NULL;
+ if (key > AvFILLp(av) || AvARRAY(av)[key] == &PL_sv_undef) {
+ emptyness:
+ return lval ? av_store(av,key,newSV(0)) : NULL;
}
- else if (AvREIFY(av)
+
+ if (AvREIFY(av)
&& (!AvARRAY(av)[key] /* eg. @_ could have freed elts */
|| SvIS_FREED(AvARRAY(av)[key]))) {
AvARRAY(av)[key] = &PL_sv_undef; /* 1/2 reify */
Stores an SV in an array. The array index is specified as C<key>. The
return value will be NULL if the operation failed or if the value did not
need to be actually stored within the array (as in the case of tied
-arrays). Otherwise it can be dereferenced to get the original C<SV*>. Note
-that the caller is responsible for suitably incrementing the reference
+arrays). Otherwise, it can be dereferenced
+to get the C<SV*> that was stored
+there (= C<val>)).
+
+Note that the caller is responsible for suitably incrementing the reference
count of C<val> before the call, and decrementing it if the function
returned NULL.
+Approximate Perl equivalent: C<$myarray[$key] = $val;>.
+
See L<perlguts/"Understanding the Magic of Tied Hashes and Arrays"> for
more information on how to use this function on tied arrays.
*/
SV**
-Perl_av_store(pTHX_ register AV *av, I32 key, SV *val)
+Perl_av_store(pTHX_ AV *av, I32 key, SV *val)
{
dVAR;
SV** ary;
- assert(av);
+ PERL_ARGS_ASSERT_AV_STORE;
+ assert(SvTYPE(av) == SVt_PVAV);
/* S_regclass relies on being able to pass in a NULL sv
(unicode_alternate may be NULL).
val = &PL_sv_undef;
if (SvRMAGICAL(av)) {
- const MAGIC * const tied_magic = mg_find((SV*)av, PERL_MAGIC_tied);
+ const MAGIC * const tied_magic = mg_find((const SV *)av, PERL_MAGIC_tied);
if (tied_magic) {
- /* Handle negative array indices 20020222 MJD */
if (key < 0) {
- bool adjust_index = 1;
- SV * const * const 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)
+ if (!S_adjust_index(aTHX_ av, tied_magic, &key))
return 0;
- }
}
if (val != &PL_sv_undef) {
- mg_copy((SV*)av, val, 0, key);
+ mg_copy(MUTABLE_SV(av), val, 0, key);
}
return NULL;
}
}
if (SvREADONLY(av) && key >= AvFILL(av))
- Perl_croak(aTHX_ PL_no_modify);
+ Perl_croak_no_modify();
if (!AvREAL(av) && AvREIFY(av))
av_reify(av);
SvREFCNT_dec(ary[key]);
ary[key] = val;
if (SvSMAGICAL(av)) {
- if (val != &PL_sv_undef) {
- const MAGIC* const mg = SvMAGIC(av);
- sv_magic(val, (SV*)av, toLOWER(mg->mg_type), 0, key);
+ const MAGIC *mg = SvMAGIC(av);
+ bool set = TRUE;
+ for (; mg; mg = mg->mg_moremagic) {
+ if (!isUPPER(mg->mg_type)) continue;
+ if (val != &PL_sv_undef) {
+ sv_magic(val, MUTABLE_SV(av), toLOWER(mg->mg_type), 0, key);
+ }
+ if (PL_delaymagic && mg->mg_type == PERL_MAGIC_isa) {
+ PL_delaymagic |= DM_ARRAY_ISA;
+ set = FALSE;
+ }
}
- mg_set((SV*)av);
+ if (set)
+ mg_set(MUTABLE_SV(av));
}
return &ary[key];
}
/*
-=for apidoc newAV
-
-Creates a new AV. The reference count is set to 1.
-
-=cut
-*/
-
-AV *
-Perl_newAV(pTHX)
-{
- register AV * const av = (AV*)newSV(0);
-
- sv_upgrade((SV *)av, SVt_PVAV);
- /* sv_upgrade does AvREAL_only() */
- AvALLOC(av) = 0;
- SvPV_set(av, NULL);
- AvMAX(av) = AvFILLp(av) = -1;
- return av;
-}
-
-/*
=for apidoc av_make
Creates a new AV and populates it with a list of SVs. The SVs are copied
into the array, so they may be freed after the call to av_make. The new AV
will have a reference count of 1.
+Perl equivalent: C<my @new_array = ($scalar1, $scalar2, $scalar3...);>
+
=cut
*/
AV *
-Perl_av_make(pTHX_ register I32 size, register SV **strp)
+Perl_av_make(pTHX_ I32 size, SV **strp)
{
- register AV * const av = (AV*)newSV(0);
-
- sv_upgrade((SV *) av,SVt_PVAV);
+ AV * const av = MUTABLE_AV(newSV_type(SVt_PVAV));
/* sv_upgrade does AvREAL_only() */
+ PERL_ARGS_ASSERT_AV_MAKE;
+ assert(SvTYPE(av) == SVt_PVAV);
+
if (size) { /* "defined" was returning undef for size==0 anyway. */
- register SV** ary;
- register I32 i;
+ SV** ary;
+ I32 i;
Newx(ary,size,SV*);
AvALLOC(av) = ary;
- SvPV_set(av, (char*)ary);
- AvFILLp(av) = AvMAX(av) = size - 1;
+ AvARRAY(av) = ary;
+ AvMAX(av) = size - 1;
+ AvFILLp(av) = -1;
+ ENTER;
+ SAVEFREESV(av);
for (i = 0; i < size; i++) {
assert (*strp);
+
+ /* Don't let sv_setsv swipe, since our source array might
+ have multiple references to the same temp scalar (e.g.
+ from a list slice) */
+
+ SvGETMAGIC(*strp); /* before newSV, in case it dies */
+ AvFILLp(av)++;
ary[i] = newSV(0);
- sv_setsv(ary[i], *strp);
+ sv_setsv_flags(ary[i], *strp,
+ SV_DO_COW_SVSETSV|SV_NOSTEAL);
strp++;
}
+ SvREFCNT_inc_simple_void_NN(av);
+ LEAVE;
}
return av;
}
/*
=for apidoc av_clear
-Clears an array, making it empty. Does not free the memory used by the
-array itself.
+Clears an array, making it empty. Does not free the memory the av uses to
+store its list of scalars. If any destructors are triggered as a result,
+the av itself may be freed when this function returns.
+
+Perl equivalent: C<@myarray = ();>.
=cut
*/
void
-Perl_av_clear(pTHX_ register AV *av)
+Perl_av_clear(pTHX_ AV *av)
{
dVAR;
I32 extra;
+ bool real;
+
+ PERL_ARGS_ASSERT_AV_CLEAR;
+ assert(SvTYPE(av) == SVt_PVAV);
- assert(av);
#ifdef DEBUGGING
- if (SvREFCNT(av) == 0 && ckWARN_d(WARN_DEBUGGING)) {
- Perl_warner(aTHX_ packWARN(WARN_DEBUGGING), "Attempt to clear deleted array");
+ if (SvREFCNT(av) == 0) {
+ Perl_ck_warner_d(aTHX_ packWARN(WARN_DEBUGGING), "Attempt to clear deleted array");
}
#endif
if (SvREADONLY(av))
- Perl_croak(aTHX_ PL_no_modify);
+ Perl_croak_no_modify();
/* Give any tie a chance to cleanup first */
- if (SvRMAGICAL(av))
- mg_clear((SV*)av);
+ if (SvRMAGICAL(av)) {
+ const MAGIC* const mg = SvMAGIC(av);
+ if (PL_delaymagic && mg && mg->mg_type == PERL_MAGIC_isa)
+ PL_delaymagic |= DM_ARRAY_ISA;
+ else
+ mg_clear(MUTABLE_SV(av));
+ }
if (AvMAX(av) < 0)
return;
- if (AvREAL(av)) {
+ if ((real = !!AvREAL(av))) {
SV** const ary = AvARRAY(av);
I32 index = AvFILLp(av) + 1;
+ ENTER;
+ SAVEFREESV(SvREFCNT_inc_simple_NN(av));
while (index) {
SV * const sv = ary[--index];
/* undef the slot before freeing the value, because a
extra = AvARRAY(av) - AvALLOC(av);
if (extra) {
AvMAX(av) += extra;
- SvPV_set(av, (char*)AvALLOC(av));
+ AvARRAY(av) = AvALLOC(av);
}
AvFILLp(av) = -1;
-
+ if (real) LEAVE;
}
/*
=for apidoc av_undef
-Undefines the array. Frees the memory used by the array itself.
+Undefines the array. Frees the memory used by the av to store its list of
+scalars. If any destructors are triggered as a result, the av itself may
+be freed.
=cut
*/
void
-Perl_av_undef(pTHX_ register AV *av)
+Perl_av_undef(pTHX_ AV *av)
{
- assert(av);
+ bool real;
+
+ PERL_ARGS_ASSERT_AV_UNDEF;
+ assert(SvTYPE(av) == SVt_PVAV);
/* Give any tie a chance to cleanup first */
- if (SvTIED_mg((SV*)av, PERL_MAGIC_tied))
- av_fill(av, -1); /* mg_clear() ? */
+ if (SvTIED_mg((const SV *)av, PERL_MAGIC_tied))
+ av_fill(av, -1);
- if (AvREAL(av)) {
- register I32 key = AvFILLp(av) + 1;
+ if ((real = !!AvREAL(av))) {
+ I32 key = AvFILLp(av) + 1;
+ ENTER;
+ SAVEFREESV(SvREFCNT_inc_simple_NN(av));
while (key)
SvREFCNT_dec(AvARRAY(av)[--key]);
}
+
Safefree(AvALLOC(av));
AvALLOC(av) = NULL;
- SvPV_set(av, NULL);
+ AvARRAY(av) = NULL;
AvMAX(av) = AvFILLp(av) = -1;
+
+ if(SvRMAGICAL(av)) mg_clear(MUTABLE_SV(av));
+ if(real) LEAVE;
+}
+
+/*
+
+=for apidoc av_create_and_push
+
+Push an SV onto the end of the array, creating the array if necessary.
+A small internal helper function to remove a commonly duplicated idiom.
+
+=cut
+*/
+
+void
+Perl_av_create_and_push(pTHX_ AV **const avp, SV *const val)
+{
+ PERL_ARGS_ASSERT_AV_CREATE_AND_PUSH;
+
+ if (!*avp)
+ *avp = newAV();
+ av_push(*avp, val);
}
/*
=for apidoc av_push
Pushes an SV onto the end of the array. The array will grow automatically
-to accommodate the addition.
+to accommodate the addition. This takes ownership of one reference count.
+
+Perl equivalent: C<push @myarray, $elem;>.
=cut
*/
void
-Perl_av_push(pTHX_ register AV *av, SV *val)
+Perl_av_push(pTHX_ AV *av, SV *val)
{
dVAR;
MAGIC *mg;
- assert(av);
+
+ PERL_ARGS_ASSERT_AV_PUSH;
+ assert(SvTYPE(av) == SVt_PVAV);
if (SvREADONLY(av))
- Perl_croak(aTHX_ PL_no_modify);
-
- if ((mg = SvTIED_mg((SV*)av, PERL_MAGIC_tied))) {
- dSP;
- PUSHSTACKi(PERLSI_MAGIC);
- PUSHMARK(SP);
- EXTEND(SP,2);
- PUSHs(SvTIED_obj((SV*)av, mg));
- PUSHs(val);
- PUTBACK;
- ENTER;
- call_method("PUSH", G_SCALAR|G_DISCARD);
- LEAVE;
- POPSTACK;
+ Perl_croak_no_modify();
+
+ if ((mg = SvTIED_mg((const SV *)av, PERL_MAGIC_tied))) {
+ Perl_magic_methcall(aTHX_ MUTABLE_SV(av), mg, SV_CONST(PUSH), G_DISCARD, 1,
+ val);
return;
}
av_store(av,AvFILLp(av)+1,val);
/*
=for apidoc av_pop
-Pops an SV off the end of the array. Returns C<&PL_sv_undef> if the array
-is empty.
+Removes one SV from the end of the array, reducing its size by one and
+returning the SV (transferring control of one reference count) to the
+caller. Returns C<&PL_sv_undef> if the array is empty.
+
+Perl equivalent: C<pop(@myarray);>
=cut
*/
SV *
-Perl_av_pop(pTHX_ register AV *av)
+Perl_av_pop(pTHX_ AV *av)
{
dVAR;
SV *retval;
MAGIC* mg;
- assert(av);
+ PERL_ARGS_ASSERT_AV_POP;
+ assert(SvTYPE(av) == SVt_PVAV);
if (SvREADONLY(av))
- Perl_croak(aTHX_ PL_no_modify);
- if ((mg = SvTIED_mg((SV*)av, PERL_MAGIC_tied))) {
- dSP;
- PUSHSTACKi(PERLSI_MAGIC);
- PUSHMARK(SP);
- XPUSHs(SvTIED_obj((SV*)av, mg));
- PUTBACK;
- ENTER;
- if (call_method("POP", G_SCALAR)) {
- retval = newSVsv(*PL_stack_sp--);
- } else {
- retval = &PL_sv_undef;
- }
- LEAVE;
- POPSTACK;
+ Perl_croak_no_modify();
+ if ((mg = SvTIED_mg((const SV *)av, PERL_MAGIC_tied))) {
+ retval = Perl_magic_methcall(aTHX_ MUTABLE_SV(av), mg, SV_CONST(POP), 0, 0);
+ if (retval)
+ retval = newSVsv(retval);
return retval;
}
if (AvFILL(av) < 0)
retval = AvARRAY(av)[AvFILLp(av)];
AvARRAY(av)[AvFILLp(av)--] = &PL_sv_undef;
if (SvSMAGICAL(av))
- mg_set((SV*)av);
+ mg_set(MUTABLE_SV(av));
return retval;
}
/*
+
+=for apidoc av_create_and_unshift_one
+
+Unshifts an SV onto the beginning of the array, creating the array if
+necessary.
+A small internal helper function to remove a commonly duplicated idiom.
+
+=cut
+*/
+
+SV **
+Perl_av_create_and_unshift_one(pTHX_ AV **const avp, SV *const val)
+{
+ PERL_ARGS_ASSERT_AV_CREATE_AND_UNSHIFT_ONE;
+
+ if (!*avp)
+ *avp = newAV();
+ av_unshift(*avp, 1);
+ return av_store(*avp, 0, val);
+}
+
+/*
=for apidoc av_unshift
Unshift the given number of C<undef> values onto the beginning of the
array. The array will grow automatically to accommodate the addition. You
must then use C<av_store> to assign values to these new elements.
+Perl equivalent: C<unshift @myarray, ( (undef) x $n );>
+
=cut
*/
void
-Perl_av_unshift(pTHX_ register AV *av, register I32 num)
+Perl_av_unshift(pTHX_ AV *av, I32 num)
{
dVAR;
- register I32 i;
+ I32 i;
MAGIC* mg;
- assert(av);
+ PERL_ARGS_ASSERT_AV_UNSHIFT;
+ assert(SvTYPE(av) == SVt_PVAV);
if (SvREADONLY(av))
- Perl_croak(aTHX_ PL_no_modify);
-
- if ((mg = SvTIED_mg((SV*)av, PERL_MAGIC_tied))) {
- dSP;
- PUSHSTACKi(PERLSI_MAGIC);
- PUSHMARK(SP);
- EXTEND(SP,1+num);
- PUSHs(SvTIED_obj((SV*)av, mg));
- while (num-- > 0) {
- PUSHs(&PL_sv_undef);
- }
- PUTBACK;
- ENTER;
- call_method("UNSHIFT", G_SCALAR|G_DISCARD);
- LEAVE;
- POPSTACK;
+ Perl_croak_no_modify();
+
+ if ((mg = SvTIED_mg((const SV *)av, PERL_MAGIC_tied))) {
+ Perl_magic_methcall(aTHX_ MUTABLE_SV(av), mg, SV_CONST(UNSHIFT),
+ G_DISCARD | G_UNDEF_FILL, num);
return;
}
AvMAX(av) += i;
AvFILLp(av) += i;
- SvPV_set(av, (char*)(AvARRAY(av) - i));
+ AvARRAY(av) = AvARRAY(av) - i;
}
if (num) {
- register SV **ary;
- I32 slide;
- i = AvFILLp(av);
+ SV **ary;
+ const I32 i = AvFILLp(av);
/* Create extra elements */
- slide = i > 0 ? i : 0;
+ const I32 slide = i > 0 ? i : 0;
num += slide;
av_extend(av, i + num);
AvFILLp(av) += num;
/* Make extra elements into a buffer */
AvMAX(av) -= slide;
AvFILLp(av) -= slide;
- SvPV_set(av, (char*)(AvARRAY(av) + slide));
+ AvARRAY(av) = AvARRAY(av) + slide;
}
}
/*
=for apidoc av_shift
-Shifts an SV off the beginning of the array.
+Removes one SV from the start of the array, reducing its size by one and
+returning the SV (transferring control of one reference count) to the
+caller. Returns C<&PL_sv_undef> if the array is empty.
+
+Perl equivalent: C<shift(@myarray);>
=cut
*/
SV *
-Perl_av_shift(pTHX_ register AV *av)
+Perl_av_shift(pTHX_ AV *av)
{
dVAR;
SV *retval;
MAGIC* mg;
- assert(av);
+ PERL_ARGS_ASSERT_AV_SHIFT;
+ assert(SvTYPE(av) == SVt_PVAV);
if (SvREADONLY(av))
- Perl_croak(aTHX_ PL_no_modify);
- if ((mg = SvTIED_mg((SV*)av, PERL_MAGIC_tied))) {
- dSP;
- PUSHSTACKi(PERLSI_MAGIC);
- PUSHMARK(SP);
- XPUSHs(SvTIED_obj((SV*)av, mg));
- PUTBACK;
- ENTER;
- if (call_method("SHIFT", G_SCALAR)) {
- retval = newSVsv(*PL_stack_sp--);
- } else {
- retval = &PL_sv_undef;
- }
- LEAVE;
- POPSTACK;
+ Perl_croak_no_modify();
+ if ((mg = SvTIED_mg((const SV *)av, PERL_MAGIC_tied))) {
+ retval = Perl_magic_methcall(aTHX_ MUTABLE_SV(av), mg, SV_CONST(SHIFT), 0, 0);
+ if (retval)
+ retval = newSVsv(retval);
return retval;
}
if (AvFILL(av) < 0)
retval = *AvARRAY(av);
if (AvREAL(av))
*AvARRAY(av) = &PL_sv_undef;
- SvPV_set(av, (char*)(AvARRAY(av) + 1));
+ AvARRAY(av) = AvARRAY(av) + 1;
AvMAX(av)--;
AvFILLp(av)--;
if (SvSMAGICAL(av))
- mg_set((SV*)av);
+ mg_set(MUTABLE_SV(av));
return retval;
}
/*
-=for apidoc av_len
+=for apidoc av_top_index
Returns the highest index in the array. The number of elements in the
-array is C<av_len(av) + 1>. Returns -1 if the array is empty.
+array is C<av_top_index(av) + 1>. Returns -1 if the array is empty.
+
+The Perl equivalent for this is C<$#myarray>.
+
+(A slightly shorter form is C<av_tindex>.)
+
+=for apidoc av_len
+
+Same as L</av_top_index>. Returns the highest index in the array. Note that the
+return value is +1 what its name implies it returns; and hence differs in
+meaning from what the similarly named L</sv_len> returns.
=cut
*/
I32
-Perl_av_len(pTHX_ register const AV *av)
+Perl_av_len(pTHX_ AV *av)
{
- assert(av);
- return AvFILL(av);
+ PERL_ARGS_ASSERT_AV_LEN;
+
+ return av_top_index(av);
}
/*
Perl's C<$#array = $fill;>.
The number of elements in the an array will be C<fill + 1> after
-av_fill() returns. If the array was previously shorter then the
+av_fill() returns. If the array was previously shorter, then the
additional elements appended are set to C<PL_sv_undef>. If the array
was longer, then the excess elements are freed. C<av_fill(av, -1)> is
the same as C<av_clear(av)>.
=cut
*/
void
-Perl_av_fill(pTHX_ register AV *av, I32 fill)
+Perl_av_fill(pTHX_ AV *av, I32 fill)
{
dVAR;
MAGIC *mg;
- assert(av);
+ PERL_ARGS_ASSERT_AV_FILL;
+ assert(SvTYPE(av) == SVt_PVAV);
if (fill < 0)
fill = -1;
- if ((mg = SvTIED_mg((SV*)av, PERL_MAGIC_tied))) {
- dSP;
- ENTER;
- SAVETMPS;
- PUSHSTACKi(PERLSI_MAGIC);
- PUSHMARK(SP);
- EXTEND(SP,2);
- PUSHs(SvTIED_obj((SV*)av, mg));
- PUSHs(sv_2mortal(newSViv(fill+1)));
- PUTBACK;
- call_method("STORESIZE", G_SCALAR|G_DISCARD);
- POPSTACK;
- FREETMPS;
- LEAVE;
+ if ((mg = SvTIED_mg((const SV *)av, PERL_MAGIC_tied))) {
+ SV *arg1 = sv_newmortal();
+ sv_setiv(arg1, (IV)(fill + 1));
+ Perl_magic_methcall(aTHX_ MUTABLE_SV(av), mg, SV_CONST(STORESIZE), G_DISCARD,
+ 1, arg1);
return;
}
if (fill <= AvMAX(av)) {
AvFILLp(av) = fill;
if (SvSMAGICAL(av))
- mg_set((SV*)av);
+ mg_set(MUTABLE_SV(av));
}
else
(void)av_store(av,fill,&PL_sv_undef);
/*
=for apidoc av_delete
-Deletes the element indexed by C<key> from the array. Returns the
-deleted element. If C<flags> equals C<G_DISCARD>, the element is freed
-and null is returned.
+Deletes the element indexed by C<key> from the array, makes the element mortal,
+and returns it. If C<flags> equals C<G_DISCARD>, the element is freed and null
+is returned. Perl equivalent: C<my $elem = delete($myarray[$idx]);> for the
+non-C<G_DISCARD> version and a void-context C<delete($myarray[$idx]);> for the
+C<G_DISCARD> version.
=cut
*/
dVAR;
SV *sv;
- assert(av);
+ PERL_ARGS_ASSERT_AV_DELETE;
+ assert(SvTYPE(av) == SVt_PVAV);
if (SvREADONLY(av))
- Perl_croak(aTHX_ PL_no_modify);
+ Perl_croak_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 */
+ const MAGIC * const tied_magic
+ = mg_find((const SV *)av, PERL_MAGIC_tied);
+ if ((tied_magic || mg_find((const SV *)av, PERL_MAGIC_regdata))) {
SV **svp;
if (key < 0) {
- unsigned adjust_index = 1;
- if (tied_magic) {
- SV * const * const 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)
+ if (!S_adjust_index(aTHX_ av, tied_magic, &key))
return NULL;
- }
}
svp = av_fetch(av, key, TRUE);
if (svp) {
else
AvARRAY(av)[key] = &PL_sv_undef;
if (SvSMAGICAL(av))
- mg_set((SV*)av);
+ mg_set(MUTABLE_SV(av));
}
if (flags & G_DISCARD) {
SvREFCNT_dec(sv);
This relies on the fact that uninitialized array elements are set to
C<&PL_sv_undef>.
+Perl equivalent: C<exists($myarray[$key])>.
+
=cut
*/
bool
Perl_av_exists(pTHX_ AV *av, I32 key)
{
dVAR;
- assert(av);
+ PERL_ARGS_ASSERT_AV_EXISTS;
+ assert(SvTYPE(av) == SVt_PVAV);
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 * const sv = sv_newmortal();
+ const MAGIC * const tied_magic
+ = mg_find((const SV *)av, PERL_MAGIC_tied);
+ const MAGIC * const regdata_magic
+ = mg_find((const SV *)av, PERL_MAGIC_regdata);
+ if (tied_magic || regdata_magic) {
MAGIC *mg;
/* Handle negative array indices 20020222 MJD */
if (key < 0) {
- unsigned adjust_index = 1;
- if (tied_magic) {
- SV * const * const 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)
+ if (!S_adjust_index(aTHX_ av, tied_magic, &key))
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 && regdata_magic) {
+ if (key <= AvFILL(av))
+ return TRUE;
+ else
+ return FALSE;
}
-
+ {
+ SV * const sv = sv_newmortal();
+ mg_copy(MUTABLE_SV(av), sv, 0, key);
+ mg = mg_find(sv, PERL_MAGIC_tiedelem);
+ if (mg) {
+ magic_existspack(sv, mg);
+ {
+ I32 retbool = SvTRUE_nomg_NN(sv);
+ return cBOOL(retbool);
+ }
+ }
+ }
}
}
return FALSE;
}
-SV **
-Perl_av_arylen_p(pTHX_ AV *av) {
+static MAGIC *
+S_get_aux_mg(pTHX_ AV *av) {
dVAR;
MAGIC *mg;
- assert(av);
+ PERL_ARGS_ASSERT_GET_AUX_MG;
+ assert(SvTYPE(av) == SVt_PVAV);
- mg = mg_find((SV*)av, PERL_MAGIC_arylen_p);
+ mg = mg_find((const SV *)av, PERL_MAGIC_arylen_p);
if (!mg) {
- mg = sv_magicext((SV*)av, 0, PERL_MAGIC_arylen_p, &PL_vtbl_arylen_p,
- 0, 0);
+ mg = sv_magicext(MUTABLE_SV(av), 0, PERL_MAGIC_arylen_p,
+ &PL_vtbl_arylen_p, 0, 0);
assert(mg);
/* sv_magicext won't set this for us because we pass in a NULL obj */
mg->mg_flags |= MGf_REFCOUNTED;
}
+ return mg;
+}
+
+SV **
+Perl_av_arylen_p(pTHX_ AV *av) {
+ MAGIC *const mg = get_aux_mg(av);
+
+ PERL_ARGS_ASSERT_AV_ARYLEN_P;
+ assert(SvTYPE(av) == SVt_PVAV);
+
return &(mg->mg_obj);
}
+IV *
+Perl_av_iter_p(pTHX_ AV *av) {
+ MAGIC *const mg = get_aux_mg(av);
+
+ PERL_ARGS_ASSERT_AV_ITER_P;
+ assert(SvTYPE(av) == SVt_PVAV);
+
+#if IVSIZE == I32SIZE
+ return (IV *)&(mg->mg_len);
+#else
+ if (!mg->mg_ptr) {
+ IV *temp;
+ mg->mg_len = IVSIZE;
+ Newxz(temp, 1, IV);
+ mg->mg_ptr = (char *) temp;
+ }
+ return (IV *)mg->mg_ptr;
+#endif
+}
+
/*
* Local variables:
* c-indentation-style: bsd
* c-basic-offset: 4
- * indent-tabs-mode: t
+ * indent-tabs-mode: nil
* End:
*
- * ex: set ts=8 sts=4 sw=4 noet:
+ * ex: set ts=8 sts=4 sw=4 et:
*/