From bd6d3ab7c01b97c0f1f5555894bffd33f966f904 Mon Sep 17 00:00:00 2001 From: Luck Date: Thu, 2 Jul 2020 12:28:30 +0100 Subject: [PATCH] Optimize PermissionHolder#hasNode --- .../common/model/PermissionHolder.java | 53 ++++---- .../luckperms/common/node/AbstractNode.java | 75 +----------- .../luckperms/common/node/NodeEquality.java | 114 ++++++++++++++++++ 3 files changed, 149 insertions(+), 93 deletions(-) create mode 100644 common/src/main/java/me/lucko/luckperms/common/node/NodeEquality.java diff --git a/common/src/main/java/me/lucko/luckperms/common/model/PermissionHolder.java b/common/src/main/java/me/lucko/luckperms/common/model/PermissionHolder.java index 4370d4f36..4ffb085e7 100644 --- a/common/src/main/java/me/lucko/luckperms/common/model/PermissionHolder.java +++ b/common/src/main/java/me/lucko/luckperms/common/model/PermissionHolder.java @@ -33,6 +33,7 @@ import me.lucko.luckperms.common.cacheddata.HolderCachedDataManager; import me.lucko.luckperms.common.cacheddata.type.MetaAccumulator; import me.lucko.luckperms.common.inheritance.InheritanceComparator; import me.lucko.luckperms.common.inheritance.InheritanceGraph; +import me.lucko.luckperms.common.node.NodeEquality; import me.lucko.luckperms.common.node.comparator.NodeWithContextComparator; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.query.DataSelector; @@ -458,10 +459,20 @@ public abstract class PermissionHolder { return Tristate.TRUE; } - return getData(type).asList().stream() - .filter(equalityPredicate.equalTo(node)) - .findFirst() - .map(n -> Tristate.of(n.getValue())).orElse(Tristate.UNDEFINED); + Collection nodes; + if (NodeEquality.comparesContexts(equalityPredicate)) { + nodes = getData(type).nodesInContext(node.getContexts()); + } else { + nodes = getData(type).asList(); + } + + for (Node other : nodes) { + if (equalityPredicate.areEqual(node, other)) { + return Tristate.of(node.getValue()); + } + } + + return Tristate.UNDEFINED; } public DataMutateResult setNode(DataType dataType, Node node, boolean callEvent) { @@ -471,11 +482,10 @@ public abstract class PermissionHolder { NodeMap data = getData(dataType); - ImmutableSet before = getData(dataType).asImmutableSet(); - + ImmutableSet before = data.asImmutableSet(); data.add(node); + ImmutableSet after = data.asImmutableSet(); - ImmutableSet after = getData(dataType).asImmutableSet(); if (callEvent) { this.plugin.getEventDispatcher().dispatchNodeAdd(node, this, dataType, before, after); } @@ -487,7 +497,7 @@ public abstract class PermissionHolder { public DataMutateResult.WithMergedNode setNode(DataType dataType, Node node, TemporaryNodeMergeStrategy mergeStrategy) { if (node.getExpiry() != null && mergeStrategy != TemporaryNodeMergeStrategy.NONE) { - Node otherMatch = getData(dataType).asList().stream() + Node otherMatch = getData(dataType).nodesInContext(node.getContexts()).stream() .filter(NodeEqualityPredicate.IGNORE_EXPIRY_TIME_AND_VALUE.equalTo(node)) .findFirst().orElse(null); @@ -513,11 +523,10 @@ public abstract class PermissionHolder { if (newNode != null) { // Remove the old Node & add the new one. - ImmutableSet before = getData(dataType).asImmutableSet(); - + ImmutableSet before = data.asImmutableSet(); data.replace(newNode, otherMatch); + ImmutableSet after = data.asImmutableSet(); - ImmutableSet after = getData(dataType).asImmutableSet(); this.plugin.getEventDispatcher().dispatchNodeAdd(newNode, this, dataType, before, after); invalidateCache(); @@ -536,11 +545,12 @@ public abstract class PermissionHolder { return DataMutateResult.FAIL_LACKS; } - ImmutableSet before = getData(dataType).asImmutableSet(); + NodeMap data = getData(dataType); - getData(dataType).remove(node); + ImmutableSet before = data.asImmutableSet(); + data.remove(node); + ImmutableSet after = data.asImmutableSet(); - ImmutableSet after = getData(dataType).asImmutableSet(); this.plugin.getEventDispatcher().dispatchNodeRemove(node, this, dataType, before, after); invalidateCache(); @@ -550,7 +560,7 @@ public abstract class PermissionHolder { public DataMutateResult.WithMergedNode unsetNode(DataType dataType, Node node, @Nullable Duration duration) { if (node.getExpiry() != null && duration != null) { - Node otherMatch = getData(dataType).asList().stream() + Node otherMatch = getData(dataType).nodesInContext(node.getContexts()).stream() .filter(NodeEqualityPredicate.IGNORE_EXPIRY_TIME_AND_VALUE.equalTo(node)) .findFirst().orElse(null); @@ -563,11 +573,10 @@ public abstract class PermissionHolder { Node newNode = node.toBuilder().expiry(newExpiry).build(); // Remove the old Node & add the new one. - ImmutableSet before = getData(dataType).asImmutableSet(); - + ImmutableSet before = data.asImmutableSet(); data.replace(newNode, otherMatch); + ImmutableSet after = data.asImmutableSet(); - ImmutableSet after = getData(dataType).asImmutableSet(); this.plugin.getEventDispatcher().dispatchNodeRemove(otherMatch, this, dataType, before, after); this.plugin.getEventDispatcher().dispatchNodeAdd(newNode, this, dataType, before, after); @@ -584,7 +593,7 @@ public abstract class PermissionHolder { public boolean removeIf(DataType dataType, @Nullable ContextSet contextSet, Predicate predicate, boolean giveDefault) { NodeMap data = getData(dataType); - ImmutableSet before = getData(dataType).asImmutableSet(); + ImmutableSet before = data.asImmutableSet(); if (contextSet == null) { if (!data.removeIf(predicate)) { @@ -600,7 +609,7 @@ public abstract class PermissionHolder { getPlugin().getUserManager().giveDefaultIfNeeded((User) this, false); } - ImmutableSet after = getData(dataType).asImmutableSet(); + ImmutableSet after = data.asImmutableSet(); this.plugin.getEventDispatcher().dispatchNodeClear(this, dataType, before, after); invalidateCache(); @@ -610,7 +619,7 @@ public abstract class PermissionHolder { public boolean clearNodes(DataType dataType, ContextSet contextSet, boolean giveDefault) { NodeMap data = getData(dataType); - ImmutableSet before = getData(dataType).asImmutableSet(); + ImmutableSet before = data.asImmutableSet(); if (contextSet == null) { data.clear(); @@ -622,7 +631,7 @@ public abstract class PermissionHolder { getPlugin().getUserManager().giveDefaultIfNeeded((User) this, false); } - ImmutableSet after = getData(dataType).asImmutableSet(); + ImmutableSet after = data.asImmutableSet(); this.plugin.getEventDispatcher().dispatchNodeClear(this, dataType, before, after); invalidateCache(); diff --git a/common/src/main/java/me/lucko/luckperms/common/node/AbstractNode.java b/common/src/main/java/me/lucko/luckperms/common/node/AbstractNode.java index 76aa5c494..3adc57af4 100644 --- a/common/src/main/java/me/lucko/luckperms/common/node/AbstractNode.java +++ b/common/src/main/java/me/lucko/luckperms/common/node/AbstractNode.java @@ -139,24 +139,15 @@ public abstract class AbstractNode, B extends NodeBui public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof Node)) return false; - return Equality.KEY_VALUE_EXPIRY_CONTEXTS.equals(this, ((AbstractNode) o)); + return NodeEquality.KEY_VALUE_EXPIRY_CONTEXTS.equals(this, ((AbstractNode) o)); } @Override public boolean equals(@NonNull Node o, @NonNull NodeEqualityPredicate equalityPredicate) { AbstractNode other = (AbstractNode) o; - if (equalityPredicate == NodeEqualityPredicate.EXACT) { - return Equality.KEY_VALUE_EXPIRY_CONTEXTS.equals(this, other); - } else if (equalityPredicate == NodeEqualityPredicate.IGNORE_VALUE) { - return Equality.KEY_EXPIRY_CONTEXTS.equals(this, other); - } else if (equalityPredicate == NodeEqualityPredicate.IGNORE_EXPIRY_TIME) { - return Equality.KEY_VALUE_HASEXPIRY_CONTEXTS.equals(this, other); - } else if (equalityPredicate == NodeEqualityPredicate.IGNORE_EXPIRY_TIME_AND_VALUE) { - return Equality.KEY_HASEXPIRY_CONTEXTS.equals(this, other); - } else if (equalityPredicate == NodeEqualityPredicate.IGNORE_VALUE_OR_IF_TEMPORARY) { - return Equality.KEY_CONTEXTS.equals(this, other); - } else if (equalityPredicate == NodeEqualityPredicate.ONLY_KEY) { - return Equality.KEY.equals(this, other); + NodeEquality nodeEquality = NodeEquality.of(equalityPredicate); + if (nodeEquality != null) { + return nodeEquality.equals(this, other); } else { return equalityPredicate.areEqual(this, o); } @@ -177,64 +168,6 @@ public abstract class AbstractNode, B extends NodeBui return result; } - private enum Equality { - KEY_VALUE_EXPIRY_CONTEXTS { - @Override - public boolean equals(AbstractNode o1, AbstractNode o2) { - return o1 == o2 || - o1.key.equals(o2.key) && - o1.value == o2.value && - o1.expireAt == o2.expireAt && - o1.getContexts().equals(o2.getContexts()); - } - }, - KEY_EXPIRY_CONTEXTS { - @Override - public boolean equals(AbstractNode o1, AbstractNode o2) { - return o1 == o2 || - o1.key.equals(o2.key) && - o1.expireAt == o2.expireAt && - o1.getContexts().equals(o2.getContexts()); - } - }, - KEY_VALUE_HASEXPIRY_CONTEXTS { - @Override - public boolean equals(AbstractNode o1, AbstractNode o2) { - return o1 == o2 || - o1.key.equals(o2.key) && - o1.value == o2.value && - o1.hasExpiry() == o2.hasExpiry() && - o1.getContexts().equals(o2.getContexts()); - } - }, - KEY_HASEXPIRY_CONTEXTS { - @Override - public boolean equals(AbstractNode o1, AbstractNode o2) { - return o1 == o2 || - o1.key.equals(o2.key) && - o1.hasExpiry() == o2.hasExpiry() && - o1.getContexts().equals(o2.getContexts()); - } - }, - KEY_CONTEXTS { - @Override - public boolean equals(AbstractNode o1, AbstractNode o2) { - return o1 == o2 || - o1.key.equals(o2.key) && - o1.getContexts().equals(o2.getContexts()); - } - }, - KEY { - @Override - public boolean equals(AbstractNode o1, AbstractNode o2) { - return o1 == o2 || - o1.key.equals(o2.key); - } - }; - - public abstract boolean equals(AbstractNode o1, AbstractNode o2); - } - @Override public String toString() { return "ImmutableNode(" + diff --git a/common/src/main/java/me/lucko/luckperms/common/node/NodeEquality.java b/common/src/main/java/me/lucko/luckperms/common/node/NodeEquality.java new file mode 100644 index 000000000..8148881b8 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/node/NodeEquality.java @@ -0,0 +1,114 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.common.node; + +import net.luckperms.api.node.NodeEqualityPredicate; + +public enum NodeEquality { + KEY_VALUE_EXPIRY_CONTEXTS { + @Override + public boolean equals(AbstractNode o1, AbstractNode o2) { + return o1 == o2 || + o1.key.equals(o2.key) && + o1.value == o2.value && + o1.expireAt == o2.expireAt && + o1.getContexts().equals(o2.getContexts()); + } + }, + KEY_EXPIRY_CONTEXTS { + @Override + public boolean equals(AbstractNode o1, AbstractNode o2) { + return o1 == o2 || + o1.key.equals(o2.key) && + o1.expireAt == o2.expireAt && + o1.getContexts().equals(o2.getContexts()); + } + }, + KEY_VALUE_HASEXPIRY_CONTEXTS { + @Override + public boolean equals(AbstractNode o1, AbstractNode o2) { + return o1 == o2 || + o1.key.equals(o2.key) && + o1.value == o2.value && + o1.hasExpiry() == o2.hasExpiry() && + o1.getContexts().equals(o2.getContexts()); + } + }, + KEY_HASEXPIRY_CONTEXTS { + @Override + public boolean equals(AbstractNode o1, AbstractNode o2) { + return o1 == o2 || + o1.key.equals(o2.key) && + o1.hasExpiry() == o2.hasExpiry() && + o1.getContexts().equals(o2.getContexts()); + } + }, + KEY_CONTEXTS { + @Override + public boolean equals(AbstractNode o1, AbstractNode o2) { + return o1 == o2 || + o1.key.equals(o2.key) && + o1.getContexts().equals(o2.getContexts()); + } + }, + KEY { + @Override + public boolean equals(AbstractNode o1, AbstractNode o2) { + return o1 == o2 || + o1.key.equals(o2.key); + } + }; + + public abstract boolean equals(AbstractNode o1, AbstractNode o2); + + public boolean comparesContexts() { + return this != KEY; + } + + public static NodeEquality of(NodeEqualityPredicate equalityPredicate) { + if (equalityPredicate == NodeEqualityPredicate.EXACT) { + return NodeEquality.KEY_VALUE_EXPIRY_CONTEXTS; + } else if (equalityPredicate == NodeEqualityPredicate.IGNORE_VALUE) { + return NodeEquality.KEY_EXPIRY_CONTEXTS; + } else if (equalityPredicate == NodeEqualityPredicate.IGNORE_EXPIRY_TIME) { + return NodeEquality.KEY_VALUE_HASEXPIRY_CONTEXTS; + } else if (equalityPredicate == NodeEqualityPredicate.IGNORE_EXPIRY_TIME_AND_VALUE) { + return NodeEquality.KEY_HASEXPIRY_CONTEXTS; + } else if (equalityPredicate == NodeEqualityPredicate.IGNORE_VALUE_OR_IF_TEMPORARY) { + return NodeEquality.KEY_CONTEXTS; + } else if (equalityPredicate == NodeEqualityPredicate.ONLY_KEY) { + return NodeEquality.KEY; + } else { + return null; + } + } + + public static boolean comparesContexts(NodeEqualityPredicate equalityPredicate) { + NodeEquality nodeEquality = of(equalityPredicate); + return nodeEquality != null && nodeEquality.comparesContexts(); + } + +}