he = (HE*) Perl_get_arena(aTHX_ PERL_ARENA_SIZE);
heend = &he[PERL_ARENA_SIZE / sizeof(HE) - 1];
- PL_body_roots[HE_SVSLOT] = ++he;
+ PL_body_roots[HE_SVSLOT] = he;
while (he < heend) {
HeNEXT(he) = (HE*)(he + 1);
he++;
he = HeNEXT(he);
del_HE(ohe);
}
- PL_hv_fetch_ent_mh = Nullhe;
+ PL_hv_fetch_ent_mh = NULL;
}
#if defined(USE_ITHREADS)
HE *ret;
if (!e)
- return Nullhe;
+ return NULL;
/* look for it in the table first */
ret = (HE*)ptr_table_fetch(PL_ptr_table, e);
if (ret)
Newx(k, HEK_BASESIZE + sizeof(SV*), char);
HeKEY_hek(entry) = (HEK*)k;
}
- HeNEXT(entry) = Nullhe;
+ HeNEXT(entry) = NULL;
HeSVKEY_set(entry, keysv);
HeVAL(entry) = sv;
sv_upgrade(sv, SVt_PVLV);
}
TAINT_IF(save_taint);
- if (!HvARRAY(hv) && !needs_store) {
+ if (!needs_store) {
if (flags & HVhek_FREEKEY)
Safefree(key);
- return Nullhe;
+ return NULL;
}
#ifdef ENV_IS_CASELESS
else if (mg_find((SV*)hv, PERL_MAGIC_env)) {
masked_flags = (flags & HVhek_MASK);
#ifdef DYNAMIC_ENV_FETCH
- if (!HvARRAY(hv)) entry = Null(HE*);
+ if (!HvARRAY(hv)) entry = NULL;
else
#endif
{
{
const HE *counter = HeNEXT(entry);
- xhv->xhv_keys++; /* HvKEYS(hv)++ */
+ xhv->xhv_keys++; /* HvTOTALKEYS(hv)++ */
if (!counter) { /* initial entry? */
xhv->xhv_fill++; /* HvFILL(hv)++ */
} else if (xhv->xhv_keys > (IV)xhv->xhv_max) {
return NULL;
}
if (SvREADONLY(hv) && HeVAL(entry) && SvREADONLY(HeVAL(entry))) {
- S_hv_notallowed(aTHX_ k_flags, key, klen,
+ hv_notallowed(k_flags, key, klen,
"Attempt to delete readonly key '%"SVf"' from"
" a restricted hash");
}
HvLAZYDEL_on(hv);
else
hv_free_ent(hv, entry);
- xhv->xhv_keys--; /* HvKEYS(hv)-- */
+ xhv->xhv_keys--; /* HvTOTALKEYS(hv)-- */
if (xhv->xhv_keys == 0)
HvHASKFLAGS_off(hv);
}
return sv;
}
if (SvREADONLY(hv)) {
- S_hv_notallowed(aTHX_ k_flags, key, klen,
+ hv_notallowed(k_flags, key, klen,
"Attempt to delete disallowed key '%"SVf"' from"
" a restricted hash");
}
return hv;
}
+/* A rather specialised version of newHVhv for copying %^H, ensuring all the
+ magic stays on it. */
+HV *
+Perl_hv_copy_hints_hv(pTHX_ HV *const ohv)
+{
+ HV * const hv = newHV();
+ STRLEN hv_fill;
+
+ if (ohv && (hv_fill = HvFILL(ohv))) {
+ STRLEN hv_max = HvMAX(ohv);
+ HE *entry;
+ const I32 riter = HvRITER_get(ohv);
+ HE * const eiter = HvEITER_get(ohv);
+
+ while (hv_max && hv_max + 1 >= hv_fill * 2)
+ hv_max = hv_max / 2;
+ HvMAX(hv) = hv_max;
+
+ hv_iterinit(ohv);
+ while ((entry = hv_iternext_flags(ohv, 0))) {
+ 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));
+ }
+ HvRITER_set(ohv, riter);
+ HvEITER_set(ohv, eiter);
+ }
+ hv_magic(hv, NULL, PERL_MAGIC_hints);
+ return hv;
+}
+
void
Perl_hv_free_ent(pTHX_ HV *hv, register HE *entry)
{
Perl_hv_clear_placeholders(pTHX_ HV *hv)
{
dVAR;
- I32 items = (I32)HvPLACEHOLDERS_get(hv);
+ const U32 items = (U32)HvPLACEHOLDERS_get(hv);
+
+ if (items)
+ clear_placeholders(hv, items);
+}
+
+static void
+S_clear_placeholders(pTHX_ HV *hv, U32 items)
+{
+ dVAR;
I32 i;
if (items == 0)
hv_free_ent(hv, entry);
}
iter->xhv_riter = -1; /* HvRITER(hv) = -1 */
- iter->xhv_eiter = Null(HE*); /* HvEITER(hv) = Null(HE*) */
+ iter->xhv_eiter = NULL; /* HvEITER(hv) = NULL */
/* There are now no allocated pointers in the aux structure. */
iter = HvAUX(hv);
iter->xhv_riter = -1; /* HvRITER(hv) = -1 */
- iter->xhv_eiter = Null(HE*); /* HvEITER(hv) = Null(HE*) */
+ iter->xhv_eiter = NULL; /* HvEITER(hv) = NULL */
iter->xhv_name = 0;
iter->xhv_backreferences = 0;
return iter;
hv_free_ent(hv, entry);
}
iter->xhv_riter = -1; /* HvRITER(hv) = -1 */
- iter->xhv_eiter = Null(HE*); /* HvEITER(hv) = Null(HE*) */
+ iter->xhv_eiter = NULL; /* HvEITER(hv) = NULL */
} else {
hv_auxinit(hv);
}
}
void
-Perl_hv_name_set(pTHX_ HV *hv, const char *name, I32 len, int flags)
+Perl_hv_name_set(pTHX_ HV *hv, const char *name, U32 len, U32 flags)
{
dVAR;
struct xpvhv_aux *iter;
PERL_UNUSED_ARG(flags);
+ if (len > I32_MAX)
+ Perl_croak(aTHX_ "panic: hv name too long (%"UVuf")", (UV) len);
+
if (SvOOK(hv)) {
iter = HvAUX(hv);
if (iter->xhv_name) {
AV **
Perl_hv_backreferences_p(pTHX_ HV *hv) {
struct xpvhv_aux * const iter = SvOOK(hv) ? HvAUX(hv) : hv_auxinit(hv);
+ PERL_UNUSED_CONTEXT;
return &(iter->xhv_backreferences);
}
magic_nextpack((SV*) hv,mg,key);
if (SvOK(key)) {
/* force key to stay around until next time */
- HeSVKEY_set(entry, SvREFCNT_inc(key));
+ HeSVKEY_set(entry, SvREFCNT_inc_simple_NN(key));
return entry; /* beware, hent_val is not set */
}
if (HeVAL(entry))
SvREFCNT_dec(HeVAL(entry));
Safefree(HeKEY_hek(entry));
del_HE(entry);
- iter->xhv_eiter = Null(HE*); /* HvEITER(hv) = Null(HE*) */
- return Null(HE*);
+ iter->xhv_eiter = NULL; /* HvEITER(hv) = NULL */
+ return NULL;
}
#ifdef DYNAMIC_ENV_FETCH /* set up %ENV for iteration */
if (!entry && SvRMAGICAL((SV*)hv) && mg_find((SV*)hv, PERL_MAGIC_env)) {
xhv->xhv_fill--; /* HvFILL(hv)-- */
}
Safefree(entry);
- xhv->xhv_keys--; /* HvKEYS(hv)-- */
+ xhv->xhv_keys--; /* HvTOTALKEYS(hv)-- */
}
}
HeNEXT(entry) = next;
*head = entry;
- xhv->xhv_keys++; /* HvKEYS(hv)++ */
+ xhv->xhv_keys++; /* HvTOTALKEYS(hv)++ */
if (!next) { /* initial entry? */
xhv->xhv_fill++; /* HvFILL(hv)++ */
} else if (xhv->xhv_keys > (IV)xhv->xhv_max /* HvKEYS(hv) > HvMAX(hv) */) {
}
/*
+=for apidoc refcounted_he_chain_2hv
+
+Generates an returns a C<HV *> by walking up the tree starting at the passed
+in C<struct refcounted_he *>.
+
+=cut
+*/
+HV *
+Perl_refcounted_he_chain_2hv(pTHX_ const struct refcounted_he *chain)
+{
+ HV *hv = newHV();
+ U32 placeholders = 0;
+ /* We could chase the chain once to get an idea of the number of keys,
+ and call ksplit. But for now we'll make a potentially inefficient
+ hash with only 8 entries in its array. */
+ const U32 max = HvMAX(hv);
+
+ if (!HvARRAY(hv)) {
+ char *array;
+ Newxz(array, PERL_HV_ARRAY_ALLOC_BYTES(max + 1), char);
+ HvARRAY(hv) = (HE**)array;
+ }
+
+ while (chain) {
+ const U32 hash = HEK_HASH(chain->refcounted_he_he.hent_hek);
+ HE **oentry = &((HvARRAY(hv))[hash & max]);
+ HE *entry = *oentry;
+
+ for (; entry; entry = HeNEXT(entry)) {
+ if (HeHASH(entry) == hash) {
+ goto next_please;
+ }
+ }
+ assert (!entry);
+ entry = new_HE();
+
+ HeKEY_hek(entry) = share_hek_hek(chain->refcounted_he_he.hent_hek);
+
+ HeVAL(entry) = chain->refcounted_he_he.he_valu.hent_val;
+ if (HeVAL(entry) == &PL_sv_placeholder)
+ placeholders++;
+ SvREFCNT_inc_void_NN(HeVAL(entry));
+
+ /* Link it into the chain. */
+ HeNEXT(entry) = *oentry;
+ if (!HeNEXT(entry)) {
+ /* initial entry. */
+ HvFILL(hv)++;
+ }
+ *oentry = entry;
+
+ HvTOTALKEYS(hv)++;
+
+ next_please:
+ chain = (struct refcounted_he *) chain->refcounted_he_he.hent_next;
+ }
+
+ if (placeholders) {
+ clear_placeholders(hv, placeholders);
+ HvTOTALKEYS(hv) -= placeholders;
+ }
+
+ /* We could check in the loop to see if we encounter any keys with key
+ flags, but it's probably not worth it, as this per-hash flag is only
+ really meant as an optimisation for things like Storable. */
+ HvHASKFLAGS_on(hv);
+ DEBUG_A(Perl_hv_assert(aTHX_ hv));
+
+ return hv;
+}
+
+/*
+=for apidoc refcounted_he_new
+
+Creates a new C<struct refcounted_he>. Assumes ownership of one reference
+to I<value>. As S<key> is copied into a shared hash key, all references remain
+the property of the caller. The C<struct refcounted_he> is returned with a
+reference count of 1.
+
+=cut
+*/
+
+struct refcounted_he *
+Perl_refcounted_he_new(pTHX_ struct refcounted_he *const parent,
+ SV *const key, SV *const value) {
+ struct refcounted_he *he;
+ U32 hash;
+ STRLEN len;
+ const char *p = SvPV_const(key, len);
+
+ PERL_HASH(hash, p, len);
+
+ Newx(he, 1, struct refcounted_he);
+
+ he->refcounted_he_he.hent_next = (HE *)parent;
+ he->refcounted_he_he.he_valu.hent_val = value;
+ he->refcounted_he_he.hent_hek
+ = share_hek(p, SvUTF8(key) ? -(I32)len : len, hash);
+ he->refcounted_he_refcnt = 1;
+
+ return he;
+}
+
+/*
+=for apidoc refcounted_he_free
+
+Decrements the reference count of the passed in C<struct refcounted_he *>
+by one. If the reference count reaches zero the structure's memory is freed,
+and C<refcounted_he_free> iterates onto the parent node.
+
+=cut
+*/
+
+void
+Perl_refcounted_he_free(pTHX_ struct refcounted_he *he) {
+ while (he) {
+ struct refcounted_he *copy;
+
+ if (--he->refcounted_he_refcnt)
+ return;
+
+ unshare_hek_or_pvn (he->refcounted_he_he.hent_hek, 0, 0, 0);
+ SvREFCNT_dec(he->refcounted_he_he.he_valu.hent_val);
+ copy = he;
+ he = (struct refcounted_he *) he->refcounted_he_he.hent_next;
+ Safefree(copy);
+ }
+}
+
+
+/*
+=for apidoc refcounted_he_dup
+
+Duplicates the C<struct refcounted_he *> for a new thread.
+
+=cut
+*/
+
+#if defined(USE_ITHREADS)
+struct refcounted_he *
+Perl_refcounted_he_dup(pTHX_ const struct refcounted_he *const he,
+ CLONE_PARAMS* param)
+{
+ struct refcounted_he *copy;
+
+ if (!he)
+ return NULL;
+
+ /* look for it in the table first */
+ copy = (struct refcounted_he *)ptr_table_fetch(PL_ptr_table, he);
+ if (copy)
+ return copy;
+
+ /* create anew and remember what it is */
+ Newx(copy, 1, struct refcounted_he);
+ ptr_table_store(PL_ptr_table, he, copy);
+
+ copy->refcounted_he_he.hent_next
+ = (HE *)Perl_refcounted_he_dup(aTHX_
+ (struct refcounted_he *)
+ he->refcounted_he_he.hent_next,
+ param);
+ copy->refcounted_he_he.he_valu.hent_val
+ = SvREFCNT_inc(sv_dup(he->refcounted_he_he.he_valu.hent_val, param));
+ copy->refcounted_he_he.hent_hek
+ = hek_dup(he->refcounted_he_he.hent_hek, param);
+ copy->refcounted_he_refcnt = he->refcounted_he_refcnt;
+ return copy;
+}
+
+/*
+=for apidoc refcounted_he_copy
+
+Copies a chain of C<struct refcounted_he *>. Used by C<pp_entereval>.
+
+=cut
+*/
+
+struct refcounted_he *
+Perl_refcounted_he_copy(pTHX_ const struct refcounted_he * he)
+{
+ struct refcounted_he *copy;
+ HEK *hek;
+ /* This is much easier to express recursively than iteratively. */
+ if (!he)
+ return NULL;
+
+ Newx(copy, 1, struct refcounted_he);
+ copy->refcounted_he_he.hent_next
+ = (HE *)Perl_refcounted_he_copy(aTHX_
+ (struct refcounted_he *)
+ he->refcounted_he_he.hent_next);
+ copy->refcounted_he_he.he_valu.hent_val
+ = newSVsv(he->refcounted_he_he.he_valu.hent_val);
+ hek = he->refcounted_he_he.hent_hek;
+ copy->refcounted_he_he.hent_hek
+ = share_hek(HEK_KEY(hek),
+ HEK_UTF8(hek) ? -(I32)HEK_LEN(hek) : HEK_LEN(hek),
+ HEK_HASH(hek));
+ copy->refcounted_he_refcnt = 1;
+ return copy;
+}
+#endif
+
+/*
=for apidoc hv_assert
Check that a hash is in an internally consistent state.
=cut
*/
+#ifdef DEBUGGING
+
void
Perl_hv_assert(pTHX_ HV *hv)
{
}
/* sanity check the keys */
if (HeSVKEY(entry)) {
- /* Don't know what to check on SV keys. */
+ /*EMPTY*/ /* Don't know what to check on SV keys. */
} else if (HeKUTF8(entry)) {
withflags++;
if (HeKWASUTF8(entry)) {
HvEITER_set(hv, eiter);
}
+#endif
+
/*
* Local variables:
* c-indentation-style: bsd