Added description to a test
[dbsrgits/DBM-Deep.git] / lib / DBM / Deep / Iterator.pm
1 package DBM::Deep::Iterator;
2
3 use 5.006_000;
4
5 use strict;
6 use warnings FATAL => 'all';
7
8 use Scalar::Util ();
9
10 use DBM::Deep::Iterator::Index;
11 use DBM::Deep::Iterator::BucketList;
12
13 sub new {
14     my $class = shift;
15     my ($args) = @_;
16
17     my $self = bless {
18         breadcrumbs => [],
19         engine      => $args->{engine},
20         base_offset => $args->{base_offset},
21     }, $class;
22
23     Scalar::Util::weaken( $self->{engine} );
24
25     return $self;
26 }
27
28 sub reset { $_[0]{breadcrumbs} = [] }
29
30 sub get_sector_iterator {
31     my $self = shift;
32     my ($loc) = @_;
33
34     my $sector = $self->{engine}->_load_sector( $loc )
35         or return;
36
37     if ( $sector->isa( 'DBM::Deep::Engine::Sector::Index' ) ) {
38         return DBM::Deep::Iterator::Index->new({
39             iterator => $self,
40             sector   => $sector,
41         });
42     }
43     elsif ( $sector->isa( 'DBM::Deep::Engine::Sector::BucketList' ) ) {
44         return DBM::Deep::Iterator::BucketList->new({
45             iterator => $self,
46             sector   => $sector,
47         });
48     }
49
50     DBM::Deep->_throw_error( "get_sector_iterator(): Why did $loc make a $sector?" );
51 }
52
53 sub get_next_key {
54     my $self = shift;
55     my ($obj) = @_;
56
57     my $crumbs = $self->{breadcrumbs};
58     my $e = $self->{engine};
59
60     warn "1\n";
61     unless ( @$crumbs ) {
62         # This will be a Reference sector
63         my $sector = $e->_load_sector( $self->{base_offset} )
64             # If no sector is found, thist must have been deleted from under us.
65             or return;
66
67         if ( $sector->staleness != $obj->_staleness ) {
68             return;
69         }
70
71         my $loc = $sector->get_blist_loc
72             or return;
73
74         push @$crumbs, $self->get_sector_iterator( $loc );
75     }
76
77     warn "2: " . $obj->_dump_file;
78     FIND_NEXT_KEY: {
79         # We're at the end.
80         unless ( @$crumbs ) {
81             $self->reset;
82             return;
83         }
84
85         my $iterator = $crumbs->[-1];
86
87         # This level is done.
88         if ( $iterator->at_end ) {
89             pop @$crumbs;
90             redo FIND_NEXT_KEY;
91         }
92
93         if ( $iterator->isa( 'DBM::Deep::Iterator::Index' ) ) {
94             # If we don't have any more, it will be caught at the
95             # prior check.
96             if ( my $next = $iterator->get_next_iterator ) {
97                 push @$crumbs, $next;
98             }
99             redo FIND_NEXT_KEY;
100         }
101
102         unless ( $iterator->isa( 'DBM::Deep::Iterator::BucketList' ) ) {
103             DBM::Deep->_throw_error(
104                 "Should have a bucketlist iterator here - instead have $iterator"
105             );
106         }
107
108         # At this point, we have a BucketList iterator
109         my $key = $iterator->get_next_key;
110         if ( defined $key ) {
111             return $key;
112         }
113         #XXX else { $iterator->set_to_end() } ?
114
115         # We hit the end of the bucketlist iterator, so redo
116         redo FIND_NEXT_KEY;
117     }
118
119     DBM::Deep->_throw_error( "get_next_key(): How did we get here?" );
120 }
121
122 1;
123 __END__