xref: /openbsd-src/gnu/usr.bin/perl/ext/Hash-Util/lib/Hash/Util.pm (revision 48950c12d106c85f315112191a0228d7b83b9510)
1package Hash::Util;
2
3require 5.007003;
4use strict;
5use Carp;
6use warnings;
7no warnings 'uninitialized';
8use warnings::register;
9use Scalar::Util qw(reftype);
10
11require Exporter;
12our @ISA        = qw(Exporter);
13our @EXPORT_OK  = qw(
14                     fieldhash fieldhashes
15
16                     all_keys
17                     lock_keys unlock_keys
18                     lock_value unlock_value
19                     lock_hash unlock_hash
20                     lock_keys_plus hash_locked
21                     hidden_keys legal_keys
22
23                     lock_ref_keys unlock_ref_keys
24                     lock_ref_value unlock_ref_value
25                     lock_hashref unlock_hashref
26                     lock_ref_keys_plus hashref_locked
27                     hidden_ref_keys legal_ref_keys
28
29                     hash_seed hv_store
30
31                    );
32our $VERSION = '0.11';
33require XSLoader;
34XSLoader::load();
35
36sub import {
37    my $class = shift;
38    if ( grep /fieldhash/, @_ ) {
39        require Hash::Util::FieldHash;
40        Hash::Util::FieldHash->import(':all'); # for re-export
41    }
42    unshift @_, $class;
43    goto &Exporter::import;
44}
45
46
47=head1 NAME
48
49Hash::Util - A selection of general-utility hash subroutines
50
51=head1 SYNOPSIS
52
53  # Restricted hashes
54
55  use Hash::Util qw(
56                     hash_seed all_keys
57                     lock_keys unlock_keys
58                     lock_value unlock_value
59                     lock_hash unlock_hash
60                     lock_keys_plus hash_locked
61                     hidden_keys legal_keys
62                   );
63
64  %hash = (foo => 42, bar => 23);
65  # Ways to restrict a hash
66  lock_keys(%hash);
67  lock_keys(%hash, @keyset);
68  lock_keys_plus(%hash, @additional_keys);
69
70  # Ways to inspect the properties of a restricted hash
71  my @legal = legal_keys(%hash);
72  my @hidden = hidden_keys(%hash);
73  my $ref = all_keys(%hash,@keys,@hidden);
74  my $is_locked = hash_locked(%hash);
75
76  # Remove restrictions on the hash
77  unlock_keys(%hash);
78
79  # Lock individual values in a hash
80  lock_value  (%hash, 'foo');
81  unlock_value(%hash, 'foo');
82
83  # Ways to change the restrictions on both keys and values
84  lock_hash  (%hash);
85  unlock_hash(%hash);
86
87  my $hashes_are_randomised = hash_seed() != 0;
88
89=head1 DESCRIPTION
90
91C<Hash::Util> and C<Hash::Util::FieldHash> contain special functions
92for manipulating hashes that don't really warrant a keyword.
93
94C<Hash::Util> contains a set of functions that support
95L<restricted hashes|/"Restricted hashes">. These are described in
96this document.  C<Hash::Util::FieldHash> contains an (unrelated)
97set of functions that support the use of hashes in
98I<inside-out classes>, described in L<Hash::Util::FieldHash>.
99
100By default C<Hash::Util> does not export anything.
101
102=head2 Restricted hashes
103
1045.8.0 introduces the ability to restrict a hash to a certain set of
105keys.  No keys outside of this set can be added.  It also introduces
106the ability to lock an individual key so it cannot be deleted and the
107ability to ensure that an individual value cannot be changed.
108
109This is intended to largely replace the deprecated pseudo-hashes.
110
111=over 4
112
113=item B<lock_keys>
114
115=item B<unlock_keys>
116
117  lock_keys(%hash);
118  lock_keys(%hash, @keys);
119
120Restricts the given %hash's set of keys to @keys.  If @keys is not
121given it restricts it to its current keyset.  No more keys can be
122added. delete() and exists() will still work, but will not alter
123the set of allowed keys. B<Note>: the current implementation prevents
124the hash from being bless()ed while it is in a locked state. Any attempt
125to do so will raise an exception. Of course you can still bless()
126the hash before you call lock_keys() so this shouldn't be a problem.
127
128  unlock_keys(%hash);
129
130Removes the restriction on the %hash's keyset.
131
132B<Note> that if any of the values of the hash have been locked they will not be unlocked
133after this sub executes.
134
135Both routines return a reference to the hash operated on.
136
137=cut
138
139sub lock_ref_keys {
140    my($hash, @keys) = @_;
141
142    Internals::hv_clear_placeholders %$hash;
143    if( @keys ) {
144        my %keys = map { ($_ => 1) } @keys;
145        my %original_keys = map { ($_ => 1) } keys %$hash;
146        foreach my $k (keys %original_keys) {
147            croak "Hash has key '$k' which is not in the new key set"
148              unless $keys{$k};
149        }
150
151        foreach my $k (@keys) {
152            $hash->{$k} = undef unless exists $hash->{$k};
153        }
154        Internals::SvREADONLY %$hash, 1;
155
156        foreach my $k (@keys) {
157            delete $hash->{$k} unless $original_keys{$k};
158        }
159    }
160    else {
161        Internals::SvREADONLY %$hash, 1;
162    }
163
164    return $hash;
165}
166
167sub unlock_ref_keys {
168    my $hash = shift;
169
170    Internals::SvREADONLY %$hash, 0;
171    return $hash;
172}
173
174sub   lock_keys (\%;@) {   lock_ref_keys(@_) }
175sub unlock_keys (\%)   { unlock_ref_keys(@_) }
176
177=item B<lock_keys_plus>
178
179  lock_keys_plus(%hash,@additional_keys)
180
181Similar to C<lock_keys()>, with the difference being that the optional key list
182specifies keys that may or may not be already in the hash. Essentially this is
183an easier way to say
184
185  lock_keys(%hash,@additional_keys,keys %hash);
186
187Returns a reference to %hash
188
189=cut
190
191
192sub lock_ref_keys_plus {
193    my ($hash,@keys)=@_;
194    my @delete;
195    Internals::hv_clear_placeholders(%$hash);
196    foreach my $key (@keys) {
197        unless (exists($hash->{$key})) {
198            $hash->{$key}=undef;
199            push @delete,$key;
200        }
201    }
202    Internals::SvREADONLY(%$hash,1);
203    delete @{$hash}{@delete};
204    return $hash
205}
206
207sub lock_keys_plus(\%;@) { lock_ref_keys_plus(@_) }
208
209
210=item B<lock_value>
211
212=item B<unlock_value>
213
214  lock_value  (%hash, $key);
215  unlock_value(%hash, $key);
216
217Locks and unlocks the value for an individual key of a hash.  The value of a
218locked key cannot be changed.
219
220Unless %hash has already been locked the key/value could be deleted
221regardless of this setting.
222
223Returns a reference to the %hash.
224
225=cut
226
227sub lock_ref_value {
228    my($hash, $key) = @_;
229    # I'm doubtful about this warning, as it seems not to be true.
230    # Marking a value in the hash as RO is useful, regardless
231    # of the status of the hash itself.
232    carp "Cannot usefully lock values in an unlocked hash"
233      if !Internals::SvREADONLY(%$hash) && warnings::enabled;
234    Internals::SvREADONLY $hash->{$key}, 1;
235    return $hash
236}
237
238sub unlock_ref_value {
239    my($hash, $key) = @_;
240    Internals::SvREADONLY $hash->{$key}, 0;
241    return $hash
242}
243
244sub   lock_value (\%$) {   lock_ref_value(@_) }
245sub unlock_value (\%$) { unlock_ref_value(@_) }
246
247
248=item B<lock_hash>
249
250=item B<unlock_hash>
251
252    lock_hash(%hash);
253
254lock_hash() locks an entire hash, making all keys and values read-only.
255No value can be changed, no keys can be added or deleted.
256
257    unlock_hash(%hash);
258
259unlock_hash() does the opposite of lock_hash().  All keys and values
260are made writable.  All values can be changed and keys can be added
261and deleted.
262
263Returns a reference to the %hash.
264
265=cut
266
267sub lock_hashref {
268    my $hash = shift;
269
270    lock_ref_keys($hash);
271
272    foreach my $value (values %$hash) {
273        Internals::SvREADONLY($value,1);
274    }
275
276    return $hash;
277}
278
279sub unlock_hashref {
280    my $hash = shift;
281
282    foreach my $value (values %$hash) {
283        Internals::SvREADONLY($value, 0);
284    }
285
286    unlock_ref_keys($hash);
287
288    return $hash;
289}
290
291sub   lock_hash (\%) {   lock_hashref(@_) }
292sub unlock_hash (\%) { unlock_hashref(@_) }
293
294=item B<lock_hash_recurse>
295
296=item B<unlock_hash_recurse>
297
298    lock_hash_recurse(%hash);
299
300lock_hash() locks an entire hash and any hashes it references recursively,
301making all keys and values read-only. No value can be changed, no keys can
302be added or deleted.
303
304B<Only> recurses into hashes that are referenced by another hash. Thus a
305Hash of Hashes (HoH) will all be restricted, but a Hash of Arrays of Hashes
306(HoAoH) will only have the top hash restricted.
307
308    unlock_hash_recurse(%hash);
309
310unlock_hash_recurse() does the opposite of lock_hash_recurse().  All keys and
311values are made writable.  All values can be changed and keys can be added
312and deleted. Identical recursion restrictions apply as to lock_hash_recurse().
313
314Returns a reference to the %hash.
315
316=cut
317
318sub lock_hashref_recurse {
319    my $hash = shift;
320
321    lock_ref_keys($hash);
322    foreach my $value (values %$hash) {
323        my $type = reftype($value);
324        if (defined($type) and $type eq 'HASH') {
325            lock_hashref_recurse($value);
326        }
327        Internals::SvREADONLY($value,1);
328    }
329    return $hash
330}
331
332sub unlock_hashref_recurse {
333    my $hash = shift;
334
335    foreach my $value (values %$hash) {
336        my $type = reftype($value);
337        if (defined($type) and $type eq 'HASH') {
338            unlock_hashref_recurse($value);
339        }
340        Internals::SvREADONLY($value,1);
341    }
342    unlock_ref_keys($hash);
343    return $hash;
344}
345
346sub   lock_hash_recurse (\%) {   lock_hashref_recurse(@_) }
347sub unlock_hash_recurse (\%) { unlock_hashref_recurse(@_) }
348
349
350=item B<hash_unlocked>
351
352  hash_unlocked(%hash) and print "Hash is unlocked!\n";
353
354Returns true if the hash and its keys are unlocked.
355
356=cut
357
358sub hashref_unlocked {
359    my $hash=shift;
360    return Internals::SvREADONLY($hash)
361}
362
363sub hash_unlocked(\%) { hashref_unlocked(@_) }
364
365=for demerphqs_editor
366sub legal_ref_keys{}
367sub hidden_ref_keys{}
368sub all_keys{}
369
370=cut
371
372sub legal_keys(\%) { legal_ref_keys(@_)  }
373sub hidden_keys(\%){ hidden_ref_keys(@_) }
374
375=item B<legal_keys>
376
377  my @keys = legal_keys(%hash);
378
379Returns the list of the keys that are legal in a restricted hash.
380In the case of an unrestricted hash this is identical to calling
381keys(%hash).
382
383=item B<hidden_keys>
384
385  my @keys = hidden_keys(%hash);
386
387Returns the list of the keys that are legal in a restricted hash but
388do not have a value associated to them. Thus if 'foo' is a
389"hidden" key of the %hash it will return false for both C<defined>
390and C<exists> tests.
391
392In the case of an unrestricted hash this will return an empty list.
393
394B<NOTE> this is an experimental feature that is heavily dependent
395on the current implementation of restricted hashes. Should the
396implementation change, this routine may become meaningless, in which
397case it will return an empty list.
398
399=item B<all_keys>
400
401  all_keys(%hash,@keys,@hidden);
402
403Populates the arrays @keys with the all the keys that would pass
404an C<exists> tests, and populates @hidden with the remaining legal
405keys that have not been utilized.
406
407Returns a reference to the hash.
408
409In the case of an unrestricted hash this will be equivalent to
410
411  $ref = do {
412      @keys = keys %hash;
413      @hidden = ();
414      \%hash
415  };
416
417B<NOTE> this is an experimental feature that is heavily dependent
418on the current implementation of restricted hashes. Should the
419implementation change this routine may become meaningless in which
420case it will behave identically to how it would behave on an
421unrestricted hash.
422
423=item B<hash_seed>
424
425    my $hash_seed = hash_seed();
426
427hash_seed() returns the seed number used to randomise hash ordering.
428Zero means the "traditional" random hash ordering, non-zero means the
429new even more random hash ordering introduced in Perl 5.8.1.
430
431B<Note that the hash seed is sensitive information>: by knowing it one
432can craft a denial-of-service attack against Perl code, even remotely,
433see L<perlsec/"Algorithmic Complexity Attacks"> for more information.
434B<Do not disclose the hash seed> to people who don't need to know it.
435See also L<perlrun/PERL_HASH_SEED_DEBUG>.
436
437=cut
438
439sub hash_seed () {
440    Internals::rehash_seed();
441}
442
443=item B<hv_store>
444
445  my $sv = 0;
446  hv_store(%hash,$key,$sv) or die "Failed to alias!";
447  $hash{$key} = 1;
448  print $sv; # prints 1
449
450Stores an alias to a variable in a hash instead of copying the value.
451
452=back
453
454=head2 Operating on references to hashes.
455
456Most subroutines documented in this module have equivalent versions
457that operate on references to hashes instead of native hashes.
458The following is a list of these subs. They are identical except
459in name and in that instead of taking a %hash they take a $hashref,
460and additionally are not prototyped.
461
462=over 4
463
464=item lock_ref_keys
465
466=item unlock_ref_keys
467
468=item lock_ref_keys_plus
469
470=item lock_ref_value
471
472=item unlock_ref_value
473
474=item lock_hashref
475
476=item unlock_hashref
477
478=item lock_hashref_recurse
479
480=item unlock_hashref_recurse
481
482=item hash_ref_unlocked
483
484=item legal_ref_keys
485
486=item hidden_ref_keys
487
488=back
489
490=head1 CAVEATS
491
492Note that the trapping of the restricted operations is not atomic:
493for example
494
495    eval { %hash = (illegal_key => 1) }
496
497leaves the C<%hash> empty rather than with its original contents.
498
499=head1 BUGS
500
501The interface exposed by this module is very close to the current
502implementation of restricted hashes. Over time it is expected that
503this behavior will be extended and the interface abstracted further.
504
505=head1 AUTHOR
506
507Michael G Schwern <schwern@pobox.com> on top of code by Nick
508Ing-Simmons and Jeffrey Friedl.
509
510hv_store() is from Array::RefElem, Copyright 2000 Gisle Aas.
511
512Additional code by Yves Orton.
513
514=head1 SEE ALSO
515
516L<Scalar::Util>, L<List::Util> and L<perlsec/"Algorithmic Complexity Attacks">.
517
518L<Hash::Util::FieldHash>.
519
520=cut
521
5221;
523