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
// 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);
return;

View File

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

View File

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

View File

@ -107,10 +107,8 @@ public interface Type<T>
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 isContainerMap();
@ -120,27 +118,22 @@ public interface Type<T>
public boolean isContainerOrdered();
public boolean isContainerSorted();
// -------------------------------------------- //
// CONTAINER > COMPARATOR
// -------------------------------------------- //
public <E> Comparator<E> getContainerComparator();
public void setContainerComparator(Comparator<?> container);
public <E> List<E> getContainerElementsOrdered(Iterable<E> elements);
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
// -------------------------------------------- //
public boolean equals(T type1, T type2, boolean strict);
public boolean equalsInner(T type1, T type2, boolean strict);
public boolean equals(T type1, T type2);
public boolean equalsInner(T type1, T type2);
// -------------------------------------------- //
// EDITOR

View File

@ -5,16 +5,10 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.Map.Entry;
import org.bukkit.ChatColor;
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.store.Entity;
import com.massivecraft.massivecore.store.SenderEntity;
import com.massivecraft.massivecore.util.MUtil;
import com.massivecraft.massivecore.util.ContainerUtil;
import com.massivecraft.massivecore.util.Txt;
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()
{
return this.isContainerCollection() || this.isContainerMap();
}
private Boolean container = null;
public boolean isContainer() { this.calcContainer(); return this.container; }
private Boolean containerMap = null;
public boolean isContainerMap()
{
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;
}
public boolean isContainerMap() { this.calcContainer(); return this.containerMap; }
private Boolean containerCollection = null;
public boolean isContainerCollection()
{
if (this.containerCollection == null) this.containerCollection = this.calcContainerCollection();
return this.containerCollection;
}
protected boolean calcContainerCollection()
public boolean isContainerCollection() { this.calcContainer(); return this.containerCollection; }
private Boolean containerIndexed = null;
public boolean isContainerIndexed() { this.calcContainer(); return this.containerIndexed; }
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();
if (instance instanceof Collection<?>) return true;
return false;
this.container = ContainerUtil.isContainer(instance);
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()
{
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;
}
// -------------------------------------------- //
// CONTAINER > COMPARATOR
// -------------------------------------------- //
private Comparator<Object> elementComparator = null;
@SuppressWarnings("unchecked")
@ -507,87 +471,22 @@ public abstract class TypeAbstract<T> implements Type<T>
@Override
public <E> List<E> getContainerElementsOrdered(T container)
{
Collection<E> elements = this.getContainerElements(container);
Collection<E> elements = ContainerUtil.getElements(container);
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
// -------------------------------------------- //
public boolean equals(T type1, T type2, boolean strict)
public boolean equals(T type1, T type2)
{
if (type1 == null) return type2 == 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);
}

View File

@ -74,20 +74,17 @@ public class TypeEntry<K, V> extends TypeCombined<Entry<K, V>>
}
@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
K key1 = type1.getKey();
K key2 = type2.getKey();
if ( ! this.getKeyType().equals(key1, key2, strict)) return false;
// Strict
if ( ! strict) return true;
if ( ! this.getKeyType().equals(key1, key2)) return false;
// Compare Values
V value1 = type1.getValue();
V value2 = type2.getValue();
if ( ! this.getValueType().equals(value1, value2, strict)) return false;
if ( ! this.getValueType().equals(value1, value2)) return false;
// Done
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.type.Type;
import com.massivecraft.massivecore.command.type.TypeAbstract;
import com.massivecraft.massivecore.util.ContainerUtil;
import com.massivecraft.massivecore.util.Txt;
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)
{
// Empty
if (this.isContainerEmpty(container)) return EMPTY;
if (ContainerUtil.isEmpty(container)) return EMPTY;
// Create
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)
{
// Empty
if (this.isContainerEmpty(container)) return "";
if (ContainerUtil.isEmpty(container)) return "";
// Create
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)
{
// Empty
if (this.isContainerEmpty(container)) return "";
if (ContainerUtil.isEmpty(container)) return "";
// Create
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();
if (arg.equalsIgnoreCase("all"))
{
this.addContainerElements(ret, allAble.getAll(sender));
ContainerUtil.addElements(ret, allAble.getAll(sender));
return ret;
}
}
@ -150,7 +151,7 @@ public abstract class TypeContainer<C extends Object, E> extends TypeAbstract<C>
{
Type<E> innerType = this.getInnerType();
E element = innerType.read(elementArg, sender);
this.addContainerElement(ret, element);
ContainerUtil.addElement(ret, element);
}
// Return
@ -188,7 +189,7 @@ public abstract class TypeContainer<C extends Object, E> extends TypeAbstract<C>
// -------------------------------------------- //
@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> 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 element2 = ordered2.get(index);
if ( ! innerType.equals(element1, element2, strict)) return false;
if ( ! innerType.equals(element1, element2)) return false;
}
return true;

View File

@ -1,8 +1,8 @@
package com.massivecraft.massivecore.store;
package com.massivecraft.massivecore.comparator;
import java.util.Comparator;
import com.massivecraft.massivecore.comparator.ComparatorNaturalOrder;
import com.massivecraft.massivecore.store.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));
if (ret != 0) return ret;
ret = Integer.compare(System.identityHashCode(object1), System.identityHashCode(object2));
if (ret != 0) 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
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;
int hash1 = type1.hashCode();
int hash2 = type2.hashCode();
ret = ComparatorHashCode.get().compare(type1, type2);
if (ret != 0) return ret;
ret = Integer.compare(hash1, hash2);
ret = ComparatorIdentityHashCode.get().compare(type1, type2);
if (ret != 0) return ret;
return 1;

View File

@ -1,7 +1,6 @@
package com.massivecraft.massivecore.comparator;
import com.massivecraft.massivecore.Prioritized;
import com.massivecraft.massivecore.store.ComparatorEntityId;
import com.massivecraft.massivecore.store.Entity;
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);
}
}
}