Representación Interna de un AV

La información sobre un array value (AV) se guarda en un nodo de tipo XPVAV:

lhp@nereida:~/Lperl/src/perlcompilerssource/perl-5.8.8$ grep 'typedef.*\ <AV;' *.h
perl.h:typedef struct av AV;
lhp@nereida:~/Lperl/src/perlcompilerssource/perl-5.8.8$ perl -ne \
  '$x = 1 if /struct av/; print if $x; exit if $x && /}/' sv.h
struct av {
    XPVAV*      sv_any;         /* pointer to something */
    U32         sv_refcnt;      /* how many references to us */
    U32         sv_flags;       /* what we are */
};

El tipo XPVAV tiene la siguiente estructura:

lhp@nereida:~/Lperl/src/perlcompilerssource/perl-5.8.8$ grep 'typedef .*XPVAV' *.h
perl.h:typedef struct xpvav XPVAV;
lhp@nereida:~/Lperl/src/perlcompilerssource/perl-5.8.8$ perl -ne \
    '$x = 1 if /struct xpvav {/; print if $x; exit if $x && /}/' av.h
struct xpvav {
    char*       xav_array;      /* pointer to first array element */
    SSize_t     xav_fill;       /* Index of last element present */
    SSize_t     xav_max;        /* max index for which array has space */
    IV          xof_off;        /* ptr is incremented by offset */
    NV          xnv_nv;         /* numeric value, if any */
    MAGIC*      xmg_magic;      /* magic for scalar array */
    HV*         xmg_stash;      /* class package */

    SV**        xav_alloc;      /* pointer to beginning of C array of SVs */
    SV*         xav_arylen;
    U8          xav_flags;
};
El campo xav_alloc apunta al primer elemento del array C asignado mientras que el campo xav_array apunta al primer elemento de la lista de valores escalares (no siempre son iguales). El campo xav_arylen apunta al valor escalar mágico que se corresponde con el constructo Perl $#array.
lhp@nereida:~/Lperl/src/XSUB/cpanexamples/String-Index-0.02$ perl -MDevel::Peek -de 0
Loading DB routines from perl5db.pl version 1.28
main::(-e:1):   0
  DB<1> @a = qw/primero segundo/
  DB<2> Dump(\@a)
SV = RV(0x817e1f0) at 0x844dc2c
  REFCNT = 1
  FLAGS = (ROK)
  RV = 0x844daa0
  SV = PVAV(0x8480e68) at 0x844daa0
    REFCNT = 2
    FLAGS = ()
    IV = 0
    NV = 0
    ARRAY = 0x816f8d0
    FILL = 1
    MAX = 3
    ARYLEN = 0x0
    FLAGS = (REAL)
    Elt No. 0
    SV = PV(0x8443440) at 0x81531b0
      REFCNT = 1
      FLAGS = (POK,pPOK)
      PV = 0x8475990 "primero"\0
      CUR = 7
      LEN = 8
    Elt No. 1
    SV = PV(0x83c975c) at 0x81526b8
      REFCNT = 1
      FLAGS = (POK,pPOK)
      PV = 0x83c9c48 "segundo"\0
      CUR = 7
      LEN = 8
El campo ARYLEN es inicializado si usamos $#a.
  DB<3> p "$#a\n"
1
  DB<4> Dump(\@a)
SV = RV(0x817e200) at 0x844dc2c
  REFCNT = 1 # esta información es relativa ala argumento de Dump: \@a
  FLAGS = (ROK)
  RV = 0x844daa0
  SV = PVAV(0x8480e68) at 0x844daa0
    REFCNT = 2 # Es referenciado por @a y por el argumento de Dump
    FLAGS = ()
    IV = 0
    NV = 0
    ARRAY = 0x816f8d0
    FILL = 1
    MAX = 3
    ARYLEN = 0x844daf4
    FLAGS = (REAL)
    Elt No. 0
    SV = PV(0x8443440) at 0x81531b0
      REFCNT = 1 # Solo una referencia a este valor
      FLAGS = (POK,pPOK) # Indican que se esta usando como cadena
      PV = 0x8475990 "primero"\0
      CUR = 7 # Longitud de la cadena
      LEN = 8 # Cantidad de memoria asignada
    Elt No. 1
    SV = PV(0x83c975c) at 0x81526b8
      REFCNT = 1
      FLAGS = (POK,pPOK)
      PV = 0x83c9c48 "segundo"\0
      CUR = 7
      LEN = 8
Si extraemos la cabecera de la lista:
  DB<5> $a = shift @a
Cambia el campo ARRAY que para apuntar al nuevo comienzo de la lista se desplaza desde 0x816f8d0 a 0x816f8d4 (un puntero mas). También cambian FILL (índice del último elemento, que pasa de 1 a 0) y MAX (máximo índice para el cual se dispone de espacio, ahora pasa a ser 2).
  DB<6> Dump(\@a)
SV = RV(0x817e210) at 0x844dc2c
  REFCNT = 1
  FLAGS = (ROK)
  RV = 0x844daa0
  SV = PVAV(0x8480e68) at 0x844daa0
    REFCNT = 2
    FLAGS = ()
    IV = 0
    NV = 0
    ARRAY = 0x816f8d4 (offset=1)
    ALLOC = 0x816f8d0
    FILL = 0
    MAX = 2
    ARYLEN = 0x844daf4
    FLAGS = (REAL)
    Elt No. 0
    SV = PV(0x83c975c) at 0x81526b8
      REFCNT = 1
      FLAGS = (POK,pPOK)
      PV = 0x83c9c48 "segundo"\0
      CUR = 7
      LEN = 8
Introduzcamos dos nuevos elementos:
  DB<7> $a = push @a, qw/tercero cuarto quinto/
Ahora ARRAY es 0x816f3a0. El array ha sido reubicado. Puesto que hay cuatro elementos FILL es 3. Se ha solicitado mas memoria ya que MAX es 11.

  DB<8> Dump(\@a)
SV = RV(0x817e228) at 0x844d6d4
  REFCNT = 1
  FLAGS = (ROK)
  RV = 0x844daa0
  SV = PVAV(0x8480e68) at 0x844daa0
    REFCNT = 2
    FLAGS = ()
    IV = 0
    NV = 0
    ARRAY = 0x816f3a0
    FILL = 3
    MAX = 11
    ARYLEN = 0x844daf4
    FLAGS = (REAL)
    Elt No. 0
    SV = PV(0x83c975c) at 0x81526b8
      REFCNT = 1
      FLAGS = (POK,pPOK)
      PV = 0x83c9c48 "segundo"\0
      CUR = 7
      LEN = 8
    Elt No. 1
    SV = PV(0x844365c) at 0x844d7a0
      REFCNT = 1
      FLAGS = (POK,pPOK)
      PV = 0x83f5a28 "tercero"\0
      CUR = 7
      LEN = 8
    Elt No. 2
    SV = PV(0x8443680) at 0x844d644
      REFCNT = 1
      FLAGS = (POK,pPOK)
      PV = 0x824d868 "cuarto"\0
      CUR = 6
      LEN = 8
    Elt No. 3
    SV = PV(0x8443608) at 0x844d5d8
      REFCNT = 1
      FLAGS = (POK,pPOK)
      PV = 0x83bc2a8 "quinto"\0
      CUR = 6
      LEN = 8

Casiano Rodríguez León
2012-02-29