Skip to content

Commit c74c758

Browse files
committed
Add a more efficient iterator for RubyArray
1 parent 24cdd13 commit c74c758

File tree

1 file changed

+64
-0
lines changed

1 file changed

+64
-0
lines changed

src/main/java/org/truffleruby/core/array/RubyArray.java

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111

1212
import java.util.Set;
1313

14+
import com.oracle.truffle.api.CompilerDirectives;
15+
import com.oracle.truffle.api.interop.StopIterationException;
16+
import com.oracle.truffle.api.interop.TruffleObject;
17+
import com.oracle.truffle.api.interop.UnsupportedMessageException;
1418
import org.truffleruby.core.klass.RubyClass;
1519
import org.truffleruby.language.RubyDynamicObject;
1620
import org.truffleruby.language.RubyGuards;
@@ -128,6 +132,66 @@ public boolean isArrayElementInsertable(long index,
128132
}
129133
// endregion
130134

135+
// region Iterable Messages
136+
@ExportMessage
137+
public boolean hasIterator() {
138+
return true;
139+
}
140+
141+
/** Override {@link RubyDynamicObject#getIterator} to avoid the extra Fiber for RubyArray */
142+
@ExportMessage
143+
public ArrayIterator getIterator() {
144+
return new ArrayIterator(this);
145+
}
146+
147+
@ExportLibrary(InteropLibrary.class)
148+
static final class ArrayIterator implements TruffleObject {
149+
150+
final RubyArray array;
151+
private long currentItemIndex;
152+
153+
ArrayIterator(RubyArray array) {
154+
this.array = array;
155+
}
156+
157+
@ExportMessage
158+
boolean isIterator() {
159+
return true;
160+
}
161+
162+
@ExportMessage
163+
boolean hasIteratorNextElement(
164+
@CachedLibrary("this.array") InteropLibrary arrays) {
165+
try {
166+
return currentItemIndex < arrays.getArraySize(array);
167+
} catch (UnsupportedMessageException e) {
168+
throw CompilerDirectives.shouldNotReachHere(e);
169+
}
170+
}
171+
172+
@ExportMessage
173+
Object getIteratorNextElement(
174+
@CachedLibrary("this.array") InteropLibrary arrays,
175+
@Cached BranchProfile concurrentModification) throws StopIterationException {
176+
try {
177+
final long size = arrays.getArraySize(array);
178+
if (currentItemIndex >= size) {
179+
throw StopIterationException.create();
180+
}
181+
182+
final Object element = arrays.readArrayElement(array, currentItemIndex);
183+
currentItemIndex++;
184+
return element;
185+
} catch (InvalidArrayIndexException e) {
186+
concurrentModification.enter();
187+
throw StopIterationException.create();
188+
} catch (UnsupportedMessageException e) {
189+
throw CompilerDirectives.shouldNotReachHere(e);
190+
}
191+
}
192+
}
193+
// endregion
194+
131195
private boolean inBounds(long index) {
132196
return index >= 0 && index < size;
133197
}

0 commit comments

Comments
 (0)