Skip to content

Commit 96308df

Browse files
committed
CursorIterator to reuse KeyVal during iteration
This makes CursorIterator consistent with the typical LmdbJava pattern of not requiring allocations except for high-level control objects (eg Evn, Dbi, Txn, Cursor, CursorIterator).
1 parent ad0c7f2 commit 96308df

File tree

1 file changed

+28
-21
lines changed

1 file changed

+28
-21
lines changed

src/main/java/org/lmdbjava/CursorIterator.java

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public final class CursorIterator<T> implements
3939
AutoCloseable {
4040

4141
private final Cursor<T> cursor;
42-
private KeyVal<T> entry;
42+
private final KeyVal<T> entry;
4343
private boolean first = true;
4444
private final T key;
4545
private State state = NOT_READY;
@@ -49,6 +49,7 @@ public final class CursorIterator<T> implements
4949
this.cursor = cursor;
5050
this.type = type;
5151
this.key = key;
52+
this.entry = new KeyVal<>();
5253
}
5354

5455
@Override
@@ -84,9 +85,7 @@ public KeyVal<T> next() throws NoSuchElementException {
8485
throw new NoSuchElementException();
8586
}
8687
state = NOT_READY;
87-
final KeyVal<T> result = entry;
88-
entry = null;
89-
return result;
88+
return entry;
9089
}
9190

9291
@Override
@@ -96,9 +95,11 @@ public void remove() {
9695

9796
private void setEntry(final boolean success) {
9897
if (success) {
99-
this.entry = new KeyVal<>(cursor.key(), cursor.val());
98+
this.entry.setKey(cursor.key());
99+
this.entry.setVal(cursor.val());
100100
} else {
101-
this.entry = null;
101+
this.entry.setKey(null);
102+
this.entry.setVal(null);
102103
}
103104
}
104105

@@ -113,7 +114,7 @@ private boolean tryToComputeNext() {
113114
setEntry(cursor.last());
114115
}
115116
first = false;
116-
if (entry == null) {
117+
if (entry.isEmpty()) {
117118
state = DONE;
118119
return false;
119120
}
@@ -123,7 +124,7 @@ private boolean tryToComputeNext() {
123124
} else {
124125
setEntry(cursor.prev());
125126
}
126-
if (entry == null) {
127+
if (entry.isEmpty()) {
127128
state = DONE;
128129
return false;
129130
}
@@ -135,23 +136,17 @@ private boolean tryToComputeNext() {
135136
/**
136137
* Holder for a key and value pair.
137138
*
139+
* <p>
140+
* The same holder instance will always be returned for a given iterator.
141+
* The returned keys and values may change or point to different memory
142+
* locations following changes in the iterator, cursor or transaction.
143+
*
138144
* @param <T> buffer type
139145
*/
140146
public static final class KeyVal<T> {
141147

142-
private final T k;
143-
private final T v;
144-
145-
/**
146-
* Obtain a key-value holder.
147-
*
148-
* @param key the key
149-
* @param val the value
150-
*/
151-
public KeyVal(final T key, final T val) {
152-
this.k = key;
153-
this.v = val;
154-
}
148+
private T k;
149+
private T v;
155150

156151
/**
157152
* The key.
@@ -171,6 +166,18 @@ public T val() {
171166
return v;
172167
}
173168

169+
void setKey(final T k) {
170+
this.k = k;
171+
}
172+
173+
void setVal(final T v) {
174+
this.v = v;
175+
}
176+
177+
boolean isEmpty() {
178+
return this.k == null && this.v == null;
179+
}
180+
174181
}
175182

176183
/**

0 commit comments

Comments
 (0)