use v6-alpha; =begin ChangeLog 2005-08-10 * New methods Array.flatten(), is_lazy() - Lazy Array changes to normal Array if all elements are known; - pushing a lazy list into a normal array turns the array into a lazy array * New method: Array.is_infinite() * Renamed methods: Array.new() -> Array.from_list(); Array.splat() -> Array.to_list * New List methods: is_contiguous(), to_str(), clone(), to_ref(), to_bit(), to_num() * New List hooks: is_contiguous( $code ), stringify( $code ) * Started syncing with Perl5 version * Removed class Lazy::Range * Lowercase methods fetch(), store() * Removed redundant methods next(), previous() 2005-08-09 * Renamed Lazy::List to Perl6::Value::List * Renamed Array::Lazy to Perl6::Container::Array * Removed fetch_slice() because it is non-standard. 2005-08-08 * New lazy array methods: FETCH(), STORE(), fetch_slice(). slice accepts a lazy list or lazy array as argument! * elems() actually works * more or less fixed Lazy::List::reverse() inheritance * Lazy::CoroList is gone * Lazy list methods (grep, map, ...) moved from Array::Lazy to Lazy::List. These methods can be accessed from an array by doing a 'splat()' first. Array::Lazy::reverse() is still supported. 2005-08-07 * Lazy Range supports 'a'..Inf * New lazy array methods: splat(), elems(), uniq(), end(), next(), previous(), kv(), keys(), values(), zip() * Code rewritten to use coroutines instead of states * New class Lazy::CoroList - takes a coroutine (or two, for shift and pop support) and creates a Lazy List, that can be used to create a Lazy Array. * Removed internal class Lazy::Generator 2005-08-06 * new lazy methods reverse(), grep(), map() * Array::Lazy supports multi-dimensional Lazy Array * new class 'Lazy::List' * lazy List / Array of junctions is tested * removed 'Iter' class; renamed 'Iter::Range' to 'Lazy::Range' =cut # TODO - test splice() with parameter 'Array @list' # TODO - add lazy/strict tests # TODO - 'dim' # TODO - sync with Perl5 version of Array # TODO - exists(), delete() - S29 # TODO - preprocessing, indexing, etc - lazily # TODO - add support for sparse arrays # - what happens when $a.FETCH(100000000) # implement this error message (from PIR.pm) # if $off > $size { # warn "splice() offset past end of array\n"; # $off = $size; # } # Things that will be solved by the compiler: # - fetch slice / store slice - @a[5,7]=('x','y') # - keys/kv/pairs/values with indexes (S29) use Perl6::Value::List; # This class should not inherit from Perl6::Value::List, because this would # cause multi-dimensional arrays to be flattened. class Perl6::Container::Array-0.01 { has Array @.items; method from_list ( $class: *@items ) { $class.new( items => [@items] ); } method _shift_n (Int $length ) returns List { my @ret; my @tmp = @.items; if $length == Inf { @.items = (); return @tmp; } while @tmp { last if @ret >= $length; unless @tmp[0].isa(Perl6::Value::List) { &*push( @ret: @tmp.shift ); next; } my $i = @tmp[0].shift; if defined $i { &*push( @ret: $i); last if @ret >= $length; } elsif @tmp.end > 0 { &*shift( @tmp ); } else { @tmp = (); } }; @.items = @tmp; return @ret; } method _pop_n (Int $length ) returns List { my @ret; my @tmp = @.items; if $length == Inf { @.items = (); return @tmp; } while @tmp { last if @ret >= $length; unless @tmp[-1].isa(Perl6::Value::List) { &*unshift(@ret: @tmp.pop); next; } my $i = @tmp[-1].pop; if defined $i { &*unshift(@ret: $i); last if @ret >= $length; } elsif @tmp.end > 0 { &*pop(@tmp); } else { @tmp = (); } }; @.items = @tmp; return @ret; } method elems () { [+] &*map({ $_.isa( 'Perl6::Value::List' ) ?? $_.Perl6::Value::List::elems !! 1; }, @.items); } method is_infinite () { [||] @.items.map:{ ($_.isa( 'Perl6::Value::List' ) && $_.is_infinite); }, Bool::False; } method is_lazy () { [||] @.items.map:{ ($_.isa( 'Perl6::Value::List' ) && $_.is_lazy); }, Bool::False; } method flatten () { # this needs optimization for @.items { $_ .= flatten if (.isa( 'Perl6::Value::List' ) && .is_lazy); } } method splice ( $offset? = 0, $length? = Inf, *@list ) returns Perl6::Container::Array { my ( @head, @body, @tail ); # say "items: ", @.items, " splice: $offset, $length, ", @list; # say 'insert: ', $_, ' ', $_.WHAT for @list; if $offset >= 0 { @head = self._shift_n( $offset ); if $length >= 0 { @body = self._shift_n( $length ); @tail = self._shift_n( Inf ); } else { @tail = self._pop_n( -$length ); @body = self._shift_n( Inf ); } } else { @tail = self._pop_n( -$offset ); @head = self._shift_n( Inf ); if $length >= 0 { # make $#body = $length while @tail { last if @body >= $length; &*push(@body, &*shift(@tail)); } } else { # make $#tail = -$length while @tail { last if @tail <= -$length; &*push(@body, &*shift(@tail)); } } }; #say 'head: ',@head, ' body: ',@body, ' tail: ',@tail, ' list: ',@list; @.items = ( @head, @list, @tail ); return Perl6::Container::Array.from_list( @body ); } method shift () { self._shift_n( 1 )[0] } method pop () { self._pop_n( 1 )[0] } method unshift ( *@item ) { # &*unshift(@.items: @item); &*unshift(@(self.items): @item); # XXX bug? return self; } method push ( *@item ) { # &*push(@.items: @item); &*push(@(self.items): @item); # XXX bug? return self; } method end () { my @x = self.pop; self.push( @x[0] ) if @x; return @x[0]; } method fetch ( Int $pos ) { # XXX - this is very inefficient # see also: slice() my $ret = self.splice( $pos, 1 ); self.splice( $pos, 0, [$ret.items] ); return $ret.items; } method store ( Int $pos, $item ) { # TODO - $pos could be a lazy list of pairs! self.splice( $pos, 1, [$item] ); return self; } # XXX - if you use this, you get: "cannot next() outside a loop" # method next () { $array.shift } # method previous () { $array.pop } # just in case method reverse () { return Perl6::Container::Array.from_list( &*reverse(@.items).map:{ .isa(Perl6::Value::List) ?? .Perl6::Value::List::reverse !! $_ } ); } method to_list () { my $ret = self.clone; # TODO - optimization - return the internal list object, if there is one return Perl6::Value::List.new( cstart => sub { $ret.shift }, cend => sub { $ret.pop }, celems => sub { $ret.elems }, ) } } # end class Lazy::Array =kwid = NAME Perl6::Container::Array - A Lazy Array = SYNOPSIS ... = DESCRIPTION ... Example: 1,2,3,-10..20,50,$obj,$span,1..Inf,10 = CONSTRUCTORS - `from_list( @list )` @list may contain "Lazy" lists. = METHODS - `splice( ... )` ... - `push( @list )` @list may contain "Lazy" lists. - `pop` - `unshift( @list )` @list may contain "Lazy" lists. - `shift` - `reverse` - `to_list` Implements the "splat" operation (*@x). Returns a lazy list containing the lazy array elements. # insert a reference to array2 into array1 $lazy_array.push( $lazy_array_2 ); # insert each of the array2 elements into array1 $lazy_array.push( $lazy_array_2.list ); - `fetch` / `store` = AUTHOR Flavio S. Glock, = COPYRIGHT Copyright (c) 2005, Flavio S. Glock. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut