/* hv.c
*
- * Copyright (c) 1991-2002, Larry Wall
+ * Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+ * 2000, 2001, 2002, 2003, 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.
return hek;
}
+/* free the pool of temporary HE/HEK pairs retunrned by hv_fetch_ent
+ * for tied hashes */
+
+void
+Perl_free_tied_hv_pool(pTHX)
+{
+ HE *ohe;
+ HE *he = PL_hv_fetch_ent_mh;
+ while (he) {
+ Safefree(HeKEY_hek(he));
+ ohe = he;
+ he = HeNEXT(he);
+ del_HE(ohe);
+ }
+}
+
#if defined(USE_ITHREADS)
HE *
Perl_he_dup(pTHX_ HE *e, bool shared, CLONE_PARAMS* param)
ptr_table_store(PL_ptr_table, e, ret);
HeNEXT(ret) = he_dup(HeNEXT(e),shared, param);
- if (HeKLEN(e) == HEf_SVKEY)
+ if (HeKLEN(e) == HEf_SVKEY) {
+ char *k;
+ New(54, k, HEK_BASESIZE + sizeof(SV*), char);
+ HeKEY_hek(ret) = (HEK*)k;
HeKEY_sv(ret) = SvREFCNT_inc(sv_dup(HeKEY_sv(e), param));
+ }
else if (shared)
HeKEY_hek(ret) = share_hek_flags(HeKEY(e), HeKLEN(e), HeHASH(e),
HeKFLAGS(e));
}
else {
/* Need to free saved eventually assign to mortal SV */
- SV *sv = sv_newmortal();
+ /* XXX is this line an error ???: SV *sv = sv_newmortal(); */
sv_usepvn(sv, (char *) key, klen);
}
if (flags & HVhek_UTF8) {
*/
if (mg_find((SV*)hv, PERL_MAGIC_tied) || SvGMAGICAL((SV*)hv)) {
sv = sv_newmortal();
+ sv_upgrade(sv, SVt_PVLV);
mg_copy((SV*)hv, sv, key, klen);
if (flags & HVhek_FREEKEY)
Safefree(key);
- PL_hv_fetch_sv = sv;
- return &PL_hv_fetch_sv;
+ LvTYPE(sv) = 't';
+ LvTARG(sv) = sv; /* fake (SV**) */
+ return &(LvTARG(sv));
}
#ifdef ENV_IS_CASELESS
else if (mg_find((SV*)hv, PERL_MAGIC_env)) {
- U32 i;
+ I32 i;
for (i = 0; i < klen; ++i)
if (isLOWER(key[i])) {
char *nkey = strupr(SvPVX(sv_2mortal(newSVpvn(key,klen))));
/* entry = (HvARRAY(hv))[hash & (I32) HvMAX(hv)]; */
entry = ((HE**)xhv->xhv_array)[hash & (I32) xhv->xhv_max];
for (; entry; entry = HeNEXT(entry)) {
+ if (!HeKEY_hek(entry))
+ continue;
if (HeHASH(entry) != hash) /* strings can't be equal */
continue;
- if (HeKLEN(entry) != klen)
+ if (HeKLEN(entry) != (I32)klen)
continue;
if (HeKEY(entry) != key && memNE(HeKEY(entry),key,klen)) /* is this it? */
continue;
if (flags & HVhek_FREEKEY)
Safefree(key);
/* if we find a placeholder, we pretend we haven't found anything */
- if (HeVAL(entry) == &PL_sv_undef)
+ if (HeVAL(entry) == &PL_sv_placeholder)
break;
return &HeVAL(entry);
if (SvRMAGICAL(hv)) {
if (mg_find((SV*)hv, PERL_MAGIC_tied) || SvGMAGICAL((SV*)hv)) {
sv = sv_newmortal();
- keysv = sv_2mortal(newSVsv(keysv));
+ keysv = newSVsv(keysv);
mg_copy((SV*)hv, sv, (char*)keysv, HEf_SVKEY);
- if (!HeKEY_hek(&PL_hv_fetch_ent_mh)) {
+ /* grab a fake HE/HEK pair from the pool or make a new one */
+ entry = PL_hv_fetch_ent_mh;
+ if (entry)
+ PL_hv_fetch_ent_mh = HeNEXT(entry);
+ else {
char *k;
+ entry = new_HE();
New(54, k, HEK_BASESIZE + sizeof(SV*), char);
- HeKEY_hek(&PL_hv_fetch_ent_mh) = (HEK*)k;
+ HeKEY_hek(entry) = (HEK*)k;
}
- HeSVKEY_set(&PL_hv_fetch_ent_mh, keysv);
- HeVAL(&PL_hv_fetch_ent_mh) = sv;
- return &PL_hv_fetch_ent_mh;
- }
+ HeNEXT(entry) = Nullhe;
+ HeSVKEY_set(entry, keysv);
+ HeVAL(entry) = sv;
+ sv_upgrade(sv, SVt_PVLV);
+ LvTYPE(sv) = 'T';
+ LvTARG(sv) = (SV*)entry; /* so we can free entry when freeing sv */
+ return entry;
+ }
#ifdef ENV_IS_CASELESS
else if (mg_find((SV*)hv, PERL_MAGIC_env)) {
U32 i;
#endif
}
+ keysave = key = SvPV(keysv, klen);
xhv = (XPVHV*)SvANY(hv);
if (!xhv->xhv_array /* !HvARRAY(hv) */) {
if (lval
return 0;
}
- keysave = key = SvPV(keysv, klen);
is_utf8 = (SvUTF8(keysv)!=0);
if (is_utf8) {
flags |= HVhek_WASUTF8 | HVhek_FREEKEY;
}
- if (!hash)
- PERL_HASH(hash, key, klen);
+ if (!hash) {
+ if SvIsCOW_shared_hash(keysv) {
+ hash = SvUVX(keysv);
+ } else {
+ PERL_HASH(hash, key, klen);
+ }
+ }
/* entry = (HvARRAY(hv))[hash & (I32) HvMAX(hv)]; */
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)
+ if (HeKLEN(entry) != (I32)klen)
continue;
if (HeKEY(entry) != key && memNE(HeKEY(entry),key,klen)) /* is this it? */
continue;
if (key != keysave)
Safefree(key);
/* if we find a placeholder, we pretend we haven't found anything */
- if (HeVAL(entry) == &PL_sv_undef)
+ if (HeVAL(entry) == &PL_sv_placeholder)
break;
return entry;
}
stored within the hash (as in the case of tied hashes). Otherwise it can
be dereferenced to get the original C<SV*>. 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.
+the call, and decrementing it if the function returned NULL. Effectively
+a successful hv_store takes ownership of one reference to C<val>. This is
+usually what you want; a newly created SV has a reference count of one, so
+if all your code does is create SVs then store them in a hash, hv_store
+will own the only reference to the new SV, and your code doesn't need to do
+anything further to tidy up. hv_store is not implemented as a call to
+hv_store_ent, and does not create a temporary SV for the key, so if your
+key data is not already in SV form then use hv_store in preference to
+hv_store_ent.
See L<perlguts/"Understanding the Magic of Tied Hashes and Arrays"> for more
information on how to use this function on tied hashes.
for (entry = *oentry; entry; i=0, entry = HeNEXT(entry)) {
if (HeHASH(entry) != hash) /* strings can't be equal */
continue;
- if (HeKLEN(entry) != klen)
+ if (HeKLEN(entry) != (I32)klen)
continue;
if (HeKEY(entry) != key && memNE(HeKEY(entry),key,klen)) /* is this it? */
continue;
if ((HeKFLAGS(entry) ^ flags) & HVhek_UTF8)
continue;
- if (HeVAL(entry) == &PL_sv_undef)
+ if (HeVAL(entry) == &PL_sv_placeholder)
xhv->xhv_placeholders--; /* yes, can store into placeholder slot */
else
SvREFCNT_dec(HeVAL(entry));
/* We have been requested to insert a placeholder. Currently
only Storable is allowed to do this. */
xhv->xhv_placeholders++;
- HeVAL(entry) = &PL_sv_undef;
+ HeVAL(entry) = &PL_sv_placeholder;
} else
HeVAL(entry) = val;
/* We have been requested to insert a placeholder. Currently
only Storable is allowed to do this. */
xhv->xhv_placeholders++;
- HeVAL(entry) = &PL_sv_undef;
+ HeVAL(entry) = &PL_sv_placeholder;
} else
HeVAL(entry) = val;
HeNEXT(entry) = *oentry;
xhv->xhv_keys++; /* HvKEYS(hv)++ */
if (i) { /* initial entry? */
xhv->xhv_fill++; /* HvFILL(hv)++ */
- if (xhv->xhv_keys > xhv->xhv_max /* HvKEYS(hv) > HvMAX(hv) */)
- hsplit(hv);
+ } else if (xhv->xhv_keys > (IV)xhv->xhv_max /* HvKEYS(hv) > HvMAX(hv) */) {
+ hsplit(hv);
}
return &HeVAL(entry);
contents of the return value can be accessed using the C<He?> macros
described here. 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.
+decrementing it if the function returned NULL. Effectively a successful
+hv_store_ent takes ownership of one reference to C<val>. This is
+usually what you want; a newly created SV has a reference count of one, so
+if all your code does is create SVs then store them in a hash, hv_store
+will own the only reference to the new SV, and your code doesn't need to do
+anything further to tidy up. Note that hv_store_ent only reads the C<key>;
+unlike C<val> it does not take ownership of it, so maintaining the correct
+reference count on C<key> is entirely the caller's responsibility. hv_store
+is not implemented as a call to hv_store_ent, and does not create a temporary
+SV for the key, so if your key data is not already in SV form then use
+hv_store in preference to hv_store_ent.
See L<perlguts/"Understanding the Magic of Tied Hashes and Arrays"> for more
information on how to use this function on tied hashes.
HvHASKFLAGS_on((SV*)hv);
}
- if (!hash)
- PERL_HASH(hash, key, klen);
+ if (!hash) {
+ if SvIsCOW_shared_hash(keysv) {
+ hash = SvUVX(keysv);
+ } else {
+ PERL_HASH(hash, key, klen);
+ }
+ }
if (!xhv->xhv_array /* !HvARRAY(hv) */)
Newz(505, xhv->xhv_array /* HvARRAY(hv) */,
for (; entry; i=0, entry = HeNEXT(entry)) {
if (HeHASH(entry) != hash) /* strings can't be equal */
continue;
- if (HeKLEN(entry) != klen)
+ if (HeKLEN(entry) != (I32)klen)
continue;
if (HeKEY(entry) != key && memNE(HeKEY(entry),key,klen)) /* is this it? */
continue;
if ((HeKFLAGS(entry) ^ flags) & HVhek_UTF8)
continue;
- if (HeVAL(entry) == &PL_sv_undef)
+ if (HeVAL(entry) == &PL_sv_placeholder)
xhv->xhv_placeholders--; /* yes, can store into placeholder slot */
else
SvREFCNT_dec(HeVAL(entry));
xhv->xhv_keys++; /* HvKEYS(hv)++ */
if (i) { /* initial entry? */
xhv->xhv_fill++; /* HvFILL(hv)++ */
- if (xhv->xhv_keys > xhv->xhv_max /* HvKEYS(hv) > HvMAX(hv) */)
+ if (xhv->xhv_keys > (IV)xhv->xhv_max /* HvKEYS(hv) > HvMAX(hv) */)
hsplit(hv);
}
if (!hv)
return Nullsv;
if (klen < 0) {
- klen = -klen;
- is_utf8 = TRUE;
+ klen = -klen;
+ is_utf8 = TRUE;
}
if (SvRMAGICAL(hv)) {
bool needs_copy;
if (needs_copy && (svp = hv_fetch(hv, key, klen, TRUE))) {
sv = *svp;
- mg_clear(sv);
+ if (SvMAGICAL(sv)) {
+ mg_clear(sv);
+ }
if (!needs_store) {
if (mg_find(sv, PERL_MAGIC_tiedelem)) {
/* No longer an element */
for (; entry; i=0, oentry = &HeNEXT(entry), entry = *oentry) {
if (HeHASH(entry) != hash) /* strings can't be equal */
continue;
- if (HeKLEN(entry) != klen)
+ if (HeKLEN(entry) != (I32)klen)
continue;
if (HeKEY(entry) != key && memNE(HeKEY(entry),key,klen)) /* is this it? */
continue;
if (k_flags & HVhek_FREEKEY)
Safefree(key);
/* if placeholder is here, it's already been deleted.... */
- if (HeVAL(entry) == &PL_sv_undef)
+ if (HeVAL(entry) == &PL_sv_placeholder)
{
if (SvREADONLY(hv))
return Nullsv; /* if still SvREADONLY, leave it deleted. */
sv = Nullsv;
else {
sv = sv_2mortal(HeVAL(entry));
- HeVAL(entry) = &PL_sv_undef;
+ HeVAL(entry) = &PL_sv_placeholder;
}
/*
* an error.
*/
if (SvREADONLY(hv)) {
- HeVAL(entry) = &PL_sv_undef;
+ HeVAL(entry) = &PL_sv_placeholder;
/* We'll be saving this slot, so the number of allocated keys
* doesn't go down, but the number placeholders goes up */
xhv->xhv_placeholders++; /* HvPLACEHOLDERS(hv)++ */
if (needs_copy && (entry = hv_fetch_ent(hv, keysv, TRUE, hash))) {
sv = HeVAL(entry);
- mg_clear(sv);
+ if (SvMAGICAL(sv)) {
+ mg_clear(sv);
+ }
if (!needs_store) {
if (mg_find(sv, PERL_MAGIC_tiedelem)) {
/* No longer an element */
for (; entry; i=0, oentry = &HeNEXT(entry), entry = *oentry) {
if (HeHASH(entry) != hash) /* strings can't be equal */
continue;
- if (HeKLEN(entry) != klen)
+ if (HeKLEN(entry) != (I32)klen)
continue;
if (HeKEY(entry) != key && memNE(HeKEY(entry),key,klen)) /* is this it? */
continue;
Safefree(key);
/* if placeholder is here, it's already been deleted.... */
- if (HeVAL(entry) == &PL_sv_undef)
+ if (HeVAL(entry) == &PL_sv_placeholder)
{
if (SvREADONLY(hv))
return Nullsv; /* if still SvREADONLY, leave it deleted. */
sv = Nullsv;
else {
sv = sv_2mortal(HeVAL(entry));
- HeVAL(entry) = &PL_sv_undef;
+ HeVAL(entry) = &PL_sv_placeholder;
}
/*
* an error.
*/
if (SvREADONLY(hv)) {
- HeVAL(entry) = &PL_sv_undef;
+ HeVAL(entry) = &PL_sv_placeholder;
/* We'll be saving this slot, so the number of allocated keys
* doesn't go down, but the number placeholders goes up */
xhv->xhv_placeholders++; /* HvPLACEHOLDERS(hv)++ */
sv = sv_newmortal();
mg_copy((SV*)hv, sv, key, klen);
magic_existspack(sv, mg_find(sv, PERL_MAGIC_tiedelem));
- return SvTRUE(sv);
+ return (bool)SvTRUE(sv);
}
#ifdef ENV_IS_CASELESS
else if (mg_find((SV*)hv, PERL_MAGIC_env)) {
if (k_flags & HVhek_FREEKEY)
Safefree(key);
/* If we find the key, but the value is a placeholder, return false. */
- if (HeVAL(entry) == &PL_sv_undef)
+ if (HeVAL(entry) == &PL_sv_placeholder)
return FALSE;
return TRUE;
keysv = sv_2mortal(newSVsv(keysv));
mg_copy((SV*)hv, sv, (char*)keysv, HEf_SVKEY);
magic_existspack(svret, mg_find(sv, PERL_MAGIC_tiedelem));
- return SvTRUE(svret);
+ return (bool)SvTRUE(svret);
}
#ifdef ENV_IS_CASELESS
else if (mg_find((SV*)hv, PERL_MAGIC_env)) {
for (; entry; entry = HeNEXT(entry)) {
if (HeHASH(entry) != hash) /* strings can't be equal */
continue;
- if (HeKLEN(entry) != klen)
+ if (HeKLEN(entry) != (I32)klen)
continue;
if (HeKEY(entry) != key && memNE(HeKEY(entry),key,klen)) /* is this it? */
continue;
if (k_flags & HVhek_FREEKEY)
Safefree(key);
/* If we find the key, but the value is a placeholder, return false. */
- if (HeVAL(entry) == &PL_sv_undef)
+ if (HeVAL(entry) == &PL_sv_placeholder)
return FALSE;
return TRUE;
}
continue;
bep = aep+oldsize;
for (oentry = aep, entry = *aep; entry; entry = *oentry) {
- if ((HeHASH(entry) & newsize) != i) {
+ if ((HeHASH(entry) & newsize) != (U32)i) {
*oentry = HeNEXT(entry);
HeNEXT(entry) = *bep;
if (!*bep)
if (!SvMAGICAL((SV *)ohv)) {
/* It's an ordinary hash, so copy it fast. AMS 20010804 */
- int i, shared = !!HvSHAREKEYS(ohv);
+ STRLEN i;
+ bool shared = !!HvSHAREKEYS(ohv);
HE **ents, **oents = (HE **)HvARRAY(ohv);
char *a;
New(0, a, PERL_HV_ARRAY_ALLOC_BYTES(hv_max+1), char);
if (!hv)
return;
- if(SvREADONLY(hv)) {
- Perl_croak(aTHX_ "Attempt to clear a restricted hash");
+ xhv = (XPVHV*)SvANY(hv);
+
+ if (SvREADONLY(hv)) {
+ /* restricted hash: convert all keys to placeholders */
+ I32 i;
+ HE* entry;
+ for (i = 0; i <= (I32) xhv->xhv_max; i++) {
+ entry = ((HE**)xhv->xhv_array)[i];
+ for (; entry; entry = HeNEXT(entry)) {
+ /* not already placeholder */
+ if (HeVAL(entry) != &PL_sv_placeholder) {
+ if (HeVAL(entry) && SvREADONLY(HeVAL(entry))) {
+ SV* keysv = hv_iterkeysv(entry);
+ Perl_croak(aTHX_
+ "Attempt to delete readonly key '%"SVf"' from a restricted hash",
+ keysv);
+ }
+ SvREFCNT_dec(HeVAL(entry));
+ HeVAL(entry) = &PL_sv_placeholder;
+ xhv->xhv_placeholders++; /* HvPLACEHOLDERS(hv)++ */
+ }
+ }
+ }
+ return;
}
- xhv = (XPVHV*)SvANY(hv);
hfreeentries(hv);
- xhv->xhv_fill = 0; /* HvFILL(hv) = 0 */
- xhv->xhv_keys = 0; /* HvKEYS(hv) = 0 */
xhv->xhv_placeholders = 0; /* HvPLACEHOLDERS(hv) = 0 */
if (xhv->xhv_array /* HvARRAY(hv) */)
(void)memzero(xhv->xhv_array /* HvARRAY(hv) */,
riter = 0;
max = HvMAX(hv);
array = HvARRAY(hv);
+ /* make everyone else think the array is empty, so that the destructors
+ * called for freed entries can't recusively mess with us */
+ HvARRAY(hv) = Null(HE**);
+ HvFILL(hv) = 0;
+ ((XPVHV*) SvANY(hv))->xhv_keys = 0;
+
entry = array[0];
for (;;) {
if (entry) {
entry = array[riter];
}
}
+ HvARRAY(hv) = array;
(void)hv_iterinit(hv);
}
hfreeentries(hv);
Safefree(xhv->xhv_array /* HvARRAY(hv) */);
if (HvNAME(hv)) {
+ if(PL_stashcache)
+ hv_delete(PL_stashcache, HvNAME(hv), strlen(HvNAME(hv)), G_DISCARD);
Safefree(HvNAME(hv));
HvNAME(hv) = 0;
}
xhv->xhv_max = 7; /* HvMAX(hv) = 7 (it's a normal hash) */
xhv->xhv_array = 0; /* HvARRAY(hv) = 0 */
- xhv->xhv_fill = 0; /* HvFILL(hv) = 0 */
- xhv->xhv_keys = 0; /* HvKEYS(hv) = 0 */
xhv->xhv_placeholders = 0; /* HvPLACEHOLDERS(hv) = 0 */
if (SvRMAGICAL(hv))
The C<flags> value will normally be zero; if HV_ITERNEXT_WANTPLACEHOLDERS is
set the placeholders keys (for restricted hashes) will be returned in addition
to normal keys. By default placeholders are automatically skipped over.
-Currently a placeholder is implemented with a value that is literally
-<&Perl_sv_undef> (a regular C<undef> value is a normal read-write SV for which
-C<!SvOK> is false). Note that the implementation of placeholders and
+Currently a placeholder is implemented with a value that is
+C<&Perl_sv_placeholder>. Note that the implementation of placeholders and
restricted hashes may change, and the implementation currently is
insufficiently abstracted for any change to be tidy.
Newz(506, xhv->xhv_array /* HvARRAY(hv) */,
PERL_HV_ARRAY_ALLOC_BYTES(xhv->xhv_max+1 /* HvMAX(hv)+1 */),
char);
+ /* At start of hash, entry is NULL. */
if (entry)
{
entry = HeNEXT(entry);
* Skip past any placeholders -- don't want to include them in
* any iteration.
*/
- while (entry && HeVAL(entry) == &PL_sv_undef) {
+ while (entry && HeVAL(entry) == &PL_sv_placeholder) {
entry = HeNEXT(entry);
}
}
}
while (!entry) {
+ /* OK. Come to the end of the current list. Grab the next one. */
+
xhv->xhv_riter++; /* HvRITER(hv)++ */
- if (xhv->xhv_riter > xhv->xhv_max /* HvRITER(hv) > HvMAX(hv) */) {
+ if (xhv->xhv_riter > (I32)xhv->xhv_max /* HvRITER(hv) > HvMAX(hv) */) {
+ /* There is no next one. End of the hash. */
xhv->xhv_riter = -1; /* HvRITER(hv) = -1 */
break;
}
entry = ((HE**)xhv->xhv_array)[xhv->xhv_riter];
if (!(flags & HV_ITERNEXT_WANTPLACEHOLDERS)) {
- /* if we have an entry, but it's a placeholder, don't count it */
- if (entry && HeVAL(entry) == &PL_sv_undef)
- entry = 0;
- }
+ /* If we have an entry, but it's a placeholder, don't count it.
+ Try the next. */
+ while (entry && HeVAL(entry) == &PL_sv_placeholder)
+ entry = HeNEXT(entry);
+ }
+ /* Will loop again if this linked list starts NULL
+ (for HV_ITERNEXT_WANTPLACEHOLDERS)
+ or if we run through it and find only placeholders. */
}
if (oldentry && HvLAZYDEL(hv)) { /* was deleted earlier? */
sv = newSVpvn ((char*)as_utf8, utf8_len);
SvUTF8_on (sv);
+ Safefree (as_utf8); /* bytes_to_utf8() allocates a new string */
} else {
sv = newSVpvn_share(HEK_KEY(hek),
(HEK_UTF8(hek) ? -HEK_LEN(hek) : HEK_LEN(hek)),
xhv->xhv_keys++; /* HvKEYS(hv)++ */
if (i) { /* initial entry? */
xhv->xhv_fill++; /* HvFILL(hv)++ */
- if (xhv->xhv_keys > xhv->xhv_max /* HvKEYS(hv) > HvMAX(hv) */)
+ if (xhv->xhv_keys > (IV)xhv->xhv_max /* HvKEYS(hv) > HvMAX(hv) */)
hsplit(PL_strtab);
}
}