MassiveCore - More work on Comparators, Container and Editor

This commit is contained in:
Olof Larsson 2016-02-03 14:00:38 +01:00
parent b3eab7df4c
commit 03d224e953
13 changed files with 289 additions and 174 deletions

View File

@ -108,7 +108,7 @@ public class CommandEditAbstract<O, V> extends MassiveCommand
// NoChange // NoChange
// We check, inform and cancel on equality. // We check, inform and cancel on equality.
if (this.getValueType().equals(before, after, true)) if (this.getValueType().equals(before, after))
{ {
msg("%s<silver> for %s<silver> already: %s", descProperty, descObject, descValue); msg("%s<silver> for %s<silver> already: %s", descProperty, descObject, descValue);
return; return;

View File

@ -7,6 +7,7 @@ import com.massivecraft.massivecore.MassiveException;
import com.massivecraft.massivecore.command.requirement.RequirementEditorPropertyCreated; import com.massivecraft.massivecore.command.requirement.RequirementEditorPropertyCreated;
import com.massivecraft.massivecore.command.type.Type; import com.massivecraft.massivecore.command.type.Type;
import com.massivecraft.massivecore.command.type.TypeNullable; import com.massivecraft.massivecore.command.type.TypeNullable;
import com.massivecraft.massivecore.util.ContainerUtil;
public abstract class CommandEditContainerAbstract<O, V> extends CommandEditAbstract<O, V> public abstract class CommandEditContainerAbstract<O, V> extends CommandEditAbstract<O, V>
{ {
@ -59,11 +60,11 @@ public abstract class CommandEditContainerAbstract<O, V> extends CommandEditAbst
// After // After
V after = this.getValueType().createNewInstance(); V after = this.getValueType().createNewInstance();
this.getValueType().addContainerElements(after, elements); ContainerUtil.addElements(after, elements);
// Order // Order
elements = this.getValueType().getContainerElementsOrdered(after); elements = this.getValueType().getContainerElementsOrdered(after);
this.getValueType().setContainerElements(after, elements); ContainerUtil.setElements(after, elements);
// Apply // Apply
this.attemptSet(after); this.attemptSet(after);

View File

@ -56,7 +56,7 @@ public class CommandEditContainerRemove<O, V> extends CommandEditContainerAbstra
while (iterator.hasNext()) while (iterator.hasNext())
{ {
Object other = iterator.hasNext(); Object other = iterator.hasNext();
if ( ! this.getValueInnerType().equals(other, element, false)) continue; if ( ! this.getValueInnerType().equals(other, element)) continue;
iterator.remove(); iterator.remove();
} }
} }

View File

@ -107,10 +107,8 @@ public interface Type<T>
public boolean allowSpaceAfterTab(); public boolean allowSpaceAfterTab();
// -------------------------------------------- // // -------------------------------------------- //
// CONTAINER // CONTAINER > IS
// -------------------------------------------- // // -------------------------------------------- //
// The "Container" is an imaginary super type for "Collection" and "Map".
// The Element class E is the entry for a map.
public boolean isContainer(); public boolean isContainer();
public boolean isContainerMap(); public boolean isContainerMap();
@ -120,27 +118,22 @@ public interface Type<T>
public boolean isContainerOrdered(); public boolean isContainerOrdered();
public boolean isContainerSorted(); public boolean isContainerSorted();
// -------------------------------------------- //
// CONTAINER > COMPARATOR
// -------------------------------------------- //
public <E> Comparator<E> getContainerComparator(); public <E> Comparator<E> getContainerComparator();
public void setContainerComparator(Comparator<?> container); public void setContainerComparator(Comparator<?> container);
public <E> List<E> getContainerElementsOrdered(Iterable<E> elements); public <E> List<E> getContainerElementsOrdered(Iterable<E> elements);
public <E> List<E> getContainerElementsOrdered(T container); public <E> List<E> getContainerElementsOrdered(T container);
public boolean isContainerEmpty(T container);
public void clearContainer(T container);
public <E> Collection<E> getContainerElements(T container);
public <E> void setContainerElements(T container, Iterable<E> elements);
public <E> boolean addContainerElement(T container, E element);
public <E> void addContainerElements(T container, Iterable<E> elements);
// -------------------------------------------- // // -------------------------------------------- //
// EQUALS // EQUALS
// -------------------------------------------- // // -------------------------------------------- //
public boolean equals(T type1, T type2, boolean strict); public boolean equals(T type1, T type2);
public boolean equalsInner(T type1, T type2, boolean strict); public boolean equalsInner(T type1, T type2);
// -------------------------------------------- // // -------------------------------------------- //
// EDITOR // EDITOR

View File

@ -5,16 +5,10 @@ import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.ListIterator; import java.util.ListIterator;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.Map.Entry;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@ -28,7 +22,7 @@ import com.massivecraft.massivecore.command.editor.Property;
import com.massivecraft.massivecore.comparator.ComparatorHashCode; import com.massivecraft.massivecore.comparator.ComparatorHashCode;
import com.massivecraft.massivecore.store.Entity; import com.massivecraft.massivecore.store.Entity;
import com.massivecraft.massivecore.store.SenderEntity; import com.massivecraft.massivecore.store.SenderEntity;
import com.massivecraft.massivecore.util.MUtil; import com.massivecraft.massivecore.util.ContainerUtil;
import com.massivecraft.massivecore.util.Txt; import com.massivecraft.massivecore.util.Txt;
public abstract class TypeAbstract<T> implements Type<T> public abstract class TypeAbstract<T> implements Type<T>
@ -402,72 +396,42 @@ public abstract class TypeAbstract<T> implements Type<T>
} }
// -------------------------------------------- // // -------------------------------------------- //
// CONTAINER // CONTAINER > IS
// -------------------------------------------- // // -------------------------------------------- //
public boolean isContainer() private Boolean container = null;
{ public boolean isContainer() { this.calcContainer(); return this.container; }
return this.isContainerCollection() || this.isContainerMap();
}
private Boolean containerMap = null; private Boolean containerMap = null;
public boolean isContainerMap() public boolean isContainerMap() { this.calcContainer(); return this.containerMap; }
{
if (this.containerMap == null) this.containerMap = this.calcContainerMap();
return this.containerMap;
}
protected boolean calcContainerMap()
{
T instance = this.createNewInstance();
if (instance instanceof Map<?, ?>) return true;
return false;
}
private Boolean containerCollection = null; private Boolean containerCollection = null;
public boolean isContainerCollection() public boolean isContainerCollection() { this.calcContainer(); return this.containerCollection; }
{
if (this.containerCollection == null) this.containerCollection = this.calcContainerCollection(); private Boolean containerIndexed = null;
return this.containerCollection; public boolean isContainerIndexed() { this.calcContainer(); return this.containerIndexed; }
}
protected boolean calcContainerCollection() private Boolean containerOrdered = null;
public boolean isContainerOrdered() { this.calcContainer(); return this.containerOrdered; }
private Boolean containerSorted = null;
public boolean isContainerSorted() { this.calcContainer(); return this.containerSorted; }
private void calcContainer()
{ {
if (this.container != null) return;
T instance = this.createNewInstance(); T instance = this.createNewInstance();
if (instance instanceof Collection<?>) return true; this.container = ContainerUtil.isContainer(instance);
return false; this.containerMap = ContainerUtil.isMap(instance);
this.containerCollection = ContainerUtil.isCollection(instance);
this.containerIndexed = ContainerUtil.isIndexed(instance);
this.containerOrdered = ContainerUtil.isOrdered(instance);
this.containerSorted = ContainerUtil.isSorted(instance);
} }
public boolean isContainerIndexed() // -------------------------------------------- //
{ // CONTAINER > COMPARATOR
return this.isContainerOrdered() || this.isContainerSorted(); // -------------------------------------------- //
}
private Boolean collectionOrdered = null;
public boolean isContainerOrdered()
{
if (this.collectionOrdered == null) this.collectionOrdered = this.calcContainerOrdered();
return this.collectionOrdered;
}
protected boolean calcContainerOrdered()
{
T instance = this.createNewInstance();
if (instance instanceof List<?>) return true;
if (instance instanceof LinkedHashMap<?, ?>) return true;
return false;
}
private Boolean collectionSorted = null;
public boolean isContainerSorted()
{
if (this.collectionSorted == null) this.collectionSorted = this.calcContainerSorted();
return this.collectionSorted;
}
protected boolean calcContainerSorted()
{
T instance = this.createNewInstance();
if (instance instanceof SortedSet<?>) return true;
if (instance instanceof SortedMap<?, ?>) return true;
return false;
}
private Comparator<Object> elementComparator = null; private Comparator<Object> elementComparator = null;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -507,87 +471,22 @@ public abstract class TypeAbstract<T> implements Type<T>
@Override @Override
public <E> List<E> getContainerElementsOrdered(T container) public <E> List<E> getContainerElementsOrdered(T container)
{ {
Collection<E> elements = this.getContainerElements(container); Collection<E> elements = ContainerUtil.getElements(container);
return this.getContainerElementsOrdered(elements); return this.getContainerElementsOrdered(elements);
} }
public boolean isContainerEmpty(T container)
{
return this.getContainerElements(container).isEmpty();
}
@Override
public void clearContainer(T container)
{
this.getContainerElements(container).clear();
}
@SuppressWarnings("unchecked")
public <E> Collection<E> getContainerElements(T container)
{
if (container instanceof Collection<?>)
{
Collection<E> collection = (Collection<E>)container;
return collection;
}
if (container instanceof Map<?, ?>)
{
Map<?, ?> map = (Map<?, ?>)container;
return (Collection<E>) map.entrySet();
}
throw new UnsupportedOperationException("not implemented");
}
public <E> void setContainerElements(T container, Iterable<E> elements)
{
this.clearContainer(container);
this.addContainerElements(container, elements);
}
@SuppressWarnings("unchecked")
public <E> boolean addContainerElement(T container, E element)
{
if (container instanceof Collection<?>)
{
Collection<E> collection = (Collection<E>)container;
return collection.add(element);
}
if (container instanceof Map<?, ?>)
{
Map<Object, Object> map = (Map<Object, Object>)container;
Entry<Object, Object> entry = (Entry<Object, Object>)element;
Object key = entry.getKey();
Object after = entry.getValue();
Object before = map.put(key, after);
return ! MUtil.equals(after, before);
}
throw new UnsupportedOperationException("not implemented");
}
public <E> void addContainerElements(T container, Iterable<E> elements)
{
for (E element : elements)
{
this.addContainerElement(container, element);
}
}
// -------------------------------------------- // // -------------------------------------------- //
// EQUALS // EQUALS
// -------------------------------------------- // // -------------------------------------------- //
public boolean equals(T type1, T type2, boolean strict) public boolean equals(T type1, T type2)
{ {
if (type1 == null) return type2 == null; if (type1 == null) return type2 == null;
if (type2 == null) return type1 == null; if (type2 == null) return type1 == null;
return this.equalsInner(type1, type2, strict); return this.equalsInner(type1, type2);
} }
public boolean equalsInner(T type1, T type2, boolean strict) public boolean equalsInner(T type1, T type2)
{ {
return type1.equals(type2); return type1.equals(type2);
} }

