Front page | perl.perl5.changes |
Postings from March 2023
[Perl/perl5] 7305c5: ext/Hash/Util.pm - support "protected hashes"
From:
Yves Orton via perl5-changes
Date:
March 12, 2023 21:47
Subject:
[Perl/perl5] 7305c5: ext/Hash/Util.pm - support "protected hashes"
Message ID:
Perl/perl5/push/refs/heads/yves/protected_hashes/cba465-7305c5@github.com
Branch: refs/heads/yves/protected_hashes
Home: https://github.com/Perl/perl5
Commit: 7305c566d60db855a9a93be4c7f84d00ff2254dc
https://github.com/Perl/perl5/commit/7305c566d60db855a9a93be4c7f84d00ff2254dc
Author: Yves Orton <demerphq@gmail.com>
Date: 2023-03-12 (Sun, 12 Mar 2023)
Changed paths:
M MANIFEST
M embed.fnc
M embed.h
M ext/Hash-Util/Util.xs
M ext/Hash-Util/lib/Hash/Util.pm
A ext/Hash-Util/t/protect.t
M hv.c
M proto.h
Log Message:
-----------
ext/Hash/Util.pm - support "protected hashes"
Restricted (aka locked) hashes are "read only" but have the special
extra behavior that they die if code attempts to read from unknown keys.
This is helpful for hash based objects but it makes locked hashes
almost useless for most other purposes where someone might want a "read
only" hash.
It turns out that we have two bits used to mark things are read only.
SVf_READONLY and SVf_PROTECTED. Ironically, SVf_PROTECTED was added
because SVf_READONLY was used for implementing "restricted hashes", and
there is an expectation that is ok to turn off the SVf_READONLY flag as
part of the "restricted/locked hash" API, and we needed a flag that
means "really read only", so the internals will set BOTH flags when
something is meant to be "really readonly", primarily on scalars. This
means that we can implement a "true" read only hash by using the same
trick for HV's.
Thus an HV that has both flags set can be treated separately from an
HV that has only the SVf_READONLY flag set, and made to *not* die
if someone wants to access a key that is not in the hash. (Yes this
sounds confusing here, but in practice it is pretty straight forward.)
Because "readonly" is a bit awkward as it does not have a verb form,
compared to the terms used for restricted hashes: "lock" is a verb, and
"locked" an adjective, we use the term "protect" and "protected" to
achieve API symmetry with "lock" and "locked".
With a compound structure like a hash there are multiple levels where
"readonly" can apply. There is the level of the keys that the hash
contains, there is the level of the values it contains, and there is
the level of the values it contains recursively. With restricted
hashes we support all three, and for protected hashes we need to do
the same thing. This patch supports "protect_hashkeys",
"protect_hash", and "protect_hash_recursive" to cover the three
levels.
The function protect_hashkeys sets the flags such that the keys in a
hash may not be changed, just like restricted hashes, with the key
difference being that fetching a non-existent key does not throw an
error, it simply returns undef, unless the fetch is in LVALUE context
in which case it will be treated as a store and throw an exception.
The function protect_hash is like protect_hashkeys, but also marks the
values in the hash as readonly. Note that for references this only
affects the reference itself, it does not affect the referenced object.
Thus in
%hash = ( k => { k2 => 1 } ); protect_hash(%hash);
the value in $hash{k} may not be changed, but the contents of the hash
it references may be changed, so for instance $hash{k}{other}=1 would be
legal.
The function protect_hash_recursive() recursively protects the entire
hash, marking every items it contains as read-only or protected,
but recursively, going as deep down the dependency tree as required and
possible.
-
[Perl/perl5] 7305c5: ext/Hash/Util.pm - support "protected hashes"
by Yves Orton via perl5-changes