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

📄 hash::util::fieldhash.3

📁 视频监控网络部分的协议ddns,的模块的实现代码,请大家大胆指正.
💻 3
📖 第 1 页 / 共 3 页
字号:
With \fIinside-out\fR classes, each class declares a (typically lexical)hash for each field it wants to use.  The reference address of anobject is used as the hash key.  By definition, the reference addressis unique to each object so this guarantees a place for each field thatis private to the class and unique to each object.  See Name_id in\&\*(L"Example 1\*(R" for a simple example..PPIn comparison to the standard implementation where the object is ahash and the fields correspond to hash keys, here the fields correspondto hashes, and the object determines the hash key.  Thus the hashesappear to be turned \fIinside out\fR..PPThe body of an object is never examined by an inside-out class, onlyits reference address is used.  This allows for the body of an actualobject to be \fIanything at all\fR while the object methods of the classstill work as designed.  This is a key feature of inside-out classes..Sh "Problems of Inside-out".IX Subsection "Problems of Inside-out"Inside-out classes give us freedom of inheritance, but as usual thereis a price..PPMost obviously, there is the necessity of retrieving the referenceaddress of an object for each data access.  It's a minor inconvenience,but it does clutter the code..PPMore important (and less obvious) is the necessity of garbagecollection.  When a normal object dies, anything stored in theobject body is garbage-collected by perl.  With inside-out objects,Perl knows nothing about the data stored in field hashes by a class,but these must be deleted when the object goes out of scope.  Thusthe class must provide a \f(CW\*(C`DESTROY\*(C'\fR method to take care of that..PPIn the presence of multiple classes it can be non-trivialto make sure that every relevant destructor is called forevery object.  Perl calls the first one it finds on theinheritance tree (if any) and that's it..PPA related issue is thread-safety.  When a new thread is created,the Perl interpreter is cloned, which implies that all referenceaddresses in use will be replaced with new ones.  Thus, if a classtries to access a field of a cloned object its (cloned) data willstill be stored under the now invalid reference address of theoriginal in the parent thread.  A general \f(CW\*(C`CLONE\*(C'\fR method mustbe provided to re-establish the association..Sh "Solutions".IX Subsection "Solutions"\&\f(CW\*(C`Hash::Util::FieldHash\*(C'\fR addresses these issues on severallevels..PPThe \f(CW\*(C`id()\*(C'\fR function is provided in addition to theexisting \f(CW\*(C`Scalar::Util::refaddr()\*(C'\fR.  Besides its short nameit can be a little faster under some circumstances (and abit slower under others).  Benchmark if it matters.  Theworking of \f(CW\*(C`id()\*(C'\fR also allows the use of the class nameas a \fIgeneric object\fR as described further down..PPThe \f(CW\*(C`id()\*(C'\fR function is incorporated in \fIid hashes\fR in the sensethat it is called automatically on every key that is used withthe hash.  No explicit call is necessary..PPThe problems of garbage collection and thread safety are bothaddressed by the function \f(CW\*(C`register()\*(C'\fR.  It registers an objecttogether with any number of hashes.  Registry means that when theobject dies, an entry in any of the hashes under the referenceaddress of this object will be deleted.  This guarantees garbagecollection in these hashes.  It also means that on threadcloning the object's entries in registered hashes will bereplaced with updated entries whose key is the cloned object'sreference address.  Thus the object-data association becomesthread-safe..PPObject registry is best done when the object is initializedfor use with a class.  That way, garbage collection and threadsafety are established for every object and every field that isinitialized..PPFinally, \fIfield hashes\fR incorporate all these functions in onepackage.  Besides automatically calling the \f(CW\*(C`id()\*(C'\fR functionon every object used as a key, the object is registered withthe field hash on first use.  Classes based on field hashesare fully garbage-collected and thread safe without furthermeasures..Sh "More Problems".IX Subsection "More Problems"Another problem that occurs with inside-out classes is serialization.Since the object data is not in its usual place, standard routineslike \f(CW\*(C`Storable::freeze()\*(C'\fR, \f(CW\*(C`Storable::thaw()\*(C'\fR and \&\f(CW\*(C`Data::Dumper::Dumper()\*(C'\fR can't deal with it on their own.  Both\&\f(CW\*(C`Data::Dumper\*(C'\fR and \f(CW\*(C`Storable\*(C'\fR provide the necessary hooks tomake things work, but the functions or methods used by the hooksmust be provided by each inside-out class..PPA general solution to the serialization problem would require anotherlevel of registry, one that that associates \fIclasses\fR and fields.So far, the functions of \f(CW\*(C`Hash::Util::FieldHash\*(C'\fR are unaware ofany classes, which I consider a feature.  Therefore \f(CW\*(C`Hash::Util::FieldHash\*(C'\fRdoesn't address the serialization problems..Sh "The Generic Object".IX Subsection "The Generic Object"Classes based on the \f(CW\*(C`id()\*(C'\fR function (and hence classes based on\&\f(CW\*(C`idhash()\*(C'\fR and \f(CW\*(C`fieldhash()\*(C'\fR) show a peculiar behavior in thatthe class name can be used like an object.  Specifically, methodsthat set or read data associated with an object continue to work asclass methods, just as if the class name were an object, distinct fromall other objects, with its own data.  This object may be calledthe \fIgeneric object\fR of the class..PPThis works because field hashes respond to keys that are not referenceslike a normal hash would and use the string offered as the hash key.Thus, if a method is called as a class method, the field hash is presentedwith the class name instead of an object and blithely uses it as a key.Since the keys of real objects are decimal numbers, there is noconflict and the slot in the field hash can be used like any other.The \f(CW\*(C`id()\*(C'\fR function behaves correspondingly with respect to non-referencearguments..PPTwo possible uses (besides ignoring the property) come to mind.A singleton class could be implemented this using the generic object.If necessary, an \f(CW\*(C`init()\*(C'\fR method could die or ignore calls withactual objects (references), so only the generic object will ever exist..PPAnother use of the generic object would be as a template.  It isa convenient place to store class-specific defaults for variousfields to be used in actual object initialization..PPUsually, the feature can be entirely ignored.  Calling \fIobjectmethods\fR as \fIclass methods\fR normally leads to an error and isn't usedroutinely anywhere.  It may be a problem that this error isn'tindicated by a class with a generic object..Sh "How to use Field Hashes".IX Subsection "How to use Field Hashes"Traditionally, the definition of an inside-out class contains a bareblock inside which a number of lexical hashes are declared and thebasic accessor methods defined, usually through \f(CW\*(C`Scalar::Util::refaddr\*(C'\fR.Further methods may be defined outside this block.  There has to bea \s-1DESTROY\s0 method and, for thread support, a \s-1CLONE\s0 method..PPWhen field hashes are used, the basic structure remains the same.Each lexical hash will be made a field hash.  The call to \f(CW\*(C`refaddr\*(C'\fRcan be omitted from the accessor methods.  \s-1DESTROY\s0 and \s-1CLONE\s0 methodsare not necessary..PPIf you have an existing inside-out class, simply making all hashesfield hashes with no other change should make no difference.  Throughthe calls to \f(CW\*(C`refaddr\*(C'\fR or equivalent, the field hashes never get tosee a reference and work like normal hashes.  Your \s-1DESTROY\s0 (and\&\s-1CLONE\s0) methods are still needed..PPTo make the field hashes kick in, it is easiest to redefine \f(CW\*(C`refaddr\*(C'\fRas.PP.Vb 1\&    sub refaddr { shift }.Ve.PPinstead of importing it from \f(CW\*(C`Scalar::Util\*(C'\fR.  It should now be possibleto disable \s-1DESTROY\s0 and \s-1CLONE\s0.  Note that while it isn't disabled,\&\s-1DESTROY\s0 will be called before the garbage collection of field hashes,so it will be invoked with a functional object and will continue tofunction..PPIt is not desirable to import the functions \f(CW\*(C`fieldhash\*(C'\fR and/or\&\f(CW\*(C`fieldhashes\*(C'\fR into every class that is going to use them.  Theyare only used once to set up the class.  When the class is up and running,these functions serve no more purpose..PPIf there are only a few field hashes to declare, it is simplest to.PP.Vb 1\&    use Hash::Util::FieldHash;.Ve.PPearly and call the functions qualified:.PP.Vb 1\&    Hash::Util::FieldHash::fieldhash my %foo;.Ve.PPOtherwise, import the functions into a convenient package like\&\f(CW\*(C`HUF\*(C'\fR or, more general, \f(CW\*(C`Aux\*(C'\fR.PP.Vb 4\&    {\&        package Aux;\&        use Hash::Util::FieldHash \*(Aq:all\*(Aq;\&    }.Ve.PPand call.PP.Vb 1\&    Aux::fieldhash my %foo;.Ve.PPas needed..Sh "Garbage-Collected Hashes".IX Subsection "Garbage-Collected Hashes"Garbage collection in a field hash means that entries will \*(L"spontaneously\*(R"disappear when the object that created them disappears.  That must beborne in mind, especially when looping over a field hash.  If anythingyou do inside the loop could cause an object to go out of scope, arandom key may be deleted from the hash you are looping over.  Thatcan throw the loop iterator, so it's best to cache a consistent snapshotof the keys and/or values and loop over that.  You will still have tocheck that a cached entry still exists when you get to it..PPGarbage collection can be confusing when keys are created in a field hashfrom normal scalars as well as references.  Once a reference is \fIused\fR 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 constitute\&\fIuse\fR 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..SH "EXAMPLES".IX Header "EXAMPLES"The examples show a very simple class that implements a \fIname\fR, consistingof a first and last name (no middle initial).  The name class has fourmethods:.IP "\(bu" 4\&\f(CW\*(C`init()\*(C'\fR.SpAn object method that initializes the first and last name to itstwo arguments. If called as a class method, \f(CW\*(C`init()\*(C'\fR creates anobject in the given class and initializes that..IP "\(bu" 4\&\f(CW\*(C`first()\*(C'\fR.SpRetrieve the first name.IP "\(bu" 4\&\f(CW\*(C`last()\*(C'\fR.SpRetrieve the last name.IP "\(bu" 4\&\f(CW\*(C`name()\*(C'\fR.SpRetrieve the full name, the first and last name joined by a blank..PPThe examples show this class implemented with different levels ofsupport by \f(CW\*(C`Hash::Util::FieldHash\*(C'\fR.  All supported combinationsare shown.  The difference between implementations is often quitesmall.  The implementations are:.IP "\(bu" 4\&\f(CW\*(C`Name_hash\*(C'\fR.SpA conventional (not inside-out) implementation where an object isa hash that stores the field values, without support by\&\f(CW\*(C`Hash::Util::FieldHash\*(C'\fR.  This implementation doesn't allowarbitrary inheritance..IP "\(bu" 4\&\f(CW\*(C`Name_id\*(C'\fR.SpInside-out implementation based on the \f(CW\*(C`id()\*(C'\fR function.  It needsa \f(CW\*(C`DESTROY\*(C'\fR method.  For thread support a \f(CW\*(C`CLONE\*(C'\fR method (not shown)would also be needed.  Instead of \f(CW\*(C`Hash::Util::FieldHash::id()\*(C'\fR thefunction \f(CW\*(C`Scalar::Util::refaddr\*(C'\fR could be used with very littlefunctional difference.  This is the basic pattern of an inside-outclass..IP "\(bu" 4\&\f(CW\*(C`Name_idhash\*(C'\fR.SpIdhash-based inside-out implementation.  Like Name_id it needsa \f(CW\*(C`DESTROY\*(C'\fR method and would need \f(CW\*(C`CLONE\*(C'\fR for thread support..IP "\(bu" 4\&\f(CW\*(C`Name_id_reg\*(C'\fR.SpInside-out implementation based on the \f(CW\*(C`id()\*(C'\fR function with explicitobject registry.  No destructor is needed and objects are thread safe..IP "\(bu" 4\&\f(CW\*(C`Name_idhash_reg\*(C'\fR.SpIdhash-based inside-out implementation with explicit object registry.No destructor is needed and objects are thread safe..IP "\(bu" 4\&\f(CW\*(C`Name_fieldhash\*(C'\fR.SpFieldHash-based inside-out implementation.  Object registry happensautomatically.  No destructor is needed and objects are thread safe..PPThese examples are realized in the code below, which could be copiedto a file \fIExample.pm\fR..Sh "Example 1".IX Subsection "Example 1".Vb 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 \*(Aq \*(Aq => $n\->first, $n\->last;\&        }\&\&    }\&\&    {

⌨️ 快捷键说明

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