package Tuple; use strict; use warnings; use parent 'Exporter'; our @EXPORT = qw( Tuple ); use overload '""' => \&to_str, 'bool' => sub{ return $_[0]->length() > 0; }, '@{}' => sub{ return ( [$_[0]->arr()] ) }, '&{}' => sub{ my $self=shift; return sub{ $self->_as_sub(@_); }; }; use Data::Dumper; my %tuples; my $cnt=0; sub new { my ($class,@values)=@_; my $self=bless({ id => ++$cnt },$class); $tuples{$cnt} = \@values; return $self; } sub DESTROY{ delete($tuples{$_[0]->{id}}); } sub Tuple { return Tuple->new(@_); } sub arr { my $self=shift; my @ret; my $arr=$tuples{$self->{id}}; push( @ret, ref($_) eq __PACKAGE__? $_->arr(): $_ ) for(@$arr); return @ret; } sub get { my $self=shift; my $arr=$tuples{$self->{id}}; my @ret; if(@_) { my $p=0; @ret = $self->_get(\$p,[@_]); } else { @ret=$self->arr() } return $ret[0] if( @ret == 1 ); return @ret if( wantarray() ); return \@ret; } sub set { my ($self, $pos, $val) = @_; return 0 unless defined $pos; my $p=0; return $self->_set(\$p,$pos,$val); } sub iter { my ($self,$from,$to,$step) = @_; if( @_ == 1 ) { delete @$self{qw(sig count step last)}; return (); } my @ret; if($to >= $from) { $step=1 unless $step; my $sig="$from,$to,$step"; if(!$self->{sig} or $self->{sig} ne $sig) { $self->{count}=0; $self->{step}=$step; $self->{sig}=$sig; } if($self->{last}) { delete @$self{qw(sig count step last)}; } else { my @pos=($self->{count} .. $self->{count}+$self->{step}-1); $self->{count}=$pos[-1]+1; my $p=0; @ret = $self->_get(\$p,\@pos); $self->{last}=1 if($self->{count} >= $p); } } return @ret; } sub to_str { no warnings; return join( $, || '' , $_[0]->arr() ); } sub length{ return ($_[0]->arr())+0; } ######################################################################## sub _as_sub { my $self=shift; return $self->iter(@{$_[0]}) if( ref $_[0] eq "ARRAY" ); if( ref $_[0] eq "HASH" ) { while(my @l = each(%{$_[0]})) { $self->set(@l); } return 1; } return $self->get(@_); } sub _get { my ($self,$index,$pos)=@_; my $arr=$tuples{$self->{id}}; my @ret; for my $elm (@$arr) { if(ref $elm eq __PACKAGE__) { push( @ret, $elm->_get($index,$pos) ); } elsif( @$pos and $pos->[0] == $$index ) { shift(@$pos); push(@ret,$elm); } $$index++; } $$index--; return @ret; } sub _set { my ($self,$index,$pos,$val)=@_; my $arr=$tuples{$self->{id}}; for my $p (0..$#$arr) { if(ref $arr->[$p] eq __PACKAGE__) { return 1 if $arr->[$p]->_set($index,$pos,$val) } elsif( $pos == $$index ) { if(ref($val) eq __PACKAGE__) { if($pos >= @$arr) { push(@$arr,$val); } else { splice(@$arr,$pos,0,$val); } } else { $arr->[$p]=$val; } return 1; } $$index++; } $$index--; return 0; } 1;