summaryrefslogtreecommitdiff
path: root/lib/Tie/SubstrHash.pm
diff options
context:
space:
mode:
authorAndy Dougherty <doughera.lafayette.edu>1996-02-03 00:53:00 +0000
committerAndy Dougherty <doughera.lafayette.edu>1996-02-03 00:53:00 +0000
commit399f14a194513745fd160c0e4e8f6f7f718779cf (patch)
treee110916dffcfdbc88bd35c14778a72a87cd6582e /lib/Tie/SubstrHash.pm
parentc07a80fdfe3926b5eb0585b674aa5d1f57b32ade (diff)
downloadperl-399f14a194513745fd160c0e4e8f6f7f718779cf.tar.gz
perl 5.002gamma: [patch introduction and re-organisations]
[ re-organisations: # Give this module a sensible home. mv pod/PerlDoc/Functions.pm lib/Pod/Functions.pm rmdir pod/PerlDoc # Tie:: finally has its own hierarchy mkdir lib/Tie mv lib/TieHash.pm lib/Tie/Hash.pm mv lib/SubstrHash.pm lib/Tie/SubstrHash.pm rm -f lib/FileHandle.pm # Duplicate of ext/FileHandle/FileHandle.pm rm -f os2/diff.MANIFEST # Obsolete (I applied a variant of it.) rm -f os2/diff.init # Obsolete. ] This is patch.2gamma to perl5.002 beta3. This takes you from 5.002beta3 to 5.002gamma. To apply this patch, run the above commands, then cd to your perl source directory and then type patch -p1 -N < patch.2gamma The changes are described after each /^Index/ line below. This is designed so you can examine each change with a command such as csplit -k patch.2gamma '/^Index:/' '{99}' (Of course since there are 116 items and most csplit's have an arbitrary limit of 100 files, you'll probably have to manually split this file first, but you get the idea. (GNU csplit doesn't have this limitation. Nor does a perl solution, of course.)) Patch and enjoy, Andy Dougherty doughera@lafcol.lafayette.edu Dept. of Physics Lafayette College, Easton PA 18042
Diffstat (limited to 'lib/Tie/SubstrHash.pm')
-rw-r--r--lib/Tie/SubstrHash.pm140
1 files changed, 140 insertions, 0 deletions
diff --git a/lib/Tie/SubstrHash.pm b/lib/Tie/SubstrHash.pm
new file mode 100644
index 0000000000..6250e73848
--- /dev/null
+++ b/lib/Tie/SubstrHash.pm
@@ -0,0 +1,140 @@
+package SubstrHash;
+use Carp;
+
+sub TIEHASH {
+ my $pack = shift;
+ my ($klen, $vlen, $tsize) = @_;
+ my $rlen = 1 + $klen + $vlen;
+ $tsize = findprime($tsize * 1.1); # Allow 10% empty.
+ $self = bless ["\0", $klen, $vlen, $tsize, $rlen, 0, -1];
+ $$self[0] x= $rlen * $tsize;
+ $self;
+}
+
+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") if $self[5] == $tsize;
+ 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; ++$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 hashkey {
+ croak(qq/Key "$key" is not $klen characters long.\n/)
+ if length($key) != $klen;
+ $hash = 2;
+ for (unpack('C*', $key)) {
+ $hash = $hash * 33 + $_;
+ }
+ $hash = $hash - int($hash / $tsize) * $tsize
+ if $hash >= $tsize;
+ $hash = 1 unless $hash;
+ $hashbase = $hash;
+}
+
+sub rehash {
+ $hash += $hashbase;
+ $hash -= $tsize if $hash >= $tsize;
+}
+
+sub findprime {
+ use integer;
+
+ my $num = shift;
+ $num++ unless $num % 2;
+
+ $max = int sqrt $num;
+
+ NUM:
+ for (;; $num += 2) {
+ for ($i = 3; $i <= $max; $i += 2) {
+ next NUM unless $num % $i;
+ }
+ return $num;
+ }
+}
+
+1;