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;