File Coverage

blib/lib/Tree/SEMETrie/Iterator.pm
Criterion Covered Total %
statement 0 36 0.0
branch 0 14 0.0
condition 0 3 0.0
subroutine 0 5 0.0
pod 0 5 0.0
total 0 63 0.0


line stmt bran cond sub pod time code
1             package Tree::SEMETrie::Iterator;
2              
3             #Private Constants
4             my $EDGE = 0;
5             my $NODE = 1;
6              
7             #Constructor
8              
9             sub new {
10 0     0 0   my $class = shift;
11 0   0       $class = ref($class) || $class;
12 0           my $self = bless {}, $class;
13              
14 0           my $current = shift;
15             #Stack of children of edge-node pairs
16 0           $self->{_ITERATOR_STACK} = [ [ ['', $current] ] ];
17 0 0         $self->next unless $current->has_value;
18              
19 0           return $self;
20             }
21              
22             #Iterator Inspectors
23              
24             sub key {
25 0     0 0   my $self = shift;
26              
27 0           return @{$self->{_ITERATOR_STACK}}
  0            
28 0 0         ? join '', map { $_->[0][$EDGE] } @{$self->{_ITERATOR_STACK}}
  0            
29             : undef;
30             }
31              
32             sub value {
33 0     0 0   my $self = shift;
34              
35 0 0         return @{$self->{_ITERATOR_STACK}}
  0            
36             ? $self->{_ITERATOR_STACK}[-1][0][$NODE]->value(@_)
37             : undef;
38             }
39              
40             #Iterator Operators
41              
42 0     0 0   sub is_done { ! @{$_[0]{_ITERATOR_STACK}} }
  0            
43              
44             sub next {
45 0     0 0   my $self = shift;
46 0           my $iterator_stack_ref = $self->{_ITERATOR_STACK};
47              
48             #Return false if there's nothing left to see
49 0 0         return 0 unless @$iterator_stack_ref;
50              
51             #There are only 2 options:
52              
53             #We stopped at an inner node so the next value is a descendant
54 0 0         if ($iterator_stack_ref->[-1][0][$NODE]->has_childs) {
55 0           while (my @childs = $iterator_stack_ref->[-1][0][$NODE]->childs) {
56 0           push @$iterator_stack_ref, \@childs;
57 0 0         last if $iterator_stack_ref->[-1][0][$NODE]->has_value;
58             }
59              
60             #We stopped at a leaf node
61             } else {
62              
63             #Try to go to the next sibling
64 0           shift @{$iterator_stack_ref->[-1]};
  0            
65             #Keep looking until some ancestor has a sibling
66 0           until (@{$iterator_stack_ref->[-1]}) {
  0            
67             #Go to the ancestor
68 0           pop @$iterator_stack_ref;
69             #We're done if there are no more ancestors
70 0 0         return 0 unless @$iterator_stack_ref;
71             #Go to the ancestor's sibling
72 0           shift @{$iterator_stack_ref->[-1]};
  0            
73             }
74              
75             #The sibling may not have a value, but one of its descendants must
76 0           until ($iterator_stack_ref->[-1][0][$NODE]->has_value) {
77             #Move to the children
78 0           my @childs = $iterator_stack_ref->[-1][0][$NODE]->childs;
79 0           push @$iterator_stack_ref, \@childs;
80             }
81             }
82              
83             #We succeeded if we didn't exhaust the stack
84 0           return @$iterator_stack_ref > 0;
85             }
86              
87             1;