{
    "content": [
        {
            "type": "text",
            "text": "# Hash::Util (info)\n\n## NAME\n\nHash::Util - A selection of general-utility hash subroutines\n\n## SYNOPSIS\n\n# Restricted hashes\nuse Hash::Util qw(\nfieldhash fieldhashes\nallkeys\nlockkeys unlockkeys\nlockvalue unlockvalue\nlockhash unlockhash\nlockkeysplus\nhashlocked hashunlocked\nhashreflocked hashrefunlocked\nhiddenkeys legalkeys\nlockrefkeys unlockrefkeys\nlockrefvalue unlockrefvalue\nlockhashref unlockhashref\nlockrefkeysplus\nhiddenrefkeys legalrefkeys\nhashseed hashvalue hvstore\nbucketstats bucketinfo bucketarray\nlockhashrecurse unlockhashrecurse\nlockhashrefrecurse unlockhashrefrecurse\nhashtraversalmask\n);\n%hash = (foo => 42, bar => 23);\n# Ways to restrict a hash\nlockkeys(%hash);\nlockkeys(%hash, @keyset);\nlockkeysplus(%hash, @additionalkeys);\n# Ways to inspect the properties of a restricted hash\nmy @legal = legalkeys(%hash);\nmy @hidden = hiddenkeys(%hash);\nmy $ref = allkeys(%hash,@keys,@hidden);\nmy $islocked = hashlocked(%hash);\n# Remove restrictions on the hash\nunlockkeys(%hash);\n# Lock individual values in a hash\nlockvalue  (%hash, 'foo');\nunlockvalue(%hash, 'foo');\n# Ways to change the restrictions on both keys and values\nlockhash  (%hash);\nunlockhash(%hash);\nmy $hashesarerandomised = hashseed() !~ /^\\0+$/;\nmy $inthashvalue = hashvalue( 'string' );\nmy $mask= hashtraversalmask(%hash);\nhashtraversalmask(%hash,1234);\n\n## DESCRIPTION\n\n\"Hash::Util\" and \"Hash::Util::FieldHash\" contain special functions for\nmanipulating hashes that don't really warrant a keyword.\n\n## Sections\n\n- **NAME**\n- **SYNOPSIS**\n- **DESCRIPTION**\n- **CAVEATS**\n- **BUGS**\n- **AUTHOR**\n- **SEE ALSO**\n\nUse structuredContent.sections for detailed options, examples, and full documentation.\n"
        }
    ],
    "structuredContent": {
        "command": "Hash::Util",
        "section": "",
        "mode": "info",
        "summary": "Hash::Util - A selection of general-utility hash subroutines",
        "synopsis": "# Restricted hashes\nuse Hash::Util qw(\nfieldhash fieldhashes\nallkeys\nlockkeys unlockkeys\nlockvalue unlockvalue\nlockhash unlockhash\nlockkeysplus\nhashlocked hashunlocked\nhashreflocked hashrefunlocked\nhiddenkeys legalkeys\nlockrefkeys unlockrefkeys\nlockrefvalue unlockrefvalue\nlockhashref unlockhashref\nlockrefkeysplus\nhiddenrefkeys legalrefkeys\nhashseed hashvalue hvstore\nbucketstats bucketinfo bucketarray\nlockhashrecurse unlockhashrecurse\nlockhashrefrecurse unlockhashrefrecurse\nhashtraversalmask\n);\n%hash = (foo => 42, bar => 23);\n# Ways to restrict a hash\nlockkeys(%hash);\nlockkeys(%hash, @keyset);\nlockkeysplus(%hash, @additionalkeys);\n# Ways to inspect the properties of a restricted hash\nmy @legal = legalkeys(%hash);\nmy @hidden = hiddenkeys(%hash);\nmy $ref = allkeys(%hash,@keys,@hidden);\nmy $islocked = hashlocked(%hash);\n# Remove restrictions on the hash\nunlockkeys(%hash);\n# Lock individual values in a hash\nlockvalue  (%hash, 'foo');\nunlockvalue(%hash, 'foo');\n# Ways to change the restrictions on both keys and values\nlockhash  (%hash);\nunlockhash(%hash);\nmy $hashesarerandomised = hashseed() !~ /^\\0+$/;\nmy $inthashvalue = hashvalue( 'string' );\nmy $mask= hashtraversalmask(%hash);\nhashtraversalmask(%hash,1234);",
        "tldr_summary": null,
        "tldr_examples": [],
        "tldr_source": null,
        "flags": [],
        "examples": [],
        "see_also": [
            {
                "name": "Util",
                "section": "3perl",
                "url": "https://www.chedong.com/phpMan.php/man/Util/3perl/json"
            }
        ],
        "section_outline": [
            {
                "name": "NAME",
                "lines": 2,
                "subsections": []
            },
            {
                "name": "SYNOPSIS",
                "lines": 59,
                "subsections": []
            },
            {
                "name": "DESCRIPTION",
                "lines": 381,
                "subsections": []
            },
            {
                "name": "CAVEATS",
                "lines": 7,
                "subsections": []
            },
            {
                "name": "BUGS",
                "lines": 4,
                "subsections": []
            },
            {
                "name": "AUTHOR",
                "lines": 7,
                "subsections": []
            },
            {
                "name": "SEE ALSO",
                "lines": 6,
                "subsections": []
            }
        ],
        "sections": {
            "NAME": {
                "content": "Hash::Util - A selection of general-utility hash subroutines\n",
                "subsections": []
            },
            "SYNOPSIS": {
                "content": "# Restricted hashes\n\nuse Hash::Util qw(\nfieldhash fieldhashes\n\nallkeys\nlockkeys unlockkeys\nlockvalue unlockvalue\nlockhash unlockhash\nlockkeysplus\nhashlocked hashunlocked\nhashreflocked hashrefunlocked\nhiddenkeys legalkeys\n\nlockrefkeys unlockrefkeys\nlockrefvalue unlockrefvalue\nlockhashref unlockhashref\nlockrefkeysplus\nhiddenrefkeys legalrefkeys\n\nhashseed hashvalue hvstore\nbucketstats bucketinfo bucketarray\nlockhashrecurse unlockhashrecurse\nlockhashrefrecurse unlockhashrefrecurse\n\nhashtraversalmask\n);\n\n%hash = (foo => 42, bar => 23);\n# Ways to restrict a hash\nlockkeys(%hash);\nlockkeys(%hash, @keyset);\nlockkeysplus(%hash, @additionalkeys);\n\n# Ways to inspect the properties of a restricted hash\nmy @legal = legalkeys(%hash);\nmy @hidden = hiddenkeys(%hash);\nmy $ref = allkeys(%hash,@keys,@hidden);\nmy $islocked = hashlocked(%hash);\n\n# Remove restrictions on the hash\nunlockkeys(%hash);\n\n# Lock individual values in a hash\nlockvalue  (%hash, 'foo');\nunlockvalue(%hash, 'foo');\n\n# Ways to change the restrictions on both keys and values\nlockhash  (%hash);\nunlockhash(%hash);\n\nmy $hashesarerandomised = hashseed() !~ /^\\0+$/;\n\nmy $inthashvalue = hashvalue( 'string' );\n\nmy $mask= hashtraversalmask(%hash);\n\nhashtraversalmask(%hash,1234);\n",
                "subsections": []
            },
            "DESCRIPTION": {
                "content": "\"Hash::Util\" and \"Hash::Util::FieldHash\" contain special functions for\nmanipulating hashes that don't really warrant a keyword.\n\n\"Hash::Util\" contains a set of functions that support restricted\nhashes. These are described in this document.  \"Hash::Util::FieldHash\"\ncontains an (unrelated) set of functions that support the use of hashes\nin inside-out classes, described in Hash::Util::FieldHash.\n\nBy default \"Hash::Util\" does not export anything.\n\nRestricted hashes\n5.8.0 introduces the ability to restrict a hash to a certain set of\nkeys.  No keys outside of this set can be added.  It also introduces\nthe ability to lock an individual key so it cannot be deleted and the\nability to ensure that an individual value cannot be changed.\n\nThis is intended to largely replace the deprecated pseudo-hashes.\n\nlockkeys\nunlockkeys\nlockkeys(%hash);\nlockkeys(%hash, @keys);\n\nRestricts the given %hash's set of keys to @keys.  If @keys is not\ngiven it restricts it to its current keyset.  No more keys can be\nadded. delete() and exists() will still work, but will not alter\nthe set of allowed keys. Note: the current implementation prevents\nthe hash from being bless()ed while it is in a locked state. Any\nattempt to do so will raise an exception. Of course you can still\nbless() the hash before you call lockkeys() so this shouldn't be a\nproblem.\n\nunlockkeys(%hash);\n\nRemoves the restriction on the %hash's keyset.\n\nNote that if any of the values of the hash have been locked they\nwill not be unlocked after this sub executes.\n\nBoth routines return a reference to the hash operated on.\n\nlockkeysplus\nlockkeysplus(%hash,@additionalkeys)\n\nSimilar to \"lockkeys()\", with the difference being that the\noptional key list specifies keys that may or may not be already in\nthe hash. Essentially this is an easier way to say\n\nlockkeys(%hash,@additionalkeys,keys %hash);\n\nReturns a reference to %hash\n\nlockvalue\nunlockvalue\nlockvalue  (%hash, $key);\nunlockvalue(%hash, $key);\n\nLocks and unlocks the value for an individual key of a hash.  The\nvalue of a locked key cannot be changed.\n\nUnless %hash has already been locked the key/value could be deleted\nregardless of this setting.\n\nReturns a reference to the %hash.\n\nlockhash\nunlockhash\nlockhash(%hash);\n\nlockhash() locks an entire hash, making all keys and values read-\nonly.  No value can be changed, no keys can be added or deleted.\n\nunlockhash(%hash);\n\nunlockhash() does the opposite of lockhash().  All keys and\nvalues are made writable.  All values can be changed and keys can\nbe added and deleted.\n\nReturns a reference to the %hash.\n\nlockhashrecurse\nunlockhashrecurse\nlockhashrecurse(%hash);\n\nlockhash() locks an entire hash and any hashes it references\nrecursively, making all keys and values read-only. No value can be\nchanged, no keys can be added or deleted.\n\nThis method only recurses into hashes that are referenced by\nanother hash.  Thus a Hash of Hashes (HoH) will all be restricted,\nbut a Hash of Arrays of Hashes (HoAoH) will only have the top hash\nrestricted.\n\nunlockhashrecurse(%hash);\n\nunlockhashrecurse() does the opposite of lockhashrecurse().\nAll keys and values are made writable.  All values can be changed\nand keys can be added and deleted. Identical recursion restrictions\napply as to lockhashrecurse().\n\nReturns a reference to the %hash.\n\nhashreflocked\nhashlocked\nhashreflocked(\\%hash) and print \"Hash is locked!\\n\";\nhashlocked(%hash) and print \"Hash is locked!\\n\";\n\nReturns true if the hash and its keys are locked.\n\nhashrefunlocked\nhashunlocked\nhashrefunlocked(\\%hash) and print \"Hash is unlocked!\\n\";\nhashunlocked(%hash) and print \"Hash is unlocked!\\n\";\n\nReturns true if the hash and its keys are unlocked.\n\nlegalkeys\nmy @keys = legalkeys(%hash);\n\nReturns the list of the keys that are legal in a restricted hash.\nIn the case of an unrestricted hash this is identical to calling\nkeys(%hash).\n\nhiddenkeys\nmy @keys = hiddenkeys(%hash);\n\nReturns the list of the keys that are legal in a restricted hash\nbut do not have a value associated to them. Thus if 'foo' is a\n\"hidden\" key of the %hash it will return false for both \"defined\"\nand \"exists\" tests.\n\nIn the case of an unrestricted hash this will return an empty list.\n\nNOTE this is an experimental feature that is heavily dependent on\nthe current implementation of restricted hashes. Should the\nimplementation change, this routine may become meaningless, in\nwhich case it will return an empty list.\n\nallkeys\nallkeys(%hash,@keys,@hidden);\n\nPopulates the arrays @keys with the all the keys that would pass an\n\"exists\" tests, and populates @hidden with the remaining legal keys\nthat have not been utilized.\n\nReturns a reference to the hash.\n\nIn the case of an unrestricted hash this will be equivalent to\n\n$ref = do {\n@keys = keys %hash;\n@hidden = ();\n\\%hash\n};\n\nNOTE this is an experimental feature that is heavily dependent on\nthe current implementation of restricted hashes. Should the\nimplementation change this routine may become meaningless in which\ncase it will behave identically to how it would behave on an\nunrestricted hash.\n\nhashseed\nmy $hashseed = hashseed();\n\nhashseed() returns the seed bytes used to randomise hash ordering.\n\nNote that the hash seed is sensitive information: by knowing it one\ncan craft a denial-of-service attack against Perl code, even\nremotely, see \"Algorithmic Complexity Attacks\" in perlsec for more\ninformation.  Do not disclose the hash seed to people who don't\nneed to know it.  See also \"PERLHASHSEEDDEBUG\" in perlrun.\n\nPrior to Perl 5.17.6 this function returned a UV, it now returns a\nstring, which may be of nearly any size as determined by the hash\nfunction your Perl has been built with. Possible sizes may be but\nare not limited to 4 bytes (for most hash algorithms) and 16 bytes\n(for siphash).\n\nhashvalue\nmy $hashvalue = hashvalue($string);\n\nhashvalue() returns the current perl's internal hash value for a\ngiven string.\n\nReturns a 32 bit integer representing the hash value of the string\npassed in. This value is only reliable for the lifetime of the\nprocess. It may be different depending on invocation, environment\nvariables,  perl version, architectures, and build options.\n\nNote that the hash value of a given string is sensitive\ninformation: by knowing it one can deduce the hash seed which in\nturn can allow one to craft a denial-of-service attack against Perl\ncode, even remotely, see \"Algorithmic Complexity Attacks\" in\nperlsec for more information.  Do not disclose the hash value of a\nstring to people who don't need to know it. See also\n\"PERLHASHSEEDDEBUG\" in perlrun.\n\nbucketinfo\nReturn a set of basic information about a hash.\n\nmy ($keys, $buckets, $used, @lengthcounts)= bucketinfo($hash);\n\nFields are as follows:\n\n0: Number of keys in the hash\n1: Number of buckets in the hash\n2: Number of used buckets in the hash\nrest : list of counts, Kth element is the number of buckets\nwith K keys in it.\n\nSee also bucketstats() and bucketarray().\n\nbucketstats\nReturns a list of statistics about a hash.\n\nmy ($keys, $buckets, $used, $quality, $utilizationratio,\n$collisionpct, $mean, $stddev, @lengthcounts)\n= bucketstats($hashref);\n\nFields are as follows:\n\n0: Number of keys in the hash\n1: Number of buckets in the hash\n2: Number of used buckets in the hash\n3: Hash Quality Score\n4: Percent of buckets used\n5: Percent of keys which are in collision\n6: Mean bucket length of occupied buckets\n7: Standard Deviation of bucket lengths of occupied buckets\nrest : list of counts, Kth element is the number of buckets\nwith K keys in it.\n\nSee also bucketinfo() and bucketarray().\n\nNote that Hash Quality Score would be 1 for an ideal hash, numbers\nclose to and below 1 indicate good hashing, and number\nsignificantly above indicate a poor score. In practice it should be\naround 0.95 to 1.05.  It is defined as:\n\n$score= sum( $count[$length] * ($length * ($length + 1) / 2) )\n/\n( ( $keys / 2 * $buckets ) *\n( $keys + ( 2 * $buckets ) - 1 ) )\n\nThe formula is from the Red Dragon book (reformulated to use the\ndata available) and is documented at\n<http://www.strchr.com/hashfunctions>\n\nbucketarray\nmy $array= bucketarray(\\%hash);\n\nReturns a packed representation of the bucket array associated with\na hash. Each element of the array is either an integer K, in which\ncase it represents K empty buckets, or a reference to another array\nwhich contains the keys that are in that bucket.\n\nNote that the information returned by bucketarray is sensitive\ninformation: by knowing it one can directly attack perl's hash\nfunction which in turn may allow one to craft a denial-of-service\nattack against Perl code, even remotely, see \"Algorithmic\nComplexity Attacks\" in perlsec for more information.  Do not\ndisclose the output of this function to people who don't need to\nknow it. See also \"PERLHASHSEEDDEBUG\" in perlrun. This function\nis provided strictly for  debugging and diagnostics purposes only,\nit is hard to imagine a reason why it would be used in production\ncode.\n\nbucketstatsformatted\nprint bucketstatsformatted($hashref);\n\nReturn a formatted report of the information returned by\nbucketstats().  An example report looks like this:\n\nKeys: 50 Buckets: 33/64 Quality-Score: 1.01 (Good)\nUtilized Buckets: 51.56% Optimal: 78.12% Keys In Collision: 34.00%\nChain Length - mean: 1.52 stddev: 0.66\nBuckets 64          [0000000000000000000000000000000111111111111111111122222222222333]\nLen   0 Pct:  48.44 [###############################]\nLen   1 Pct:  29.69 [###################]\nLen   2 Pct:  17.19 [###########]\nLen   3 Pct:   4.69 [###]\nKeys    50          [11111111111111111111111111111111122222222222222333]\nPos   1 Pct:  66.00 [#################################]\nPos   2 Pct:  28.00 [##############]\nPos   3 Pct:   6.00 [###]\n\nThe first set of stats gives some summary statistical information,\nincluding the quality score translated into \"Good\", \"Poor\" and\n\"Bad\", (score<=1.05, score<=1.2, score>1.2). See the documentation\nin bucketstats() for more details.\n\nThe two sets of barcharts give stats and a visual indication of\nperformance of the hash.\n\nThe first gives data on bucket chain lengths and provides insight\non how much work a fetch *miss* will take. In this case we have to\ninspect every item in a bucket before we can be sure the item is\nnot in the list. The performance for an insert is equivalent to\nthis case, as is a delete where the item is not in the hash.\n\nThe second gives data on how many keys are at each depth in the\nchain, and gives an idea of how much work a fetch *hit* will take.\nThe performance for an update or delete of an item in the hash is\nequivalent to this case.\n\nNote that these statistics are summary only. Actual performance\nwill depend on real hit/miss ratios accessing the hash. If you are\nconcerned by hit ratios you are recommended to \"oversize\" your hash\nby using something like:\n\nkeys(%hash)= keys(%hash) << $k;\n\nWith $k chosen carefully, and likely to be a small number like 1 or\n2. In theory the larger the bucket array the less chance of\ncollision.\n\nhvstore\nmy $sv = 0;\nhvstore(%hash,$key,$sv) or die \"Failed to alias!\";\n$hash{$key} = 1;\nprint $sv; # prints 1\n\nStores an alias to a variable in a hash instead of copying the\nvalue.\n\nhashtraversalmask\nAs of Perl 5.18 every hash has its own hash traversal order, and\nthis order changes every time a new element is inserted into the\nhash. This functionality is provided by maintaining an unsigned\ninteger mask (U32) which is xor'ed with the actual bucket id during\na traversal of the hash buckets using keys(), values() or each().\n\nYou can use this subroutine to get and set the traversal mask for a\nspecific hash. Setting the mask ensures that a given hash will\nproduce the same key order. Note that this does not guarantee that\ntwo hashes will produce the same key order for the same hash seed\nand traversal mask, items that collide into one bucket may have\ndifferent orders regardless of this setting.\n\nbucketratio\nThis function behaves the same way that scalar(%hash) behaved prior\nto Perl 5.25. Specifically if the hash is tied, then it calls the\nSCALAR tied hash method, if untied then if the hash is empty it\nreturn 0, otherwise it returns a string containing the number of\nused buckets in the hash, followed by a slash, followed by the\ntotal number of buckets in the hash.\n\nmy %hash=(\"foo\"=>1);\nprint Hash::Util::bucketratio(%hash); # prints \"1/8\"\n\nusedbuckets\nThis function returns the count of used buckets in the hash. It is\nexpensive to calculate and the value is NOT cached, so avoid use of\nthis function in production code.\n\nnumbuckets\nThis function returns the total number of buckets the hash holds,\nor would hold if the array were created. (When a hash is freshly\ncreated the array may not be allocated even though this value will\nbe non-zero.)\n\nOperating on references to hashes.\nMost subroutines documented in this module have equivalent versions\nthat operate on references to hashes instead of native hashes.  The\nfollowing is a list of these subs. They are identical except in name\nand in that instead of taking a %hash they take a $hashref, and\nadditionally are not prototyped.\n\nlockrefkeys\nunlockrefkeys\nlockrefkeysplus\nlockrefvalue\nunlockrefvalue\nlockhashref\nunlockhashref\nlockhashrefrecurse\nunlockhashrefrecurse\nhashrefunlocked\nlegalrefkeys\nhiddenrefkeys\n",
                "subsections": []
            },
            "CAVEATS": {
                "content": "Note that the trapping of the restricted operations is not atomic: for\nexample\n\neval { %hash = (illegalkey => 1) }\n\nleaves the %hash empty rather than with its original contents.\n",
                "subsections": []
            },
            "BUGS": {
                "content": "The interface exposed by this module is very close to the current\nimplementation of restricted hashes. Over time it is expected that this\nbehavior will be extended and the interface abstracted further.\n",
                "subsections": []
            },
            "AUTHOR": {
                "content": "Michael G Schwern <schwern@pobox.com> on top of code by Nick Ing-\nSimmons and Jeffrey Friedl.\n\nhvstore() is from Array::RefElem, Copyright 2000 Gisle Aas.\n\nAdditional code by Yves Orton.\n",
                "subsections": []
            },
            "SEE ALSO": {
                "content": "Scalar::Util, List::Util and \"Algorithmic Complexity Attacks\" in\nperlsec.\n\nHash::Util::FieldHash.\n\nperl v5.34.0                      2026-06-23                 Hash::Util(3perl)",
                "subsections": []
            }
        }
    }
}