diff options
author | Alan Burlison <Alan.Burlison@uk.sun.com> | 2003-11-20 10:34:30 +0000 |
---|---|---|
committer | Rafael Garcia-Suarez <rgarciasuarez@gmail.com> | 2003-11-20 12:04:46 +0000 |
commit | 3540d4cee8e95432ee25b1c5b90430e9473f2e95 (patch) | |
tree | a889cfa37f37207490972888ed020784c590f535 /hv.c | |
parent | 2baadb76de5602fd6919cac96dea41124e89d11a (diff) | |
download | perl-3540d4cee8e95432ee25b1c5b90430e9473f2e95.tar.gz |
promote hv_clear_placeholders to perl API
Message-ID: <3FBC98B6.6090909@sun.com>
p4raw-id: //depot/perl@21756
Diffstat (limited to 'hv.c')
-rw-r--r-- | hv.c | 55 |
1 files changed, 55 insertions, 0 deletions
@@ -1621,6 +1621,61 @@ Perl_hv_clear(pTHX_ HV *hv) 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) { |