2020
2121package org .lmdbjava ;
2222
23+ import java .util .Comparator ;
2324import java .util .Iterator ;
2425import java .util .NoSuchElementException ;
25- import static org .lmdbjava .CursorIterator .IteratorType .FORWARD ;
26- import static org .lmdbjava .CursorIterator .State .DONE ;
27- import static org .lmdbjava .CursorIterator .State .NOT_READY ;
28- import static org .lmdbjava .CursorIterator .State .READY ;
26+ import static org .lmdbjava .CursorIterator .State .RELEASED ;
27+ import static org .lmdbjava .CursorIterator .State .REQUIRES_INITIAL_OP ;
28+ import static org .lmdbjava .CursorIterator .State .REQUIRES_ITERATOR_OP ;
29+ import static org .lmdbjava .CursorIterator .State .REQUIRES_NEXT_OP ;
30+ import static org .lmdbjava .CursorIterator .State .TERMINATED ;
2931import static org .lmdbjava .GetOp .MDB_SET_RANGE ;
32+ import org .lmdbjava .KeyRange .CursorOp ;
33+ import org .lmdbjava .KeyRange .IteratorOp ;
3034
3135/**
32- * Iterator for entries that follow the same semantics as Cursors with regards
33- * to read and write transactions and how they are closed.
36+ * {@link Iterator} that iterates over a {@link Cursor} as specified by a
37+ * {@link KeyRange}.
38+ *
39+ * <p>
40+ * An instance will create and close its own cursor.
3441 *
3542 * @param <T> buffer type
3643 */
3744public final class CursorIterator <T > implements
38- Iterator <CursorIterator .KeyVal <T >>,
39- AutoCloseable {
45+ Iterator <CursorIterator .KeyVal <T >>, AutoCloseable {
4046
47+ private final Comparator <T > comparator ;
4148 private final Cursor <T > cursor ;
4249 private final KeyVal <T > entry ;
43- private boolean first = true ;
44- private final T key ;
45- private State state = NOT_READY ;
46- private final IteratorType type ;
47-
48- CursorIterator (final Cursor <T > cursor , final T key , final IteratorType type ) {
49- this .cursor = cursor ;
50- this .type = type ;
51- this .key = key ;
50+ private final KeyRange <T > range ;
51+ private State state = REQUIRES_INITIAL_OP ;
52+
53+ CursorIterator (final Txn <T > txn , final Dbi <T > dbi , final KeyRange <T > range ,
54+ final Comparator <T > comparator ) {
55+ this .cursor = dbi .openCursor (txn );
56+ this .range = range ;
57+ this .comparator = comparator ;
5258 this .entry = new KeyVal <>();
5359 }
5460
@@ -60,14 +66,10 @@ public void close() {
6066 @ Override
6167 @ SuppressWarnings ("checkstyle:returncount" )
6268 public boolean hasNext () {
63- switch (state ) {
64- case DONE :
65- return false ;
66- case READY :
67- return true ;
68- default :
69+ while (state != RELEASED && state != TERMINATED ) {
70+ update ();
6971 }
70- return tryToComputeNext () ;
72+ return state == RELEASED ;
7173 }
7274
7375 /**
@@ -84,7 +86,7 @@ public KeyVal<T> next() throws NoSuchElementException {
8486 if (!hasNext ()) {
8587 throw new NoSuchElementException ();
8688 }
87- state = NOT_READY ;
89+ state = REQUIRES_NEXT_OP ;
8890 return entry ;
8991 }
9092
@@ -93,44 +95,67 @@ public void remove() {
9395 throw new UnsupportedOperationException ();
9496 }
9597
96- private void setEntry (final boolean success ) {
97- if (success ) {
98- this .entry .setKey (cursor .key ());
99- this .entry .setVal (cursor .val ());
100- } else {
101- this .entry .setKey (null );
102- this .entry .setVal (null );
98+ private void executeCursorOp (final CursorOp op ) {
99+ final boolean found ;
100+ switch (op ) {
101+ case FIRST :
102+ found = cursor .first ();
103+ break ;
104+ case LAST :
105+ found = cursor .last ();
106+ break ;
107+ case NEXT :
108+ found = cursor .next ();
109+ break ;
110+ case PREV :
111+ found = cursor .prev ();
112+ break ;
113+ case GET_START_KEY :
114+ found = cursor .get (range .getStart (), MDB_SET_RANGE );
115+ break ;
116+ default :
117+ throw new IllegalStateException ("Unknown cursor operation" );
103118 }
119+ entry .setK (found ? cursor .key () : null );
120+ entry .setV (found ? cursor .val () : null );
104121 }
105122
106- @ SuppressWarnings ("checkstyle:returncount" )
107- private boolean tryToComputeNext () {
108- if (first ) {
109- if (key != null ) { // NOPMD
110- setEntry (cursor .get (key , MDB_SET_RANGE ));
111- } else if (type == FORWARD ) {
112- setEntry (cursor .first ());
113- } else {
114- setEntry (cursor .last ());
115- }
116- first = false ;
117- if (entry .isEmpty ()) {
118- state = DONE ;
119- return false ;
120- }
121- } else {
122- if (type == FORWARD ) {
123- setEntry (cursor .next ());
124- } else {
125- setEntry (cursor .prev ());
126- }
127- if (entry .isEmpty ()) {
128- state = DONE ;
129- return false ;
130- }
123+ private void executeIteratorOp () {
124+ final IteratorOp op = range .iteratorOp (comparator , entry .key ());
125+ switch (op ) {
126+ case CALL_NEXT_OP :
127+ executeCursorOp (range .nextOp ());
128+ state = REQUIRES_ITERATOR_OP ;
129+ break ;
130+ case TERMINATE :
131+ state = TERMINATED ;
132+ break ;
133+ case RELEASE :
134+ state = RELEASED ;
135+ break ;
136+ default :
137+ throw new IllegalStateException ("Unknown operation" );
138+ }
139+ }
140+
141+ private void update () {
142+ switch (state ) {
143+ case REQUIRES_INITIAL_OP :
144+ executeCursorOp (range .initialOp ());
145+ state = REQUIRES_ITERATOR_OP ;
146+ break ;
147+ case REQUIRES_NEXT_OP :
148+ executeCursorOp (range .nextOp ());
149+ state = REQUIRES_ITERATOR_OP ;
150+ break ;
151+ case REQUIRES_ITERATOR_OP :
152+ executeIteratorOp ();
153+ break ;
154+ case TERMINATED :
155+ break ;
156+ default :
157+ throw new IllegalStateException ("Unknown state" );
131158 }
132- state = READY ;
133- return true ;
134159 }
135160
136161 /**
@@ -174,13 +199,14 @@ void setV(final T val) {
174199 this .v = val ;
175200 }
176201
177- boolean isEmpty () {
178- return this .k == null && this .v == null ;
179202 }
180203
181204 /**
182205 * Direction in terms of key ordering for CursorIterator.
206+ *
207+ * @deprecated use {@link KeyRange} instead
183208 */
209+ @ Deprecated
184210 public enum IteratorType {
185211 /**
186212 * Move forward.
@@ -196,7 +222,8 @@ public enum IteratorType {
196222 * Represents the internal {@link CursorIterator} state.
197223 */
198224 enum State {
199- READY , NOT_READY , DONE , FAILED ,
225+ REQUIRES_INITIAL_OP , REQUIRES_NEXT_OP , REQUIRES_ITERATOR_OP , RELEASED ,
226+ TERMINATED
200227 }
201228
202229}
0 commit comments