On Mon, 10 Mar 2003, Steve Hay wrote:

[snip]
> Yes, this works.
>
> I think the mistake in my attempted use of sv_inc() was to call
> hv_store() afterwards, rather like inserting
>
> hv_store(hash, "total", 5, *hval, 0);
>
> after the sv_setiv() call in your code snippet above.

HV *hash;
SV *svtotal;
...
svtotal = *hv_fetch(hash, "total", 5, 0);
sv_inc(svtotal);
hv_store(hash, "total", 5, svtotal, 0);

Hmm... retrieve and dereferenve an SV** to an SV*
increment SV*
write SV* back on top of itself <--- *bang*

I _think_ what heppens there is, when perl unlinks the SV*
from the hash (in the hv_store), it decrements its ref count.
The SV* then gets written _back into the hash_, but its ref
count is not incremented: IOW hv_store does not alter the ref
count of its argument, but it does alter the ref count of
the existing SV* stored at the target location. In this case,
both are the same value (bizarre), so you end up with a value
stored back in its old location with a ref count of 0: As soon
as the value is removed from the hash again, (eg another self
targeted hv_store), ref count -> -1 : Bad stuff happens.

> Presumably, then, *hval (an SV *) is a pointer to the value actually
> held in the hash, so having modified the value through that pointer
> there is no need to store it back in the hash.  Is this correct?

Yes, hv_store and hv_fetch both return a pointer to the SV* that holds the
hash value.

> been thinking that the SV * was disassociated from the hash so that
> after changing it, I would need to store it back.)

> Having said all that, however, it may be easier just to accumulate this
> data in simple C arrays and then copy it all to the Perl hash when I've
> finished.

Whatever fits your data structures/algorithm better. I had a multilayered
hash of hashes structure in one program: I represented it in C
thusly:

typedef struct scalar
{                   /* These types chosen to match perlguts nomenclature */
    char      type; /* n = number (double), p = pointer (char), i = int  */
    SV     ** svpp; /* points to a pointer to an actual perl SV          */
    char    * pval; /* char *, if it's a string. malloc'd to size 'size' */
    long      ival; /* integer value, if integer                         */
    double    nval; /* float value, if applicable                        */
    char   ** keys; /* NULL terminated key list for multilevel hash      */
    uint      size; /* max size the perl SV should hold.                 */
} SCALAR;

...

const char * TYPE_KEY[]             = {"__TYPE__", NULL};
const char * NELEM_KEY[]            = {"__NELEM__", NULL};
const char * host[]                 = {"host", NULL};
const char * login__name[]          = {"login","name", NULL};
const char * login__system[]        = {"login","system", NULL};

...

static SCALAR SA_NULL[] =
{
    { 'i', NULL, NULL, 0, 0, (char **)NELEM_KEY,          -1 },
    { 'p', NULL, NULL, 0, 0, (char **)host,               64 },
    { 'i', NULL, NULL, 0, 0, (char **)rcode,               0 },
    { 'i', NULL, NULL, 0, 0, (char **)status_code,         0 },
    { 'p', NULL, NULL, 0, 0, (char **)rpc_message,  RPC_ELEN },
    { 'i', NULL, NULL, 0, 0, (char **)TYPE_KEY,            0 },
    { '\0',NULL, NULL, 0, 0, (char **)NULL,                0 }
};

and wrote a big scary function(tm) to automatically traverse SA_NULL[]
and create/populate a perl hash, or traverse a perl hash and populate
SA_NULL.

This may or may not be overkill for you, but it was quite necessary
for my sanity at the time :)



Reply via email to