```{index} single: Hash::Util; Perl module ``` # Hash::Util ```{pperl-module-badges} Hash::Util ``` General-utility hash subroutines — lock and unlock keys or values, inspect bucket layout, and seed the hash function. A *restricted* hash is an ordinary hash that rejects new keys and, optionally, refuses writes to its values. You build one by calling `lock_keys` on a populated hash; from that point on a write to any key not already present croaks. Locking individual values with `lock_value`, or the whole hash with `lock_hash`, makes the existing values immutable as well. Every lock has a matching unlock. Alongside the locking primitives the module exposes a handful of introspection helpers: `bucket_ratio`, `num_buckets`, `used_buckets`, `bucket_info`, `bucket_array`, and the summary reports `bucket_stats` and `bucket_stats_formatted`. They report how the hash is laid out internally and are useful when tuning the size of very large hashes. `hash_seed` and `hash_value` expose the hash function itself — the random per-process seed, and the integer hash of a given string under that seed (or a caller-supplied seed). Both are sensitive: handing them to untrusted code enables algorithmic-complexity attacks against any hash in the program. Every `ref`-suffixed variant (`lock_ref_keys`, `lock_hashref`, `hashref_locked`, `legal_ref_keys`, `hidden_ref_keys`, etc.) does the same work as its plain counterpart but takes an already-taken hash reference rather than relying on the `\%` prototype. ## Synopsis use Hash::Util qw(lock_keys unlock_keys lock_value hash_locked hidden_keys); my %h = (foo => 1, bar => 2); lock_keys(%h); # fix the keyset $h{foo} = 10; # ok eval { $h{baz} = 99 }; # croaks — attempt to access disallowed key lock_value(%h, 'foo'); # make $h{foo} immutable too print hash_locked(%h) ? "yes" : "no"; # yes unlock_keys(%h); # lift the keyset restriction ## Security `hash_seed`, `hash_value`, and `bucket_array` reveal enough about the hash function to enable collision attacks. Do not expose their output to code you do not trust. ## Functions ### Hash locking #### [`lock_keys`](Util/lock_keys) Restrict a hash to its current keys, or to an explicit list. #### [`unlock_keys`](Util/unlock_keys) Lift the keyset restriction imposed by `lock_keys`. #### [`lock_ref_keys`](Util/lock_ref_keys) Hash-reference variant of `lock_keys`. #### `unlock_ref_keys` Hash-reference variant of `unlock_keys`. **Synopsis** unlock_ref_keys($href); Lifts the keyset restriction on the referenced hash. See `unlock_keys` for the full story on placeholders and values that remain locked. #### [`lock_ref_keys_plus`](Util/lock_ref_keys_plus) Lock the hash to the union of its current keys and a given extra list. #### [`lock_value`](Util/lock_value) Make the value under a given key immutable. #### `unlock_value` Undo a previous `lock_value`, making the value at `$key` writable again. **Synopsis** unlock_value(%hash, $key); Does nothing (silently) if the key is absent or was never locked. Returns a reference to the hash. #### `lock_ref_value` Hash-reference variant of `lock_value`. **Synopsis** lock_ref_value($href, $key); Same behaviour as `lock_value` but takes a hash reference. #### `unlock_ref_value` Hash-reference variant of `unlock_value`. **Synopsis** unlock_ref_value($href, $key); Same behaviour as `unlock_value` but takes a hash reference. #### [`lock_hash`](Util/lock_hash) Lock the whole hash: both its keyset and every value. #### `unlock_hash` Undo a previous `lock_hash`, making every key and value writable again. **Synopsis** unlock_hash(%hash); Clears the read-only flag on each existing value and lifts the keyset restriction. Returns a reference to the hash. #### `lock_hashref` Hash-reference variant of `lock_hash`. **Synopsis** lock_hashref($href); Same behaviour as `lock_hash` but takes a hash reference. #### `unlock_hashref` Hash-reference variant of `unlock_hash`. **Synopsis** unlock_hashref($href); Same behaviour as `unlock_hash` but takes a hash reference. #### [`lock_hash_recurse`](Util/lock_hash_recurse) Lock a hash and every nested hash it references, transitively. #### `unlock_hash_recurse` Undo a previous `lock_hash_recurse`, unlocking every nested hash it touched. **Synopsis** unlock_hash_recurse(%hash); Traverses the same subset of references as `lock_hash_recurse` — hash-valued entries only. Returns a reference to the hash. #### `lock_hashref_recurse` Hash-reference variant of `lock_hash_recurse`. **Synopsis** lock_hashref_recurse($href); Same behaviour as `lock_hash_recurse` but takes a hash reference. #### `unlock_hashref_recurse` Hash-reference variant of `unlock_hash_recurse`. **Synopsis** unlock_hashref_recurse($href); Same behaviour as `unlock_hash_recurse` but takes a hash reference. #### `hash_locked` Report whether the hash's keyset is currently locked. **Synopsis** hash_locked(%hash) and print "restricted\n"; Returns `1` when `lock_keys` (or an equivalent) has been applied to the hash, `0` otherwise. Value-level locks alone do not count — this only reports the keyset restriction. #### `hash_unlocked` Report whether the hash's keyset is *not* currently locked. **Synopsis** hash_unlocked(%hash) and print "open\n"; The logical inverse of `hash_locked`: returns `1` on an unlocked hash, `0` on a locked one. Handy in conditions where testing for the open state reads more naturally than negating the locked one. #### `hashref_locked` Hash-reference variant of `hash_locked`. **Synopsis** hashref_locked($href) and print "restricted\n"; Same behaviour as `hash_locked` but takes a hash reference. #### `hashref_unlocked` Hash-reference variant of `hash_unlocked`. **Synopsis** hashref_unlocked($href) and print "open\n"; Same behaviour as `hash_unlocked` but takes a hash reference. #### [`hidden_keys`](Util/hidden_keys) List the "hidden" placeholder keys of a restricted hash — legal keys that currently have no value assigned. #### `hidden_ref_keys` Hash-reference variant of `hidden_keys`. **Synopsis** my @hidden = hidden_ref_keys($href); Same behaviour as `hidden_keys` but takes a hash reference. #### `legal_keys` List every key the restricted hash *is allowed to carry* — visible keys plus hidden placeholders. **Synopsis** my @legal = legal_keys(%hash); On an unrestricted hash this is equivalent to `keys %hash`. On a restricted hash it is the visible keys (`keys %hash`) merged with whatever `hidden_keys` would report. #### `legal_ref_keys` Hash-reference variant of `legal_keys`. **Synopsis** my @legal = legal_ref_keys($href); Same behaviour as `legal_keys` but takes a hash reference. #### [`all_keys`](Util/all_keys) Split a restricted hash's keys into visible and hidden buckets, writing the results into the caller's arrays. #### [`hv_store`](Util/hv_store) Install an *alias* from `$hash{$key}` to an existing scalar, instead of copying its value in the usual way. #### `clear_placeholders` Strip all hidden placeholder entries from a hash. **Synopsis** Hash::Util::_clear_placeholders(%hash); Intended for internal use by `Hash::Util` itself when preparing a hash for a new lock cycle. The leading underscore marks it as unsupported for application code — its behaviour may change without notice. ### Bucket introspection #### [`bucket_ratio`](Util/bucket_ratio) Return a `"used/total"` string describing how many of the hash's internal buckets hold at least one key. #### `num_buckets` Return the total number of buckets the hash holds (or would hold if its bucket array were allocated). **Synopsis** my $n = num_buckets(%hash); A freshly created hash may report a non-zero bucket count even before its bucket array has been materialised — Perl allocates buckets lazily. The value is always a power of two. #### `used_buckets` Return the count of buckets that currently hold at least one key. **Synopsis** my $used = used_buckets(%hash); The value is computed from scratch on every call by walking the bucket array — there is no cache. Avoid calling it inside a hot loop on a large hash. #### [`bucket_info`](Util/bucket_info) Return a flat list summarising the hash's bucket layout. #### [`bucket_array`](Util/bucket_array) Return a packed array-of-arrays describing which key lives in which bucket. #### [`hash_traversal_mask`](Util/hash_traversal_mask) Read or set the per-hash bucket-traversal mask used by `keys`, `values`, and `each`. #### [`bucket_stats`](Util/bucket_stats) Return a rich statistical summary of the hash's bucket layout. #### [`bucket_stats_formatted`](Util/bucket_stats_formatted) Return a multi-line human-readable report of `bucket_stats`, complete with ASCII barcharts. ### Hash function #### [`hash_seed`](Util/hash_seed) Return the per-process random bytes that seed the hash function. #### [`hash_value`](Util/hash_value) Return the integer hash value of a string under the current (or a supplied) seed. ```{toctree} :hidden: :maxdepth: 1 Util/hash_seed Util/hash_value Util/bucket_ratio Util/bucket_info Util/bucket_array Util/hash_traversal_mask Util/bucket_stats Util/bucket_stats_formatted Util/lock_keys Util/unlock_keys Util/lock_ref_keys Util/lock_ref_keys_plus Util/lock_value Util/lock_hash Util/lock_hash_recurse Util/hidden_keys Util/all_keys Util/hv_store ```