Skip to content

Commit eff0d6a

Browse files
Implement index tracking to optimize list operations (#8519)
1 parent 6ad6073 commit eff0d6a

File tree

8 files changed

+574
-42
lines changed

8 files changed

+574
-42
lines changed

src/main/java/ch/njol/skript/expressions/ExprAmount.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import ch.njol.skript.lang.ExpressionList;
1212
import ch.njol.skript.lang.ExpressionType;
1313
import ch.njol.skript.lang.SkriptParser.ParseResult;
14+
import ch.njol.skript.lang.Variable;
1415
import ch.njol.skript.lang.util.SimpleExpression;
1516
import ch.njol.skript.lang.util.common.AnyAmount;
1617
import ch.njol.skript.util.LiteralUtils;
@@ -42,6 +43,7 @@ public class ExprAmount extends SimpleExpression<Number> {
4243
@SuppressWarnings("null")
4344
private ExpressionList<?> exprs;
4445
private @Nullable Expression<AnyAmount> any;
46+
private @Nullable Variable<?> list;
4547

4648
@Override
4749
public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
@@ -54,7 +56,6 @@ public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelaye
5456
this.exprs = exprs[0] instanceof ExpressionList<?> exprList
5557
? exprList
5658
: new ExpressionList<>(new Expression<?>[]{ exprs[0] }, Object.class, false);
57-
5859
this.exprs = (ExpressionList<?>) LiteralUtils.defendExpression(this.exprs);
5960
if (!LiteralUtils.canInitSafely(this.exprs)) {
6061
return false;
@@ -65,13 +66,20 @@ public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelaye
6566
return false;
6667
}
6768

69+
if (exprs[0] instanceof Variable<?> variable)
70+
this.list = variable;
71+
6872
return true;
6973
}
7074

7175
@Override
7276
protected Number[] get(Event event) {
7377
if (any != null)
7478
return new Number[] {any.getOptionalSingle(event).orElse(() -> 0).amount()};
79+
80+
if (list != null)
81+
return new Long[]{(long) list.size(event)};
82+
7583
return new Long[]{(long) exprs.getArray(event).length};
7684
}
7785

src/main/java/ch/njol/skript/lang/Variable.java

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
import ch.njol.skript.structures.StructVariables.DefaultVariables;
1515
import ch.njol.skript.util.StringMode;
1616
import ch.njol.skript.util.Utils;
17+
import com.google.common.base.Preconditions;
18+
import org.skriptlang.skript.util.IndexTrackingTreeMap;
1719
import ch.njol.skript.variables.Variables;
1820
import ch.njol.util.Kleenean;
1921
import ch.njol.util.Pair;
@@ -446,7 +448,7 @@ private T[] getConvertedArray(Event event) {
446448
}
447449

448450
private void set(Event event, @Nullable Object value) {
449-
Variables.setVariable("" + name.toString(event), value, event, local);
451+
Variables.setVariable(name.toString(event), value, event, local);
450452
}
451453

452454
private void setIndex(Event event, String index, @Nullable Object value) {
@@ -456,6 +458,33 @@ private void setIndex(Event event, String index, @Nullable Object value) {
456458
Variables.setVariable(name.substring(0, name.length() - 1) + index, value, event, local);
457459
}
458460

461+
public int size(Event event) {
462+
Preconditions.checkState(list, "Cannot get the size of a single variable");
463+
Map<?, ?> map = (Map<?, ?>) getRaw(event);
464+
if (map == null)
465+
return 0;
466+
467+
int size = map.size();
468+
if (map.containsKey(null)) // if we're trying to get the size of {_list::*}, exclude {_list} from being counted
469+
size--;
470+
471+
if (!(map instanceof IndexTrackingTreeMap<?> indexTrackingMap)) {
472+
for (Object value : map.values()) {
473+
if (value instanceof Map<?, ?> sublist && !sublist.containsKey(null))
474+
size--;
475+
}
476+
return size;
477+
}
478+
479+
Collection<String> sublistIndices = indexTrackingMap.mapIndices();
480+
for (String sublistIndex : sublistIndices) {
481+
if (!((Map<?, ?>) map.get(sublistIndex)).containsKey(null))
482+
size--;
483+
}
484+
485+
return size;
486+
}
487+
459488
@Override
460489
public Class<?> @Nullable [] acceptChange(ChangeMode mode) {
461490
if (!list && mode == ChangeMode.SET)
@@ -494,22 +523,6 @@ public void change(Event event, Object @NotNull [] delta, ChangeMode mode, @NotN
494523
public void change(Event event, Object @Nullable [] delta, ChangeMode mode) throws UnsupportedOperationException {
495524
switch (mode) {
496525
case DELETE:
497-
if (list) {
498-
ArrayList<String> toDelete = new ArrayList<>();
499-
Map<String, Object> map = (Map<String, Object>) getRaw(event);
500-
if (map == null)
501-
return;
502-
for (Entry<String, Object> entry : map.entrySet()) {
503-
if (entry.getKey() != null){
504-
toDelete.add(entry.getKey());
505-
}
506-
}
507-
for (String index : toDelete) {
508-
assert index != null;
509-
setIndex(event, index, null);
510-
}
511-
}
512-
513526
set(event, null);
514527
break;
515528
case SET:
@@ -594,6 +607,13 @@ public void change(Event event, Object @Nullable [] delta, ChangeMode mode) thro
594607
}
595608
} else {
596609
assert mode == ChangeMode.ADD;
610+
if (map instanceof IndexTrackingTreeMap<Object> indexTrackingMap) {
611+
for (Object value : delta) {
612+
int index = indexTrackingMap.nextOpenIndex();
613+
setIndex(event, String.valueOf(index), value);
614+
}
615+
return;
616+
}
597617
int i = 1;
598618
for (Object value : delta) {
599619
if (map != null)

src/main/java/ch/njol/skript/variables/VariablesMap.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import ch.njol.skript.lang.Variable;
44
import ch.njol.util.StringUtils;
55
import org.jetbrains.annotations.Nullable;
6+
import org.skriptlang.skript.util.IndexTrackingTreeMap;
67

78
import java.util.Comparator;
89
import java.util.HashMap;
@@ -216,7 +217,7 @@ void setVariable(String name, @Nullable Object value) {
216217
break;
217218
} else if (value != null) {
218219
// Create child node, add it to parent and continue iteration
219-
childNode = new TreeMap<>(VARIABLE_NAME_COMPARATOR);
220+
childNode = new IndexTrackingTreeMap<>(VARIABLE_NAME_COMPARATOR);
220221

221222
parent.put(childNodeName, childNode);
222223
parent = (TreeMap<String, Object>) childNode;
@@ -269,7 +270,7 @@ void setVariable(String name, @Nullable Object value) {
269270
break;
270271
} else if (value != null) {
271272
// Need to continue iteration, create new child node and put old value in it
272-
TreeMap<String, Object> newChildNodeMap = new TreeMap<>(VARIABLE_NAME_COMPARATOR);
273+
TreeMap<String, Object> newChildNodeMap = new IndexTrackingTreeMap<>(VARIABLE_NAME_COMPARATOR);
273274
newChildNodeMap.put(null, childNode);
274275

275276
// Add new child node to parent
@@ -334,7 +335,7 @@ public VariablesMap copy() {
334335
*/
335336
@SuppressWarnings("unchecked")
336337
private static TreeMap<String, Object> copyTreeMap(TreeMap<String, Object> original) {
337-
TreeMap<String, Object> copy = new TreeMap<>(VARIABLE_NAME_COMPARATOR);
338+
TreeMap<String, Object> copy = new IndexTrackingTreeMap<>(VARIABLE_NAME_COMPARATOR);
338339

339340
for (Entry<String, Object> child : original.entrySet()) {
340341
String key = child.getKey();

src/main/java/org/skriptlang/skript/common/properties/expressions/PropExprAmount.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import ch.njol.skript.lang.Expression;
77
import ch.njol.skript.lang.ExpressionList;
88
import ch.njol.skript.lang.SkriptParser.ParseResult;
9+
import ch.njol.skript.lang.Variable;
910
import ch.njol.skript.util.LiteralUtils;
1011
import ch.njol.util.Kleenean;
1112
import org.bukkit.event.Event;
@@ -40,6 +41,7 @@ public static void register(SyntaxRegistry registry, Origin origin) {
4041
}
4142

4243
private ExpressionList<?> exprs;
44+
private @Nullable Variable<?> list;
4345
private boolean useProperties;
4446

4547
@Override
@@ -48,13 +50,14 @@ public boolean init(Expression<?>[] expressions, int matchedPattern, Kleenean is
4850
// amounts of x, y -> property
4951
// amount of x, y -> list length
5052
useProperties = parseResult.hasTag("s") || expressions[0].isSingle();
51-
if (useProperties) {
53+
if (useProperties)
5254
return super.init(expressions, matchedPattern, isDelayed, parseResult);
53-
} else {
54-
// if exprlist or varlist, count elements
55-
this.exprs = asExprList(expressions[0]);
56-
return LiteralUtils.canInitSafely(this.exprs);
57-
}
55+
56+
// if exprlist or varlist, count elements
57+
this.exprs = asExprList(expressions[0]);
58+
if (expressions[0] instanceof Variable<?> variable)
59+
this.list = variable;
60+
return LiteralUtils.canInitSafely(this.exprs);
5861
}
5962

6063
/**
@@ -78,6 +81,10 @@ public static ExpressionList<?> asExprList(Expression<?> expr) {
7881
protected Object @Nullable [] get(Event event) {
7982
if (useProperties)
8083
return super.get(event);
84+
85+
if (list != null)
86+
return new Long[]{(long) list.size(event)};
87+
8188
return new Long[]{(long) exprs.getArray(event).length};
8289
}
8390

src/main/java/org/skriptlang/skript/common/properties/expressions/PropExprNumber.java

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import ch.njol.skript.lang.Expression;
77
import ch.njol.skript.lang.ExpressionList;
88
import ch.njol.skript.lang.SkriptParser.ParseResult;
9+
import ch.njol.skript.lang.Variable;
910
import ch.njol.skript.util.LiteralUtils;
1011
import ch.njol.util.Kleenean;
1112
import org.bukkit.event.Event;
@@ -37,27 +38,33 @@ public static void register(SyntaxRegistry registry, Origin origin) {
3738
}
3839

3940
private ExpressionList<?> exprs;
41+
private @Nullable Variable<?> list;
4042
private boolean useProperties;
4143

4244
@Override
4345
public boolean init(Expression<?>[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
44-
// size[s] of x -> property
45-
// sizes of x, y -> property
46-
// size of x, y -> list length
46+
// number[s] of x -> property
47+
// numbers of x, y -> property
48+
// number of x, y -> list length
4749
useProperties = parseResult.hasTag("s") || expressions[0].isSingle();
48-
if (useProperties) {
50+
if (useProperties)
4951
return super.init(expressions, matchedPattern, isDelayed, parseResult);
50-
} else {
51-
// if exprlist or varlist, count elements
52-
this.exprs = PropExprAmount.asExprList(expressions[0]);
53-
return LiteralUtils.canInitSafely(this.exprs);
54-
}
52+
53+
// if exprlist or varlist, count elements
54+
this.exprs = PropExprAmount.asExprList(expressions[0]);
55+
if (expressions[0] instanceof Variable<?> variable)
56+
this.list = variable;
57+
return LiteralUtils.canInitSafely(this.exprs);
5558
}
5659

5760
@Override
5861
protected Object @Nullable [] get(Event event) {
5962
if (useProperties)
6063
return super.get(event);
64+
65+
if (list != null)
66+
return new Long[]{(long) list.size(event)};
67+
6168
return new Long[]{(long) exprs.getArray(event).length};
6269
}
6370

src/main/java/org/skriptlang/skript/common/properties/expressions/PropExprSize.java

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import ch.njol.skript.lang.Expression;
77
import ch.njol.skript.lang.ExpressionList;
88
import ch.njol.skript.lang.SkriptParser.ParseResult;
9+
import ch.njol.skript.lang.Variable;
910
import ch.njol.skript.util.LiteralUtils;
1011
import ch.njol.util.Kleenean;
1112
import org.bukkit.event.Event;
@@ -37,6 +38,7 @@ public static void register(SyntaxRegistry registry, Origin origin) {
3738
}
3839

3940
private ExpressionList<?> exprs;
41+
private @Nullable Variable<?> list;
4042
private boolean useProperties;
4143

4244
@Override
@@ -45,19 +47,24 @@ public boolean init(Expression<?>[] expressions, int matchedPattern, Kleenean is
4547
// sizes of x, y -> property
4648
// size of x, y -> list length
4749
useProperties = parseResult.hasTag("s") || expressions[0].isSingle();
48-
if (useProperties) {
50+
if (useProperties)
4951
return super.init(expressions, matchedPattern, isDelayed, parseResult);
50-
} else {
51-
// if exprlist or varlist, count elements
52-
this.exprs = PropExprAmount.asExprList(expressions[0]);
53-
return LiteralUtils.canInitSafely(this.exprs);
54-
}
52+
53+
// if exprlist or varlist, count elements
54+
this.exprs = PropExprAmount.asExprList(expressions[0]);
55+
if (expressions[0] instanceof Variable<?> variable)
56+
this.list = variable;
57+
return LiteralUtils.canInitSafely(this.exprs);
5558
}
5659

5760
@Override
5861
protected Object @Nullable [] get(Event event) {
5962
if (useProperties)
6063
return super.get(event);
64+
65+
if (list != null)
66+
return new Long[]{(long) list.size(event)};
67+
6168
return new Long[]{(long) exprs.getArray(event).length};
6269
}
6370

0 commit comments

Comments
 (0)