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#

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#

Restrict a hash to its current keys, or to an explicit list.

unlock_keys#

Lift the keyset restriction imposed by lock_keys.

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#

Lock the hash to the union of its current keys and a given extra list.

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#

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#

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#

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.

all_keys#

Split a restricted hash’s keys into visible and hidden buckets, writing the results into the caller’s arrays.

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#

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#

Return a flat list summarising the hash’s bucket layout.

bucket_array#

Return a packed array-of-arrays describing which key lives in which bucket.

hash_traversal_mask#

Read or set the per-hash bucket-traversal mask used by keys, values, and each.

bucket_stats#

Return a rich statistical summary of the hash’s bucket layout.

bucket_stats_formatted#

Return a multi-line human-readable report of bucket_stats, complete with ASCII barcharts.

Hash function#

hash_seed#

Return the per-process random bytes that seed the hash function.

hash_value#

Return the integer hash value of a string under the current (or a supplied) seed.