Apd |SV* |hv_iterkeysv |HE* entry
Apd |HE* |hv_iternext |HV* tb
Apd |SV* |hv_iternextsv |HV* hv|char** key|I32* retlen
-ApM |HE* |hv_iternext_flags|HV* tb|I32 flags
+ApMd |HE* |hv_iternext_flags|HV* tb|I32 flags
Apd |SV* |hv_iterval |HV* tb|HE* entry
Ap |void |hv_ksplit |HV* hv|IV newmax
Apd |void |hv_magic |HV* hv|GV* gv|int how
Returns entries from a hash iterator. See C<hv_iterinit>.
+You may call C<hv_delete> or C<hv_delete_ent> on the hash entry that the
+iterator currently points to, without losing your place or invalidating your
+iterator. Note that in this case the current entry is deleted from the hash
+with your iterator holding the last reference to it. Your iterator is flagged
+to free the entry on the next call to C<hv_iternext>, so you must not discard
+your iterator immediately else the entry will leak - call C<hv_iternext> to
+trigger the resource deallocation.
+
=cut
*/
}
/*
-XXX=for apidoc hv_iternext
-
-Returns entries from a hash iterator. See C<hv_iterinit>.
+=for apidoc hv_iternext_flags
+
+Returns entries from a hash iterator. See C<hv_iterinit> and C<hv_iternext>.
+The C<flags> value will normally be zero; if HV_ITERNEXT_WANTPLACEHOLDERS is
+set the placeholders keys (for restricted hashes) will be returned in addition
+to normal keys. By default placeholders are automatically skipped over.
+Currently a placeholder is implemented with a value that is literally
+<&Perl_sv_undef> (a regular C<undef> value is a normal read-write SV for which
+C<!SvOK> is false). Note that the implementation of placeholders and
+restricted hashes may change, and the implementation currently is
+insufficiently abstracted for any change to be tidy.
-XXX=cut
+=cut
*/
HE *
I32 riter = HvRITER(hv);
HE *eiter = HvEITER(hv);
hv_iterinit(hv);
- while (items
- && (entry
- = hv_iternext_flags(hv, HV_ITERNEXT_WANTPLACEHOLDERS))) {
+ /* 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_undef) {