sM |bool |hv_exists_common|HV* tb|SV* key_sv|const char* key|I32 klen|U32 hash
sM |HE* |hv_fetch_common|HV* tb|SV* key_sv|const char* key|I32 klen|int flags|int action|U32 hash
#endif
-END_EXTERN_C
+Apd |void |hv_clear_placeholders|HV* hb
+
+END_EXTERN_C
#define hv_fetch_common S_hv_fetch_common
#endif
#endif
+#define hv_clear_placeholders Perl_hv_clear_placeholders
#define ck_anoncode Perl_ck_anoncode
#define ck_bitop Perl_ck_bitop
#define ck_concat Perl_ck_concat
#define hv_fetch_common(a,b,c,d,e,f,g) S_hv_fetch_common(aTHX_ a,b,c,d,e,f,g)
#endif
#endif
+#define hv_clear_placeholders(a) Perl_hv_clear_placeholders(aTHX_ a)
#define ck_anoncode(a) Perl_ck_anoncode(aTHX_ a)
#define ck_bitop(a) Perl_ck_bitop(aTHX_ a)
#define ck_concat(a) Perl_ck_concat(aTHX_ a)
Perl_PerlIO_stderr
Perl_save_set_svflags
Perl_hv_assert
+Perl_hv_clear_placeholders
HvREHASH_off(hv);
}
+/*
+=for apidoc hv_clear_placeholders
+
+Clears any placeholders from a hash. If a restricted hash has any of its keys
+marked as readonly and the key is subsequently deleted, the key is not actually
+deleted but is marked by assigning it a value of &PL_sv_placeholder. This tags
+it so it will be ignored by future operations such as iterating over the hash,
+but will still allow the hash to have a value reaasigned to the key at some
+future point. This function clears any such placeholder keys from the hash.
+See Hash::Util::lock_keys() for an example of its use.
+
+=cut
+*/
+
+void
+Perl_hv_clear_placeholders(pTHX_ HV *hv)
+{
+ I32 items;
+ items = (I32)HvPLACEHOLDERS(hv);
+ if (items) {
+ HE *entry;
+ I32 riter = HvRITER(hv);
+ HE *eiter = HvEITER(hv);
+ hv_iterinit(hv);
+ /* This may look suboptimal with the items *after* the iternext, but
+ it's quite deliberate. We only get here with items==0 if we've
+ just deleted the last placeholder in the hash. If we've just done
+ that then it means that the hash is in lazy delete mode, and the
+ HE is now only referenced in our iterator. If we just quit the loop
+ and discarded our iterator then the HE leaks. So we do the && the
+ other way to ensure iternext is called just one more time, which
+ has the side effect of triggering the lazy delete. */
+ while ((entry = hv_iternext_flags(hv, HV_ITERNEXT_WANTPLACEHOLDERS))
+ && items) {
+ SV *val = hv_iterval(hv, entry);
+
+ if (val == &PL_sv_placeholder) {
+
+ /* It seems that I have to go back in the front of the hash
+ API to delete a hash, even though I have a HE structure
+ pointing to the very entry I want to delete, and could hold
+ onto the previous HE that points to it. And it's easier to
+ go in with SVs as I can then specify the precomputed hash,
+ and don't have fun and games with utf8 keys. */
+ SV *key = hv_iterkeysv(entry);
+
+ hv_delete_ent (hv, key, G_DISCARD, HeHASH(entry));
+ items--;
+ }
+ }
+ HvRITER(hv) = riter;
+ HvEITER(hv) = eiter;
+ }
+}
+
STATIC void
S_hfreeentries(pTHX_ HV *hv)
{
=for hackers
Found in file hv.c
+=item hv_clear_placeholders
+
+Clears any placeholders from a hash. If a restricted hash has any of its keys
+marked as readonly and the key is subsequently deleted, the key is not actually
+deleted but is marked by assigning it a value of &PL_sv_placeholder. This tags
+it so it will be ignored by future operations such as iterating over the hash,
+but will still allow the hash to have a value reaasigned to the key at some
+future point. This function clears any such placeholder keys from the hash.
+See Hash::Util::lock_keys() for an example of its use.
+
+ void hv_clear_placeholders(HV* hb)
+
+=for hackers
+Found in file hv.c
+
=item hv_delete
Deletes a key/value pair in the hash. The value SV is removed from the
STATIC bool S_hv_exists_common(pTHX_ HV* tb, SV* key_sv, const char* key, I32 klen, U32 hash);
STATIC HE* S_hv_fetch_common(pTHX_ HV* tb, SV* key_sv, const char* key, I32 klen, int flags, int action, U32 hash);
#endif
-END_EXTERN_C
+PERL_CALLCONV void Perl_hv_clear_placeholders(pTHX_ HV* hb);
+
+END_EXTERN_C
XSRETURN_UNDEF; /* Can't happen. */
}
-/* Maybe this should return the number of placeholders found in scalar context,
- and a list of them in list context. */
XS(XS_Internals_hv_clear_placehold)
{
dXSARGS;
HV *hv = (HV *) SvRV(ST(0));
-
- /* I don't care how many parameters were passed in, but I want to avoid
- the unused variable warning. */
-
- items = (I32)HvPLACEHOLDERS(hv);
-
- if (items) {
- HE *entry;
- I32 riter = HvRITER(hv);
- HE *eiter = HvEITER(hv);
- hv_iterinit(hv);
- /* This may look suboptimal with the items *after* the iternext, but
- it's quite deliberate. We only get here with items==0 if we've
- just deleted the last placeholder in the hash. If we've just done
- that then it means that the hash is in lazy delete mode, and the
- HE is now only referenced in our iterator. If we just quit the loop
- and discarded our iterator then the HE leaks. So we do the && the
- other way to ensure iternext is called just one more time, which
- has the side effect of triggering the lazy delete. */
- while ((entry = hv_iternext_flags(hv, HV_ITERNEXT_WANTPLACEHOLDERS))
- && items) {
- SV *val = hv_iterval(hv, entry);
-
- if (val == &PL_sv_placeholder) {
-
- /* It seems that I have to go back in the front of the hash
- API to delete a hash, even though I have a HE structure
- pointing to the very entry I want to delete, and could hold
- onto the previous HE that points to it. And it's easier to
- go in with SVs as I can then specify the precomputed hash,
- and don't have fun and games with utf8 keys. */
- SV *key = hv_iterkeysv(entry);
-
- hv_delete_ent (hv, key, G_DISCARD, HeHASH(entry));
- items--;
- }
- }
- HvRITER(hv) = riter;
- HvEITER(hv) = eiter;
- }
-
+ if (items != 1)
+ Perl_croak(aTHX_ "Usage: UNIVERSAL::hv_clear_placeholders(hv)");
+ hv_clear_placeholders(hv);
XSRETURN(0);
}