View File

@ -74,20 +74,17 @@ public class TypeEntry<K, V> extends TypeCombined<Entry<K, V>>
} }
@Override @Override
public boolean equalsInner(Entry<K, V> type1, Entry<K, V> type2, boolean strict) public boolean equalsInner(Entry<K, V> type1, Entry<K, V> type2)
{ {
// Compare Keys // Compare Keys
K key1 = type1.getKey(); K key1 = type1.getKey();
K key2 = type2.getKey(); K key2 = type2.getKey();
if ( ! this.getKeyType().equals(key1, key2, strict)) return false; if ( ! this.getKeyType().equals(key1, key2)) return false;
// Strict
if ( ! strict) return true;
// Compare Values // Compare Values
V value1 = type1.getValue(); V value1 = type1.getValue();
V value2 = type2.getValue(); V value2 = type2.getValue();
if ( ! this.getValueType().equals(value1, value2, strict)) return false; if ( ! this.getValueType().equals(value1, value2)) return false;
// Done // Done
return true; return true;

View File

@ -14,6 +14,7 @@ import com.massivecraft.massivecore.command.editor.EditSettings;
import com.massivecraft.massivecore.command.editor.Property; import com.massivecraft.massivecore.command.editor.Property;
import com.massivecraft.massivecore.command.type.Type; import com.massivecraft.massivecore.command.type.Type;
import com.massivecraft.massivecore.command.type.TypeAbstract; import com.massivecraft.massivecore.command.type.TypeAbstract;
import com.massivecraft.massivecore.util.ContainerUtil;
import com.massivecraft.massivecore.util.Txt; import com.massivecraft.massivecore.util.Txt;
public abstract class TypeContainer<C extends Object, E> extends TypeAbstract<C> public abstract class TypeContainer<C extends Object, E> extends TypeAbstract<C>
@ -50,7 +51,7 @@ public abstract class TypeContainer<C extends Object, E> extends TypeAbstract<C>
public String getVisualInner(C container, CommandSender sender) public String getVisualInner(C container, CommandSender sender)
{ {
// Empty // Empty
if (this.isContainerEmpty(container)) return EMPTY; if (ContainerUtil.isEmpty(container)) return EMPTY;
// Create // Create
List<String> parts = new MassiveList<String>(); List<String> parts = new MassiveList<String>();
@ -78,7 +79,7 @@ public abstract class TypeContainer<C extends Object, E> extends TypeAbstract<C>
public String getNameInner(C container) public String getNameInner(C container)
{ {
// Empty // Empty
if (this.isContainerEmpty(container)) return ""; if (ContainerUtil.isEmpty(container)) return "";
// Create // Create
List<String> parts = new MassiveList<String>(); List<String> parts = new MassiveList<String>();
@ -104,7 +105,7 @@ public abstract class TypeContainer<C extends Object, E> extends TypeAbstract<C>
public String getIdInner(C container) public String getIdInner(C container)
{ {
// Empty // Empty
if (this.isContainerEmpty(container)) return ""; if (ContainerUtil.isEmpty(container)) return "";
// Create // Create
List<String> parts = new MassiveList<String>(); List<String> parts = new MassiveList<String>();
@ -139,7 +140,7 @@ public abstract class TypeContainer<C extends Object, E> extends TypeAbstract<C>
AllAble<E> allAble = (AllAble<E>)this.getInnerType(); AllAble<E> allAble = (AllAble<E>)this.getInnerType();
if (arg.equalsIgnoreCase("all")) if (arg.equalsIgnoreCase("all"))
{ {
this.addContainerElements(ret, allAble.getAll(sender)); ContainerUtil.addElements(ret, allAble.getAll(sender));
return ret; return ret;
} }
} }
@ -150,7 +151,7 @@ public abstract class TypeContainer<C extends Object, E> extends TypeAbstract<C>
{ {
Type<E> innerType = this.getInnerType(); Type<E> innerType = this.getInnerType();
E element = innerType.read(elementArg, sender); E element = innerType.read(elementArg, sender);
this.addContainerElement(ret, element); ContainerUtil.addElement(ret, element);
} }
// Return // Return
@ -188,7 +189,7 @@ public abstract class TypeContainer<C extends Object, E> extends TypeAbstract<C>
// -------------------------------------------- // // -------------------------------------------- //
@Override @Override
public boolean equalsInner(C container1, C container2, boolean strict) public boolean equalsInner(C container1, C container2)
{ {
List<E> ordered1 = this.getContainerElementsOrdered(container1); List<E> ordered1 = this.getContainerElementsOrdered(container1);
List<E> ordered2 = this.getContainerElementsOrdered(container2); List<E> ordered2 = this.getContainerElementsOrdered(container2);
@ -201,7 +202,7 @@ public abstract class TypeContainer<C extends Object, E> extends TypeAbstract<C>
E element1 = ordered1.get(index); E element1 = ordered1.get(index);
E element2 = ordered2.get(index); E element2 = ordered2.get(index);
if ( ! innerType.equals(element1, element2, strict)) return false; if ( ! innerType.equals(element1, element2)) return false;
} }
return true; return true;

View File

@ -1,8 +1,8 @@
package com.massivecraft.massivecore.store; package com.massivecraft.massivecore.comparator;
import java.util.Comparator; import java.util.Comparator;
import com.massivecraft.massivecore.comparator.ComparatorNaturalOrder; import com.massivecraft.massivecore.store.Entity;
public class ComparatorEntityId implements Comparator<Entity<?>> public class ComparatorEntityId implements Comparator<Entity<?>>
{ {

View File

@ -23,9 +23,6 @@ public class ComparatorHashCode extends ComparatorAbstract<Object>
ret = Integer.compare(Objects.hashCode(object1), Objects.hashCode(object2)); ret = Integer.compare(Objects.hashCode(object1), Objects.hashCode(object2));
if (ret != 0) return ret; if (ret != 0) return ret;
ret = Integer.compare(System.identityHashCode(object1), System.identityHashCode(object2));
if (ret != 0) return ret;
return ret; return ret;
} }

View File

@ -0,0 +1,27 @@
package com.massivecraft.massivecore.comparator;
public class ComparatorIdentityHashCode extends ComparatorAbstract<Object>
{
// -------------------------------------------- //
// INSTANCE & CONSTRUCT
// -------------------------------------------- //
private static transient ComparatorIdentityHashCode i = new ComparatorIdentityHashCode();
public static ComparatorIdentityHashCode get() { return i; }
// -------------------------------------------- //
// OVERRIDE
// -------------------------------------------- //
@Override
public int compareInner(Object object1, Object object2)
{
int ret;
ret = Integer.compare(System.identityHashCode(object1), System.identityHashCode(object2));
if (ret != 0) return ret;
return ret;
}
}

View File

@ -21,13 +21,15 @@ public class ComparatorLenient<T> extends ComparatorAbstractWrapper<T, T>
@Override @Override
public int compare(T type1, T type2) public int compare(T type1, T type2)
{ {
int ret = this.getComparator().compare(type1, type2); int ret;
ret = this.getComparator().compare(type1, type2);
if (ret != 0) return ret; if (ret != 0) return ret;
int hash1 = type1.hashCode(); ret = ComparatorHashCode.get().compare(type1, type2);
int hash2 = type2.hashCode(); if (ret != 0) return ret;
ret = Integer.compare(hash1, hash2); ret = ComparatorIdentityHashCode.get().compare(type1, type2);
if (ret != 0) return ret; if (ret != 0) return ret;
return 1; return 1;

View File

@ -1,7 +1,6 @@
package com.massivecraft.massivecore.comparator; package com.massivecraft.massivecore.comparator;
import com.massivecraft.massivecore.Prioritized; import com.massivecraft.massivecore.Prioritized;
import com.massivecraft.massivecore.store.ComparatorEntityId;
import com.massivecraft.massivecore.store.Entity; import com.massivecraft.massivecore.store.Entity;
public class ComparatorPriority extends ComparatorAbstract<Prioritized> public class ComparatorPriority extends ComparatorAbstract<Prioritized>

View File

@ -0,0 +1,199 @@
package com.massivecraft.massivecore.util;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.Map.Entry;
/**
* The ContainerUtil provides an imaginary super class to Collection and Map.
* In Java they do not have a common interface yet many methods are similar and exists in both.
* This some times results in twice the amount of source code, which we aim to remedy with this utility class.
*
* We take an approach where we largely see a Map as a Collection of entries.
* The "Container" class is simply an Object.
* The return values are auto cast generics.
*
* We have also added some information gatherers related to sorting and order.
*/
public class ContainerUtil
{
// -------------------------------------------- //
// IS > CORE
// -------------------------------------------- //
public static boolean isContainer(Object container)
{
return isCollection(container) || isMap(container);
}
public static boolean isCollection(Object container)
{
return container instanceof Collection<?>;
}
public static boolean isMap(Object container)
{
return container instanceof Map<?, ?>;
}
// -------------------------------------------- //
// IS > BEHAVIOR
// -------------------------------------------- //
public static boolean isIndexed(Object container)
{
return isOrdered(container) || isSorted(container);
}
public static boolean isOrdered(Object container)
{
return container instanceof List<?> || container instanceof LinkedHashMap<?, ?>;
}
public static boolean isSorted(Object container)
{
return container instanceof SortedSet<?> || container instanceof SortedMap<?, ?>;
}
// -------------------------------------------- //
// AS > CORE
// -------------------------------------------- //
@SuppressWarnings("unchecked")
public static <C extends Collection<? extends Object>> C asCollection(Object container)
{
if ( ! isCollection(container)) return null;
return (C)container;
}
@SuppressWarnings("unchecked")
public static <M extends Map<? extends Object, ? extends Object>> M asMap(Object container)
{
if ( ! isMap(container)) return null;
return (M)container;
}
// -------------------------------------------- //
// METHODS > SIZE
// -------------------------------------------- //
public static boolean isEmpty(Object container)
{
Collection<Object> collection = asCollection(container);
if (collection != null)
{
return collection.isEmpty();
}
Map<Object, Object> map = asMap(container);
if (map != null)
{
return map.isEmpty();
}
throw new IllegalArgumentException();
}
public static int size(Object container)
{
Collection<Object> collection = asCollection(container);
if (collection != null)
{
return collection.size();
}
Map<Object, Object> map = asMap(container);
if (map != null)
{
return map.size();
}
throw new IllegalArgumentException();
}
// -------------------------------------------- //
// METHODS > GET
// -------------------------------------------- //
@SuppressWarnings("unchecked")
public static <E> Collection<E> getElements(Object container)
{
Collection<E> collection = asCollection(container);
if (collection != null)
{
return collection;
}
Map<Object, Object> map = asMap(container);
if (map != null)
{
return (Collection<E>) map.entrySet();
}
throw new IllegalArgumentException();
}
// -------------------------------------------- //
// METHODS > SET
// -------------------------------------------- //
public static void clear(Object container)
{
Collection<Object> collection = asCollection(container);
if (collection != null)
{
collection.clear();
return;
}
Map<Object, Object> map = asMap(container);
if (map != null)
{
map.clear();
return;
}
throw new IllegalArgumentException();
}
public static void setElements(Object container, Iterable<? extends Object> elements)
{
clear(container);
addElements(container, elements);
}
@SuppressWarnings("unchecked")
public static boolean addElement(Object container, Object element)
{
Collection<Object> collection = asCollection(container);
if (collection != null)
{
return collection.add(element);
}
Map<Object, Object> map = asMap(container);
if (map != null)
{
Entry<Object, Object> entry = (Entry<Object, Object>)element;
Object key = entry.getKey();
Object after = entry.getValue();
Object before = map.put(key, after);
return ! MUtil.equals(after, before);
}
throw new IllegalArgumentException();
}
public static void addElements(Object container, Iterable<? extends Object> elements)
{
for (Object element : elements)
{
addElement(container, element);
}
}
}