See L<perlguts/"Understanding the Magic of Tied Hashes and Arrays"> for more
information on how to use this function on tied hashes.
-=cut
-*/
-
-SV**
-Perl_hv_store(pTHX_ HV *hv, const char *key, I32 klen_i32, SV *val, U32 hash)
-{
- HE *hek;
- STRLEN klen;
- int flags;
-
- if (klen_i32 < 0) {
- klen = -klen_i32;
- flags = HVhek_UTF8;
- } else {
- klen = klen_i32;
- flags = 0;
- }
- hek = hv_fetch_common (hv, NULL, key, klen, flags,
- (HV_FETCH_ISSTORE|HV_FETCH_JUST_SV), val, hash);
- return hek ? &HeVAL(hek) : NULL;
-}
-
-/* XXX This looks like an ideal candidate to inline */
-SV**
-Perl_hv_store_flags(pTHX_ HV *hv, const char *key, I32 klen, SV *val,
- register U32 hash, int flags)
-{
- HE * const hek = hv_fetch_common (hv, NULL, key, klen, flags,
- (HV_FETCH_ISSTORE|HV_FETCH_JUST_SV), val, hash);
- return hek ? &HeVAL(hek) : NULL;
-}
-
-/*
=for apidoc hv_store_ent
Stores C<val> in a hash. The hash key is specified as C<key>. The C<hash>
See L<perlguts/"Understanding the Magic of Tied Hashes and Arrays"> for more
information on how to use this function on tied hashes.
-=cut
-*/
-
-/* XXX This looks like an ideal candidate to inline */
-HE *
-Perl_hv_store_ent(pTHX_ HV *hv, SV *keysv, SV *val, U32 hash)
-{
- return hv_fetch_common(hv, keysv, NULL, 0, 0, HV_FETCH_ISSTORE, val, hash);
-}
-
-/*
=for apidoc hv_exists
Returns a boolean indicating whether the specified hash key exists. The
C<klen> is the length of the key.
-=cut
-*/
-
-bool
-Perl_hv_exists(pTHX_ HV *hv, const char *key, I32 klen_i32)
-{
- STRLEN klen;
- int flags;
-
- if (klen_i32 < 0) {
- klen = -klen_i32;
- flags = HVhek_UTF8;
- } else {
- klen = klen_i32;
- flags = 0;
- }
- return hv_fetch_common(hv, NULL, key, klen, flags, HV_FETCH_ISEXISTS, 0, 0)
- ? TRUE : FALSE;
-}
-
-/*
=for apidoc hv_fetch
Returns the SV which corresponds to the specified key in the hash. The
See L<perlguts/"Understanding the Magic of Tied Hashes and Arrays"> for more
information on how to use this function on tied hashes.
-=cut
-*/
-
-SV**
-Perl_hv_fetch(pTHX_ HV *hv, const char *key, I32 klen_i32, I32 lval)
-{
- HE *hek;
- STRLEN klen;
- int flags;
-
- if (klen_i32 < 0) {
- klen = -klen_i32;
- flags = HVhek_UTF8;
- } else {
- klen = klen_i32;
- flags = 0;
- }
- hek = hv_fetch_common (hv, NULL, key, klen, flags,
- lval ? (HV_FETCH_JUST_SV | HV_FETCH_LVALUE) : HV_FETCH_JUST_SV,
- NULL, 0);
- return hek ? &HeVAL(hek) : NULL;
-}
-
-/*
=for apidoc hv_exists_ent
Returns a boolean indicating whether the specified hash key exists. C<hash>
=cut
*/
-/* XXX This looks like an ideal candidate to inline */
-bool
-Perl_hv_exists_ent(pTHX_ HV *hv, SV *keysv, U32 hash)
-{
- return hv_fetch_common(hv, keysv, NULL, 0, 0, HV_FETCH_ISEXISTS, 0, hash)
- ? TRUE : FALSE;
-}
-
/* returns an HE * structure with the all fields set */
/* note that hent_val will be a mortal sv for MAGICAL hashes */
/*
=cut
*/
-HE *
-Perl_hv_fetch_ent(pTHX_ HV *hv, SV *keysv, I32 lval, register U32 hash)
+/* Common code for hv_delete()/hv_exists()/hv_fetch()/hv_store() */
+void *
+Perl_hv_common_key_len(pTHX_ HV *hv, const char *key, I32 klen_i32,
+ const int action, SV *val, const U32 hash)
{
- return hv_fetch_common(hv, keysv, NULL, 0, 0,
- (lval ? HV_FETCH_LVALUE : 0), NULL, hash);
+ STRLEN klen;
+ int flags;
+
+ if (klen_i32 < 0) {
+ klen = -klen_i32;
+ flags = HVhek_UTF8;
+ } else {
+ klen = klen_i32;
+ flags = 0;
+ }
+ return hv_common(hv, NULL, key, klen, flags, action, val, hash);
}
-STATIC HE *
-S_hv_fetch_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen,
- int flags, int action, SV *val, register U32 hash)
+void *
+Perl_hv_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen,
+ int flags, int action, SV *val, register U32 hash)
{
dVAR;
XPVHV* xhv;
SV *sv;
bool is_utf8;
int masked_flags;
+ const int return_svp = action & HV_FETCH_JUST_SV;
if (!hv)
return NULL;
+ if (SvTYPE(hv) == SVTYPEMASK)
+ return NULL;
+
+ assert(SvTYPE(hv) == SVt_PVHV);
if (SvSMAGICAL(hv) && SvGMAGICAL(hv) && !(action & HV_DISABLE_UVAR_XKEY)) {
MAGIC* mg;
}
if (action & HV_DELETE) {
- return (HE *) hv_delete_common(hv, keysv, key, klen,
- flags | (is_utf8 ? HVhek_UTF8 : 0),
- action, hash);
+ return (void *) hv_delete_common(hv, keysv, key, klen,
+ flags | (is_utf8 ? HVhek_UTF8 : 0),
+ action, hash);
}
xhv = (XPVHV*)SvANY(hv);
if (SvRMAGICAL(hv) && !(action & (HV_FETCH_ISSTORE|HV_FETCH_ISEXISTS))) {
if ( mg_find((SV*)hv, PERL_MAGIC_tied) || SvGMAGICAL((SV*)hv))
{
- /* XXX should be able to skimp on the HE/HEK here when
+ /* FIXME should be able to skimp on the HE/HEK here when
HV_FETCH_JUST_SV is true. */
if (!keysv) {
keysv = newSVpvn(key, klen);
if (flags & HVhek_FREEKEY)
Safefree(key);
- return entry;
+ if (return_svp) {
+ return entry ? (void *) &HeVAL(entry) : NULL;
+ }
+ return (void *) entry;
}
#ifdef ENV_IS_CASELESS
else if (mg_find((SV*)hv, PERL_MAGIC_env)) {
const char * const nkey = strupr(savepvn(key,klen));
/* Note that this fetch is for nkey (the uppercased
key) whereas the store is for key (the original) */
- entry = hv_fetch_common(hv, NULL, nkey, klen,
- HVhek_FREEKEY, /* free nkey */
- 0 /* non-LVAL fetch */
- | HV_DISABLE_UVAR_XKEY,
- NULL /* no value */,
- 0 /* compute hash */);
- if (!entry && (action & HV_FETCH_LVALUE)) {
+ void *result = hv_common(hv, NULL, nkey, klen,
+ HVhek_FREEKEY, /* free nkey */
+ 0 /* non-LVAL fetch */
+ | HV_DISABLE_UVAR_XKEY
+ | return_svp,
+ NULL /* no value */,
+ 0 /* compute hash */);
+ if (!result && (action & HV_FETCH_LVALUE)) {
/* This call will free key if necessary.
Do it this way to encourage compiler to tail
call optimise. */
- entry = hv_fetch_common(hv, keysv, key, klen,
- flags,
- HV_FETCH_ISSTORE
- | HV_DISABLE_UVAR_XKEY,
- newSV(0), hash);
+ result = hv_common(hv, keysv, key, klen, flags,
+ HV_FETCH_ISSTORE
+ | HV_DISABLE_UVAR_XKEY
+ | return_svp,
+ newSV(0), hash);
} else {
if (flags & HVhek_FREEKEY)
Safefree(key);
}
- return entry;
+ return result;
}
}
#endif
/* This cast somewhat evil, but I'm merely using NULL/
not NULL to return the boolean exists.
And I know hv is not NULL. */
- return SvTRUE(svret) ? (HE *)hv : NULL;
+ return SvTRUE(svret) ? (void *)hv : NULL;
}
#ifdef ENV_IS_CASELESS
else if (mg_find((SV*)hv, PERL_MAGIC_env)) {
if (flags & HVhek_FREEKEY)
Safefree(key);
- return 0;
+ return NULL;
}
}
}
if (flags & HVhek_FREEKEY)
Safefree(key);
+ if (return_svp) {
+ return entry ? (void *) &HeVAL(entry) : NULL;
+ }
return entry;
}
#ifdef DYNAMIC_ENV_FETCH /* %ENV lookup? If so, try to fetch the value now */
if (env) {
sv = newSVpvn(env,len);
SvTAINTED_on(sv);
- return hv_fetch_common(hv, keysv, key, klen, flags,
- HV_FETCH_ISSTORE|HV_DISABLE_UVAR_XKEY, sv,
- hash);
+ return hv_common(hv, keysv, key, klen, flags,
+ HV_FETCH_ISSTORE|HV_DISABLE_UVAR_XKEY|return_svp,
+ sv, hash);
}
}
#endif
/* Not doing some form of store, so return failure. */
if (flags & HVhek_FREEKEY)
Safefree(key);
- return 0;
+ return NULL;
}
if (action & HV_FETCH_LVALUE) {
val = newSV(0);
However, as we replace the original key with the converted
key, this would result in a double conversion, which would show
up as a bug if the conversion routine is not idempotent. */
- return hv_fetch_common(hv, keysv, key, klen, flags,
- HV_FETCH_ISSTORE|HV_DISABLE_UVAR_XKEY, val,
- hash);
+ return hv_common(hv, keysv, key, klen, flags,
+ HV_FETCH_ISSTORE|HV_DISABLE_UVAR_XKEY|return_svp,
+ val, hash);
/* XXX Surely that could leak if the fetch-was-store fails?
Just like the hv_fetch. */
}
}
}
- return entry;
+ if (return_svp) {
+ return entry ? (void *) &HeVAL(entry) : NULL;
+ }
+ return (void *) entry;
}
STATIC void
The C<flags> value will normally be zero; if set to G_DISCARD then NULL
will be returned.
-=cut
-*/
-
-SV *
-Perl_hv_delete(pTHX_ HV *hv, const char *key, I32 klen_i32, I32 flags)
-{
- STRLEN klen;
- int k_flags;
-
- if (klen_i32 < 0) {
- klen = -klen_i32;
- k_flags = HVhek_UTF8;
- } else {
- klen = klen_i32;
- k_flags = 0;
- }
- return (SV *) hv_fetch_common(hv, NULL, key, klen, k_flags,
- flags | HV_DELETE, NULL, 0);
-}
-
-/*
=for apidoc hv_delete_ent
Deletes a key/value pair in the hash. The value SV is removed from the
=cut
*/
-/* XXX This looks like an ideal candidate to inline */
-SV *
-Perl_hv_delete_ent(pTHX_ HV *hv, SV *keysv, I32 flags, U32 hash)
-{
- return (SV *) hv_fetch_common(hv, keysv, NULL, 0, 0, flags | HV_DELETE,
- NULL, hash);
-}
-
STATIC SV *
S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen,
int k_flags, I32 d_flags, U32 hash)
if (needs_copy) {
SV *sv;
- entry = hv_fetch_common(hv, keysv, key, klen,
- k_flags & ~HVhek_FREEKEY,
- HV_FETCH_LVALUE|HV_DISABLE_UVAR_XKEY,
- NULL, hash);
+ entry = (HE *) hv_common(hv, keysv, key, klen,
+ k_flags & ~HVhek_FREEKEY,
+ HV_FETCH_LVALUE|HV_DISABLE_UVAR_XKEY,
+ NULL, hash);
sv = entry ? HeVAL(entry) : NULL;
if (sv) {
if (SvMAGICAL(sv)) {
}
}
-/*
-=for apidoc newHV
-
-Creates a new HV. The reference count is set to 1.
-
-=cut
-*/
-
-HV *
-Perl_newHV(pTHX)
-{
- register XPVHV* xhv;
- HV * const hv = (HV*)newSV_type(SVt_PVHV);
- xhv = (XPVHV*)SvANY(hv);
- assert(!SvOK(hv));
-#ifndef NODEFAULT_SHAREKEYS
- HvSHAREKEYS_on(hv); /* key-sharing on by default */
-#endif
-
- xhv->xhv_max = 7; /* HvMAX(hv) = 7 (start with 8 buckets) */
- xhv->xhv_fill = 0; /* HvFILL(hv) = 0 */
- return hv;
-}
-
HV *
Perl_newHVhv(pTHX_ HV *ohv)
{
hv_iterinit(ohv);
while ((entry = hv_iternext_flags(ohv, 0))) {
- hv_store_flags(hv, HeKEY(entry), HeKLEN(entry),
- newSVsv(HeVAL(entry)), HeHASH(entry),
- HeKFLAGS(entry));
+ (void)hv_store_flags(hv, HeKEY(entry), HeKLEN(entry),
+ newSVsv(HeVAL(entry)), HeHASH(entry),
+ HeKFLAGS(entry));
}
HvRITER_set(ohv, riter);
HvEITER_set(ohv, eiter);
SV *const sv = newSVsv(HeVAL(entry));
sv_magic(sv, NULL, PERL_MAGIC_hintselem,
(char *)newSVhek (HeKEY_hek(entry)), HEf_SVKEY);
- hv_store_flags(hv, HeKEY(entry), HeKLEN(entry),
- sv, HeHASH(entry), HeKFLAGS(entry));
+ (void)hv_store_flags(hv, HeKEY(entry), HeKLEN(entry),
+ sv, HeHASH(entry), HeKFLAGS(entry));
}
HvRITER_set(ohv, riter);
HvEITER_set(ohv, eiter);
if (!entry)
return;
val = HeVAL(entry);
- if (val && isGV(val) && GvCVu(val) && HvNAME_get(hv))
+ if (val && isGV(val) && isGV_with_GP(val) && GvCVu(val) && HvNAME_get(hv))
mro_method_changed_in(hv); /* deletion of method from stash */
SvREFCNT_dec(val);
if (HeKLEN(entry) == HEf_SVKEY) {
hfreeentries(hv);
if (name) {
- if(PL_stashcache)
- hv_delete(PL_stashcache, name, HvNAMELEN_get(hv), G_DISCARD);
+ if (PL_stashcache)
+ (void)hv_delete(PL_stashcache, name, HvNAMELEN_get(hv), G_DISCARD);
hv_name_set(hv, NULL, 0, 0);
}
SvFLAGS(hv) &= ~SVf_OOK;