Use static empty context set where appropriate, cache reversed comparator instances
This commit is contained in:
@@ -40,7 +40,7 @@ public class MetaComparator implements Comparator<Map.Entry<Integer, LocalizedNo
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
return NodeWithContextComparator.get().compare(o1.getValue(), o2.getValue());
|
||||
return NodeWithContextComparator.normal().compare(o1.getValue(), o2.getValue());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -35,13 +35,15 @@ import java.util.Map;
|
||||
|
||||
public class ContextSetComparator implements Comparator<ImmutableContextSet> {
|
||||
|
||||
private static final ContextSetComparator INSTANCE = new ContextSetComparator();
|
||||
public static Comparator<ImmutableContextSet> get() {
|
||||
private static final Comparator<ImmutableContextSet> INSTANCE = new ContextSetComparator();
|
||||
private static final Comparator<ImmutableContextSet> REVERSE = INSTANCE.reversed();
|
||||
|
||||
public static Comparator<ImmutableContextSet> normal() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public static Comparator<ImmutableContextSet> reverse() {
|
||||
return INSTANCE.reversed();
|
||||
return REVERSE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+5
-1
@@ -61,10 +61,14 @@ public class ContextSetConfigurateSerializer {
|
||||
return data;
|
||||
}
|
||||
|
||||
public static MutableContextSet deserializeContextSet(ConfigurationNode data) {
|
||||
public static ContextSet deserializeContextSet(ConfigurationNode data) {
|
||||
Preconditions.checkArgument(data.hasMapChildren());
|
||||
Map<Object, ? extends ConfigurationNode> dataMap = data.getChildrenMap();
|
||||
|
||||
if (dataMap.isEmpty()) {
|
||||
return ContextSet.empty();
|
||||
}
|
||||
|
||||
MutableContextSet map = MutableContextSet.create();
|
||||
for (Map.Entry<Object, ? extends ConfigurationNode> e : dataMap.entrySet()) {
|
||||
String k = e.getKey().toString();
|
||||
|
||||
+20
-1
@@ -28,6 +28,7 @@ package me.lucko.luckperms.common.contexts;
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
@@ -66,10 +67,28 @@ public class ContextSetJsonSerializer {
|
||||
return data;
|
||||
}
|
||||
|
||||
public static MutableContextSet deserializeContextSet(JsonElement element) {
|
||||
public static ContextSet deserializeContextSet(Gson gson, String json) {
|
||||
Preconditions.checkNotNull(json, "json");
|
||||
if (json.equals("{}")) {
|
||||
return ContextSet.empty();
|
||||
}
|
||||
|
||||
JsonObject context = gson.fromJson(json, JsonObject.class);
|
||||
if (context == null || context.size() == 0) {
|
||||
return ContextSet.empty();
|
||||
}
|
||||
|
||||
return deserializeContextSet(context);
|
||||
}
|
||||
|
||||
public static ContextSet deserializeContextSet(JsonElement element) {
|
||||
Preconditions.checkArgument(element.isJsonObject());
|
||||
JsonObject data = element.getAsJsonObject();
|
||||
|
||||
if (data.size() == 0) {
|
||||
return ContextSet.empty();
|
||||
}
|
||||
|
||||
MutableContextSet map = MutableContextSet.create();
|
||||
for (Map.Entry<String, JsonElement> e : data.entrySet()) {
|
||||
String k = e.getKey();
|
||||
|
||||
@@ -26,17 +26,21 @@
|
||||
package me.lucko.luckperms.common.node;
|
||||
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.common.utils.CollationKeyCache;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
public class NodeComparator implements Comparator<Node> {
|
||||
private static final NodeComparator INSTANCE = new NodeComparator();
|
||||
public static Comparator<Node> get() {
|
||||
|
||||
private static final Comparator<Node> INSTANCE = new NodeComparator();
|
||||
private static final Comparator<Node> REVERSE = INSTANCE.reversed();
|
||||
|
||||
public static Comparator<Node> normal() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public static Comparator<Node> reverse() {
|
||||
return INSTANCE.reversed();
|
||||
return REVERSE;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -61,7 +65,7 @@ public class NodeComparator implements Comparator<Node> {
|
||||
return o1.getWildcardLevel() > o2.getWildcardLevel() ? 1 : -1;
|
||||
}
|
||||
|
||||
return NodeWithContextComparator.get().compareStrings(o1.getPermission(), o2.getPermission()) == 1 ? -1 : 1;
|
||||
return CollationKeyCache.compareStrings(o1.getPermission(), o2.getPermission()) == 1 ? -1 : 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -74,13 +74,13 @@ public final class NodeModel {
|
||||
|
||||
public synchronized Node toNode() {
|
||||
if (node == null) {
|
||||
Node.Builder builder = NodeFactory.newBuilder(permission);
|
||||
builder.setValue(value);
|
||||
builder.setServer(server);
|
||||
builder.setWorld(world);
|
||||
builder.setExpiry(expiry);
|
||||
builder.withExtraContext(contexts);
|
||||
node = builder.build();
|
||||
node = NodeFactory.newBuilder(permission)
|
||||
.setValue(value)
|
||||
.setServer(server)
|
||||
.setWorld(world)
|
||||
.setExpiry(expiry)
|
||||
.withExtraContext(contexts)
|
||||
.build();
|
||||
}
|
||||
|
||||
return node;
|
||||
|
||||
@@ -28,16 +28,11 @@ package me.lucko.luckperms.common.node;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
|
||||
import me.lucko.luckperms.api.LocalizedNode;
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.common.utils.CollationKeyCache;
|
||||
|
||||
import java.text.CollationKey;
|
||||
import java.text.Collator;
|
||||
import java.util.Comparator;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Compares permission nodes based upon their supposed "priority".
|
||||
@@ -45,16 +40,16 @@ import java.util.Locale;
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class NodeWithContextComparator implements Comparator<LocalizedNode> {
|
||||
|
||||
private static final NodeWithContextComparator INSTANCE = new NodeWithContextComparator();
|
||||
public static NodeWithContextComparator get() {
|
||||
private static final Comparator<LocalizedNode> INSTANCE = new NodeWithContextComparator();
|
||||
private static final Comparator<LocalizedNode> REVERSE = INSTANCE.reversed();
|
||||
|
||||
public static Comparator<LocalizedNode> normal() {
|
||||
return INSTANCE;
|
||||
}
|
||||
public static Comparator<LocalizedNode> reverse() {
|
||||
return INSTANCE.reversed();
|
||||
}
|
||||
|
||||
private final Collator collator = Collator.getInstance(Locale.ENGLISH);
|
||||
private final LoadingCache<String, CollationKey> collationKeyCache = Caffeine.newBuilder().build(collator::getCollationKey);
|
||||
public static Comparator<LocalizedNode> reverse() {
|
||||
return REVERSE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(LocalizedNode one, LocalizedNode two) {
|
||||
@@ -97,27 +92,8 @@ public class NodeWithContextComparator implements Comparator<LocalizedNode> {
|
||||
return o1.getWildcardLevel() > o2.getWildcardLevel() ? 1 : -1;
|
||||
}
|
||||
|
||||
return compareStrings(o1.getPermission(), o2.getPermission()) == 1 ? -1 : 1;
|
||||
return CollationKeyCache.compareStrings(o1.getPermission(), o2.getPermission()) == 1 ? -1 : 1;
|
||||
}
|
||||
|
||||
public int compareStrings(String o1, String o2) {
|
||||
if (o1.equals(o2)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
try {
|
||||
CollationKey o1c = collationKeyCache.get(o1);
|
||||
CollationKey o2c = collationKeyCache.get(o2);
|
||||
int i = o1c.compareTo(o2c);
|
||||
if (i != 0) {
|
||||
return i;
|
||||
}
|
||||
|
||||
// fallback to standard string comparison
|
||||
return o1.compareTo(o2);
|
||||
} catch (Exception e) {
|
||||
// ignored
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ import lombok.Getter;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import me.lucko.luckperms.api.HeldPermission;
|
||||
@@ -1129,7 +1128,6 @@ public class SqlDao extends AbstractDao {
|
||||
}
|
||||
|
||||
private NodeModel deserializeNode(String permission, boolean value, String server, String world, long expiry, String contexts) {
|
||||
JsonObject context = gson.fromJson(contexts, JsonObject.class);
|
||||
return NodeModel.of(permission, value, server, world, expiry, ContextSetJsonSerializer.deserializeContextSet(context).makeImmutable());
|
||||
return NodeModel.of(permission, value, server, world, expiry, ContextSetJsonSerializer.deserializeContextSet(gson, contexts).makeImmutable());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* 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.utils;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
|
||||
import java.text.CollationKey;
|
||||
import java.text.Collator;
|
||||
import java.util.Comparator;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public final class CollationKeyCache implements Comparator<String> {
|
||||
private static final CollationKeyCache INSTANCE = new CollationKeyCache();
|
||||
|
||||
private static final Collator COLLATOR = Collator.getInstance(Locale.ENGLISH);
|
||||
|
||||
static {
|
||||
COLLATOR.setStrength(Collator.IDENTICAL);
|
||||
COLLATOR.setDecomposition(Collator.FULL_DECOMPOSITION);
|
||||
}
|
||||
|
||||
private static final LoadingCache<String, CollationKey> CACHE = Caffeine.newBuilder()
|
||||
.maximumSize(1000)
|
||||
.expireAfterAccess(5, TimeUnit.MINUTES)
|
||||
.build(COLLATOR::getCollationKey);
|
||||
|
||||
public static Comparator<String> comparator() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private CollationKeyCache() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(String o1, String o2) {
|
||||
return compareStrings(o1, o2);
|
||||
}
|
||||
|
||||
public static int compareStrings(String o1, String o2) {
|
||||
//noinspection StringEquality
|
||||
if (o1 == o2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
try {
|
||||
CollationKey o1c = CACHE.get(o1);
|
||||
CollationKey o2c = CACHE.get(o2);
|
||||
|
||||
if (o1c != null && o2c != null) {
|
||||
int i = o1c.compareTo(o2c);
|
||||
if (i != 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// fallback to standard string comparison
|
||||
return o1.compareTo(o2);
|
||||
} catch (Exception e) {
|
||||
// ignored
|
||||
}
|
||||
|
||||
// shrug
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user