1 package # hide from the pauses
2 namespace::clean::_PP_OSE;
8 use Hash::Util::FieldHash 'fieldhash';
10 # Here we rely on a combination of several behaviors:
12 # * %^H is deallocated on scope exit, so any references to it disappear
13 # * A lost weakref in a fieldhash causes the corresponding key to be deleted
14 # * Deletion of a key on a tied hash triggers DELETE
16 # Therefore the DELETE of a tied fieldhash containing a %^H reference will
17 # be the hook to fire all our callbacks.
19 # The SUPER:: gimmick is there to ensure the fieldhash is cleaned up in a
20 # timely manner. When you call delete() in non-void context, you get a mortal
21 # scalar whose reference count decreases at the end of the current statement.
22 # During scope exit, ‘statement’ is not clearly defined, so more scope
23 # unwinding could happen before the mortal gets freed. Forcing the DELETE
24 # in void context localizes the life of the mortal scalar.
28 package namespace::clean::_TieHintHashFieldHash;
29 use base 'Tie::StdHash';
31 $_->() for @{ $_[0]->{$_[1]} };
32 shift->SUPER::DELETE(@_);
33 1; # put the preceding statement in void context so the free is immediate
37 sub on_scope_end (&) {
40 tie(%hh, 'namespace::clean::_TieHintHashFieldHash')
43 push @{ $hh{\%^H} ||= [] }, shift;