File Coverage

lib/Tie/Multidim.pm
Criterion Covered Total %
statement 37 44 84.0
branch 8 16 50.0
condition n/a
subroutine 7 9 77.7
pod 2 2 100.0
total 54 71 76.0


line stmt bran cond sub pod time code
1              
2             package Tie::Multidim;
3              
4 1     1   2302 use strict;
  1         1  
  1         36  
5 1     1   5 use vars qw( $VERSION );
  1         2  
  1         1287  
6              
7             $VERSION = '0.04';
8              
9              
10             =head1 NAME
11              
12             Tie::Multidim - "tie"-like multidimensional data structures
13              
14             =head1 SYNOPSIS
15              
16             use Tie::Multidim;
17             my $foo = new Tie::Multidim \%h, '%@%';
18             $foo->[2]{'die'}[4] = "isa";
19              
20             =head1 DESCRIPTION
21              
22             This module implements multi-dimensional data structures on a hash.
23             C<$foo-E[2]{'die'}[4]> gets "mapped" to C<$bar{"2;die;4"}>, where
24             the ';' is actually $SUBSEP ($;), and %bar is a hash you provide.
25              
26             It is particularly useful in two, not disjoint, situations:
27              
28             =over 1
29              
30             =item 1.
31             the data space (matrix, if you prefer) is sparsely populated;
32              
33             =item 2.
34             the hash into which the data is mapped is tied.
35              
36             =back
37              
38             This illustrates (1):
39              
40             my %matrix; # hash to store the data in.
41             local $; = ' ';
42             my $foo = new Tie::Multidim \%matrix, '@@'; # array-of-arrays.
43              
44             print $foo->[5432][9876];
45             # prints the value of $matrix{"5432 9876"}.
46              
47              
48             This illustrates (2):
49              
50             my %matrix;
51             tie %matrix, 'Matrix'; # some hashtie-able class.
52             local $; = ";"; # gets remembered by the object.
53             my $foo = new Tie::Multidim \%matrix, '%@%';
54             # 3-level structure: hash of arrays of hashes.
55              
56             $foo->{'human'}[666]{'beast'} = "value";
57              
58             # causes a call to
59             sub Matrix::STORE {
60             my( $self, $index, $value ) = @_;
61             my( $x, $y, $z ) = split $;, $index;
62             # with $x = 'human', $y = 666, and $z = 'beast'.
63             }
64              
65              
66             =head1 METHODS
67              
68             =head2 new
69              
70             This is the constructor.
71              
72             The first argument is a hash-reference. This hash will be used by the
73             Tie::Multidim object to actually store the data.
74             The reference can be to an anonymous hash, to a normal hash, or to a
75             tied hash. Tie::Multidim doesn't care, as long as it supports the
76             normal hash get and set operations (STORE and FETCH methods, in TIEHASH
77             terminology).
78              
79             The second argument is a string containing '@' and '%' characters
80             (a al function prototypes). The multidimensional data structure will
81             be constructed to have as many dimensions as there are characters in
82             this string; and each dimension will be of the type indicated by the
83             character. '@%' is an array of hashes; '%@' is a hash of arrays; and
84             so on.
85              
86             =cut
87              
88             sub new {
89 3     3 1 97 my( $pkg, $storage, $level_types, @index ) = @_;
90             # print "new( @_ )\n";
91 3         8 $level_types =~ s/[^@%]//;
92 3 50       8 length $level_types or
93             die "Level types string contains no level types!";
94              
95 3         6 my $level_type = substr $level_types, scalar @index, 1;
96              
97 3         16 my $tied = bless {
98             'storage' => $storage,
99             'level_types' => $level_types,
100             'index' => [ @index ], # copy
101             'sep' => $;,
102             }, $pkg;
103              
104 3 100       17 if ( $level_type eq '@' ) {
    50          
105 1         2 my @a;
106 1         5 tie @a, $pkg, $tied;
107 1         5 return \@a;
108             }
109             elsif ( $level_type eq '%' ) {
110 2         2 my %h;
111 2         6 tie %h, $pkg, $tied;
112 2         14 return \%h;
113             }
114 0         0 else { die "Illegal level type? '$level_types'\n" }
115             }
116              
117             sub FETCHSIZE {
118 0     0   0 my( $self ) = @_;
119 0         0 0
120             }
121              
122             sub FETCH {
123 3     3   65 my( $self, $index ) = @_;
124 3         12 local $; = $self->{'sep'};
125              
126 2         7 @{ $self->{'index'} } < length( $self->{'level_types'} )-1 and
  3         14  
127             return new Tie::Multidim
128             $self->{'storage'},
129             $self->{'level_types'},
130 3 100       8 @{ $self->{'index'} }, $index;
131              
132             # do the real, final index:
133 1         3 $self->{'storage'}{ join $;, @{ $self->{'index'} }, $index }
  1         5  
134             }
135              
136             sub STORE {
137 1     1   2 my( $self, $index, $value ) = @_;
138 1         4 local $; = $self->{'sep'};
139              
140             # ignore attempts to set members of internal hash/array members:
141 1 50       2 @{ $self->{'index'} } > 0 or return();
  1         3  
142              
143 1 50       2 @{ $self->{'index'} } == length( $self->{'level_types'} )-1 or die "YOW!";
  1         4  
144              
145             # do the real, final index:
146 1         2 $self->{'storage'}{ join $;, @{ $self->{'index'} }, $index } = $value;
  1         6  
147             }
148              
149              
150             =head2 storage
151              
152             This returns the same hash reference that was passed as the first
153             argument to the constructor.
154             Not exactly a method, it must be called as a package function,
155             and passed the multidim reference.
156              
157             $foo = new Tie::Multidim, \%h, '@@';
158             $hashref = Tie::Multidim::storage( $foo );
159             # same effect as:
160             $hashref = \%h;
161              
162             =cut
163              
164             sub storage {
165 0     0 1 0 my $tied_ref = shift;
166 0 0       0 $tied_ref =~ /\bARRAY\b/ and return( tied( @$tied_ref )->{'storage'} );
167 0 0       0 $tied_ref =~ /\bHASH\b/ and return( tied( %$tied_ref )->{'storage'} );
168 0         0 die "'$tied_ref': not an array or hash ref!";
169             }
170              
171              
172 1     1   2 sub TIEARRAY { shift; shift; }
  1         3  
173              
174 2     2   3 sub TIEHASH { shift; shift; }
  2         4  
175              
176              
177             =head1 AUTHOR
178              
179             jdporter@min.net (John Porter)
180              
181             =head1 COPYRIGHT
182              
183             This module is free software; you may redistribute it and/or
184             modify it under the same terms as Perl itself.
185              
186             =cut
187              
188              
189             1;
190              
191