flags = is_utf8 ? HVhek_UTF8 : 0;
}
} else {
- is_utf8 = ((flags & HVhek_UTF8) ? TRUE : FALSE);
+ is_utf8 = cBOOL(flags & HVhek_UTF8);
}
if (action & HV_DELETE) {
if (!entry && SvREADONLY(hv) && !(action & HV_FETCH_ISEXISTS)) {
hv_notallowed(flags, key, klen,
- "Attempt to access disallowed key '%"SVf"' in"
+ "Attempt to access disallowed key '%" SVf "' in"
" a restricted hash");
}
if (!(action & (HV_FETCH_LVALUE|HV_FETCH_ISSTORE))) {
HeKEY_hek(entry) = save_hek_flags(key, klen, hash, flags);
HeVAL(entry) = val;
- if (!*oentry && SvOOK(hv)) {
- /* initial entry, and aux struct present. */
- struct xpvhv_aux *const aux = HvAUX(hv);
- if (aux->xhv_fill_lazy)
- ++aux->xhv_fill_lazy;
- }
-
#ifdef PERL_HASH_RANDOMIZE_KEYS
/* This logic semi-randomizes the insert order in a bucket.
* Either we insert into the top, or the slot below the top,
/*
=for apidoc hv_scalar
-Evaluates the hash in scalar context and returns the result. Handles magic
-when the hash is tied.
+Evaluates the hash in scalar context and returns the result.
+
+When the hash is tied dispatches through to the SCALAR method,
+otherwise returns a mortal SV containing the number of keys
+in the hash.
+
+Note, prior to 5.25 this function returned what is now
+returned by the hv_bucket_ratio() function.
=cut
*/
}
sv = sv_newmortal();
- if (HvTOTALKEYS((const HV *)hv))
+ sv_setuv(sv, HvUSEDKEYS(hv));
+
+ return sv;
+}
+
+/*
+=for apidoc hv_bucket_ratio
+
+If the hash is tied dispatches through to the SCALAR tied method,
+otherwise if the hash contains no keys returns 0, otherwise returns
+a mortal sv containing a string specifying the number of used buckets,
+followed by a slash, followed by the number of available buckets.
+
+This function is expensive, it must scan all of the buckets
+to determine which are used, and the count is NOT cached.
+In a large hash this could be a lot of buckets.
+
+=cut
+*/
+
+SV *
+Perl_hv_bucket_ratio(pTHX_ HV *hv)
+{
+ SV *sv;
+
+ PERL_ARGS_ASSERT_HV_BUCKET_RATIO;
+
+ if (SvRMAGICAL(hv)) {
+ MAGIC * const mg = mg_find((const SV *)hv, PERL_MAGIC_tied);
+ if (mg)
+ return magic_scalarpack(hv, mg);
+ }
+
+ sv = sv_newmortal();
+ if (HvUSEDKEYS((HV *)hv))
Perl_sv_setpvf(aTHX_ sv, "%ld/%ld",
(long)HvFILL(hv), (long)HvMAX(hv) + 1);
else
HE *entry;
HE **oentry;
HE **first_entry;
- bool is_utf8 = (k_flags & HVhek_UTF8) ? TRUE : FALSE;
+ bool is_utf8 = cBOOL(k_flags & HVhek_UTF8);
int masked_flags;
HEK *keysv_hek = NULL;
U8 mro_changes = 0; /* 1 = isa; 2 = package moved */
}
if (SvREADONLY(hv) && HeVAL(entry) && SvREADONLY(HeVAL(entry))) {
hv_notallowed(k_flags, key, klen,
- "Attempt to delete readonly key '%"SVf"' from"
+ "Attempt to delete readonly key '%" SVf "' from"
" a restricted hash");
}
if (k_flags & HVhek_FREEKEY)
sv_2mortal((SV *)gv)
);
}
- else if (klen == 3 && strnEQ(key, "ISA", 3))
+ else if (klen == 3 && strEQs(key, "ISA") && GvAV(gv)) {
+ AV *isa = GvAV(gv);
+ MAGIC *mg = mg_find((SV*)isa, PERL_MAGIC_isa);
+
mro_changes = 1;
+ if (mg) {
+ if (mg->mg_obj == (SV*)gv) {
+ /* This is the only stash this ISA was used for.
+ * The isaelem magic asserts if there's no
+ * isa magic on the array, so explicitly
+ * remove the magic on both the array and its
+ * elements. @ISA shouldn't be /too/ large.
+ */
+ SV **svp, **end;
+ strip_magic:
+ svp = AvARRAY(isa);
+ end = svp + AvFILLp(isa)+1;
+ while (svp < end) {
+ if (*svp)
+ mg_free_type(*svp, PERL_MAGIC_isaelem);
+ ++svp;
+ }
+ mg_free_type((SV*)GvAV(gv), PERL_MAGIC_isa);
+ }
+ else {
+ /* mg_obj is an array of stashes
+ Note that the array doesn't keep a reference
+ count on the stashes.
+ */
+ AV *av = (AV*)mg->mg_obj;
+ SV **svp, **arrayp;
+ SSize_t index;
+ SSize_t items;
+
+ assert(SvTYPE(mg->mg_obj) == SVt_PVAV);
+
+ /* remove the stash from the magic array */
+ arrayp = svp = AvARRAY(av);
+ items = AvFILLp(av) + 1;
+ if (items == 1) {
+ assert(*arrayp == (SV *)gv);
+ mg->mg_obj = NULL;
+ /* avoid a double free on the last stash */
+ AvFILLp(av) = -1;
+ /* The magic isn't MGf_REFCOUNTED, so release
+ * the array manually.
+ */
+ SvREFCNT_dec_NN(av);
+ goto strip_magic;
+ }
+ else {
+ while (items--) {
+ if (*svp == (SV*)gv)
+ break;
+ ++svp;
+ }
+ index = svp - arrayp;
+ assert(index >= 0 && index <= AvFILLp(av));
+ if (index < AvFILLp(av)) {
+ arrayp[index] = arrayp[AvFILLp(av)];
+ }
+ arrayp[AvFILLp(av)] = NULL;
+ --AvFILLp(av);
+ }
+ }
+ }
+ }
}
sv = d_flags & G_DISCARD ? HeVAL(entry) : sv_2mortal(HeVAL(entry));
HvPLACEHOLDERS(hv)++;
else {
*oentry = HeNEXT(entry);
- if(!*first_entry && SvOOK(hv)) {
- /* removed last entry, and aux struct present. */
- struct xpvhv_aux *const aux = HvAUX(hv);
- if (aux->xhv_fill_lazy)
- --aux->xhv_fill_lazy;
- }
if (SvOOK(hv) && entry == HvAUX(hv)->xhv_eiter /* HvEITER(hv) */)
HvLAZYDEL_on(hv);
else {
not_found:
if (SvREADONLY(hv)) {
hv_notallowed(k_flags, key, klen,
- "Attempt to delete disallowed key '%"SVf"' from"
+ "Attempt to delete disallowed key '%" SVf "' from"
" a restricted hash");
}
#ifdef PERL_HASH_RANDOMIZE_KEYS
dest->xhv_rand = (U32)PL_hash_rand_bits;
#endif
- /* For now, just reset the lazy fill counter.
- It would be possible to update the counter in the code below
- instead. */
- dest->xhv_fill_lazy = 0;
} else {
/* no existing aux structure, but we allocated space for one
* so initialize it properly. This unrolls hv_auxinit() a bit,
Frees the all the elements of a hash, leaving it empty.
The XS equivalent of C<%hash = ()>. See also L</hv_undef>.
-If any destructors are triggered as a result, the hv itself may
-be freed.
+See L</av_clear> for a note about the hash possibly being invalid on
+return.
=cut
*/
Perl_hv_clear(pTHX_ HV *hv)
{
dVAR;
+ SSize_t orig_ix;
+
XPVHV* xhv;
if (!hv)
return;
xhv = (XPVHV*)SvANY(hv);
- ENTER;
- SAVEFREESV(SvREFCNT_inc_simple_NN(hv));
+ /* avoid hv being freed when calling destructors below */
+ EXTEND_MORTAL(1);
+ PL_tmps_stack[++PL_tmps_ix] = SvREFCNT_inc_simple_NN(hv);
+ orig_ix = PL_tmps_ix;
if (SvREADONLY(hv) && HvARRAY(hv) != NULL) {
/* restricted hash: convert all keys to placeholders */
STRLEN i;
if (SvREADONLY(HeVAL(entry))) {
SV* const keysv = hv_iterkeysv(entry);
Perl_croak_nocontext(
- "Attempt to delete readonly key '%"SVf"' from a restricted hash",
+ "Attempt to delete readonly key '%" SVf "' from a restricted hash",
(void*)keysv);
}
SvREFCNT_dec_NN(HeVAL(entry));
mro_isa_changed_in(hv);
HvEITER_set(hv, NULL);
}
- LEAVE;
+ /* disarm hv's premature free guard */
+ if (LIKELY(PL_tmps_ix == orig_ix))
+ PL_tmps_ix--;
+ else
+ PL_tmps_stack[orig_ix] = &PL_sv_undef;
+ SvREFCNT_dec_NN(hv);
}
/*
iter->xhv_last_rand = iter->xhv_rand;
#endif
}
- /* Reset any cached HvFILL() to "unknown". It's unlikely that anyone
- will actually call HvFILL() on a hash under destruction, so it
- seems pointless attempting to track the number of keys remaining.
- But if they do, we want to reset it again. */
- if (iter->xhv_fill_lazy)
- iter->xhv_fill_lazy = 0;
}
if (!((XPVHV*)SvANY(hv))->xhv_keys)
As well as freeing all the elements of the hash (like C<hv_clear()>), this
also frees any auxiliary data and storage associated with the hash.
-If any destructors are triggered as a result, the hv itself may
-be freed.
-
-See also L</hv_clear>.
+See L</av_clear> for a note about the hash possibly being invalid on
+return.
=cut
*/
{
XPVHV* xhv;
bool save;
+ SSize_t orig_ix;
if (!hv)
return;
- save = !!SvREFCNT(hv);
+ save = cBOOL(SvREFCNT(hv));
DEBUG_A(Perl_hv_assert(aTHX_ hv));
xhv = (XPVHV*)SvANY(hv);
if (PL_phase != PERL_PHASE_DESTRUCT && HvNAME(hv)) {
if (PL_stashcache) {
DEBUG_o(Perl_deb(aTHX_ "hv_undef_flags clearing PL_stashcache for '%"
- HEKf"'\n", HEKfARG(HvNAME_HEK(hv))));
+ HEKf "'\n", HEKfARG(HvNAME_HEK(hv))));
(void)hv_deletehek(PL_stashcache, HvNAME_HEK(hv), G_DISCARD);
}
hv_name_set(hv, NULL, 0, 0);
}
if (save) {
- ENTER;
- SAVEFREESV(SvREFCNT_inc_simple_NN(hv));
+ /* avoid hv being freed when calling destructors below */
+ EXTEND_MORTAL(1);
+ PL_tmps_stack[++PL_tmps_ix] = SvREFCNT_inc_simple_NN(hv);
+ orig_ix = PL_tmps_ix;
}
hfreeentries(hv);
if (SvOOK(hv)) {
mro_isa_changed_in(hv);
if (PL_stashcache) {
DEBUG_o(Perl_deb(aTHX_ "hv_undef_flags clearing PL_stashcache for effective name '%"
- HEKf"'\n", HEKfARG(HvENAME_HEK(hv))));
+ HEKf "'\n", HEKfARG(HvENAME_HEK(hv))));
(void)hv_deletehek(PL_stashcache, HvENAME_HEK(hv), G_DISCARD);
}
}
if (flags & HV_NAME_SETALL ? !!HvAUX(hv)->xhv_name_u.xhvnameu_name : !!name) {
if (name && PL_stashcache) {
DEBUG_o(Perl_deb(aTHX_ "hv_undef_flags clearing PL_stashcache for name '%"
- HEKf"'\n", HEKfARG(HvNAME_HEK(hv))));
+ HEKf "'\n", HEKfARG(HvNAME_HEK(hv))));
(void)hv_deletehek(PL_stashcache, HvNAME_HEK(hv), G_DISCARD);
}
hv_name_set(hv, NULL, 0, flags);
if (SvRMAGICAL(hv))
mg_clear(MUTABLE_SV(hv));
- if (save) LEAVE;
+
+ if (save) {
+ /* disarm hv's premature free guard */
+ if (LIKELY(PL_tmps_ix == orig_ix))
+ PL_tmps_ix--;
+ else
+ PL_tmps_stack[orig_ix] = &PL_sv_undef;
+ SvREFCNT_dec_NN(hv);
+ }
}
/*
=for apidoc hv_fill
-Returns the number of hash buckets that
-happen to be in use. This function is
-wrapped by the macro C<HvFILL>.
+Returns the number of hash buckets that happen to be in use.
-Previously this value was always stored in the HV structure, which created an
-overhead on every hash (and pretty much every object) for something that was
-rarely used. Now we calculate it on demand the first
-time that it is needed, and cache it if that calculation
-is going to be costly to repeat. The cached
-value is updated by insertions and deletions, but (currently) discarded if
-the hash is split.
+This function is wrapped by the macro C<HvFILL>.
+
+As of perl 5.25 this function is used only for debugging
+purposes, and the number of used hash buckets is not
+in any way cached, thus this function can be costly
+to execute as it must iterate over all the buckets in the
+hash.
=cut
*/
{
STRLEN count = 0;
HE **ents = HvARRAY(hv);
- struct xpvhv_aux *aux = SvOOK(hv) ? HvAUX(hv) : NULL;
+ PERL_UNUSED_CONTEXT;
PERL_ARGS_ASSERT_HV_FILL;
/* No keys implies no buckets used.
if (HvTOTALKEYS(hv) < 2)
return HvTOTALKEYS(hv);
-#ifndef DEBUGGING
- if (aux && aux->xhv_fill_lazy)
- return aux->xhv_fill_lazy;
-#endif
-
if (ents) {
+ /* I wonder why we count down here...
+ * Is it some micro-optimisation?
+ * I would have thought counting up was better.
+ * - Yves
+ */
HE *const *const last = ents + HvMAX(hv);
count = last + 1 - ents;
--count;
} while (++ents <= last);
}
- if (aux) {
-#ifdef DEBUGGING
- if (aux->xhv_fill_lazy)
- assert(aux->xhv_fill_lazy == count);
-#endif
- aux->xhv_fill_lazy = count;
- } else if (HvMAX(hv) >= HV_FILL_THRESHOLD) {
- aux = hv_auxinit(hv);
- aux->xhv_fill_lazy = count;
- }
return count;
}
#ifdef PERL_HASH_RANDOMIZE_KEYS
iter->xhv_last_rand = iter->xhv_rand;
#endif
- iter->xhv_fill_lazy = 0;
iter->xhv_name_u.xhvnameu_name = 0;
iter->xhv_name_count = 0;
iter->xhv_backreferences = 0;
=for apidoc hv_iterinit
Prepares a starting point to traverse a hash table. Returns the number of
-keys in the hash (i.e. the same as C<HvUSEDKEYS(hv)>). The return value is
-currently only meaningful for hashes without tie magic.
+keys in the hash, including placeholders (i.e. the same as C<HvTOTALKEYS(hv)>).
+The return value is currently only meaningful for hashes without tie magic.
NOTE: Before version 5.004_65, C<hv_iterinit> used to return the number of
hash buckets that happen to be in use. If you still need that esoteric
hv_auxinit(hv);
}
- /* used to be xhv->xhv_fill before 5.004_65 */
+ /* note this includes placeholders! */
return HvTOTALKEYS(hv);
}
PERL_ARGS_ASSERT_HV_NAME_SET;
if (len > I32_MAX)
- Perl_croak(aTHX_ "panic: hv name too long (%"UVuf")", (UV) len);
+ Perl_croak(aTHX_ "panic: hv name too long (%" UVuf ")", (UV) len);
if (SvOOK(hv)) {
iter = HvAUX(hv);
PERL_ARGS_ASSERT_HV_ENAME_ADD;
if (len > I32_MAX)
- Perl_croak(aTHX_ "panic: hv name too long (%"UVuf")", (UV) len);
+ Perl_croak(aTHX_ "panic: hv name too long (%" UVuf ")", (UV) len);
PERL_HASH(hash, name, len);
PERL_ARGS_ASSERT_HV_ENAME_DELETE;
if (len > I32_MAX)
- Perl_croak(aTHX_ "panic: hv name too long (%"UVuf")", (UV) len);
+ Perl_croak(aTHX_ "panic: hv name too long (%" UVuf ")", (UV) len);
if (!SvOOK(hv)) return;
return;
}
if (
- count > 0 && (HEK_UTF8(*namep) || (flags & SVf_UTF8))
+ count > 0 && ((HEK_UTF8(*namep) || (flags & SVf_UTF8))
? hek_eq_pvn_flags(aTHX_ *namep, name, (I32)len, flags)
: (HEK_LEN(*namep) == (I32)len && memEQ(HEK_KEY(*namep), name, len))
+ )
) {
aux->xhv_name_count = -count;
}
SvUTF8_on(value);
break;
default:
- Perl_croak(aTHX_ "panic: refcounted_he_value bad flags %"UVxf,
+ Perl_croak(aTHX_ "panic: refcounted_he_value bad flags %" UVxf,
(UV)he->refcounted_he_data[0]);
}
return value;
U32 placeholders, max;
if (flags)
- Perl_croak(aTHX_ "panic: refcounted_he_chain_2hv bad flags %"UVxf,
+ Perl_croak(aTHX_ "panic: refcounted_he_chain_2hv bad flags %" UVxf,
(UV)flags);
/* We could chase the chain once to get an idea of the number of keys,
PERL_ARGS_ASSERT_REFCOUNTED_HE_FETCH_PVN;
if (flags & ~(REFCOUNTED_HE_KEY_UTF8|REFCOUNTED_HE_EXISTS))
- Perl_croak(aTHX_ "panic: refcounted_he_fetch_pvn bad flags %"UVxf,
+ Perl_croak(aTHX_ "panic: refcounted_he_fetch_pvn bad flags %" UVxf,
(UV)flags);
if (!chain)
goto ret;
}
else {
p++;
- *q = (char) TWO_BYTE_UTF8_TO_NATIVE(c, *p);
+ *q = (char) EIGHT_BIT_UTF8_TO_NATIVE(c, *p);
}
}
}
STRLEN keylen;
PERL_ARGS_ASSERT_REFCOUNTED_HE_FETCH_SV;
if (flags & REFCOUNTED_HE_KEY_UTF8)
- Perl_croak(aTHX_ "panic: refcounted_he_fetch_sv bad flags %"UVxf,
+ Perl_croak(aTHX_ "panic: refcounted_he_fetch_sv bad flags %" UVxf,
(UV)flags);
keypv = SvPV_const(key, keylen);
if (SvUTF8(key))
}
else {
p++;
- *q = (char) TWO_BYTE_UTF8_TO_NATIVE(c, *p);
+ *q = (char) EIGHT_BIT_UTF8_TO_NATIVE(c, *p);
}
}
}
STRLEN keylen;
PERL_ARGS_ASSERT_REFCOUNTED_HE_NEW_SV;
if (flags & REFCOUNTED_HE_KEY_UTF8)
- Perl_croak(aTHX_ "panic: refcounted_he_new_sv bad flags %"UVxf,
+ Perl_croak(aTHX_ "panic: refcounted_he_new_sv bad flags %" UVxf,
(UV)flags);
keypv = SvPV_const(key, keylen);
if (SvUTF8(key))
Save a label into a C<cop_hints_hash>.
You need to set flags to C<SVf_UTF8>
-for a utf-8 label.
+for a UTF-8 label.
=cut
*/