Update to Java 8 and Minecraft 1.8.8
This commit is contained in:
		@@ -1,5 +1,5 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2011-2018 lishid. All rights reserved.
 | 
			
		||||
 * Copyright (C) 2011-2019 lishid. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
@@ -21,6 +21,11 @@ import com.lishid.openinv.internal.IInventoryAccess;
 | 
			
		||||
import com.lishid.openinv.internal.ISpecialEnderChest;
 | 
			
		||||
import com.lishid.openinv.internal.ISpecialInventory;
 | 
			
		||||
import com.lishid.openinv.internal.ISpecialPlayerInventory;
 | 
			
		||||
import com.lishid.openinv.util.InventoryAccess;
 | 
			
		||||
import com.lishid.openinv.util.StringMetric;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
import java.util.logging.Logger;
 | 
			
		||||
import org.bukkit.Bukkit;
 | 
			
		||||
import org.bukkit.OfflinePlayer;
 | 
			
		||||
import org.bukkit.entity.Player;
 | 
			
		||||
import org.bukkit.inventory.InventoryView;
 | 
			
		||||
@@ -59,7 +64,10 @@ public interface IOpenInv {
 | 
			
		||||
     * @return the IInventoryAccess
 | 
			
		||||
     * @throws IllegalStateException if the server version is unsupported
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull IInventoryAccess getInventoryAccess();
 | 
			
		||||
    @Deprecated
 | 
			
		||||
    default @NotNull IInventoryAccess getInventoryAccess() {
 | 
			
		||||
        return new InventoryAccess();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the provided player's AnyChest setting.
 | 
			
		||||
@@ -78,7 +86,9 @@ public interface IOpenInv {
 | 
			
		||||
     * @return the identifier
 | 
			
		||||
     * @throws IllegalStateException if the server version is unsupported
 | 
			
		||||
     */
 | 
			
		||||
    @NotNull String getPlayerID(@NotNull OfflinePlayer offline);
 | 
			
		||||
    default @NotNull String getPlayerID(@NotNull OfflinePlayer offline) {
 | 
			
		||||
        return offline.getUniqueId().toString();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a player's SilentChest setting.
 | 
			
		||||
@@ -137,7 +147,76 @@ public interface IOpenInv {
 | 
			
		||||
     * @param name the name of the Player
 | 
			
		||||
     * @return the OfflinePlayer with the closest matching name or null if no players have ever logged in
 | 
			
		||||
     */
 | 
			
		||||
    @Nullable OfflinePlayer matchPlayer(@NotNull String name);
 | 
			
		||||
    default @Nullable OfflinePlayer matchPlayer(@NotNull String name) {
 | 
			
		||||
 | 
			
		||||
        // Warn if called on the main thread - if we resort to searching offline players, this may take several seconds.
 | 
			
		||||
        if (Bukkit.getServer().isPrimaryThread()) {
 | 
			
		||||
            this.getLogger().warning("Call to OpenInv#matchPlayer made on the main thread!");
 | 
			
		||||
            this.getLogger().warning("This can cause the server to hang, potentially severely.");
 | 
			
		||||
            this.getLogger().warning("Trace:");
 | 
			
		||||
            for (StackTraceElement element : new Throwable().fillInStackTrace().getStackTrace()) {
 | 
			
		||||
                this.getLogger().warning(element.toString());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        OfflinePlayer player;
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            UUID uuid = UUID.fromString(name);
 | 
			
		||||
            player = Bukkit.getOfflinePlayer(uuid);
 | 
			
		||||
            // Ensure player is a real player, otherwise return null
 | 
			
		||||
            if (player.hasPlayedBefore() || player.isOnline()) {
 | 
			
		||||
                return player;
 | 
			
		||||
            }
 | 
			
		||||
        } catch (IllegalArgumentException ignored) {
 | 
			
		||||
            // Not a UUID
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Ensure name is valid if server is in online mode to avoid unnecessary searching
 | 
			
		||||
        if (Bukkit.getServer().getOnlineMode() && !name.matches("[a-zA-Z0-9_]{3,16}")) {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        player = Bukkit.getServer().getPlayerExact(name);
 | 
			
		||||
 | 
			
		||||
        if (player != null) {
 | 
			
		||||
            return player;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        player = Bukkit.getServer().getOfflinePlayer(name);
 | 
			
		||||
 | 
			
		||||
        if (player.hasPlayedBefore()) {
 | 
			
		||||
            return player;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        player = Bukkit.getServer().getPlayer(name);
 | 
			
		||||
 | 
			
		||||
        if (player != null) {
 | 
			
		||||
            return player;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        float bestMatch = 0;
 | 
			
		||||
        for (OfflinePlayer offline : Bukkit.getServer().getOfflinePlayers()) {
 | 
			
		||||
            if (offline.getName() == null) {
 | 
			
		||||
                // Loaded by UUID only, name has never been looked up.
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            float currentMatch = StringMetric.compareJaroWinkler(name, offline.getName());
 | 
			
		||||
 | 
			
		||||
            if (currentMatch == 1.0F) {
 | 
			
		||||
                return offline;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (currentMatch > bestMatch) {
 | 
			
		||||
                bestMatch = currentMatch;
 | 
			
		||||
                player = offline;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Only null if no players have played ever, otherwise even the worst match will do.
 | 
			
		||||
        return player;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Open an ISpecialInventory for a Player.
 | 
			
		||||
@@ -225,4 +304,6 @@ public interface IOpenInv {
 | 
			
		||||
     */
 | 
			
		||||
    void unload(@NotNull OfflinePlayer offline);
 | 
			
		||||
 | 
			
		||||
    Logger getLogger();
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -20,6 +20,7 @@ import org.bukkit.inventory.Inventory;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
import org.jetbrains.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
@Deprecated
 | 
			
		||||
public interface IInventoryAccess {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -29,6 +30,7 @@ public interface IInventoryAccess {
 | 
			
		||||
     * @param inventory the Inventory
 | 
			
		||||
     * @return the ISpecialEnderChest or null
 | 
			
		||||
     */
 | 
			
		||||
    @Deprecated
 | 
			
		||||
    @Nullable ISpecialEnderChest getSpecialEnderChest(@NotNull Inventory inventory);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -38,6 +40,7 @@ public interface IInventoryAccess {
 | 
			
		||||
     * @param inventory the Inventory
 | 
			
		||||
     * @return the ISpecialPlayerInventory or null
 | 
			
		||||
     */
 | 
			
		||||
    @Deprecated
 | 
			
		||||
    @Nullable ISpecialPlayerInventory getSpecialPlayerInventory(@NotNull Inventory inventory);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -46,6 +49,7 @@ public interface IInventoryAccess {
 | 
			
		||||
     * @param inventory the Inventory
 | 
			
		||||
     * @return true if the Inventory is backed by an ISpecialEnderChest
 | 
			
		||||
     */
 | 
			
		||||
    @Deprecated
 | 
			
		||||
    boolean isSpecialEnderChest(@NotNull Inventory inventory);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -54,6 +58,7 @@ public interface IInventoryAccess {
 | 
			
		||||
     * @param inventory the Inventory
 | 
			
		||||
     * @return true if the Inventory is backed by an ISpecialPlayerInventory
 | 
			
		||||
     */
 | 
			
		||||
    @Deprecated
 | 
			
		||||
    boolean isSpecialPlayerInventory(@NotNull Inventory inventory);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										145
									
								
								api/src/main/java/com/lishid/openinv/util/InventoryAccess.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								api/src/main/java/com/lishid/openinv/util/InventoryAccess.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,145 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2011-2019 lishid. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, version 3.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package com.lishid.openinv.util;
 | 
			
		||||
 | 
			
		||||
import com.lishid.openinv.internal.IInventoryAccess;
 | 
			
		||||
import com.lishid.openinv.internal.ISpecialEnderChest;
 | 
			
		||||
import com.lishid.openinv.internal.ISpecialPlayerInventory;
 | 
			
		||||
import java.lang.reflect.Field;
 | 
			
		||||
import java.lang.reflect.Method;
 | 
			
		||||
import org.bukkit.Bukkit;
 | 
			
		||||
import org.bukkit.inventory.Inventory;
 | 
			
		||||
import org.jetbrains.annotations.NotNull;
 | 
			
		||||
import org.jetbrains.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
public class InventoryAccess implements IInventoryAccess {
 | 
			
		||||
 | 
			
		||||
    private static Class<?> craftInventory = null;
 | 
			
		||||
    private static Method getInventory = null;
 | 
			
		||||
 | 
			
		||||
    static {
 | 
			
		||||
        String packageName = Bukkit.getServer().getClass().getPackage().getName();
 | 
			
		||||
        String version = packageName.substring(packageName.lastIndexOf('.') + 1);
 | 
			
		||||
        try {
 | 
			
		||||
            craftInventory = Class.forName("org.bukkit.craftbukkit." + version + ".inventory.CraftInventory");
 | 
			
		||||
        } catch (ClassNotFoundException ignored) {}
 | 
			
		||||
        try {
 | 
			
		||||
            getInventory = craftInventory.getDeclaredMethod("getInventory");
 | 
			
		||||
        } catch (NoSuchMethodException ignored) {}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static boolean isUseable() {
 | 
			
		||||
        return craftInventory != null && getInventory != null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static boolean isPlayerInventory(@NotNull Inventory inventory) {
 | 
			
		||||
        if (craftInventory.isAssignableFrom(inventory.getClass())) {
 | 
			
		||||
            try {
 | 
			
		||||
                return getInventory.invoke(inventory) instanceof ISpecialPlayerInventory;
 | 
			
		||||
            } catch (ReflectiveOperationException ignored) {}
 | 
			
		||||
        }
 | 
			
		||||
        return grabFieldOfTypeFromObject(ISpecialPlayerInventory.class, inventory) != null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static ISpecialPlayerInventory getPlayerInventory(@NotNull Inventory inventory) {
 | 
			
		||||
        Object inv = null;
 | 
			
		||||
        if (craftInventory.isAssignableFrom(inventory.getClass())) {
 | 
			
		||||
            try {
 | 
			
		||||
                inv = getInventory.invoke(inventory);
 | 
			
		||||
            } catch (ReflectiveOperationException ignored) {}
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (inv == null) {
 | 
			
		||||
            inv = grabFieldOfTypeFromObject(ISpecialPlayerInventory.class, inventory);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (inv instanceof ISpecialPlayerInventory) {
 | 
			
		||||
            return (ISpecialPlayerInventory) inv;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static boolean isEnderChest(@NotNull Inventory inventory) {
 | 
			
		||||
        if (craftInventory.isAssignableFrom(inventory.getClass())) {
 | 
			
		||||
            try {
 | 
			
		||||
                return getInventory.invoke(inventory) instanceof ISpecialEnderChest;
 | 
			
		||||
            } catch (ReflectiveOperationException ignored) {}
 | 
			
		||||
        }
 | 
			
		||||
        return grabFieldOfTypeFromObject(ISpecialEnderChest.class, inventory) != null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static ISpecialEnderChest getEnderChest(@NotNull Inventory inventory) {
 | 
			
		||||
        Object inv = null;
 | 
			
		||||
        if (craftInventory.isAssignableFrom(inventory.getClass())) {
 | 
			
		||||
            try {
 | 
			
		||||
                inv = getInventory.invoke(inventory);
 | 
			
		||||
            } catch (ReflectiveOperationException ignored) {}
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (inv == null) {
 | 
			
		||||
            inv = grabFieldOfTypeFromObject(ISpecialEnderChest.class, inventory);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (inv instanceof ISpecialEnderChest) {
 | 
			
		||||
            return (ISpecialEnderChest) inv;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static <T> T grabFieldOfTypeFromObject(final Class<T> type, final Object object) {
 | 
			
		||||
        // Use reflection to find the IInventory
 | 
			
		||||
        Class<?> clazz = object.getClass();
 | 
			
		||||
        T result = null;
 | 
			
		||||
        for (Field f : clazz.getDeclaredFields()) {
 | 
			
		||||
            f.setAccessible(true);
 | 
			
		||||
            if (type.isAssignableFrom(f.getDeclaringClass())) {
 | 
			
		||||
                try {
 | 
			
		||||
                    result = type.cast(f.get(object));
 | 
			
		||||
                } catch (Exception e) {
 | 
			
		||||
                    e.printStackTrace();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Deprecated
 | 
			
		||||
    @Override
 | 
			
		||||
    public @Nullable ISpecialEnderChest getSpecialEnderChest(@NotNull Inventory inventory) {
 | 
			
		||||
        return getEnderChest(inventory);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Deprecated
 | 
			
		||||
    @Override
 | 
			
		||||
    public @Nullable ISpecialPlayerInventory getSpecialPlayerInventory(@NotNull Inventory inventory) {
 | 
			
		||||
        return getPlayerInventory(inventory);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Deprecated
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean isSpecialEnderChest(@NotNull Inventory inventory) {
 | 
			
		||||
        return isEnderChest(inventory);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Deprecated
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean isSpecialPlayerInventory(@NotNull Inventory inventory) {
 | 
			
		||||
        return isPlayerInventory(inventory);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										165
									
								
								api/src/main/java/com/lishid/openinv/util/StringMetric.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								api/src/main/java/com/lishid/openinv/util/StringMetric.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,165 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2011-2019 lishid. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, version 3.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * *
 | 
			
		||||
 * Copyright (C) 2014 - 2018 Simmetrics Authors
 | 
			
		||||
 * Copyright (C) 2010 The Guava Authors
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *      http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package com.lishid.openinv.util;
 | 
			
		||||
 | 
			
		||||
public class StringMetric {
 | 
			
		||||
 | 
			
		||||
    public static float compareJaroWinkler(String a, String b) {
 | 
			
		||||
        final float jaroScore = compareJaro(a, b);
 | 
			
		||||
 | 
			
		||||
        if (jaroScore < (float) 0.1) {
 | 
			
		||||
            return jaroScore;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        String prefix = commonPrefix(a, b);
 | 
			
		||||
        int prefixLength = Math.min(prefix.codePointCount(0, prefix.length()), 4);
 | 
			
		||||
 | 
			
		||||
        return jaroScore + (prefixLength * (float) 0.7 * (1.0f - jaroScore));
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static float compareJaro(String a, String b) {
 | 
			
		||||
        if (a.isEmpty() && b.isEmpty()) {
 | 
			
		||||
            return 1.0f;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (a.isEmpty() || b.isEmpty()) {
 | 
			
		||||
            return 0.0f;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        final int[] charsA = a.codePoints().toArray();
 | 
			
		||||
        final int[] charsB = b.codePoints().toArray();
 | 
			
		||||
 | 
			
		||||
        // Intentional integer division to round down.
 | 
			
		||||
        final int halfLength = Math.max(0, Math.max(charsA.length, charsB.length) / 2 - 1);
 | 
			
		||||
 | 
			
		||||
        final int[] commonA = getCommonCodePoints(charsA, charsB, halfLength);
 | 
			
		||||
        final int[] commonB = getCommonCodePoints(charsB, charsA, halfLength);
 | 
			
		||||
 | 
			
		||||
        // commonA and commonB will always contain the same multi-set of
 | 
			
		||||
        // characters. Because getCommonCharacters has been optimized, commonA
 | 
			
		||||
        // and commonB are -1-padded. So in this loop we count transposition
 | 
			
		||||
        // and use commonCharacters to determine the length of the multi-set.
 | 
			
		||||
        float transpositions = 0;
 | 
			
		||||
        int commonCharacters = 0;
 | 
			
		||||
        for (int length = commonA.length; commonCharacters < length
 | 
			
		||||
                && commonA[commonCharacters] > -1; commonCharacters++) {
 | 
			
		||||
            if (commonA[commonCharacters] != commonB[commonCharacters]) {
 | 
			
		||||
                transpositions++;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (commonCharacters == 0) {
 | 
			
		||||
            return 0.0f;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        float aCommonRatio = commonCharacters / (float) charsA.length;
 | 
			
		||||
        float bCommonRatio = commonCharacters / (float) charsB.length;
 | 
			
		||||
        float transpositionRatio = (commonCharacters - transpositions / 2.0f) / commonCharacters;
 | 
			
		||||
 | 
			
		||||
        return (aCommonRatio + bCommonRatio + transpositionRatio) / 3.0f;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Returns an array of code points from a within b. A character in b is
 | 
			
		||||
     * counted as common when it is within separation distance from the position
 | 
			
		||||
     * in a.
 | 
			
		||||
     */
 | 
			
		||||
    private static int[] getCommonCodePoints(final int[] charsA, final int[] charsB, final int separation) {
 | 
			
		||||
        final int[] common = new int[Math.min(charsA.length, charsB.length)];
 | 
			
		||||
        final boolean[] matched = new boolean[charsB.length];
 | 
			
		||||
 | 
			
		||||
        // Iterate of string a and find all characters that occur in b within
 | 
			
		||||
        // the separation distance. Mark any matches found to avoid
 | 
			
		||||
        // duplicate matchings.
 | 
			
		||||
        int commonIndex = 0;
 | 
			
		||||
        for (int i = 0, length = charsA.length; i < length; i++) {
 | 
			
		||||
            final int character = charsA[i];
 | 
			
		||||
            final int index = indexOf(character, charsB, i - separation, i
 | 
			
		||||
                    + separation + 1, matched);
 | 
			
		||||
            if (index > -1) {
 | 
			
		||||
                common[commonIndex++] = character;
 | 
			
		||||
                matched[index] = true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (commonIndex < common.length) {
 | 
			
		||||
            common[commonIndex] = -1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Both invocations will yield the same multi-set terminated by -1, so
 | 
			
		||||
        // they can be compared for transposition without making a copy.
 | 
			
		||||
        return common;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Search for code point in buffer starting at fromIndex to toIndex - 1.
 | 
			
		||||
     *
 | 
			
		||||
     * Returns -1 when not found.
 | 
			
		||||
     */
 | 
			
		||||
    private static int indexOf(int character, int[] buffer, int fromIndex, int toIndex, boolean[] matched) {
 | 
			
		||||
 | 
			
		||||
        // compare char with range of characters to either side
 | 
			
		||||
        for (int j = Math.max(0, fromIndex), length = Math.min(toIndex, buffer.length); j < length; j++) {
 | 
			
		||||
            // check if found
 | 
			
		||||
            if (buffer[j] == character && !matched[j]) {
 | 
			
		||||
                return j;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static String commonPrefix(CharSequence a, CharSequence b) {
 | 
			
		||||
        int maxPrefixLength = Math.min(a.length(), b.length());
 | 
			
		||||
 | 
			
		||||
        int p;
 | 
			
		||||
 | 
			
		||||
        p = 0;
 | 
			
		||||
        while (p < maxPrefixLength && a.charAt(p) == b.charAt(p)) {
 | 
			
		||||
            ++p;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (validSurrogatePairAt(a, p - 1) || validSurrogatePairAt(b, p - 1)) {
 | 
			
		||||
            --p;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return a.subSequence(0, p).toString();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static boolean validSurrogatePairAt(CharSequence string, int index) {
 | 
			
		||||
        return index >= 0 && index <= string.length() - 2 && Character.isHighSurrogate(string.charAt(index)) && Character.isLowSurrogate(string.charAt(index + 1));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private StringMetric(){}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user