1*0Sstevel@tonic-gatepackage Tie::Array; 2*0Sstevel@tonic-gate 3*0Sstevel@tonic-gateuse 5.006_001; 4*0Sstevel@tonic-gateuse strict; 5*0Sstevel@tonic-gateuse Carp; 6*0Sstevel@tonic-gateour $VERSION = '1.03'; 7*0Sstevel@tonic-gate 8*0Sstevel@tonic-gate# Pod documentation after __END__ below. 9*0Sstevel@tonic-gate 10*0Sstevel@tonic-gatesub DESTROY { } 11*0Sstevel@tonic-gatesub EXTEND { } 12*0Sstevel@tonic-gatesub UNSHIFT { scalar shift->SPLICE(0,0,@_) } 13*0Sstevel@tonic-gatesub SHIFT { shift->SPLICE(0,1) } 14*0Sstevel@tonic-gatesub CLEAR { shift->STORESIZE(0) } 15*0Sstevel@tonic-gate 16*0Sstevel@tonic-gatesub PUSH 17*0Sstevel@tonic-gate{ 18*0Sstevel@tonic-gate my $obj = shift; 19*0Sstevel@tonic-gate my $i = $obj->FETCHSIZE; 20*0Sstevel@tonic-gate $obj->STORE($i++, shift) while (@_); 21*0Sstevel@tonic-gate} 22*0Sstevel@tonic-gate 23*0Sstevel@tonic-gatesub POP 24*0Sstevel@tonic-gate{ 25*0Sstevel@tonic-gate my $obj = shift; 26*0Sstevel@tonic-gate my $newsize = $obj->FETCHSIZE - 1; 27*0Sstevel@tonic-gate my $val; 28*0Sstevel@tonic-gate if ($newsize >= 0) 29*0Sstevel@tonic-gate { 30*0Sstevel@tonic-gate $val = $obj->FETCH($newsize); 31*0Sstevel@tonic-gate $obj->STORESIZE($newsize); 32*0Sstevel@tonic-gate } 33*0Sstevel@tonic-gate $val; 34*0Sstevel@tonic-gate} 35*0Sstevel@tonic-gate 36*0Sstevel@tonic-gatesub SPLICE { 37*0Sstevel@tonic-gate my $obj = shift; 38*0Sstevel@tonic-gate my $sz = $obj->FETCHSIZE; 39*0Sstevel@tonic-gate my $off = (@_) ? shift : 0; 40*0Sstevel@tonic-gate $off += $sz if ($off < 0); 41*0Sstevel@tonic-gate my $len = (@_) ? shift : $sz - $off; 42*0Sstevel@tonic-gate $len += $sz - $off if $len < 0; 43*0Sstevel@tonic-gate my @result; 44*0Sstevel@tonic-gate for (my $i = 0; $i < $len; $i++) { 45*0Sstevel@tonic-gate push(@result,$obj->FETCH($off+$i)); 46*0Sstevel@tonic-gate } 47*0Sstevel@tonic-gate $off = $sz if $off > $sz; 48*0Sstevel@tonic-gate $len -= $off + $len - $sz if $off + $len > $sz; 49*0Sstevel@tonic-gate if (@_ > $len) { 50*0Sstevel@tonic-gate # Move items up to make room 51*0Sstevel@tonic-gate my $d = @_ - $len; 52*0Sstevel@tonic-gate my $e = $off+$len; 53*0Sstevel@tonic-gate $obj->EXTEND($sz+$d); 54*0Sstevel@tonic-gate for (my $i=$sz-1; $i >= $e; $i--) { 55*0Sstevel@tonic-gate my $val = $obj->FETCH($i); 56*0Sstevel@tonic-gate $obj->STORE($i+$d,$val); 57*0Sstevel@tonic-gate } 58*0Sstevel@tonic-gate } 59*0Sstevel@tonic-gate elsif (@_ < $len) { 60*0Sstevel@tonic-gate # Move items down to close the gap 61*0Sstevel@tonic-gate my $d = $len - @_; 62*0Sstevel@tonic-gate my $e = $off+$len; 63*0Sstevel@tonic-gate for (my $i=$off+$len; $i < $sz; $i++) { 64*0Sstevel@tonic-gate my $val = $obj->FETCH($i); 65*0Sstevel@tonic-gate $obj->STORE($i-$d,$val); 66*0Sstevel@tonic-gate } 67*0Sstevel@tonic-gate $obj->STORESIZE($sz-$d); 68*0Sstevel@tonic-gate } 69*0Sstevel@tonic-gate for (my $i=0; $i < @_; $i++) { 70*0Sstevel@tonic-gate $obj->STORE($off+$i,$_[$i]); 71*0Sstevel@tonic-gate } 72*0Sstevel@tonic-gate return wantarray ? @result : pop @result; 73*0Sstevel@tonic-gate} 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gatesub EXISTS { 76*0Sstevel@tonic-gate my $pkg = ref $_[0]; 77*0Sstevel@tonic-gate croak "$pkg doesn't define an EXISTS method"; 78*0Sstevel@tonic-gate} 79*0Sstevel@tonic-gate 80*0Sstevel@tonic-gatesub DELETE { 81*0Sstevel@tonic-gate my $pkg = ref $_[0]; 82*0Sstevel@tonic-gate croak "$pkg doesn't define a DELETE method"; 83*0Sstevel@tonic-gate} 84*0Sstevel@tonic-gate 85*0Sstevel@tonic-gatepackage Tie::StdArray; 86*0Sstevel@tonic-gateuse vars qw(@ISA); 87*0Sstevel@tonic-gate@ISA = 'Tie::Array'; 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gatesub TIEARRAY { bless [], $_[0] } 90*0Sstevel@tonic-gatesub FETCHSIZE { scalar @{$_[0]} } 91*0Sstevel@tonic-gatesub STORESIZE { $#{$_[0]} = $_[1]-1 } 92*0Sstevel@tonic-gatesub STORE { $_[0]->[$_[1]] = $_[2] } 93*0Sstevel@tonic-gatesub FETCH { $_[0]->[$_[1]] } 94*0Sstevel@tonic-gatesub CLEAR { @{$_[0]} = () } 95*0Sstevel@tonic-gatesub POP { pop(@{$_[0]}) } 96*0Sstevel@tonic-gatesub PUSH { my $o = shift; push(@$o,@_) } 97*0Sstevel@tonic-gatesub SHIFT { shift(@{$_[0]}) } 98*0Sstevel@tonic-gatesub UNSHIFT { my $o = shift; unshift(@$o,@_) } 99*0Sstevel@tonic-gatesub EXISTS { exists $_[0]->[$_[1]] } 100*0Sstevel@tonic-gatesub DELETE { delete $_[0]->[$_[1]] } 101*0Sstevel@tonic-gate 102*0Sstevel@tonic-gatesub SPLICE 103*0Sstevel@tonic-gate{ 104*0Sstevel@tonic-gate my $ob = shift; 105*0Sstevel@tonic-gate my $sz = $ob->FETCHSIZE; 106*0Sstevel@tonic-gate my $off = @_ ? shift : 0; 107*0Sstevel@tonic-gate $off += $sz if $off < 0; 108*0Sstevel@tonic-gate my $len = @_ ? shift : $sz-$off; 109*0Sstevel@tonic-gate return splice(@$ob,$off,$len,@_); 110*0Sstevel@tonic-gate} 111*0Sstevel@tonic-gate 112*0Sstevel@tonic-gate1; 113*0Sstevel@tonic-gate 114*0Sstevel@tonic-gate__END__ 115*0Sstevel@tonic-gate 116*0Sstevel@tonic-gate=head1 NAME 117*0Sstevel@tonic-gate 118*0Sstevel@tonic-gateTie::Array - base class for tied arrays 119*0Sstevel@tonic-gate 120*0Sstevel@tonic-gate=head1 SYNOPSIS 121*0Sstevel@tonic-gate 122*0Sstevel@tonic-gate package Tie::NewArray; 123*0Sstevel@tonic-gate use Tie::Array; 124*0Sstevel@tonic-gate @ISA = ('Tie::Array'); 125*0Sstevel@tonic-gate 126*0Sstevel@tonic-gate # mandatory methods 127*0Sstevel@tonic-gate sub TIEARRAY { ... } 128*0Sstevel@tonic-gate sub FETCH { ... } 129*0Sstevel@tonic-gate sub FETCHSIZE { ... } 130*0Sstevel@tonic-gate 131*0Sstevel@tonic-gate sub STORE { ... } # mandatory if elements writeable 132*0Sstevel@tonic-gate sub STORESIZE { ... } # mandatory if elements can be added/deleted 133*0Sstevel@tonic-gate sub EXISTS { ... } # mandatory if exists() expected to work 134*0Sstevel@tonic-gate sub DELETE { ... } # mandatory if delete() expected to work 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gate # optional methods - for efficiency 137*0Sstevel@tonic-gate sub CLEAR { ... } 138*0Sstevel@tonic-gate sub PUSH { ... } 139*0Sstevel@tonic-gate sub POP { ... } 140*0Sstevel@tonic-gate sub SHIFT { ... } 141*0Sstevel@tonic-gate sub UNSHIFT { ... } 142*0Sstevel@tonic-gate sub SPLICE { ... } 143*0Sstevel@tonic-gate sub EXTEND { ... } 144*0Sstevel@tonic-gate sub DESTROY { ... } 145*0Sstevel@tonic-gate 146*0Sstevel@tonic-gate package Tie::NewStdArray; 147*0Sstevel@tonic-gate use Tie::Array; 148*0Sstevel@tonic-gate 149*0Sstevel@tonic-gate @ISA = ('Tie::StdArray'); 150*0Sstevel@tonic-gate 151*0Sstevel@tonic-gate # all methods provided by default 152*0Sstevel@tonic-gate 153*0Sstevel@tonic-gate package main; 154*0Sstevel@tonic-gate 155*0Sstevel@tonic-gate $object = tie @somearray,Tie::NewArray; 156*0Sstevel@tonic-gate $object = tie @somearray,Tie::StdArray; 157*0Sstevel@tonic-gate $object = tie @somearray,Tie::NewStdArray; 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate 160*0Sstevel@tonic-gate 161*0Sstevel@tonic-gate=head1 DESCRIPTION 162*0Sstevel@tonic-gate 163*0Sstevel@tonic-gateThis module provides methods for array-tying classes. See 164*0Sstevel@tonic-gateL<perltie> for a list of the functions required in order to tie an array 165*0Sstevel@tonic-gateto a package. The basic B<Tie::Array> package provides stub C<DESTROY>, 166*0Sstevel@tonic-gateand C<EXTEND> methods that do nothing, stub C<DELETE> and C<EXISTS> 167*0Sstevel@tonic-gatemethods that croak() if the delete() or exists() builtins are ever called 168*0Sstevel@tonic-gateon the tied array, and implementations of C<PUSH>, C<POP>, C<SHIFT>, 169*0Sstevel@tonic-gateC<UNSHIFT>, C<SPLICE> and C<CLEAR> in terms of basic C<FETCH>, C<STORE>, 170*0Sstevel@tonic-gateC<FETCHSIZE>, C<STORESIZE>. 171*0Sstevel@tonic-gate 172*0Sstevel@tonic-gateThe B<Tie::StdArray> package provides efficient methods required for tied arrays 173*0Sstevel@tonic-gatewhich are implemented as blessed references to an "inner" perl array. 174*0Sstevel@tonic-gateIt inherits from B<Tie::Array>, and should cause tied arrays to behave exactly 175*0Sstevel@tonic-gatelike standard arrays, allowing for selective overloading of methods. 176*0Sstevel@tonic-gate 177*0Sstevel@tonic-gateFor developers wishing to write their own tied arrays, the required methods 178*0Sstevel@tonic-gateare briefly defined below. See the L<perltie> section for more detailed 179*0Sstevel@tonic-gatedescriptive, as well as example code: 180*0Sstevel@tonic-gate 181*0Sstevel@tonic-gate=over 4 182*0Sstevel@tonic-gate 183*0Sstevel@tonic-gate=item TIEARRAY classname, LIST 184*0Sstevel@tonic-gate 185*0Sstevel@tonic-gateThe class method is invoked by the command C<tie @array, classname>. Associates 186*0Sstevel@tonic-gatean array instance with the specified class. C<LIST> would represent 187*0Sstevel@tonic-gateadditional arguments (along the lines of L<AnyDBM_File> and compatriots) needed 188*0Sstevel@tonic-gateto complete the association. The method should return an object of a class which 189*0Sstevel@tonic-gateprovides the methods below. 190*0Sstevel@tonic-gate 191*0Sstevel@tonic-gate=item STORE this, index, value 192*0Sstevel@tonic-gate 193*0Sstevel@tonic-gateStore datum I<value> into I<index> for the tied array associated with 194*0Sstevel@tonic-gateobject I<this>. If this makes the array larger then 195*0Sstevel@tonic-gateclass's mapping of C<undef> should be returned for new positions. 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate=item FETCH this, index 198*0Sstevel@tonic-gate 199*0Sstevel@tonic-gateRetrieve the datum in I<index> for the tied array associated with 200*0Sstevel@tonic-gateobject I<this>. 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gate=item FETCHSIZE this 203*0Sstevel@tonic-gate 204*0Sstevel@tonic-gateReturns the total number of items in the tied array associated with 205*0Sstevel@tonic-gateobject I<this>. (Equivalent to C<scalar(@array)>). 206*0Sstevel@tonic-gate 207*0Sstevel@tonic-gate=item STORESIZE this, count 208*0Sstevel@tonic-gate 209*0Sstevel@tonic-gateSets the total number of items in the tied array associated with 210*0Sstevel@tonic-gateobject I<this> to be I<count>. If this makes the array larger then 211*0Sstevel@tonic-gateclass's mapping of C<undef> should be returned for new positions. 212*0Sstevel@tonic-gateIf the array becomes smaller then entries beyond count should be 213*0Sstevel@tonic-gatedeleted. 214*0Sstevel@tonic-gate 215*0Sstevel@tonic-gate=item EXTEND this, count 216*0Sstevel@tonic-gate 217*0Sstevel@tonic-gateInformative call that array is likely to grow to have I<count> entries. 218*0Sstevel@tonic-gateCan be used to optimize allocation. This method need do nothing. 219*0Sstevel@tonic-gate 220*0Sstevel@tonic-gate=item EXISTS this, key 221*0Sstevel@tonic-gate 222*0Sstevel@tonic-gateVerify that the element at index I<key> exists in the tied array I<this>. 223*0Sstevel@tonic-gate 224*0Sstevel@tonic-gateThe B<Tie::Array> implementation is a stub that simply croaks. 225*0Sstevel@tonic-gate 226*0Sstevel@tonic-gate=item DELETE this, key 227*0Sstevel@tonic-gate 228*0Sstevel@tonic-gateDelete the element at index I<key> from the tied array I<this>. 229*0Sstevel@tonic-gate 230*0Sstevel@tonic-gateThe B<Tie::Array> implementation is a stub that simply croaks. 231*0Sstevel@tonic-gate 232*0Sstevel@tonic-gate=item CLEAR this 233*0Sstevel@tonic-gate 234*0Sstevel@tonic-gateClear (remove, delete, ...) all values from the tied array associated with 235*0Sstevel@tonic-gateobject I<this>. 236*0Sstevel@tonic-gate 237*0Sstevel@tonic-gate=item DESTROY this 238*0Sstevel@tonic-gate 239*0Sstevel@tonic-gateNormal object destructor method. 240*0Sstevel@tonic-gate 241*0Sstevel@tonic-gate=item PUSH this, LIST 242*0Sstevel@tonic-gate 243*0Sstevel@tonic-gateAppend elements of LIST to the array. 244*0Sstevel@tonic-gate 245*0Sstevel@tonic-gate=item POP this 246*0Sstevel@tonic-gate 247*0Sstevel@tonic-gateRemove last element of the array and return it. 248*0Sstevel@tonic-gate 249*0Sstevel@tonic-gate=item SHIFT this 250*0Sstevel@tonic-gate 251*0Sstevel@tonic-gateRemove the first element of the array (shifting other elements down) 252*0Sstevel@tonic-gateand return it. 253*0Sstevel@tonic-gate 254*0Sstevel@tonic-gate=item UNSHIFT this, LIST 255*0Sstevel@tonic-gate 256*0Sstevel@tonic-gateInsert LIST elements at the beginning of the array, moving existing elements 257*0Sstevel@tonic-gateup to make room. 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gate=item SPLICE this, offset, length, LIST 260*0Sstevel@tonic-gate 261*0Sstevel@tonic-gatePerform the equivalent of C<splice> on the array. 262*0Sstevel@tonic-gate 263*0Sstevel@tonic-gateI<offset> is optional and defaults to zero, negative values count back 264*0Sstevel@tonic-gatefrom the end of the array. 265*0Sstevel@tonic-gate 266*0Sstevel@tonic-gateI<length> is optional and defaults to rest of the array. 267*0Sstevel@tonic-gate 268*0Sstevel@tonic-gateI<LIST> may be empty. 269*0Sstevel@tonic-gate 270*0Sstevel@tonic-gateReturns a list of the original I<length> elements at I<offset>. 271*0Sstevel@tonic-gate 272*0Sstevel@tonic-gate=back 273*0Sstevel@tonic-gate 274*0Sstevel@tonic-gate=head1 CAVEATS 275*0Sstevel@tonic-gate 276*0Sstevel@tonic-gateThere is no support at present for tied @ISA. There is a potential conflict 277*0Sstevel@tonic-gatebetween magic entries needed to notice setting of @ISA, and those needed to 278*0Sstevel@tonic-gateimplement 'tie'. 279*0Sstevel@tonic-gate 280*0Sstevel@tonic-gateVery little consideration has been given to the behaviour of tied arrays 281*0Sstevel@tonic-gatewhen C<$[> is not default value of zero. 282*0Sstevel@tonic-gate 283*0Sstevel@tonic-gate=head1 AUTHOR 284*0Sstevel@tonic-gate 285*0Sstevel@tonic-gateNick Ing-Simmons E<lt>nik@tiuk.ti.comE<gt> 286*0Sstevel@tonic-gate 287*0Sstevel@tonic-gate=cut 288