Starlark: faster dict.keys
Calling `Dict.entries()` to implement `keys` is suboptimal because it:
* wraps with unmodifiable map
* creates `Map.Entry` object for each iteration
This commit also calls `contents.entrySet()` for `items`, but that's
done mostly for consistency.
Test:
```
def test():
for i in range(10):
d = {1: 2, 3: 4}
for j in range(3000000):
d.keys()
test()
```
Result:
```
A: N=17, r=4.813+-0.260
B: N=17, r=4.373+-0.212
B/A: 0.909
```
Closes #12480.
PiperOrigin-RevId: 419645062
diff --git a/src/main/java/net/starlark/java/eval/Dict.java b/src/main/java/net/starlark/java/eval/Dict.java
index 229b84c..4dff1c3 100644
--- a/src/main/java/net/starlark/java/eval/Dict.java
+++ b/src/main/java/net/starlark/java/eval/Dict.java
@@ -361,7 +361,7 @@
public StarlarkList<?> items(StarlarkThread thread) throws EvalException {
Object[] array = new Object[size()];
int i = 0;
- for (Map.Entry<?, ?> e : entrySet()) {
+ for (Map.Entry<?, ?> e : contents.entrySet()) {
array[i++] = Tuple.pair(e.getKey(), e.getValue());
}
return StarlarkList.wrap(thread.mutability(), array);
@@ -377,8 +377,8 @@
public StarlarkList<?> keys(StarlarkThread thread) throws EvalException {
Object[] array = new Object[size()];
int i = 0;
- for (Map.Entry<?, ?> e : entrySet()) {
- array[i++] = e.getKey();
+ for (K e : contents.keySet()) {
+ array[i++] = e;
}
return StarlarkList.wrap(thread.mutability(), array);
}