0
  1   ˆl—Ðz¾”Êe¶…6 ¸Û7}LZ7ÿ¿„î¾_‹uÐb&=LV[(ÂÄ ?÷     package Hash::Util::FieldHash;

use 5.009004;
use strict;
use warnings;
use Scalar::Util qw( reftype);

our $VERSION = '1.20';

require Exporter;
our @ISA = qw(Exporter);
our %EXPORT_TAGS = (
    'all' => [ qw(
        fieldhash
        fieldhashes
        idhash
        idhashes
        id
        id_2obj
        register
    )],
);
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );

{
    require XSLoader;
    my %ob_reg; # private object registry
    sub _ob_reg { \ %ob_reg }
    XSLoader::load();
}

sub fieldhash (\%) {
    for ( shift ) {
        return unless ref() && reftype( $_) eq 'HASH';
        return $_ if Hash::Util::FieldHash::_fieldhash( $_, 0);
        return $_ if Hash::Util::FieldHash::_fieldhash( $_, 2) == 2;
        return;
    }
}

sub idhash (\%) {
    for ( shift ) {
        return unless ref() && reftype( $_) eq 'HASH';
        return $_ if Hash::Util::FieldHash::_fieldhash( $_, 0);
        return $_ if Hash::Util::FieldHash::_fieldhash( $_, 1) == 1;
        return;
    }
}

sub fieldhashes { map &fieldhash( $_), @_ }
sub idhashes { map &idhash( $_), @_ }

1;
__END__

=head1 NAME

Hash::Util::FieldHash - Support for Inside-Out Classes

=head1 SYNOPSIS

  ### Create fieldhashes
  use Hash::Util qw(fieldhash fieldhashes);

  # Create a single field hash
  fieldhash my %foo;

  # Create three at once...
  fieldhashes \ my(%foo, %bar, %baz);
  # ...or any number
  fieldhashes @hashrefs;

  ### Create an idhash and register it for garbage collection
  use Hash::Util::FieldHash qw(idhash register);
  idhash my %name;
  my $object = \ do { my $o };
  # register the idhash for garbage collection with $object
  register($object, \ %name);
  # the following entry will be deleted when $object goes out of scope
  $name{$object} = 'John Doe';

  ### Register an ordinary hash for garbage collection
  use Hash::Util::FieldHash qw(id register);
  my %name;
  my $object = \ do { my $o };
  # register the hash %name for garbage collection of $object's id
  register $object, \ %name;
  # the following entry will be deleted when $object goes out of scope
  $name{id $object} = 'John Doe';

=head1 FUNCTIONS

C<Hash::Util::FieldHash> offers a number of functions in support of
L<The Inside-out Technique> of class construction.

=over

=item id

    id($obj)

Returns the reference address of a reference $obj.  If $obj is
not a reference, returns $obj.

This function is a stand-in replacement for
L<Scalar::Util::refaddr|Scalar::Util/refaddr>,
that is, it returns
the reference address of its argument as a numeric value.  The only
difference is that C<refaddr()> returns C<undef> when given a
non-reference while C<id()> returns its argument unchanged.

C<id()> also uses a caching technique that makes it faster when
the id of an object is requested often, but slower if it is needed
only once or twice.

=item id_2obj

    $obj = id_2obj($id)

If C<$id> is the id of a registered object (see L</register>), returns
the object, otherwise an undefined value.  For registered objects this
is the inverse function of C<id()>.

=item register

    register($obj)
    register($obj, @hashrefs)

In the first form, registers an object to work with for the function
C<id_2obj()>.  In the second form, it additionally marks the given
hashrefs down for garbage collection.  This means that when the object
goes out of scope, any entries in the given hashes under the key of
C<id($obj)> will be deleted from the hashes.

It is a fatal error to register a non-reference $obj.  Any non-hashrefs
among the following arguments are silently ignored.

It is I<not> an error to register the same object multiple times with
varying sets of hashrefs.  Any hashrefs that are not registered yet
will be added, others ignored.

Registry also implies thread support.  When a new thread is created,
all references are replaced with new ones, including all objects.
If a hash uses the reference address of an object as a key, that
connection would be broken.  With a registered object, its id will
be updated in a