# Hash::Util
📦 min
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
```none
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.md)
Restrict a hash to its current keys, or to an explicit list.
#### [`unlock_keys`](Util/unlock_keys.md)
Lift the keyset restriction imposed by `lock_keys`.
#### [`lock_ref_keys`](Util/lock_ref_keys.md)
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.md)
Lock the hash to the union of its current keys and a given extra list.
#### [`lock_value`](Util/lock_value.md)
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.md)
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.md)
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.md)
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.md)
Split a restricted hash’s keys into visible and hidden buckets, writing the results into the caller’s arrays.
#### [`hv_store`](Util/hv_store.md)
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.md)
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.md)
Return a flat list summarising the hash’s bucket layout.
#### [`bucket_array`](Util/bucket_array.md)
Return a packed array-of-arrays describing which key lives in which bucket.
#### [`hash_traversal_mask`](Util/hash_traversal_mask.md)
Read or set the per-hash bucket-traversal mask used by `keys`, `values`, and `each`.
#### [`bucket_stats`](Util/bucket_stats.md)
Return a rich statistical summary of the hash’s bucket layout.
#### [`bucket_stats_formatted`](Util/bucket_stats_formatted.md)
Return a multi-line human-readable report of `bucket_stats`, complete with ASCII barcharts.
### Hash function
#### [`hash_seed`](Util/hash_seed.md)
Return the per-process random bytes that seed the hash function.
#### [`hash_value`](Util/hash_value.md)
Return the integer hash value of a string under the current (or a supplied) seed.