⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fieldhash.pm

📁 source of perl for linux application,
💻 PM
📖 第 1 页 / 共 2 页
字号:
Garbage collection can be confusing when keys are created in a field hashfrom normal scalars as well as references.  Once a reference is I<used> witha field hash, the entry will be collected, even if it was later overwrittenwith a plain scalar key (every positive integer is a candidate).  Thisis true even if the original entry was deleted in the meantime.  In fact,deletion from a field hash, and also a test for existence constituteI<use> in this sense and create a liability to delete the entry whenthe reference goes out of scope.  If you happen to create an entrywith an identical key from a string or integer, that will be collectedinstead.  Thus, mixed use of references and plain scalars as field hashkeys is not entirely supported.=head1 EXAMPLESThe examples show a very simple class that implements a I<name>, consistingof a first and last name (no middle initial).  The name class has fourmethods:=over=item * C<init()>An object method that initializes the first and last name to itstwo arguments. If called as a class method, C<init()> creates anobject in the given class and initializes that.=item * C<first()>Retrieve the first name=item * C<last()>Retrieve the last name=item * C<name()>Retrieve the full name, the first and last name joined by a blank.=backThe examples show this class implemented with different levels ofsupport by C<Hash::Util::FieldHash>.  All supported combinationsare shown.  The difference between implementations is often quitesmall.  The implementations are:=over=item * C<Name_hash>A conventional (not inside-out) implementation where an object isa hash that stores the field values, without support byC<Hash::Util::FieldHash>.  This implementation doesn't allowarbitrary inheritance.=item * C<Name_id>Inside-out implementation based on the C<id()> function.  It needsa C<DESTROY> method.  For thread support a C<CLONE> method (not shown)would also be needed.  Instead of C<Hash::Util::FieldHash::id()> thefunction C<Scalar::Util::refaddr> could be used with very littlefunctional difference.  This is the basic pattern of an inside-outclass.=item * C<Name_idhash>Idhash-based inside-out implementation.  Like L<Name_id> it needsa C<DESTROY> method and would need C<CLONE> for thread support.=item * C<Name_id_reg>Inside-out implementation based on the C<id()> function with explicitobject registry.  No destructor is needed and objects are thread safe.=item * C<Name_idhash_reg>Idhash-based inside-out implementation with explicit object registry.No destructor is needed and objects are thread safe.=item * C<Name_fieldhash>FieldHash-based inside-out implementation.  Object registry happensautomatically.  No destructor is needed and objects are thread safe.=backThese examples are realized in the code below, which could be copiedto a file F<Example.pm>.=head2 Example 1    use strict; use warnings;    {        package Name_hash; # standard implementation: the object is a hash        sub init {            my $obj = shift;            my ($first, $last) = @_;            # create an object if called as class method            $obj = bless {}, $obj unless ref $obj;            $obj->{ first} = $first;            $obj->{ last} = $last;            $obj;        }        sub first { shift()->{ first} }        sub last { shift()->{ last} }        sub name {            my $n = shift;            join ' ' => $n->first, $n->last;        }    }    {        package Name_id;        use Hash::Util::FieldHash qw(id);        my (%first, %last);        sub init {            my $obj = shift;            my ($first, $last) = @_;            # create an object if called as class method            $obj = bless \ my $o, $obj unless ref $obj;            $first{ id $obj} = $first;            $last{ id $obj} = $last;            $obj;        }        sub first { $first{ id shift()} }        sub last { $last{ id shift()} }        sub name {            my $n = shift;            join ' ' => $n->first, $n->last;        }        sub DESTROY {            my $id = id shift;            delete $first{ $id};            delete $last{ $id};        }    }    {        package Name_idhash;        use Hash::Util::FieldHash;        Hash::Util::FieldHash::idhashes( \ my (%first, %last) );        sub init {            my $obj = shift;            my ($first, $last) = @_;            # create an object if called as class method            $obj = bless \ my $o, $obj unless ref $obj;            $first{ $obj} = $first;            $last{ $obj} = $last;            $obj;        }        sub first { $first{ shift()} }        sub last { $last{ shift()} }        sub name {            my $n = shift;            join ' ' => $n->first, $n->last;        }        sub DESTROY {            my $n = shift;            delete $first{ $n};            delete $last{ $n};        }    }    {        package Name_id_reg;        use Hash::Util::FieldHash qw(id register);        my (%first, %last);        sub init {            my $obj = shift;            my ($first, $last) = @_;            # create an object if called as class method            $obj = bless \ my $o, $obj unless ref $obj;            register( $obj, \ (%first, %last) );            $first{ id $obj} = $first;            $last{ id $obj} = $last;            $obj;        }        sub first { $first{ id shift()} }        sub last { $last{ id shift()} }        sub name {            my $n = shift;            join ' ' => $n->first, $n->last;        }    }    {        package Name_idhash_reg;        use Hash::Util::FieldHash qw(register);        Hash::Util::FieldHash::idhashes \ my (%first, %last);        sub init {            my $obj = shift;            my ($first, $last) = @_;            # create an object if called as class method            $obj = bless \ my $o, $obj unless ref $obj;            register( $obj, \ (%first, %last) );            $first{ $obj} = $first;            $last{ $obj} = $last;            $obj;        }        sub first { $first{ shift()} }        sub last { $last{ shift()} }        sub name {            my $n = shift;            join ' ' => $n->first, $n->last;        }    }    {        package Name_fieldhash;        use Hash::Util::FieldHash;        Hash::Util::FieldHash::fieldhashes \ my (%first, %last);        sub init {            my $obj = shift;            my ($first, $last) = @_;            # create an object if called as class method            $obj = bless \ my $o, $obj unless ref $obj;            $first{ $obj} = $first;            $last{ $obj} = $last;            $obj;        }        sub first { $first{ shift()} }        sub last { $last{ shift()} }        sub name {            my $n = shift;            join ' ' => $n->first, $n->last;        }    }    1;To exercise the various implementations the script L<below|/"Example 2"> canbe used.It sets up a class C<Name> that is a mirror of one of the implementationclasses C<Name_hash>, C<Name_id>, ..., C<Name_fieldhash>.  That determineswhich implementation is run.The script first verifies the function of the C<Name> class.In the second step, the free inheritability of the implementation(or lack thereof) is demonstrated.  For this purpose it constructsa class called C<NamedFile> which is a common subclass of C<Name> andthe standard class C<IO::File>.  This puts inheritability to the testbecause objects of C<IO::File> I<must> be globrefs.  Objects of C<NamedFile>should behave like a file opened for reading and also support the C<name()>method.  This class juncture works with exception of the C<Name_hash>implementation, where object initialization fails because of theincompatibility of object bodies.=head2 Example 2    use strict; use warnings; $| = 1;    use Example;    {        package Name;        use base 'Name_id';      # define here which implementation to run    }    # Verify that the base package works    my $n = Name->init(qw(Albert Einstein));    print $n->name, "\n";    print "\n";    # Create a named file handle (See definition below)    my $nf = NamedFile->init(qw(/tmp/x Filomena File));    # use as a file handle...    for ( 1 .. 3 ) {        my $l = <$nf>;        print "line $_: $l";    }    # ...and as a Name object    print "...brought to you by ", $nf->name, "\n";    exit;    # Definition of NamedFile    package NamedFile;    use base 'Name';    use base 'IO::File';    sub init {        my $obj = shift;        my ($file, $first, $last) = @_;        $obj = $obj->IO::File::new() unless ref $obj;        $obj->open($file) or die "Can't read '$file': $!";        $obj->Name::init($first, $last);    }    __END__=head1 GUTSTo make C<Hash::Util::FieldHash> work, there were two changes toF<perl> itself.  C<PERL_MAGIC_uvar> was made avalaible for hashes,and weak references now call uvar C<get> magic after a weakref has beencleared.  The first feature is used to make field hashes intercepttheir keys upon access.  The second one triggers garbage collection.=head2 The C<PERL_MAGIC_uvar> interface for hashesC<PERL_MAGIC_uvar> I<get> magic is called from C<hv_fetch_common> andC<hv_delete_common> through the function C<hv_magic_uvar_xkey>, whichdefines the interface.  The call happens for hashes with "uvar" magicif the C<ufuncs> structure has equal values in the C<uf_val> and C<uf_set>fields.  Hashes are unaffected if (and as long as) these fieldshold different values.Upon the call, the C<mg_obj> field will hold the hash key to be accessed.Upon return, the C<SV*> value in C<mg_obj> will be used in place of theoriginal key in the hash access.  The integer index value in the firstparameter will be the C<action> value from C<hv_fetch_common>, or -1if the call is from C<hv_delete_common>.This is a template for a function suitable for the C<uf_val> field ina C<ufuncs> structure for this call.  The C<uf_set> and C<uf_index>fields are irrelevant.    IV watch_key(pTHX_ IV action, SV* field) {        MAGIC* mg = mg_find(field, PERL_MAGIC_uvar);        SV* keysv = mg->mg_obj;        /* Do whatever you need to.  If you decide to           supply a different key newkey, return it like this        */        sv_2mortal(newkey);        mg->mg_obj = newkey;        return 0;    }=head2 Weakrefs call uvar magicWhen a weak reference is stored in an C<SV> that has "uvar" magic, C<set>magic is called after the reference has gone stale.  This hook can beused to trigger further garbage-collection activities associated withthe referenced object.=head2 How field hashes workThe three features of key hashes, I<key replacement>, I<thread support>,and I<garbage collection> are supported by a data structure calledthe I<object registry>.  This is a private hash where every objectis stored.  An "object" in this sense is any reference (blessed orunblessed) that has been used as a field hash key.The object registry keeps track of references that have been used asfield hash keys.  The keys are generated from the reference addresslike in a field hash (though the registry isn't a field hash).  Eachvalue is a weak copy of the original reference, stored in an C<SV> thatis itself magical (C<PERL_MAGIC_uvar> again).  The magical structureholds a list (another hash, really) of field hashes that the referencehas been used with.  When the weakref becomes stale, the magic isactivated and uses the list to delete the reference from all fieldhashes it has been used with.  After that, the entry is removed fromthe object registry itself.  Implicitly, that frees the magic structureand the storage it has been using.Whenever a reference is used as a field hash key, the object registryis checked and a new entry is made if necessary.  The field hash isthen added to the list of fields this reference has used.The object registry is also used to repair a field hash after threadcloning.  Here, the entire object registry is processed.  For everyreference found there, the field hashes it has used are visited andthe entry is updated.=head2 Internal function Hash::Util::FieldHash::_fieldhash    # test if %hash is a field hash    my $result = _fieldhash \ %hash, 0;    # make %hash a field hash    my $result = _fieldhash \ %hash, 1;C<_fieldhash> is the internal function used to create field hashes.It takes two arguments, a hashref and a mode.  If the mode is booleanfalse, the hash is not changed but tested if it is a field hash.  Ifthe hash isn't a field hash the return value is boolean false.  If itis, the return value indicates the mode of field hash.  When called witha boolean true mode, it turns the given hash into a field hash of thismode, returning the mode of the created field hash.  C<_fieldhash>does not erase the given hash.Currently there is only one type of field hash, and only the booleanvalue of the mode makes a difference, but that may change.=head1 AUTHORAnno Siegel (ANNO) wrote the xs code and the changes in perl properJerry Hedden (JDHEDDEN) made it faster=head1 COPYRIGHT AND LICENSECopyright (C) 2006-2007 by (Anno Siegel)This library is free software; you can redistribute it and/or modifyit under the same terms as Perl itself, either Perl version 5.8.7 or,at your option, any later version of Perl 5 you may have available.=cut

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -