# Module of TWiki Enterprise Collaboration Platform, http://TWiki.org/ # # Copyright (C) 2000-2018 Peter Thoeny, peter[at]thoeny.org # and TWiki Contributors. All Rights Reserved. TWiki Contributors # are listed in the AUTHORS file in the root of this distribution. # NOTE: Please extend that file, not this notice. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 3 # of the License, or (at your option) any later version. For # more details read LICENSE in the root of this distribution. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # # As per the GPL, removal of this notice is prohibited. =pod ---+ package TWiki::AggregateIterator combine multiple iterators =cut package TWiki::AggregateIterator; use strict; =pod ---++ new(\@list, $unique) Create a new iterator over the given list of iterators. The list is not damaged in any way. if $unique is set, we try to not repeat values. Warning: $unique assumes that the values are strings (so works for cUID's ) =cut sub new { my ($class, $list, $unique) = @_; my $this = bless({ Itr_list => $list, Itr_index => 0, index => 0, process => undef, filter => undef, next => undef, unique => $unique, unique_hash => {} }, $class); return $this; } =pod ---++ hasNext() -> $boolean Returns false when the iterator is exhausted. my $it = new TWiki::ListIterator(\@list); while ($it->hasNext()) { ... =cut sub hasNext { my( $this ) = @_; return 1 if $this->{next}; my $n; do { unless ( $this->{list} ) { if ($this->{Itr_index} < scalar(@{$this->{Itr_list}}) ) { $this->{list} = $this->{Itr_list}->[$this->{Itr_index}++]; } else { return 0; #no more iterators in list } } if( $this->{list}->hasNext()) { $n = $this->{list}->next(); } else { $this->{list} = undef; #goto next iterator } } while (!$this->{list} || ($this->{filter} && !&{$this->{filter}}($n)) || ($this->{unique} && !$this->unique($n))); $this->{next} = $n; return 1; } sub unique { my ($this, $value) = @_; unless (defined($this->{unique_hash}{$value})) { $this->{unique_hash}{$value} = 1; return 1; } return 0; } =pod ---++ next() -> $data Return the next entry in the list. The iterator object can be customised to pre- and post-process entries from the list before returning them. This is done by setting two fields in the iterator object: * ={filter}= can be defined to be a sub that filters each entry. The entry will be ignored (next() will not return it) if the filter returns false. * ={process}= can be defined to be a sub to process each entry before it is returned by next. The value returned from next is the value returned by the process function. =cut sub next { my $this = shift; $this->hasNext(); my $n = $this->{next}; $this->{next} = undef; $n = &{$this->{process}}($n) if $this->{process}; #print STDERR "next - $n \n"; return $n; } 1;