In reflection of dws's and Zaxo's comments below, and with the help of a tip from Jarich an rob_au in the CB, I've re-cast my uFIFO code.
It's not designed nor destined to become a module. It's just an exploration of closures and what can be done with them.
#! perl -w
use strict;
sub uFIFO {
=pod
uFIFO - a FIFO that retains only unique values with the ability to
+ iterate
(with multiple independant iterators) implemented using closures.
One copy of any value except undef will be retained.
Calling syntax:
my $fifo = uFIFO();
my $count = $fifo{add}( @list ); # counts only unique value
+s added.
my $iter1 = $fifo{iterator}(); # Values added whilst the
+iterator is active
my $iter2 = $fifo{iterator}(); # are handled correctly
my $first = $iter1{first}(); # Resets to the oldest val
+ue (and returns it)
my $next = $iter{next}(); # get the next or undef
my @unique= $fifo{all)(); # all entries, undefined o
+rder
my $unique= $fifo{all}(); # Size of the fifo
my $sorted= $fifo{ordered}(); # All in fifo order (scala
+r context as above)
=cut
my (%fifo, @fifo);
return {
# Push input item or list onto the fifo, return the number of
+items added
add => sub {
return scalar grep {
defined $_ && !exists $fifo{ $_ }
and push @fifo, \($fifo { $_ } = $_ );
} @_;
},
# returns an indepentent iterator for the fifo,
iterator => sub {
my $next = 0;
return {
# resets the iterator and returns the first item (Does
+n't increment!)
first => sub {
return scalar @fifo ? ${ $fifo[ $next = 0 ] } : u
+ndef;
},
# get the next item from the fifo,
#or resets and returns undef if at no more
next => sub {
return scalar @fifo && $next < @fifo? ${ $fifo[$ne
+xt++] } : undef;
},
},
},
# returns all the values from the fifo
# (in a non-determinant order (efficiently)) in a list context
# or a count of them in a scalar context
all => sub { return keys %fifo; },
# returns all the values in the order in which they were added
# earlier values remain in place. Later duplicates do not caus
+e promotion.
ordered => sub { return map { ${ $_ }} @fifo; },
}
}
If your interested in seeing in use and tested click
# TEST CODE ONLY BELOW HERE
my $fifo1 = uFIFO(); # create a fifo - we can have as many as we need
# create some test data and shuffle it
my @test = ('a' .. 'z', 'i' .. 'r');
($a=$_+rand @test-$_) and @test[$_,$a] = @test[$a,$_] for (0..$#test);
printf "%15.15s: %s\n", 'Initial data', "@test"; # data in original or
+der for comparison later
#add some test data 26 stored from 36 passed
print sprintf( '%15.15s: ', 'How many'), $fifo1->{add}( @test ),$/;
print sprintf( '%15.15s: ', 'How many'), $fifo1->{add}( 'W' ),$/; # ad
+d a single value
print sprintf( '%15.15s: ', 'How many'), $fifo1->{add}( qw( X Y Z ) ),
+$/; # add a list
print sprintf( '%15.15s: ', 'How many'), $fifo1->{add}(),$/; #Add noth
+ing?
# add some 'somethings' interspersed with some 'nothings'
# and return how many were added: should be 3 ('A', 0, '') ; undef are
+n't stored and 0 =~ "0"
print sprintf( '%15.15s: ', 'How many added'),$fifo1->{add}( undef, ch
+r(65), undef, 0, "", "0" ), $/;
# Show only one copy of each made it in
print sprintf( '%15.15s: ', 'Count & show'), 0+$fifo1->{all}(), ' : ',
+ "@{[$fifo1->{all}()]}", $/;
# process the list, randomly adding some more and printing them out as
+ we process
my $i;
printf '%15.15s: ', 'Processed';
my $iterator = $fifo1->{iterator}();
while( my $temp = $iterator->{next}() ) {
print $temp, ' ' ;
(0 == int(rand 4)) and $fifo1->{add}( ++$i ); # Randomly add new v
+alues
}
print $/;
print sprintf( '%15.15s: ', 'Ordered'), "@{ [ $fifo1->{ordered}() ] }"
+, $/;
print sprintf( '%15.15s: ', 'Unordered'), "@{ [ $fifo1->{all}() ] }"
+ , $/;
__END__
# Output from testing
C:\test>uFIFO
Initial data: l f s p l q r p q j m h j d r m n u n v i e o o x a c
+ y z t g w b k i k
How many: 26
How many: 1
How many: 3
How many: 0
How many added: 3
Count & show: 33 : A W X Y Z a b c d e f g h i j k l m n 0 o p q r
+ s t u v w x y z
Processed: l f s p q r j m h d n u v i e o x a c y z t g w b k W
+ X Y Z A
Ordered: l f s p q r j m h d n u v i e o x a c y z t g w b k W
+ X Y Z A 0 1 2 3 4 5 6 7 8 9
Unordered: A W X Y Z a b c d e f g h i j k l m n 0 1 o 2 p 3 q
+4 r 5 s 6 t 7 u 8 v 9 w x y z
Well It's better than the Abottoire, but Yorkshire!