Initial Commit

This commit is contained in:
Riley Schneider
2025-12-03 16:38:10 +01:00
parent c5e26bf594
commit b732d8d4b5
17680 changed files with 5977495 additions and 2 deletions

View File

@@ -0,0 +1,283 @@
package Tie::Array;
use 5.006_001;
use strict;
use Carp;
our $VERSION = '1.07';
# Pod documentation after __END__ below.
sub DESTROY { }
sub EXTEND { }
sub UNSHIFT { scalar shift->SPLICE(0,0,@_) }
sub SHIFT { shift->SPLICE(0,1) }
sub CLEAR { shift->STORESIZE(0) }
sub PUSH
{
my $obj = shift;
my $i = $obj->FETCHSIZE;
$obj->STORE($i++, shift) while (@_);
}
sub POP
{
my $obj = shift;
my $newsize = $obj->FETCHSIZE - 1;
my $val;
if ($newsize >= 0)
{
$val = $obj->FETCH($newsize);
$obj->STORESIZE($newsize);
}
$val;
}
sub SPLICE {
my $obj = shift;
my $sz = $obj->FETCHSIZE;
my $off = (@_) ? shift : 0;
$off += $sz if ($off < 0);
my $len = (@_) ? shift : $sz - $off;
$len += $sz - $off if $len < 0;
my @result;
for (my $i = 0; $i < $len; $i++) {
push(@result,$obj->FETCH($off+$i));
}
$off = $sz if $off > $sz;
$len -= $off + $len - $sz if $off + $len > $sz;
if (@_ > $len) {
# Move items up to make room
my $d = @_ - $len;
my $e = $off+$len;
$obj->EXTEND($sz+$d);
for (my $i=$sz-1; $i >= $e; $i--) {
my $val = $obj->FETCH($i);
$obj->STORE($i+$d,$val);
}
}
elsif (@_ < $len) {
# Move items down to close the gap
my $d = $len - @_;
my $e = $off+$len;
for (my $i=$off+$len; $i < $sz; $i++) {
my $val = $obj->FETCH($i);
$obj->STORE($i-$d,$val);
}
$obj->STORESIZE($sz-$d);
}
for (my $i=0; $i < @_; $i++) {
$obj->STORE($off+$i,$_[$i]);
}
return wantarray ? @result : pop @result;
}
sub EXISTS {
my $pkg = ref $_[0];
croak "$pkg doesn't define an EXISTS method";
}
sub DELETE {
my $pkg = ref $_[0];
croak "$pkg doesn't define a DELETE method";
}
package Tie::StdArray;
our @ISA = 'Tie::Array';
sub TIEARRAY { bless [], $_[0] }
sub FETCHSIZE { scalar @{$_[0]} }
sub STORESIZE { $#{$_[0]} = $_[1]-1 }
sub STORE { $_[0]->[$_[1]] = $_[2] }
sub FETCH { $_[0]->[$_[1]] }
sub CLEAR { @{$_[0]} = () }
sub POP { pop(@{$_[0]}) }
sub PUSH { my $o = shift; push(@$o,@_) }
sub SHIFT { shift(@{$_[0]}) }
sub UNSHIFT { my $o = shift; unshift(@$o,@_) }
sub EXISTS { exists $_[0]->[$_[1]] }
sub DELETE { delete $_[0]->[$_[1]] }
sub SPLICE
{
my $ob = shift;
my $sz = $ob->FETCHSIZE;
my $off = @_ ? shift : 0;
$off += $sz if $off < 0;
my $len = @_ ? shift : $sz-$off;
return splice(@$ob,$off,$len,@_);
}
1;
__END__
=head1 NAME
Tie::Array - base class for tied arrays
=head1 SYNOPSIS
package Tie::NewArray;
use Tie::Array;
@ISA = ('Tie::Array');
# mandatory methods
sub TIEARRAY { ... }
sub FETCH { ... }
sub FETCHSIZE { ... }
sub STORE { ... } # mandatory if elements writeable
sub STORESIZE { ... } # mandatory if elements can be added/deleted
sub EXISTS { ... } # mandatory if exists() expected to work
sub DELETE { ... } # mandatory if delete() expected to work
# optional methods - for efficiency
sub CLEAR { ... }
sub PUSH { ... }
sub POP { ... }
sub SHIFT { ... }
sub UNSHIFT { ... }
sub SPLICE { ... }
sub EXTEND { ... }
sub DESTROY { ... }
package Tie::NewStdArray;
use Tie::Array;
@ISA = ('Tie::StdArray');
# all methods provided by default
package main;
$object = tie @somearray,'Tie::NewArray';
$object = tie @somearray,'Tie::StdArray';
$object = tie @somearray,'Tie::NewStdArray';
=head1 DESCRIPTION
This module provides methods for array-tying classes. See
L<perltie> for a list of the functions required in order to tie an array
to a package. The basic B<Tie::Array> package provides stub C<DESTROY>,
and C<EXTEND> methods that do nothing, stub C<DELETE> and C<EXISTS>
methods that croak() if the delete() or exists() builtins are ever called
on the tied array, and implementations of C<PUSH>, C<POP>, C<SHIFT>,
C<UNSHIFT>, C<SPLICE> and C<CLEAR> in terms of basic C<FETCH>, C<STORE>,
C<FETCHSIZE>, C<STORESIZE>.
The B<Tie::StdArray> package provides efficient methods required for tied arrays
which are implemented as blessed references to an "inner" perl array.
It inherits from B<Tie::Array>, and should cause tied arrays to behave exactly
like standard arrays, allowing for selective overloading of methods.
For developers wishing to write their own tied arrays, the required methods
are briefly defined below. See the L<perltie> section for more detailed
descriptive, as well as example code:
=over 4
=item TIEARRAY classname, LIST
The class method is invoked by the command C<tie @array, classname>. Associates
an array instance with the specified class. C<LIST> would represent
additional arguments (along the lines of L<AnyDBM_File> and compatriots) needed
to complete the association. The method should return an object of a class which
provides the methods below.
=item STORE this, index, value
Store datum I<value> into I<index> for the tied array associated with
object I<this>. If this makes the array larger then
class's mapping of C<undef> should be returned for new positions.
=item FETCH this, index
Retrieve the datum in I<index> for the tied array associated with
object I<this>.
=item FETCHSIZE this
Returns the total number of items in the tied array associated with
object I<this>. (Equivalent to C<scalar(@array)>).
=item STORESIZE this, count
Sets the total number of items in the tied array associated with
object I<this> to be I<count>. If this makes the array larger then
class's mapping of C<undef> should be returned for new positions.
If the array becomes smaller then entries beyond count should be
deleted.
=item EXTEND this, count
Informative call that array is likely to grow to have I<count> entries.
Can be used to optimize allocation. This method need do nothing.
=item EXISTS this, key
Verify that the element at index I<key> exists in the tied array I<this>.
The B<Tie::Array> implementation is a stub that simply croaks.
=item DELETE this, key
Delete the element at index I<key> from the tied array I<this>.
The B<Tie::Array> implementation is a stub that simply croaks.
=item CLEAR this
Clear (remove, delete, ...) all values from the tied array associated with
object I<this>.
=item DESTROY this
Normal object destructor method.
=item PUSH this, LIST
Append elements of LIST to the array.
=item POP this
Remove last element of the array and return it.
=item SHIFT this
Remove the first element of the array (shifting other elements down)
and return it.
=item UNSHIFT this, LIST
Insert LIST elements at the beginning of the array, moving existing elements
up to make room.
=item SPLICE this, offset, length, LIST
Perform the equivalent of C<splice> on the array.
I<offset> is optional and defaults to zero, negative values count back
from the end of the array.
I<length> is optional and defaults to rest of the array.
I<LIST> may be empty.
Returns a list of the original I<length> elements at I<offset>.
=back
=head1 CAVEATS
There is no support at present for tied @ISA. There is a potential conflict
between magic entries needed to notice setting of @ISA, and those needed to
implement 'tie'.
=head1 AUTHOR
Nick Ing-Simmons E<lt>nik@tiuk.ti.comE<gt>
=cut

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,201 @@
package Tie::Handle;
use 5.006_001;
our $VERSION = '4.2';
# Tie::StdHandle used to be inside Tie::Handle. For backwards compatibility
# loading Tie::Handle has to make Tie::StdHandle available.
use Tie::StdHandle;
=head1 NAME
Tie::Handle - base class definitions for tied handles
=head1 SYNOPSIS
package NewHandle;
require Tie::Handle;
@ISA = qw(Tie::Handle);
sub READ { ... } # Provide a needed method
sub TIEHANDLE { ... } # Overrides inherited method
package main;
tie *FH, 'NewHandle';
=head1 DESCRIPTION
This module provides some skeletal methods for handle-tying classes. See
L<perltie> for a list of the functions required in tying a handle to a package.
The basic B<Tie::Handle> package provides a C<new> method, as well as methods
C<TIEHANDLE>, C<PRINT>, C<PRINTF> and C<GETC>.
For developers wishing to write their own tied-handle classes, the methods
are summarized below. The L<perltie> section not only documents these, but
has sample code as well:
=over 4
=item TIEHANDLE classname, LIST
The method invoked by the command C<tie *glob, classname>. Associates a new
glob instance with the specified class. C<LIST> would represent additional
arguments (along the lines of L<AnyDBM_File> and compatriots) needed to
complete the association.
=item WRITE this, scalar, length, offset
Write I<length> bytes of data from I<scalar> starting at I<offset>.
=item PRINT this, LIST
Print the values in I<LIST>
=item PRINTF this, format, LIST
Print the values in I<LIST> using I<format>
=item READ this, scalar, length, offset
Read I<length> bytes of data into I<scalar> starting at I<offset>.
=item READLINE this
Read a single line
=item GETC this
Get a single character
=item CLOSE this
Close the handle
=item OPEN this, filename
(Re-)open the handle
=item BINMODE this
Specify content is binary
=item EOF this
Test for end of file.
=item TELL this
Return position in the file.
=item SEEK this, offset, whence
Position the file.
Test for end of file.
=item DESTROY this
Free the storage associated with the tied handle referenced by I<this>.
This is rarely needed, as Perl manages its memory quite well. But the
option exists, should a class wish to perform specific actions upon the
destruction of an instance.
=back
=head1 MORE INFORMATION
The L<perltie> section contains an example of tying handles.
=head1 COMPATIBILITY
This version of Tie::Handle is neither related to nor compatible with
the Tie::Handle (3.0) module available on CPAN. It was due to an
accident that two modules with the same name appeared. The namespace
clash has been cleared in favor of this module that comes with the
perl core in September 2000 and accordingly the version number has
been bumped up to 4.0.
=cut
use Carp;
use warnings::register;
sub new {
my $pkg = shift;
$pkg->TIEHANDLE(@_);
}
# "Grandfather" the new, a la Tie::Hash
sub TIEHANDLE {
my $pkg = shift;
if (defined &{"{$pkg}::new"}) {
warnings::warnif("WARNING: calling ${pkg}->new since ${pkg}->TIEHANDLE is missing");
$pkg->new(@_);
}
else {
croak "$pkg doesn't define a TIEHANDLE method";
}
}
sub PRINT {
my $self = shift;
if($self->can('WRITE') != \&WRITE) {
my $buf = join(defined $, ? $, : "",@_);
$buf .= $\ if defined $\;
$self->WRITE($buf,length($buf),0);
}
else {
croak ref($self)," doesn't define a PRINT method";
}
}
sub PRINTF {
my $self = shift;
if($self->can('WRITE') != \&WRITE) {
my $buf = sprintf(shift,@_);
$self->WRITE($buf,length($buf),0);
}
else {
croak ref($self)," doesn't define a PRINTF method";
}
}
sub READLINE {
my $pkg = ref $_[0];
croak "$pkg doesn't define a READLINE method";
}
sub GETC {
my $self = shift;
if($self->can('READ') != \&READ) {
my $buf;
$self->READ($buf,1);
return $buf;
}
else {
croak ref($self)," doesn't define a GETC method";
}
}
sub READ {
my $pkg = ref $_[0];
croak "$pkg doesn't define a READ method";
}
sub WRITE {
my $pkg = ref $_[0];
croak "$pkg doesn't define a WRITE method";
}
sub CLOSE {
my $pkg = ref $_[0];
croak "$pkg doesn't define a CLOSE method";
}
1;

View File

@@ -0,0 +1,270 @@
package Tie::Hash;
our $VERSION = '1.05';
=head1 NAME
Tie::Hash, Tie::StdHash, Tie::ExtraHash - base class definitions for tied hashes
=head1 SYNOPSIS
package NewHash;
require Tie::Hash;
@ISA = qw(Tie::Hash);
sub DELETE { ... } # Provides needed method
sub CLEAR { ... } # Overrides inherited method
package NewStdHash;
require Tie::Hash;
@ISA = qw(Tie::StdHash);
# All methods provided by default, define
# only those needing overrides
# Accessors access the storage in %{$_[0]};
# TIEHASH should return a reference to the actual storage
sub DELETE { ... }
package NewExtraHash;
require Tie::Hash;
@ISA = qw(Tie::ExtraHash);
# All methods provided by default, define
# only those needing overrides
# Accessors access the storage in %{$_[0][0]};
# TIEHASH should return an array reference with the first element
# being the reference to the actual storage
sub DELETE {
$_[0][1]->('del', $_[0][0], $_[1]); # Call the report writer
delete $_[0][0]->{$_[1]}; # $_[0]->SUPER::DELETE($_[1])
}
package main;
tie %new_hash, 'NewHash';
tie %new_std_hash, 'NewStdHash';
tie %new_extra_hash, 'NewExtraHash',
sub {warn "Doing \U$_[1]\E of $_[2].\n"};
=head1 DESCRIPTION
This module provides some skeletal methods for hash-tying classes. See
L<perltie> for a list of the functions required in order to tie a hash
to a package. The basic B<Tie::Hash> package provides a C<new> method, as well
as methods C<TIEHASH>, C<EXISTS> and C<CLEAR>. The B<Tie::StdHash> and
B<Tie::ExtraHash> packages
provide most methods for hashes described in L<perltie> (the exceptions
are C<UNTIE> and C<DESTROY>). They cause tied hashes to behave exactly like standard hashes,
and allow for selective overwriting of methods. B<Tie::Hash> grandfathers the
C<new> method: it is used if C<TIEHASH> is not defined
in the case a class forgets to include a C<TIEHASH> method.
For developers wishing to write their own tied hashes, the required methods
are briefly defined below. See the L<perltie> section for more detailed
descriptive, as well as example code:
=over 4
=item TIEHASH classname, LIST
The method invoked by the command C<tie %hash, classname>. Associates a new
hash instance with the specified class. C<LIST> would represent additional
arguments (along the lines of L<AnyDBM_File> and compatriots) needed to
complete the association.
=item STORE this, key, value
Store datum I<value> into I<key> for the tied hash I<this>.
=item FETCH this, key
Retrieve the datum in I<key> for the tied hash I<this>.
=item FIRSTKEY this
Return the first key in the hash.
=item NEXTKEY this, lastkey
Return the next key in the hash.
=item EXISTS this, key
Verify that I<key> exists with the tied hash I<this>.
The B<Tie::Hash> implementation is a stub that simply croaks.
=item DELETE this, key
Delete the key I<key> from the tied hash I<this>.
=item CLEAR this
Clear all values from the tied hash I<this>.
=item SCALAR this
Returns what evaluating the hash in scalar context yields.
B<Tie::Hash> does not implement this method (but B<Tie::StdHash>
and B<Tie::ExtraHash> do).
=back
=head1 Inheriting from B<Tie::StdHash>
The accessor methods assume that the actual storage for the data in the tied
hash is in the hash referenced by C<tied(%tiedhash)>. Thus overwritten
C<TIEHASH> method should return a hash reference, and the remaining methods
should operate on the hash referenced by the first argument:
package ReportHash;
our @ISA = 'Tie::StdHash';
sub TIEHASH {
my $storage = bless {}, shift;
warn "New ReportHash created, stored in $storage.\n";
$storage
}
sub STORE {
warn "Storing data with key $_[1] at $_[0].\n";
$_[0]{$_[1]} = $_[2]
}
=head1 Inheriting from B<Tie::ExtraHash>
The accessor methods assume that the actual storage for the data in the tied
hash is in the hash referenced by C<(tied(%tiedhash))-E<gt>[0]>. Thus overwritten
C<TIEHASH> method should return an array reference with the first
element being a hash reference, and the remaining methods should operate on the
hash C<< %{ $_[0]->[0] } >>:
package ReportHash;
our @ISA = 'Tie::ExtraHash';
sub TIEHASH {
my $class = shift;
my $storage = bless [{}, @_], $class;
warn "New ReportHash created, stored in $storage.\n";
$storage;
}
sub STORE {
warn "Storing data with key $_[1] at $_[0].\n";
$_[0][0]{$_[1]} = $_[2]
}
The default C<TIEHASH> method stores "extra" arguments to tie() starting
from offset 1 in the array referenced by C<tied(%tiedhash)>; this is the
same storage algorithm as in TIEHASH subroutine above. Hence, a typical
package inheriting from B<Tie::ExtraHash> does not need to overwrite this
method.
=head1 C<SCALAR>, C<UNTIE> and C<DESTROY>
The methods C<UNTIE> and C<DESTROY> are not defined in B<Tie::Hash>,
B<Tie::StdHash>, or B<Tie::ExtraHash>. Tied hashes do not require
presence of these methods, but if defined, the methods will be called in
proper time, see L<perltie>.
C<SCALAR> is only defined in B<Tie::StdHash> and B<Tie::ExtraHash>.
If needed, these methods should be defined by the package inheriting from
B<Tie::Hash>, B<Tie::StdHash>, or B<Tie::ExtraHash>. See L<perltie/"SCALAR">
to find out what happens when C<SCALAR> does not exist.
=head1 MORE INFORMATION
The packages relating to various DBM-related implementations (F<DB_File>,
F<NDBM_File>, etc.) show examples of general tied hashes, as does the
L<Config> module. While these do not utilize B<Tie::Hash>, they serve as
good working examples.
=cut
use Carp;
use warnings::register;
sub new {
my $pkg = shift;
$pkg->TIEHASH(@_);
}
# Grandfather "new"
sub TIEHASH {
my $pkg = shift;
my $pkg_new = $pkg -> can ('new');
if ($pkg_new and $pkg ne __PACKAGE__) {
my $my_new = __PACKAGE__ -> can ('new');
if ($pkg_new == $my_new) {
#
# Prevent recursion
#
croak "$pkg must define either a TIEHASH() or a new() method";
}
warnings::warnif ("WARNING: calling ${pkg}->new since " .
"${pkg}->TIEHASH is missing");
$pkg -> new (@_);
}
else {
croak "$pkg doesn't define a TIEHASH method";
}
}
sub EXISTS {
my $pkg = ref $_[0];
croak "$pkg doesn't define an EXISTS method";
}
sub CLEAR {
my $self = shift;
my $key = $self->FIRSTKEY(@_);
my @keys;
while (defined $key) {
push @keys, $key;
$key = $self->NEXTKEY(@_, $key);
}
foreach $key (@keys) {
$self->DELETE(@_, $key);
}
}
# The Tie::StdHash package implements standard perl hash behaviour.
# It exists to act as a base class for classes which only wish to
# alter some parts of their behaviour.
package Tie::StdHash;
# @ISA = qw(Tie::Hash); # would inherit new() only
sub TIEHASH { bless {}, $_[0] }
sub STORE { $_[0]->{$_[1]} = $_[2] }
sub FETCH { $_[0]->{$_[1]} }
sub FIRSTKEY { my $a = scalar keys %{$_[0]}; each %{$_[0]} }
sub NEXTKEY { each %{$_[0]} }
sub EXISTS { exists $_[0]->{$_[1]} }
sub DELETE { delete $_[0]->{$_[1]} }
sub CLEAR { %{$_[0]} = () }
sub SCALAR { scalar %{$_[0]} }
package Tie::ExtraHash;
sub TIEHASH { my $p = shift; bless [{}, @_], $p }
sub STORE { $_[0][0]{$_[1]} = $_[2] }
sub FETCH { $_[0][0]{$_[1]} }
sub FIRSTKEY { my $a = scalar keys %{$_[0][0]}; each %{$_[0][0]} }
sub NEXTKEY { each %{$_[0][0]} }
sub EXISTS { exists $_[0][0]->{$_[1]} }
sub DELETE { delete $_[0][0]->{$_[1]} }
sub CLEAR { %{$_[0][0]} = () }
sub SCALAR { scalar %{$_[0][0]} }
1;

View File

@@ -0,0 +1,49 @@
use strict;
package Tie::Hash::NamedCapture;
our $VERSION = "0.13";
__END__
=head1 NAME
Tie::Hash::NamedCapture - Named regexp capture buffers
=head1 SYNOPSIS
tie my %hash, "Tie::Hash::NamedCapture";
# %hash now behaves like %+
tie my %hash, "Tie::Hash::NamedCapture", all => 1;
# %hash now access buffers from regexp in $qr like %-
=head1 DESCRIPTION
This module is used to implement the special hashes C<%+> and C<%->, but it
can be used to tie other variables as you choose.
When the C<all> parameter is provided, then the tied hash elements will be
array refs listing the contents of each capture buffer whose name is the
same as the associated hash key. If none of these buffers were involved in
the match, the contents of that array ref will be as many C<undef> values
as there are capture buffers with that name. In other words, the tied hash
will behave as C<%->.
When the C<all> parameter is omitted or false, then the tied hash elements
will be the contents of the leftmost defined buffer with the name of the
associated hash key. In other words, the tied hash will behave as
C<%+>.
The keys of C<%->-like hashes correspond to all buffer names found in the
regular expression; the keys of C<%+>-like hashes list only the names of
buffers that have captured (and that are thus associated to defined values).
This implementation has been moved into the core executable, but you
can still load this module for backward compatibility.
=head1 SEE ALSO
L<perlreapi>, L<re>, L<perlmodlib/Pragmatic Modules>, L<perlvar/"%+">,
L<perlvar/"%-">.
=cut

View File

@@ -0,0 +1,128 @@
use strict;
package Tie::Memoize;
use Tie::Hash;
our @ISA = 'Tie::ExtraHash';
our $VERSION = '1.1';
our $exists_token = \undef;
sub croak {require Carp; goto &Carp::croak}
# Format: [0: STORAGE, 1: EXISTS-CACHE, 2: FETCH_function;
# 3: EXISTS_function, 4: DATA, 5: EXISTS_different ]
sub FETCH {
my ($h,$key) = ($_[0][0], $_[1]);
my $res = $h->{$key};
return $res if defined $res; # Shortcut if accessible
return $res if exists $h->{$key}; # Accessible, but undef
my $cache = $_[0][1]{$key};
return if defined $cache and not $cache; # Known to not exist
my @res = $_[0][2]->($key, $_[0][4]); # Autoload
$_[0][1]{$key} = 0, return unless @res; # Cache non-existence
delete $_[0][1]{$key}; # Clear existence cache, not needed any more
$_[0][0]{$key} = $res[0]; # Store data and return
}
sub EXISTS {
my ($a,$key) = (shift, shift);
return 1 if exists $a->[0]{$key}; # Have data
my $cache = $a->[1]{$key};
return $cache if defined $cache; # Existence cache
my @res = $a->[3]($key,$a->[4]);
$a->[1]{$key} = 0, return unless @res; # Cache non-existence
# Now we know it exists
return ($a->[1]{$key} = 1) if $a->[5]; # Only existence reported
# Now know the value
$a->[0]{$key} = $res[0]; # Store data
return 1
}
sub TIEHASH {
croak 'syntax: tie %hash, \'Tie::AutoLoad\', \&fetch_subr' if @_ < 2;
croak 'syntax: tie %hash, \'Tie::AutoLoad\', \&fetch_subr, $data, \&exists_subr, \%data_cache, \%existence_cache' if @_ > 6;
push @_, undef if @_ < 3; # Data
push @_, $_[1] if @_ < 4; # exists
push @_, {} while @_ < 6; # initial value and caches
bless [ @_[4,5,1,3,2], $_[1] ne $_[3]], $_[0]
}
1;
=head1 NAME
Tie::Memoize - add data to hash when needed
=head1 SYNOPSIS
require Tie::Memoize;
tie %hash, 'Tie::Memoize',
\&fetch, # The rest is optional
$DATA, \&exists,
{%ini_value}, {%ini_existence};
=head1 DESCRIPTION
This package allows a tied hash to autoload its values on the first access,
and to use the cached value on the following accesses.
Only read-accesses (via fetching the value or C<exists>) result in calls to
the functions; the modify-accesses are performed as on a normal hash.
The required arguments during C<tie> are the hash, the package, and
the reference to the C<FETCH>ing function. The optional arguments are
an arbitrary scalar $data, the reference to the C<EXISTS> function,
and initial values of the hash and of the existence cache.
Both the C<FETCH>ing function and the C<EXISTS> functions have the
same signature: the arguments are C<$key, $data>; $data is the same
value as given as argument during tie()ing. Both functions should
return an empty list if the value does not exist. If C<EXISTS>
function is different from the C<FETCH>ing function, it should return
a TRUE value on success. The C<FETCH>ing function should return the
intended value if the key is valid.
=head1 Inheriting from B<Tie::Memoize>
The structure of the tied() data is an array reference with elements
0: cache of known values
1: cache of known existence of keys
2: FETCH function
3: EXISTS function
4: $data
The rest is for internal usage of this package. In particular, if
TIEHASH is overwritten, it should call SUPER::TIEHASH.
=head1 EXAMPLE
sub slurp {
my ($key, $dir) = shift;
open my $h, '<', "$dir/$key" or return;
local $/; <$h> # slurp it all
}
sub exists { my ($key, $dir) = shift; return -f "$dir/$key" }
tie %hash, 'Tie::Memoize', \&slurp, $directory, \&exists,
{ fake_file1 => $content1, fake_file2 => $content2 },
{ pretend_does_not_exists => 0, known_to_exist => 1 };
This example treats the slightly modified contents of $directory as a
hash. The modifications are that the keys F<fake_file1> and
F<fake_file2> fetch values $content1 and $content2, and
F<pretend_does_not_exists> will never be accessed. Additionally, the
existence of F<known_to_exist> is never checked (so if it does not
exists when its content is needed, the user of %hash may be confused).
=head1 BUGS
FIRSTKEY and NEXTKEY methods go through the keys which were already read,
not all the possible keys of the hash.
=head1 AUTHOR
Ilya Zakharevich L<mailto:perl-module-hash-memoize@ilyaz.org>.
=cut

View File

@@ -0,0 +1,375 @@
package Tie::RefHash; # git description: Tie-RefHash-1.39-10-g2cfa4bd
# ABSTRACT: Use references as hash keys
our $VERSION = '1.40';
#pod =head1 SYNOPSIS
#pod
#pod require 5.004;
#pod use Tie::RefHash;
#pod tie HASHVARIABLE, 'Tie::RefHash', LIST;
#pod tie HASHVARIABLE, 'Tie::RefHash::Nestable', LIST;
#pod
#pod untie HASHVARIABLE;
#pod
#pod =head1 DESCRIPTION
#pod
#pod This module provides the ability to use references as hash keys if you
#pod first C<tie> the hash variable to this module. Normally, only the
#pod keys of the tied hash itself are preserved as references; to use
#pod references as keys in hashes-of-hashes, use Tie::RefHash::Nestable,
#pod included as part of Tie::RefHash.
#pod
#pod It is implemented using the standard perl TIEHASH interface. Please
#pod see the C<tie> entry in perlfunc(1) and perltie(1) for more information.
#pod
#pod The Nestable version works by looking for hash references being stored
#pod and converting them to tied hashes so that they too can have
#pod references as keys. This will happen without warning whenever you
#pod store a reference to one of your own hashes in the tied hash.
#pod
#pod =head1 EXAMPLE
#pod
#pod use Tie::RefHash;
#pod tie %h, 'Tie::RefHash';
#pod $a = [];
#pod $b = {};
#pod $c = \*main;
#pod $d = \"gunk";
#pod $e = sub { 'foo' };
#pod %h = ($a => 1, $b => 2, $c => 3, $d => 4, $e => 5);
#pod $a->[0] = 'foo';
#pod $b->{foo} = 'bar';
#pod for (keys %h) {
#pod print ref($_), "\n";
#pod }
#pod
#pod tie %h, 'Tie::RefHash::Nestable';
#pod $h{$a}->{$b} = 1;
#pod for (keys %h, keys %{$h{$a}}) {
#pod print ref($_), "\n";
#pod }
#pod
#pod =head1 THREAD SUPPORT
#pod
#pod L<Tie::RefHash> fully supports threading using the C<CLONE> method.
#pod
#pod =head1 STORABLE SUPPORT
#pod
#pod L<Storable> hooks are provided for semantically correct serialization and
#pod cloning of tied refhashes.
#pod
#pod =head1 AUTHORS
#pod
#pod Gurusamy Sarathy <gsar@activestate.com>
#pod
#pod Tie::RefHash::Nestable by Ed Avis <ed@membled.com>
#pod
#pod =head1 SEE ALSO
#pod
#pod perl(1), perlfunc(1), perltie(1)
#pod
#pod =cut
use Tie::Hash;
our @ISA = qw(Tie::Hash);
use strict;
use Carp ();
BEGIN {
local $@;
# determine whether we need to take care of threads
use Config ();
my $usethreads = $Config::Config{usethreads}; # && exists $INC{"threads.pm"}
*_HAS_THREADS = $usethreads ? sub () { 1 } : sub () { 0 };
*_HAS_SCALAR_UTIL = eval { require Scalar::Util; 1 } ? sub () { 1 } : sub () { 0 };
*_HAS_WEAKEN = defined(&Scalar::Util::weaken) ? sub () { 1 } : sub () { 0 };
}
BEGIN {
# create a refaddr function
local $@;
if ( _HAS_SCALAR_UTIL ) {
*refaddr = sub { goto \&Scalar::Util::refaddr }
} else {
require overload;
*refaddr = sub {
if ( overload::StrVal($_[0]) =~ /\( 0x ([a-zA-Z0-9]+) \)$/x) {
return $1;
} else {
die "couldn't parse StrVal: " . overload::StrVal($_[0]);
}
};
}
}
my (@thread_object_registry, $count); # used by the CLONE method to rehash the keys after their refaddr changed
sub TIEHASH {
my $c = shift;
my $s = [];
bless $s, $c;
while (@_) {
$s->STORE(shift, shift);
}
if (_HAS_THREADS ) {
if ( _HAS_WEAKEN ) {
# remember the object so that we can rekey it on CLONE
push @thread_object_registry, $s;
# but make this a weak reference, so that there are no leaks
Scalar::Util::weaken( $thread_object_registry[-1] );
if ( ++$count > 1000 ) {
# this ensures we don't fill up with a huge array dead weakrefs
@thread_object_registry = grep defined, @thread_object_registry;
$count = 0;
}
} else {
$count++; # used in the warning
}
}
return $s;
}
my $storable_format_version = join("/", __PACKAGE__, "0.01");
sub STORABLE_freeze {
my ( $self, $is_cloning ) = @_;
my ( $refs, $reg ) = @$self;
return ( $storable_format_version, [ values %$refs ], $reg || {} );
}
sub STORABLE_thaw {
my ( $self, $is_cloning, $version, $refs, $reg ) = @_;
Carp::croak "incompatible versions of Tie::RefHash between freeze and thaw"
unless $version eq $storable_format_version;
@$self = ( {}, $reg );
$self->_reindex_keys( $refs );
}
sub CLONE {
my $pkg = shift;
if ( $count and not _HAS_WEAKEN ) {
warn "Tie::RefHash is not threadsafe without Scalar::Util::weaken";
}
# when the thread has been cloned all the objects need to be updated.
# dead weakrefs are undefined, so we filter them out
@thread_object_registry = grep defined && do { $_->_reindex_keys; 1 }, @thread_object_registry;
$count = 0; # we just cleaned up
}
sub _reindex_keys {
my ( $self, $extra_keys ) = @_;
# rehash all the ref keys based on their new StrVal
%{ $self->[0] } = map +(Scalar::Util::refaddr($_->[0]) => $_), (values(%{ $self->[0] }), @{ $extra_keys || [] });
}
sub FETCH {
my($s, $k) = @_;
if (ref $k) {
my $kstr = Scalar::Util::refaddr($k);
if (defined $s->[0]{$kstr}) {
$s->[0]{$kstr}[1];
}
else {
undef;
}
}
else {
$s->[1]{$k};
}
}
sub STORE {
my($s, $k, $v) = @_;
if (ref $k) {
$s->[0]{Scalar::Util::refaddr($k)} = [$k, $v];
}
else {
$s->[1]{$k} = $v;
}
$v;
}
sub DELETE {
my($s, $k) = @_;
(ref $k)
? (delete($s->[0]{Scalar::Util::refaddr($k)}) || [])->[1]
: delete($s->[1]{$k});
}
sub EXISTS {
my($s, $k) = @_;
(ref $k) ? exists($s->[0]{Scalar::Util::refaddr($k)}) : exists($s->[1]{$k});
}
sub FIRSTKEY {
my $s = shift;
keys %{$s->[0]}; # reset iterator
keys %{$s->[1]}; # reset iterator
$s->[2] = 0; # flag for iteration, see NEXTKEY
$s->NEXTKEY;
}
sub NEXTKEY {
my $s = shift;
my ($k, $v);
if (!$s->[2]) {
if (($k, $v) = each %{$s->[0]}) {
return $v->[0];
}
else {
$s->[2] = 1;
}
}
return each %{$s->[1]};
}
sub CLEAR {
my $s = shift;
$s->[2] = 0;
%{$s->[0]} = ();
%{$s->[1]} = ();
}
package # hide from PAUSE
Tie::RefHash::Nestable;
our @ISA = 'Tie::RefHash';
sub STORE {
my($s, $k, $v) = @_;
if (ref($v) eq 'HASH' and not tied %$v) {
my @elems = %$v;
tie %$v, ref($s), @elems;
}
$s->SUPER::STORE($k, $v);
}
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
Tie::RefHash - Use references as hash keys
=head1 VERSION
version 1.40
=head1 SYNOPSIS
require 5.004;
use Tie::RefHash;
tie HASHVARIABLE, 'Tie::RefHash', LIST;
tie HASHVARIABLE, 'Tie::RefHash::Nestable', LIST;
untie HASHVARIABLE;
=head1 DESCRIPTION
This module provides the ability to use references as hash keys if you
first C<tie> the hash variable to this module. Normally, only the
keys of the tied hash itself are preserved as references; to use
references as keys in hashes-of-hashes, use Tie::RefHash::Nestable,
included as part of Tie::RefHash.
It is implemented using the standard perl TIEHASH interface. Please
see the C<tie> entry in perlfunc(1) and perltie(1) for more information.
The Nestable version works by looking for hash references being stored
and converting them to tied hashes so that they too can have
references as keys. This will happen without warning whenever you
store a reference to one of your own hashes in the tied hash.
=head1 EXAMPLE
use Tie::RefHash;
tie %h, 'Tie::RefHash';
$a = [];
$b = {};
$c = \*main;
$d = \"gunk";
$e = sub { 'foo' };
%h = ($a => 1, $b => 2, $c => 3, $d => 4, $e => 5);
$a->[0] = 'foo';
$b->{foo} = 'bar';
for (keys %h) {
print ref($_), "\n";
}
tie %h, 'Tie::RefHash::Nestable';
$h{$a}->{$b} = 1;
for (keys %h, keys %{$h{$a}}) {
print ref($_), "\n";
}
=head1 THREAD SUPPORT
L<Tie::RefHash> fully supports threading using the C<CLONE> method.
=head1 STORABLE SUPPORT
L<Storable> hooks are provided for semantically correct serialization and
cloning of tied refhashes.
=head1 SEE ALSO
perl(1), perlfunc(1), perltie(1)
=head1 SUPPORT
Bugs may be submitted through L<the RT bug tracker|https://rt.cpan.org/Public/Dist/Display.html?Name=Tie-RefHash>
(or L<bug-Tie-RefHash@rt.cpan.org|mailto:bug-Tie-RefHash@rt.cpan.org>).
=head1 AUTHORS
Gurusamy Sarathy <gsar@activestate.com>
Tie::RefHash::Nestable by Ed Avis <ed@membled.com>
=head1 CONTRIBUTORS
=for stopwords Yuval Kogman Karen Etheridge Florian Ragwitz Jerry D. Hedden
=over 4
=item *
Yuval Kogman <nothingmuch@woobling.org>
=item *
Karen Etheridge <ether@cpan.org>
=item *
Florian Ragwitz <rafl@debian.org>
=item *
Jerry D. Hedden <jdhedden@cpan.org>
=back
=head1 COPYRIGHT AND LICENCE
This software is copyright (c) 2006 by יובל קוג'מן (Yuval Kogman) <nothingmuch@woobling.org>.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut

View File

@@ -0,0 +1,164 @@
package Tie::Scalar;
our $VERSION = '1.05';
=head1 NAME
Tie::Scalar, Tie::StdScalar - base class definitions for tied scalars
=head1 SYNOPSIS
package NewScalar;
require Tie::Scalar;
@ISA = qw(Tie::Scalar);
sub FETCH { ... } # Provide a needed method
sub TIESCALAR { ... } # Overrides inherited method
package NewStdScalar;
require Tie::Scalar;
@ISA = qw(Tie::StdScalar);
# All methods provided by default, so define
# only what needs be overridden
sub FETCH { ... }
package main;
tie $new_scalar, 'NewScalar';
tie $new_std_scalar, 'NewStdScalar';
=head1 DESCRIPTION
This module provides some skeletal methods for scalar-tying classes. See
L<perltie> for a list of the functions required in tying a scalar to a
package. The basic B<Tie::Scalar> package provides a C<new> method, as well
as methods C<TIESCALAR>, C<FETCH> and C<STORE>. The B<Tie::StdScalar>
package provides all the methods specified in L<perltie>. It inherits from
B<Tie::Scalar> and causes scalars tied to it to behave exactly like the
built-in scalars, allowing for selective overloading of methods. The C<new>
method is provided as a means of grandfathering, for classes that forget to
provide their own C<TIESCALAR> method.
For developers wishing to write their own tied-scalar classes, the methods
are summarized below. The L<perltie> section not only documents these, but
has sample code as well:
=over 4
=item TIESCALAR classname, LIST
The method invoked by the command C<tie $scalar, classname>. Associates a new
scalar instance with the specified class. C<LIST> would represent additional
arguments (along the lines of L<AnyDBM_File> and compatriots) needed to
complete the association.
=item FETCH this
Retrieve the value of the tied scalar referenced by I<this>.
=item STORE this, value
Store data I<value> in the tied scalar referenced by I<this>.
=item DESTROY this
Free the storage associated with the tied scalar referenced by I<this>.
This is rarely needed, as Perl manages its memory quite well. But the
option exists, should a class wish to perform specific actions upon the
destruction of an instance.
=back
=head2 Tie::Scalar vs Tie::StdScalar
C<< Tie::Scalar >> provides all the necessary methods, but one should realize
they do not do anything useful. Calling C<< Tie::Scalar::FETCH >> or
C<< Tie::Scalar::STORE >> results in a (trappable) croak. And if you inherit
from C<< Tie::Scalar >>, you I<must> provide either a C<< new >> or a
C<< TIESCALAR >> method.
If you are looking for a class that does everything for you that you don't
define yourself, use the C<< Tie::StdScalar >> class, not the
C<< Tie::Scalar >> one.
=head1 MORE INFORMATION
The L<perltie> section uses a good example of tying scalars by associating
process IDs with priority.
=cut
use Carp;
use warnings::register;
sub new {
my $pkg = shift;
$pkg->TIESCALAR(@_);
}
# "Grandfather" the new, a la Tie::Hash
sub TIESCALAR {
my $pkg = shift;
my $pkg_new = $pkg -> can ('new');
if ($pkg_new and $pkg ne __PACKAGE__) {
my $my_new = __PACKAGE__ -> can ('new');
if ($pkg_new == $my_new) {
#
# Prevent recursion
#
croak "$pkg must define either a TIESCALAR() or a new() method";
}
warnings::warnif ("WARNING: calling ${pkg}->new since " .
"${pkg}->TIESCALAR is missing");
$pkg -> new (@_);
}
else {
croak "$pkg doesn't define a TIESCALAR method";
}
}
sub FETCH {
my $pkg = ref $_[0];
croak "$pkg doesn't define a FETCH method";
}
sub STORE {
my $pkg = ref $_[0];
croak "$pkg doesn't define a STORE method";
}
#
# The Tie::StdScalar package provides scalars that behave exactly like
# Perl's built-in scalars. Good base to inherit from, if you're only going to
# tweak a small bit.
#
package Tie::StdScalar;
@ISA = qw(Tie::Scalar);
sub TIESCALAR {
my $class = shift;
my $instance = @_ ? shift : undef;
return bless \$instance => $class;
}
sub FETCH {
return ${$_[0]};
}
sub STORE {
${$_[0]} = $_[1];
}
sub DESTROY {
undef ${$_[0]};
}
1;

View File

@@ -0,0 +1,71 @@
package Tie::StdHandle;
use strict;
use Tie::Handle;
our @ISA = 'Tie::Handle';
our $VERSION = '4.6';
=head1 NAME
Tie::StdHandle - base class definitions for tied handles
=head1 SYNOPSIS
package NewHandle;
require Tie::Handle;
@ISA = qw(Tie::Handle);
sub READ { ... } # Provide a needed method
sub TIEHANDLE { ... } # Overrides inherited method
package main;
tie *FH, 'NewHandle';
=head1 DESCRIPTION
The B<Tie::StdHandle> package provide most methods for file handles described
in L<perltie> (the exceptions are C<UNTIE> and C<DESTROY>). It causes tied
file handles to behave exactly like standard file handles and allow for
selective overwriting of methods.
=cut
sub TIEHANDLE
{
my $class = shift;
my $fh = \do { local *HANDLE};
bless $fh,$class;
$fh->OPEN(@_) if (@_);
return $fh;
}
sub EOF { eof($_[0]) }
sub TELL { tell($_[0]) }
sub FILENO { fileno($_[0]) }
sub SEEK { seek($_[0],$_[1],$_[2]) }
sub CLOSE { close($_[0]) }
sub BINMODE { &CORE::binmode(shift, @_) }
sub OPEN
{
$_[0]->CLOSE if defined($_[0]->FILENO);
@_ == 2 ? open($_[0], $_[1]) : open($_[0], $_[1], $_[2]);
}
sub READ { &CORE::read(shift, \shift, @_) }
sub READLINE { my $fh = $_[0]; <$fh> }
sub GETC { getc($_[0]) }
sub WRITE
{
my $fh = $_[0];
local $\; # don't print any line terminator
print $fh substr($_[1], $_[3], $_[2]);
}
1;

View File

@@ -0,0 +1,215 @@
package Tie::SubstrHash;
our $VERSION = '1.00';
=head1 NAME
Tie::SubstrHash - Fixed-table-size, fixed-key-length hashing
=head1 SYNOPSIS
require Tie::SubstrHash;
tie %myhash, 'Tie::SubstrHash', $key_len, $value_len, $table_size;
=head1 DESCRIPTION
The B<Tie::SubstrHash> package provides a hash-table-like interface to
an array of determinate size, with constant key size and record size.
Upon tying a new hash to this package, the developer must specify the
size of the keys that will be used, the size of the value fields that the
keys will index, and the size of the overall table (in terms of key-value
pairs, not size in hard memory). I<These values will not change for the
duration of the tied hash>. The newly-allocated hash table may now have
data stored and retrieved. Efforts to store more than C<$table_size>
elements will result in a fatal error, as will efforts to store a value
not exactly C<$value_len> characters in length, or reference through a
key not exactly C<$key_len> characters in length. While these constraints
may seem excessive, the result is a hash table using much less internal
memory than an equivalent freely-allocated hash table.
=head1 CAVEATS
Because the current implementation uses the table and key sizes for the
hashing algorithm, there is no means by which to dynamically change the
value of any of the initialization parameters.
The hash does not support exists().
=cut
use Carp;
sub TIEHASH {
my $pack = shift;
my ($klen, $vlen, $tsize) = @_;
my $rlen = 1 + $klen + $vlen;
$tsize = [$tsize,
findgteprime($tsize * 1.1)]; # Allow 10% empty.
local $self = bless ["\0", $klen, $vlen, $tsize, $rlen, 0, -1];
$$self[0] x= $rlen * $tsize->[1];
$self;
}
sub CLEAR {
local($self) = @_;
$$self[0] = "\0" x ($$self[4] * $$self[3]->[1]);
$$self[5] = 0;
$$self[6] = -1;
}
sub FETCH {
local($self,$key) = @_;
local($klen, $vlen, $tsize, $rlen) = @$self[1..4];
&hashkey;
for (;;) {
$offset = $hash * $rlen;
$record = substr($$self[0], $offset, $rlen);
if (ord($record) == 0) {
return undef;
}
elsif (ord($record) == 1) {
}
elsif (substr($record, 1, $klen) eq $key) {
return substr($record, 1+$klen, $vlen);
}
&rehash;
}
}
sub STORE {
local($self,$key,$val) = @_;
local($klen, $vlen, $tsize, $rlen) = @$self[1..4];
croak("Table is full ($tsize->[0] elements)") if $$self[5] > $tsize->[0];
croak(qq/Value "$val" is not $vlen characters long/)
if length($val) != $vlen;
my $writeoffset;
&hashkey;
for (;;) {
$offset = $hash * $rlen;
$record = substr($$self[0], $offset, $rlen);
if (ord($record) == 0) {
$record = "\2". $key . $val;
die "panic" unless length($record) == $rlen;
$writeoffset = $offset unless defined $writeoffset;
substr($$self[0], $writeoffset, $rlen) = $record;
++$$self[5];
return;
}
elsif (ord($record) == 1) {
$writeoffset = $offset unless defined $writeoffset;
}
elsif (substr($record, 1, $klen) eq $key) {
$record = "\2". $key . $val;
die "panic" unless length($record) == $rlen;
substr($$self[0], $offset, $rlen) = $record;
return;
}
&rehash;
}
}
sub DELETE {
local($self,$key) = @_;
local($klen, $vlen, $tsize, $rlen) = @$self[1..4];
&hashkey;
for (;;) {
$offset = $hash * $rlen;
$record = substr($$self[0], $offset, $rlen);
if (ord($record) == 0) {
return undef;
}
elsif (ord($record) == 1) {
}
elsif (substr($record, 1, $klen) eq $key) {
substr($$self[0], $offset, 1) = "\1";
return substr($record, 1+$klen, $vlen);
--$$self[5];
}
&rehash;
}
}
sub FIRSTKEY {
local($self) = @_;
$$self[6] = -1;
&NEXTKEY;
}
sub NEXTKEY {
local($self) = @_;
local($klen, $vlen, $tsize, $rlen, $entries, $iterix) = @$self[1..6];
for (++$iterix; $iterix < $tsize->[1]; ++$iterix) {
next unless substr($$self[0], $iterix * $rlen, 1) eq "\2";
$$self[6] = $iterix;
return substr($$self[0], $iterix * $rlen + 1, $klen);
}
$$self[6] = -1;
undef;
}
sub EXISTS {
croak "Tie::SubstrHash does not support exists()";
}
sub hashkey {
croak(qq/Key "$key" is not $klen characters long/)
if length($key) != $klen;
$hash = 2;
for (unpack('C*', $key)) {
$hash = $hash * 33 + $_;
&_hashwrap if $hash >= 1e13;
}
&_hashwrap if $hash >= $tsize->[1];
$hash = 1 unless $hash;
$hashbase = $hash;
}
sub _hashwrap {
$hash -= int($hash / $tsize->[1]) * $tsize->[1];
}
sub rehash {
$hash += $hashbase;
$hash -= $tsize->[1] if $hash >= $tsize->[1];
}
# using POSIX::ceil() would be too heavy, and not all platforms have it.
sub ceil {
my $num = shift;
$num = int($num + 1) unless $num == int $num;
return $num;
}
# See:
#
# http://www-groups.dcs.st-andrews.ac.uk/~history/HistTopics/Prime_numbers.html
#
sub findgteprime { # find the smallest prime integer greater than or equal to
use integer;
my $num = ceil(shift);
return 2 if $num <= 2;
$num++ unless $num % 2;
my $i;
my $sqrtnum = int sqrt $num;
my $sqrtnumsquared = $sqrtnum * $sqrtnum;
NUM:
for (;; $num += 2) {
if ($sqrtnumsquared < $num) {
$sqrtnum++;
$sqrtnumsquared = $sqrtnum * $sqrtnum;
}
for ($i = 3; $i <= $sqrtnum; $i += 2) {
next NUM unless $num % $i;
}
return $num;
}
}
1;