From 03de1f16a7769a588e308816c2f7db04ad97d5f9 Mon Sep 17 00:00:00 2001
From: Pieter12345
Date: Fri, 17 Jan 2025 07:48:13 +0100
Subject: [PATCH] Optimize array_contains functions
Improve runtime performance on `array_contains()`, `array_scontains()` and `array_contains_ic()` by iterating over the array values whenever possible, rather than creating a keyset to iterate over and calling the getter to get all values.
---
.../laytonsmith/core/constructs/CArray.java | 2 +-
.../core/constructs/CByteArray.java | 33 ++++++++++++++-
.../laytonsmith/core/constructs/CSlice.java | 37 ++++++++++++++++
.../core/functions/ArrayHandling.java | 42 +++++++++++++++----
4 files changed, 103 insertions(+), 11 deletions(-)
diff --git a/src/main/java/com/laytonsmith/core/constructs/CArray.java b/src/main/java/com/laytonsmith/core/constructs/CArray.java
index 7558591574..12f77698e9 100644
--- a/src/main/java/com/laytonsmith/core/constructs/CArray.java
+++ b/src/main/java/com/laytonsmith/core/constructs/CArray.java
@@ -814,7 +814,7 @@ public Version since() {
@Override
public Iterator iterator() {
if(associativeMode) {
- throw new RuntimeException("iterator() cannot be called on an associative array");
+ return associativeArray.values().iterator();
} else {
return array.iterator();
}
diff --git a/src/main/java/com/laytonsmith/core/constructs/CByteArray.java b/src/main/java/com/laytonsmith/core/constructs/CByteArray.java
index a6f93a368f..2bf6d553c4 100644
--- a/src/main/java/com/laytonsmith/core/constructs/CByteArray.java
+++ b/src/main/java/com/laytonsmith/core/constructs/CByteArray.java
@@ -583,7 +583,20 @@ public void removeValues(Mixed construct) {
@Override
public Iterator iterator() {
- throw new CREUnsupportedOperationException("Iterating a byte array is not supported.", getTarget());
+ return new Iterator() {
+
+ private int index = 0;
+
+ @Override
+ public boolean hasNext() {
+ return this.index <= maxValue;
+ }
+
+ @Override
+ public Mixed next() {
+ return new CInt(data.get(this.index++), Target.UNKNOWN);
+ }
+ };
}
@Override
@@ -696,6 +709,24 @@ protected SortedMap getAssociativeArray() {
throw new Error("This error should not happen. Please report this bug to the developers");
}
+ @Override
+ public Iterator iterator() {
+ return new Iterator() {
+
+ private int index = 0;
+
+ @Override
+ public boolean hasNext() {
+ return this.index <= backing.length;
+ }
+
+ @Override
+ public Mixed next() {
+ return new CInt(backing[this.index++], Target.UNKNOWN);
+ }
+ };
+ }
+
@Override
public String docs() {
return "A read-only subclass of array, which is used to make reading byte arrays more efficient.";
diff --git a/src/main/java/com/laytonsmith/core/constructs/CSlice.java b/src/main/java/com/laytonsmith/core/constructs/CSlice.java
index 26a539f7b3..4a40eefd4d 100644
--- a/src/main/java/com/laytonsmith/core/constructs/CSlice.java
+++ b/src/main/java/com/laytonsmith/core/constructs/CSlice.java
@@ -165,6 +165,43 @@ public int size() {
};
}
+ @Override
+ public Iterator iterator() {
+ if(start <= finish) {
+ return new Iterator() {
+
+ private long current = start;
+ private long last = finish;
+
+ @Override
+ public boolean hasNext() {
+ return this.current <= this.last;
+ }
+
+ @Override
+ public Mixed next() {
+ return new CInt(this.current++, Target.UNKNOWN);
+ }
+ };
+ } else {
+ return new Iterator() {
+
+ private long current = start;
+ private long last = finish;
+
+ @Override
+ public boolean hasNext() {
+ return this.current >= this.last;
+ }
+
+ @Override
+ public Mixed next() {
+ return new CInt(this.current--, Target.UNKNOWN);
+ }
+ };
+ }
+ }
+
@Override
public long size() {
return size;
diff --git a/src/main/java/com/laytonsmith/core/functions/ArrayHandling.java b/src/main/java/com/laytonsmith/core/functions/ArrayHandling.java
index 9a3f375c14..baffb8cb93 100644
--- a/src/main/java/com/laytonsmith/core/functions/ArrayHandling.java
+++ b/src/main/java/com/laytonsmith/core/functions/ArrayHandling.java
@@ -712,9 +712,17 @@ public Mixed exec(Target t, Environment env, Mixed... args) throws CancelCommand
CArray ca = ArgumentValidation.getArray(args[0], t);
aa = ca;
}
- for(Mixed key : aa.keySet()) {
- if(new equals().exec(t, env, aa.get(key, t), args[1]).getBoolean()) {
- return CBoolean.TRUE;
+ if(aa instanceof CArray ca) {
+ for(Mixed val : ca) {
+ if(new equals().exec(t, env, val, args[1]).getBoolean()) {
+ return CBoolean.TRUE;
+ }
+ }
+ } else {
+ for(Mixed key : aa.keySet()) {
+ if(new equals().exec(t, env, aa.get(key, t), args[1]).getBoolean()) {
+ return CBoolean.TRUE;
+ }
}
}
return CBoolean.FALSE;
@@ -822,9 +830,17 @@ public Mixed exec(Target t, Environment environment, Mixed... args) throws Confi
} else {
aa = ArgumentValidation.getArray(args[0], t);
}
- for(Mixed key : aa.keySet()) {
- if(new equals_ic().exec(t, environment, aa.get(key, t), args[1]).getBoolean()) {
- return CBoolean.TRUE;
+ if(aa instanceof CArray ca) {
+ for(Mixed val : ca) {
+ if(new equals_ic().exec(t, environment, val, args[1]).getBoolean()) {
+ return CBoolean.TRUE;
+ }
+ }
+ } else {
+ for(Mixed key : aa.keySet()) {
+ if(new equals_ic().exec(t, environment, aa.get(key, t), args[1]).getBoolean()) {
+ return CBoolean.TRUE;
+ }
}
}
return CBoolean.FALSE;
@@ -876,9 +892,17 @@ public Mixed exec(Target t, Environment env, Mixed... args) throws CancelCommand
} else {
aa = ArgumentValidation.getArray(args[0], t);
}
- for(Mixed key : aa.keySet()) {
- if(new sequals().exec(t, env, aa.get(key, t), args[1]).getBoolean()) {
- return CBoolean.TRUE;
+ if(aa instanceof CArray ca) {
+ for(Mixed val : ca) {
+ if(new sequals().exec(t, env, val, args[1]).getBoolean()) {
+ return CBoolean.TRUE;
+ }
+ }
+ } else {
+ for(Mixed key : aa.keySet()) {
+ if(new sequals().exec(t, env, aa.get(key, t), args[1]).getBoolean()) {
+ return CBoolean.TRUE;
+ }
}
}
return CBoolean.FALSE;