New Works.

-Added: Set
-Added: Sorted Set
-Added: HashSet
-Added: LinkedHashSet
-Changed: HASH method was changed to TO_HASH
-Added: New Patterns.
This commit is contained in:
Speiger 2020-12-13 20:14:22 +01:00
parent fc7bca3500
commit 16efec5ca4
14 changed files with 1260 additions and 34 deletions

View File

@ -79,14 +79,30 @@ public enum ClassType
return this == BYTE || this == SHORT || this == CHAR || this == FLOAT;
}
public String getEquals()
public boolean needsCast()
{
return this == BYTE || this == SHORT || this == CHAR;
}
public String getComparableValue()
{
switch(this)
{
case DOUBLE: return "Double.doubleToLongBits(%1$s) == Double.doubleToLongBits(%2$s)";
case FLOAT: return "Float.floatToIntBits(%1$s) == Float.floatToIntBits(%2$s)";
case OBJECT: return "Objects.equals(%1$s, %2$s)";
default: return "%1$s == %2$s";
case DOUBLE: return "Double.doubleToLongBits(%1$s)";
case FLOAT: return "Float.floatToIntBits(%1$s)";
case OBJECT: return "%1$s";
default: return "%1$s";
}
}
public String getEquals(boolean not)
{
switch(this)
{
case DOUBLE: return "Double.doubleToLongBits(%1$s) "+(not ? "!=" : "==")+" Double.doubleToLongBits(%2$s)";
case FLOAT: return "Float.floatToIntBits(%1$s) "+(not ? "!=" : "==")+" Float.floatToIntBits(%2$s)";
case OBJECT: return (not ? "!" : "")+"Objects.equals(%1$s, %2$s)";
default: return "%1$s "+(not ? "!=" : "==")+" %2$s";
}
}

View File

@ -52,13 +52,16 @@ public class GlobalVariables
public GlobalVariables createHelperVariables()
{
addArgumentMapper("EQUALS_KEY_TYPE", type.isObject() ? "Objects.equals(%2$s, %1$s)" : "Objects.equals(%2$s, KEY_TO_OBJ(%1$s))").removeBraces();
addArgumentMapper("EQUALS", type.getEquals()).removeBraces();
addInjectMapper("EQUALS_NOT_NULL", type.getComparableValue()+" != "+(type.isPrimitiveBlocking() ? type.getEmptyValue() : (type.needsCast() ? type.getEmptyValue() : "0"))).removeBraces();
addInjectMapper("EQUALS_NULL", type.getComparableValue()+" == "+(type.isPrimitiveBlocking() ? type.getEmptyValue() : (type.needsCast() ? type.getEmptyValue() : "0"))).removeBraces();
addArgumentMapper("EQUALS_NOT", type.getEquals(true)).removeBraces();
addArgumentMapper("EQUALS", type.getEquals(false)).removeBraces();
addArgumentMapper("COMPARE_TO", type.isObject() ? "%1$s.compareTo(%2$s)" : type.getClassType()+".compare(%1$s, %2$s)").removeBraces();
addInjectMapper("KEY_TO_OBJ", type.isObject() ? "%s" : type.getClassType()+".valueOf(%s)").removeBraces();
addInjectMapper("OBJ_TO_KEY", type.isObject() ? "%s" : "%s."+type.getKeyType()+"Value()").removeBraces();
addInjectMapper("CLASS_TO_KEY", "(("+type.getClassType()+")%s)."+type.getKeyType()+"Value()").removeBraces();
addSimpleMapper("APPLY", "applyAs"+type.getCustomJDKType().getNonFileType());
addInjectMapper("HASH", type.getClassType()+".hashCode(%s)").removeBraces();
addInjectMapper("TO_HASH", type.isObject() ? "%s.hashCode()" : type.getClassType()+".hashCode(%s)").removeBraces();
return this;
}
@ -67,6 +70,34 @@ public class GlobalVariables
addSimpleMapper("JAVA_PREDICATE", type.isPrimitiveBlocking() ? "" : type.getCustomJDKType().getFileType()+"Predicate");
addSimpleMapper("JAVA_CONSUMER", type.isPrimitiveBlocking() ? "" : "java.util.function."+type.getCustomJDKType().getFileType()+"Consumer");
addSimpleMapper("UNARY_OPERATOR", type.isObject() ? "" : type == ClassType.BOOLEAN ? "BinaryOperator" : type.getCustomJDKType().getFileType()+"UnaryOperator");
//Final Classes
addClassMapper("ARRAY_LIST", "ArrayList");
addClassMapper("LINKED_HASH_SET", "LinkedOpenHashSet");
addClassMapper("HASH_SET", "OpenHashSet");
//Abstract Classes
addClassMapper("ABSTRACT_COLLECTION", "AbstractCollection");
addClassMapper("ABSTRACT_SET", "AbstractSet");
addClassMapper("ABSTRACT_LIST", "AbstractList");
addClassMapper("SUB_LIST", "SubList");
//Helper Classes
addClassMapper("LISTS", "Lists");
addClassMapper("COLLECTIONS", "Collections");
addClassMapper("ARRAYS", "Arrays");
addClassMapper("ITERATORS", "Iterators");
//Interfaces
addClassMapper("LIST_ITERATOR", "ListIterator");
addClassMapper("BI_ITERATOR", "BidirectionalIterator");
addClassMapper("ITERATOR", "Iterator");
addClassMapper("ITERABLE", "Iterable");
addClassMapper("COLLECTION", "Collection");
addClassMapper("LIST", "List");
addClassMapper("SORTED_SET", "SortedSet");
addClassMapper("SET", "Set");
addClassMapper("STACK", "Stack");
if(type.isObject())
{
addSimpleMapper("CONSUMER", "Consumer");
@ -79,22 +110,8 @@ public class GlobalVariables
addClassMapper("COMPARATOR", "Comparator");
addFunctionMappers("IARRAY", "I%sArray");
}
addClassMapper("ITERATORS", "Iterators");
addClassMapper("BI_ITERATOR", "BidirectionalIterator");
addClassMapper("LIST_ITERATOR", "ListIterator");
addClassMapper("ITERATOR", "Iterator");
addClassMapper("ITERABLE", "Iterable");
addClassMapper("ABSTRACT_COLLECTION", "AbstractCollection");
addClassMapper("COLLECTIONS", "Collections");
addClassMapper("COLLECTION", "Collection");
addClassMapper("ARRAYS", "Arrays");
addClassMapper("ABSTRACT_LIST", "AbstractList");
//Dependency
addClassMapper("LIST_ITER", "ListIter");
addClassMapper("LISTS", "Lists");
addClassMapper("SUB_LIST", "SubList");
addClassMapper("ARRAY_LIST", "ArrayList");
addClassMapper("LIST", "List");
addClassMapper("STACK", "Stack");
return this;
}
@ -112,6 +129,10 @@ public class GlobalVariables
addFunctionMapper("TOP", "top");
addFunctionMappers("REPLACE", "replace%ss");
addFunctionMappers("SORT", "sort%ss");
addFunctionMapper("POLL_FIRST_KEY", "pollFirst");
addFunctionMapper("FIRST_KEY", "first");
addFunctionMapper("POLL_LAST_KEY", "pollLast");
addFunctionMapper("LAST_KEY", "last");
return this;
}

View File

@ -0,0 +1,46 @@
package speiger.src.collections.utils;
public class HashUtil
{
public static final int DEFAULT_MIN_CAPACITY = 16;
public static final float DEFAULT_LOAD_FACTOR = 0.75F;
public static final float FAST_LOAD_FACTOR = 0.5F;
public static final float FASTER_LOAD_FACTOR = 0.25F;
private static final int INT_PHI = 0x9E3779B9;
private static final int INV_INT_PHI = 0x144cbc89;
public static int mix(final int x) {
final int h = x * INT_PHI;
return h ^ (h >>> 16);
}
public static int invMix(final int x) {
return (x ^ x >>> 16) * INV_INT_PHI;
}
public static int nextPowerOfTwo(int x) {
if(x == 0) return 1;
x--;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
return (x | x >> 16) + 1;
}
public static long nextPowerOfTwo(long x) {
if(x == 0) return 1L;
x--;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return (x | x >> 32) + 1L;
}
public static int arraySize(int size, float loadFactor) {
return (int)Math.min(1 << 30, Math.max(2, nextPowerOfTwo((long)Math.ceil(size / loadFactor))));
}
}

View File

@ -9,13 +9,13 @@ public interface ITrimmable
/**
* Trims the original collection down to the size of the current elements
*/
public default void trim() {
trim(0);
public default boolean trim() {
return trim(0);
}
/**
* Trims the original collection down to the size of the current elements or the requested size depending which is bigger
* @param size the requested trim size.
*/
public void trim(int size);
public boolean trim(int size);
}

View File

@ -32,6 +32,6 @@ public interface COMPARATOR extends Comparator<CLASS_TYPE>
*/
public static COMPARATOR of(Comparator<CLASS_TYPE> c) {
Objects.requireNonNull(c);
return (K, V) -> c.compare(KEY_TO_OBJ(K), KEY_TO_OBJ(V))
return (K, V) -> c.compare(KEY_TO_OBJ(K), KEY_TO_OBJ(V));
}
}

View File

@ -192,7 +192,7 @@ public abstract class ABSTRACT_LIST KEY_GENERIC_TYPE extends ABSTRACT_COLLECTION
#if TYPE_OBJECT
hashCode = 31 * hashCode + i.next().hashCode();
#else
hashCode = 31 * hashCode + HASH(i.NEXT());
hashCode = 31 * hashCode + TO_HASH(i.NEXT());
#endif
return hashCode;
}

View File

@ -637,12 +637,17 @@ public class ARRAY_LIST KEY_GENERIC_TYPE extends ABSTRACT_LIST KEY_GENERIC_TYPE
@Override
@Primitive
public void replaceAll(UnaryOperator<CLASS_TYPE> o) {
#if PRIMITIVES
Objects.requireNonNull(o);
#if TYPE_OBJECT
REPLACE(T -> KEY_TO_OBJ(o.APPLY(OBJ_TO_KEY(T))));
#if TYPE_BYTE || TYPE_SHORT || TYPE_CHAR || TYPE_FLOAT
REPLACE(T -> OBJ_TO_KEY(o.apply(KEY_TO_OBJ(SanityChecks.SANITY_CAST(T)))));
#else
for(int i = 0;i<size;i++)
data[i] = OBJ_TO_KEY(o.apply(KEY_TO_OBJ(data[i])));
REPLACE(T -> OBJ_TO_KEY(o.apply(KEY_TO_OBJ(T))));
#endif
#else
Objects.requireNonNull(o);
for(int i = 0;i<size;i++)
data[i] = OBJ_TO_KEY(o.apply(KEY_TO_OBJ(data[i])));
#endif
}
@ -922,14 +927,15 @@ public class ARRAY_LIST KEY_GENERIC_TYPE extends ABSTRACT_LIST KEY_GENERIC_TYPE
* @param size the requested trim size.
*/
@Override
public void trim(int size) {
if(size > size() || size() == data.length) return;
public boolean trim(int size) {
if(size > size() || size() == data.length) return false;
int value = Math.min(size, size());
#if TYPE_OBJECT
data = value == 0 ? (KEY_TYPE[])ARRAYS.EMPTY_ARRAY : Arrays.copyOf(data, value);
#else
data = value == 0 ? ARRAYS.EMPTY_ARRAY : Arrays.copyOf(data, value);
#endif
return true;
}
/**

View File

@ -0,0 +1,53 @@
package speiger.src.collections.PACKAGE.sets;
import java.util.Iterator;
import java.util.Objects;
import java.util.Set;
import speiger.src.collections.PACKAGE.collections.ABSTRACT_COLLECTION;
import speiger.src.collections.PACKAGE.collections.ITERATOR;
public abstract class ABSTRACT_SET KEY_GENERIC_TYPE extends ABSTRACT_COLLECTION KEY_GENERIC_TYPE implements SET KEY_GENERIC_TYPE
{
@Override
public int hashCode() {
int hashCode = 1;
ITERATOR KEY_GENERIC_TYPE i = iterator();
while(i.hasNext())
#if TYPE_OBJECT
hashCode = 31 * hashCode + i.next().hashCode();
#else
hashCode = 31 * hashCode + TO_HASH(i.NEXT());
#endif
return hashCode;
}
@Override
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Set))
return false;
Set<?> l = (Set<?>)o;
if(l.size() != size()) return false;
#if !TYPE_OBJECT
if(l instanceof SET)
{
ITERATOR e1 = iterator();
ITERATOR e2 = ((SET)l).iterator();
while (e1.hasNext() && e2.hasNext()) {
if(!(EQUALS(e1.NEXT(), e2.NEXT())))
return false;
}
return !(e1.hasNext() || e2.hasNext());
}
#endif
Iterator<CLASS_TYPE> e1 = iterator();
Iterator<?> e2 = l.iterator();
while (e1.hasNext() && e2.hasNext()) {
if(!Objects.equals(e1.next(), e2.next()))
return false;
}
return !(e1.hasNext() || e2.hasNext());
}
}

View File

@ -0,0 +1,562 @@
package speiger.src.collections.PACKAGE.sets;
#if TYPE_OBJECT
import java.util.Comparator;
#endif
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
#if TYPE_OBJECT
import java.util.Objects;
#endif
import speiger.src.collections.PACKAGE.collections.COLLECTION;
#if !TYPE_OBJECT
import speiger.src.collections.PACKAGE.collections.ITERATOR;
#endif
import speiger.src.collections.PACKAGE.collections.BI_ITERATOR;
#if !TYPE_OBJECT
import speiger.src.collections.PACKAGE.functions.COMPARATOR;
#endif
import speiger.src.collections.PACKAGE.lists.LIST_ITERATOR;
#if !TYPE_OBJECT
import speiger.src.collections.PACKAGE.utils.ITERATORS;
#endif
import speiger.src.collections.utils.HashUtil;
import speiger.src.collections.utils.SanityChecks;
public class LINKED_HASH_SET KEY_GENERIC_TYPE extends HASH_SET KEY_GENERIC_TYPE implements SORTED_SET KEY_GENERIC_TYPE
{
protected long[] links;
protected int firstIndex = -1;
protected int lastIndex = -1;
public LINKED_HASH_SET() {
this(HashUtil.DEFAULT_MIN_CAPACITY, HashUtil.DEFAULT_LOAD_FACTOR);
}
public LINKED_HASH_SET(int minCapacity) {
this(minCapacity, HashUtil.DEFAULT_LOAD_FACTOR);
}
public LINKED_HASH_SET(int minCapacity, float loadFactor) {
super(minCapacity, loadFactor);
links = new long[nullIndex + 1];
}
public LINKED_HASH_SET(KEY_TYPE[] array) {
this(array, 0, array.length, HashUtil.DEFAULT_LOAD_FACTOR);
}
public LINKED_HASH_SET(KEY_TYPE[] array, float loadFactor) {
this(array, 0, array.length, loadFactor);
}
public LINKED_HASH_SET(KEY_TYPE[] array, int offset, int length) {
this(array, offset, length, HashUtil.DEFAULT_LOAD_FACTOR);
}
public LINKED_HASH_SET(KEY_TYPE[] array, int offset, int length, float loadFactor) {
this(length < 0 ? 0 : length);
SanityChecks.checkArrayCapacity(array.length, offset, length);
for(int i = 0;i<length;i++) add(array[offset+i]);
}
@Deprecated
public LINKED_HASH_SET(Collection<? extends CLASS_TYPE> collection) {
this(collection, HashUtil.DEFAULT_LOAD_FACTOR);
}
@Deprecated
public LINKED_HASH_SET(Collection<? extends CLASS_TYPE> collection, float loadFactor) {
this(collection.size(), loadFactor);
addAll(collection);
}
public LINKED_HASH_SET(COLLECTION KEY_GENERIC_TYPE collection) {
this(collection, HashUtil.DEFAULT_LOAD_FACTOR);
}
public LINKED_HASH_SET(COLLECTION KEY_GENERIC_TYPE collection, float loadFactor) {
this(collection.size());
addAll(collection);
}
public LINKED_HASH_SET(Iterator<CLASS_TYPE> iterator) {
this(iterator, HashUtil.DEFAULT_LOAD_FACTOR);
}
public LINKED_HASH_SET(Iterator<CLASS_TYPE> iterator, float loadFactor) {
#if !TYPE_OBJECT
this(ITERATORS.wrap(iterator), loadFactor);
#else
this(HashUtil.DEFAULT_MIN_CAPACITY, loadFactor);
while(iterator.hasNext()) add(iterator.next());
#endif
}
#if !TYPE_OBJECT
public LINKED_HASH_SET(ITERATOR KEY_GENERIC_TYPE iterator) {
this(iterator, HashUtil.DEFAULT_LOAD_FACTOR);
}
public LINKED_HASH_SET(ITERATOR KEY_GENERIC_TYPE iterator, float loadFactor) {
this(HashUtil.DEFAULT_MIN_CAPACITY, loadFactor);
while(iterator.hasNext()) add(iterator.NEXT());
}
#endif
@Override
public boolean addAndMoveToFirst(KEY_TYPE o) {
if(EQUALS_NULL(o)) {
if(containsNull) {
moveToFirstIndex(nullIndex);
return false;
}
containsNull = true;
onNodeAdded(nullIndex);
}
else {
int pos = HashUtil.mix(TO_HASH(o)) & mask;
while(EQUALS_NOT_NULL(keys[pos])) {
if(EQUALS(keys[pos], o)) {
moveToFirstIndex(pos);
return false;
}
pos = ++pos & mask;
}
keys[pos] = o;
onNodeAdded(pos);
}
if(size++ >= maxFill) rehash(HashUtil.arraySize(size+1, loadFactor));
return true;
}
@Override
public boolean addAndMoveToLast(KEY_TYPE o) {
if(EQUALS_NULL(o)) {
if(containsNull) {
moveToLastIndex(nullIndex);
return false;
}
containsNull = true;
onNodeAdded(nullIndex);
}
else {
int pos = HashUtil.mix(TO_HASH(o)) & mask;
while(EQUALS_NOT_NULL(keys[pos])) {
if(EQUALS(keys[pos], o)) {
moveToLastIndex(pos);
return false;
}
pos = ++pos & mask;
}
keys[pos] = o;
onNodeAdded(pos);
}
if(size++ >= maxFill) rehash(HashUtil.arraySize(size+1, loadFactor));
return true;
}
@Override
public boolean moveToFirst(KEY_TYPE o) {
if(EQUALS_NULL(o)) {
if(containsNull) {
moveToFirstIndex(nullIndex);
return true;
}
}
else {
int pos = HashUtil.mix(TO_HASH(o)) & mask;
while(EQUALS_NOT_NULL(keys[pos])) {
if(EQUALS(keys[pos], o)) {
moveToFirstIndex(pos);
return true;
}
pos = ++pos & mask;
}
keys[pos] = o;
}
return false;
}
@Override
public boolean moveToLast(KEY_TYPE o) {
if(EQUALS_NULL(o)) {
if(containsNull) {
moveToLastIndex(nullIndex);
return true;
}
}
else {
int pos = HashUtil.mix(TO_HASH(o)) & mask;
while(EQUALS_NOT_NULL(keys[pos])) {
if(EQUALS(keys[pos], o)) {
moveToLastIndex(pos);
return true;
}
pos = ++pos & mask;
}
keys[pos] = o;
}
return false;
}
protected void moveToFirstIndex(int startPos) {
if(size == 1 || firstIndex == startPos) return;
if(lastIndex == startPos) {
lastIndex = (int)(links[startPos] >>> 32);
links[lastIndex] |= 0xFFFFFFFFL;
}
else {
long link = links[startPos];
int prev = (int) ( link >>> 32 );
int next = (int) link;
links[prev] ^= ((links[prev] ^ (link & 0xFFFFFFFFL)) & 0xFFFFFFFFL);
links[next] ^= ((links[next] ^ (link & 0xFFFFFFFF00000000L)) & 0xFFFFFFFF00000000L);
}
links[firstIndex] ^= ((links[firstIndex] ^ ((startPos & 0xFFFFFFFFL) << 32)) & 0xFFFFFFFF00000000L);
links[startPos] = ((-1 & 0xFFFFFFFFL) << 32) | (firstIndex & 0xFFFFFFFFL);
firstIndex = startPos;
}
protected void moveToLastIndex(int startPos) {
if(size == 1 || lastIndex == startPos) return;
if(firstIndex == startPos) {
firstIndex = (int)links[startPos];
links[lastIndex] |= 0xFFFFFFFF00000000L;
}
else {
long link = links[startPos];
int prev = (int)(link >>> 32);
int next = (int)link;
links[prev] ^= ((links[prev] ^ (link & 0xFFFFFFFFL)) & 0xFFFFFFFFL);
links[next] ^= ((links[next] ^ (link & 0xFFFFFFFF00000000L)) & 0xFFFFFFFF00000000L);
}
links[lastIndex] ^= ((links[lastIndex] ^ (startPos & 0xFFFFFFFFL)) & 0xFFFFFFFFL);
links[startPos] = ((lastIndex & 0xFFFFFFFFL) << 32) | (-1 & 0xFFFFFFFFL);
lastIndex = startPos;
}
@Override
public KEY_TYPE FIRST_KEY() {
if(size == 0) throw new NoSuchElementException();
return keys[firstIndex];
}
@Override
public KEY_TYPE POLL_FIRST_KEY() {
if(size == 0) throw new NoSuchElementException();
int pos = firstIndex;
firstIndex = (int)links[pos];
if(0 <= firstIndex) links[firstIndex] |= 0xFFFFFFFF00000000L;
KEY_TYPE result = keys[pos];
size--;
if(EQUALS_NULL(result)) {
containsNull = false;
keys[nullIndex] = EMPTY_VALUE;
}
else shiftKeys(pos);
if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2);
return result;
}
@Override
public KEY_TYPE LAST_KEY() {
if(size == 0) throw new NoSuchElementException();
return keys[lastIndex];
}
@Override
public KEY_TYPE POLL_LAST_KEY() {
if(size == 0) throw new NoSuchElementException();
int pos = lastIndex;
lastIndex = (int)(links[pos] >>> 32);
if(0 <= lastIndex) links[lastIndex] |= 0xFFFFFFFFL;
KEY_TYPE result = keys[pos];
size--;
if(EQUALS_NULL(result)) {
containsNull = false;
keys[nullIndex] = EMPTY_VALUE;
}
else shiftKeys(pos);
if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2);
return result;
}
@Override
protected void onNodeAdded(int pos) {
if(size == 0) {
firstIndex = lastIndex = pos;
links[pos] = -1L;
}
else {
links[lastIndex] ^= ((links[lastIndex] ^ (pos & 0xFFFFFFFFL)) & 0xFFFFFFFFL);
links[pos] = ((lastIndex & 0xFFFFFFFFL) << 32) | (-1 & 0xFFFFFFFFL);
lastIndex = pos;
}
}
@Override
protected void onNodeRemoved(int pos) {
if(size == 0) firstIndex = lastIndex = 0;
else if(firstIndex == pos) {
firstIndex = (int)links[pos];
if(0 <= firstIndex) links[firstIndex] |= 0xFFFFFFFF00000000L;
}
else if(lastIndex == pos) {
lastIndex = (int)(links[pos] >>> 32);
if(0 <= lastIndex) links[pos] |= 0xFFFFFFFFL;
}
else {
long link = links[pos];
int prev = (int)(link >>> 32);
int next = (int)link;
links[prev] ^= ((links[prev] ^ (link & 0xFFFFFFFFL)) & 0xFFFFFFFFL);
links[next] ^= ((links[next] ^ (link & 0xFFFFFFFF00000000L)) & 0xFFFFFFFF00000000L);
}
}
@Override
protected void onNodeMoved(int from, int to) {
if(size == 1) {
firstIndex = lastIndex = to;
links[to] = -1L;
}
else if(firstIndex == from) {
firstIndex = to;
links[(int)links[from]] ^= ((links[(int)links[from]] ^ ((to & 0xFFFFFFFFL) << 32)) & 0xFFFFFFFF00000000L);
links[to] = links[from];
}
else if(lastIndex == from) {
lastIndex = to;
links[(int)(links[from] >>> 32)] ^= ((links[(int)(links[from] >>> 32)] ^ (to & 0xFFFFFFFFL)) & 0xFFFFFFFFL);
links[to] = links[from];
}
else {
long link = links[from];
int prev = (int)(link >>> 32);
int next = (int)link;
links[prev] ^= ((links[prev] ^ (to & 0xFFFFFFFFL)) & 0xFFFFFFFFL);
links[next] ^= ((links[next] ^ ((to & 0xFFFFFFFFL) << 32)) & 0xFFFFFFFF00000000L);
links[to] = link;
}
}
@Override
protected void rehash(int newSize) {
int newMask = newSize - 1;
#if TYPE_OBJECT
KEY_TYPE[] newKeys = (KEY_TYPE[])new Object[newSize + 1];
#else
KEY_TYPE[] newKeys = new KEY_TYPE[newSize + 1];
#endif
long[] newLinks = new long[newSize + 1];
int newPrev = -1;
for(int j = size, i = firstIndex, pos = 0, prev = -1;j != 0;) {
if(EQUALS_NULL(keys[i])) pos = newSize;
else {
pos = HashUtil.mix(TO_HASH(keys[i])) & newMask;
while(EQUALS_NOT_NULL(newKeys[pos])) pos = ++pos & newMask;
}
newKeys[pos] = keys[i];
if(prev != -1) {
newLinks[newPrev] ^= ((newLinks[newPrev] ^ (pos & 0xFFFFFFFFL)) & 0xFFFFFFFFL);
newLinks[pos] ^= ((newLinks[pos] ^ ((newPrev & 0xFFFFFFFFL) << 32)) & 0xFFFFFFFF00000000L);
newPrev = pos;
}
else {
newPrev = firstIndex = pos;
newLinks[pos] = -1L;
}
i = (int)links[prev = i];
}
links = newLinks;
lastIndex = newPrev;
if(newPrev != -1) newLinks[newPrev] |= 0xFFFFFFFFL;
nullIndex = newSize;
mask = newMask;
maxFill = Math.min((int)Math.ceil(nullIndex * loadFactor), nullIndex - 1);
keys = newKeys;
}
@Override
public void clear() {
super.clear();
firstIndex = lastIndex = -1;
}
@Override
public LIST_ITERATOR KEY_GENERIC_TYPE iterator() {
return new SetIterator();
}
@Override
public BI_ITERATOR KEY_GENERIC_TYPE iterator(KEY_TYPE fromElement) {
return new SetIterator(fromElement);
}
@Override
public COMPARATOR KEY_GENERIC_TYPE comparator() { return null; }
@Override
public SORTED_SET KEY_GENERIC_TYPE subSet(KEY_TYPE fromElement, KEY_TYPE toElement) { throw new UnsupportedOperationException(); }
@Override
public SORTED_SET KEY_GENERIC_TYPE headSet(KEY_TYPE toElement) { throw new UnsupportedOperationException(); }
@Override
public SORTED_SET KEY_GENERIC_TYPE tailSet(KEY_TYPE fromElement) { throw new UnsupportedOperationException(); }
private class SetIterator implements LIST_ITERATOR KEY_GENERIC_TYPE {
int previous = -1;
int next = -1;
int current = -1;
int index = 0;
SetIterator() {
next = firstIndex;
}
SetIterator(KEY_TYPE from) {
if(EQUALS_NULL(from)) {
if(containsNull) {
next = (int) links[nullIndex];
previous = nullIndex;
}
else throw new NoSuchElementException("The null element is not in the set");
}
else if(EQUALS(keys[lastIndex], from)) {
previous = lastIndex;
index = size;
}
else {
int pos = HashUtil.mix(TO_HASH(from)) & mask;
while(EQUALS_NOT_NULL(keys[pos])) {
if(EQUALS(keys[pos], from)) {
next = (int)links[pos];
previous = pos;
break;
}
pos = ++pos & mask;
}
if(previous == -1 && next == -1)
throw new NoSuchElementException("The element was not found");
}
}
@Override
public boolean hasNext() {
return next != -1;
}
@Override
public boolean hasPrevious() {
return previous != -1;
}
@Override
public int nextIndex() {
ensureIndexKnown();
return index;
}
@Override
public int previousIndex() {
ensureIndexKnown();
return index - 1;
}
@Override
public void remove() {
if(current == -1) throw new IllegalStateException();
ensureIndexKnown();
if(current == previous) {
index--;
previous = (int)(links[current] >> 32);
}
else next = (int)links[current];
size--;
if(previous == -1) firstIndex = next;
else links[previous] ^= ((links[previous] ^ (next & 0xFFFFFFFFL)) & 0xFFFFFFFFL);
if (next == -1) lastIndex = previous;
else links[next] ^= ((links[next] ^ ((previous & 0xFFFFFFFFL) << 32)) & 0xFFFFFFFF00000000L);
if(current == nullIndex) {
current = -1;
containsNull = false;
keys[nullIndex] = EMPTY_VALUE;
}
else {
int slot, last, startPos = current;
current = -1;
KEY_TYPE current;
while(true) {
last = ((last = startPos) + 1) & mask;
while(true){
if(EQUALS_NULL((current = keys[startPos]))) {
keys[last] = EMPTY_VALUE;
return;
}
slot = HashUtil.mix(TO_HASH(current)) & mask;
if(last <= startPos ? (last >= slot || slot > startPos) : (last >= slot && slot > startPos)) break;
startPos = ++startPos & mask;
}
keys[last] = current;
if(next == startPos) next = last;
if(previous == startPos) previous = last;
onNodeMoved(startPos, last);
}
}
}
@Override
public KEY_TYPE PREVIOUS() {
if(!hasPrevious()) throw new NoSuchElementException();
current = previous;
previous = (int)(links[current] >> 32);
next = current;
if(index >= 0) index--;
return keys[current];
}
@Override
public KEY_TYPE NEXT() {
if(!hasPrevious()) throw new NoSuchElementException();
current = next;
next = (int)(links[current]);
previous = current;
if(index >= 0) index++;
return keys[current];
}
private void ensureIndexKnown() {
if(index == -1) {
if(previous == -1) {
index = 0;
}
else if(next == -1) {
index = size;
}
else {
index = 1;
for(int pos = firstIndex;pos != previous;pos = (int)links[pos], index++);
}
}
}
#if TYPE_OBJECT
@Override
public void set(Object e) { throw new UnsupportedOperationException(); }
@Override
public void add(Object e) { throw new UnsupportedOperationException(); }
#else
@Override
public void set(KEY_TYPE e) { throw new UnsupportedOperationException(); }
@Override
public void add(KEY_TYPE e) { throw new UnsupportedOperationException(); }
#endif
}
}

View File

@ -0,0 +1,379 @@
package speiger.src.collections.PACKAGE.sets;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
#if TYPE_OBJECT
import java.util.Objects;
#endif
import speiger.src.collections.PACKAGE.collections.COLLECTION;
import speiger.src.collections.PACKAGE.collections.ITERATOR;
import speiger.src.collections.PACKAGE.lists.ARRAY_LIST;
import speiger.src.collections.PACKAGE.lists.LIST;
#if !TYPE_OBJECT
import speiger.src.collections.PACKAGE.utils.ITERATORS;
#endif
import speiger.src.collections.utils.HashUtil;
import speiger.src.collections.utils.ITrimmable;
import speiger.src.collections.utils.SanityChecks;
public class HASH_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE implements ITrimmable
{
protected transient KEY_TYPE[] keys;
protected transient boolean containsNull;
protected transient int minCapacity;
protected transient int nullIndex;
protected transient int maxFill;
protected transient int mask;
protected int size;
protected final float loadFactor;
public HASH_SET() {
this(HashUtil.DEFAULT_MIN_CAPACITY, HashUtil.DEFAULT_LOAD_FACTOR);
}
public HASH_SET(int minCapacity) {
this(minCapacity, HashUtil.DEFAULT_LOAD_FACTOR);
}
public HASH_SET(int minCapacity, float loadFactor) {
if(minCapacity < 0) throw new IllegalStateException("Minimum Capacity is negative. This is not allowed");
if(loadFactor <= 0 || loadFactor >= 1F) throw new IllegalStateException("Load Factor is not between 0 and 1");
this.loadFactor = loadFactor;
this.minCapacity = nullIndex = HashUtil.arraySize(minCapacity, loadFactor);
mask = nullIndex - 1;
maxFill = Math.min((int)Math.ceil(nullIndex * loadFactor), nullIndex - 1);
#if TYPE_OBJECT
keys = (KEY_TYPE[])new Object[nullIndex + 1];
#else
keys = new KEY_TYPE[nullIndex + 1];
#endif
}
public HASH_SET(KEY_TYPE[] array) {
this(array, 0, array.length, HashUtil.DEFAULT_LOAD_FACTOR);
}
public HASH_SET(KEY_TYPE[] array, float loadFactor) {
this(array, 0, array.length, loadFactor);
}
public HASH_SET(KEY_TYPE[] array, int offset, int length) {
this(array, offset, length, HashUtil.DEFAULT_LOAD_FACTOR);
}
public HASH_SET(KEY_TYPE[] array, int offset, int length, float loadFactor) {
this(length < 0 ? 0 : length);
SanityChecks.checkArrayCapacity(array.length, offset, length);
for(int i = 0;i<length;i++) add(array[offset+i]);
}
@Deprecated
public HASH_SET(Collection<? extends CLASS_TYPE> collection) {
this(collection, HashUtil.DEFAULT_LOAD_FACTOR);
}
@Deprecated
public HASH_SET(Collection<? extends CLASS_TYPE> collection, float loadFactor) {
this(collection.size(), loadFactor);
addAll(collection);
}
public HASH_SET(COLLECTION KEY_GENERIC_TYPE collection) {
this(collection, HashUtil.DEFAULT_LOAD_FACTOR);
}
public HASH_SET(COLLECTION KEY_GENERIC_TYPE collection, float loadFactor) {
this(collection.size());
addAll(collection);
}
public HASH_SET(Iterator<CLASS_TYPE> iterator) {
this(iterator, HashUtil.DEFAULT_LOAD_FACTOR);
}
public HASH_SET(Iterator<CLASS_TYPE> iterator, float loadFactor) {
#if !TYPE_OBJECT
this(ITERATORS.wrap(iterator), loadFactor);
#else
this(HashUtil.DEFAULT_MIN_CAPACITY, loadFactor);
while(iterator.hasNext()) add(iterator.next());
#endif
}
#if !TYPE_OBJECT
public HASH_SET(ITERATOR KEY_GENERIC_TYPE iterator) {
this(iterator, HashUtil.DEFAULT_LOAD_FACTOR);
}
public HASH_SET(ITERATOR KEY_GENERIC_TYPE iterator, float loadFactor) {
this(HashUtil.DEFAULT_MIN_CAPACITY, loadFactor);
while(iterator.hasNext()) add(iterator.NEXT());
}
#endif
@Override
public boolean add(KEY_TYPE o) {
if(EQUALS_NULL(o)) {
if(containsNull) return false;
containsNull = true;
onNodeAdded(nullIndex);
}
else {
int pos = HashUtil.mix(TO_HASH(o)) & mask;
KEY_TYPE current = keys[pos];
if(EQUALS_NOT_NULL(current)) {
if(EQUALS(current, o)) return false;
while(EQUALS_NOT_NULL((current = keys[++pos & mask])))
if(EQUALS(current, o)) return false;
}
keys[pos] = o;
onNodeAdded(pos);
}
if(size++ >= maxFill) rehash(HashUtil.arraySize(size+1, loadFactor));
return true;
}
@Override
@Deprecated
public boolean addAll(Collection<? extends CLASS_TYPE> c) {
if(loadFactor <= 0.5F) ensureCapacity(c.size());
else ensureCapacity(c.size() + size());
return super.addAll(c);
}
@Override
public boolean addAll(COLLECTION KEY_GENERIC_TYPE c) {
if(loadFactor <= 0.5F) ensureCapacity(c.size());
else ensureCapacity(c.size() + size());
return super.addAll(c);
}
#if TYPE_OBJECT
@Override
public boolean contains(Object o) {
if(EQUALS_NULL(o)) return containsNull;
int pos = HashUtil.mix(TO_HASH(o)) & mask;
KEY_TYPE current = keys[pos];
if(EQUALS_NULL(current)) return false;
if(EQUALS(current, o)) return true;
while(true) {
if(EQUALS_NULL((current = keys[++pos & mask]))) return false;
else if(EQUALS(current, o)) return true;
}
}
@Override
public boolean remove(Object o) {
if(EQUALS_NULL(o)) return (containsNull ? removeNullIndex() : false);
int pos = HashUtil.mix(TO_HASH(o)) & mask;
KEY_TYPE current = keys[pos];
if(EQUALS_NULL(current)) return false;
if(EQUALS(current, o)) return removeIndex(pos);
while(true) {
if(EQUALS_NULL((current = keys[++pos & mask]))) return false;
else if(EQUALS(current, o)) return removeIndex(pos);
}
}
#else
@Override
public boolean contains(KEY_TYPE o) {
if(EQUALS_NULL(o)) return containsNull;
int pos = HashUtil.mix(TO_HASH(o)) & mask;
KEY_TYPE current = keys[pos];
if(EQUALS_NULL(current)) return false;
if(EQUALS(current, o)) return true;
while(true) {
if(EQUALS_NULL((current = keys[++pos & mask]))) return false;
else if(EQUALS(current, o)) return true;
}
}
@Override
public boolean remove(KEY_TYPE o) {
if(EQUALS_NULL(o)) return (containsNull ? removeNullIndex() : false);
int pos = HashUtil.mix(TO_HASH(o)) & mask;
KEY_TYPE current = keys[pos];
if(EQUALS_NULL(current)) return false;
if(EQUALS(current, o)) return removeIndex(pos);
while(true) {
if(EQUALS_NULL((current = keys[++pos & mask]))) return false;
else if(EQUALS(current, o)) return removeIndex(pos);
}
}
#endif
@Override
public boolean trim(int size) {
int newSize = HashUtil.nextPowerOfTwo((int)Math.ceil(size / loadFactor));
if(newSize >= nullIndex || size >= Math.min((int)Math.ceil(newSize * loadFactor), newSize - 1)) return false;
try {
rehash(newSize);
}
catch(OutOfMemoryError e) { return false; }
return true;
}
private void ensureCapacity(int newCapacity) {
int size = HashUtil.arraySize(newCapacity, loadFactor);
if(size > nullIndex) rehash(size);
}
protected boolean removeIndex(int pos) {
size--;
onNodeRemoved(pos);
shiftKeys(pos);
if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2);
return true;
}
protected boolean removeNullIndex() {
containsNull = false;
keys[nullIndex] = EMPTY_VALUE;
size--;
onNodeRemoved(nullIndex);
if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2);
return true;
}
protected void onNodeAdded(int pos) {
}
protected void onNodeRemoved(int pos) {
}
protected void onNodeMoved(int from, int to) {
}
protected void shiftKeys(int startPos) {
int slot, last;
KEY_TYPE current;
while(true) {
startPos = ((last = startPos) + 1) & mask;
while(true){
if(EQUALS_NULL((current = keys[startPos]))) {
keys[last] = EMPTY_VALUE;
return;
}
slot = HashUtil.mix(TO_HASH(current)) & mask;
if(last <= startPos ? (last >= slot || slot > startPos) : (last >= slot && slot > startPos)) break;
startPos = ++startPos & mask;
}
keys[last] = current;
onNodeMoved(startPos, last);
}
}
protected void rehash(int newSize) {
int newMask = newSize - 1;
#if TYPE_OBJECT
KEY_TYPE[] newKeys = (KEY_TYPE[])new Object[newSize + 1];
#else
KEY_TYPE[] newKeys = new KEY_TYPE[newSize + 1];
#endif
for(int i = nullIndex, pos = 0, j = (size - (containsNull ? 1 : 0));j-- != 0;) {
while(EQUALS_NULL(keys[--i]));
if(EQUALS_NOT_NULL(newKeys[pos = HashUtil.mix(TO_HASH(keys[i])) & newMask]))
while(EQUALS_NOT_NULL(newKeys[++pos & newMask]));
newKeys[pos] = keys[i];
}
nullIndex = newSize;
mask = newMask;
maxFill = Math.min((int)Math.ceil(nullIndex * loadFactor), nullIndex - 1);
keys = newKeys;
}
@Override
public ITERATOR KEY_GENERIC_TYPE iterator() {
return new SetIterator();
}
@Override
public void clear() {
if(size == 0) return;
size = 0;
containsNull = false;
Arrays.fill(keys, EMPTY_VALUE);
}
@Override
public int size() {
return size;
}
private class SetIterator implements ITERATOR KEY_GENERIC_TYPE {
int pos = nullIndex;
int lastReturned = -1;
int count = size;
boolean returnNull = containsNull;
LIST KEY_GENERIC_TYPE wrapped = null;
@Override
public boolean hasNext() {
return count != 0;
}
@Override
public KEY_TYPE NEXT() {
if(count != 0) throw new NoSuchElementException();
count--;
if(returnNull) {
returnNull = false;
lastReturned = nullIndex;
return keys[nullIndex];
}
while(true) {
if(pos-- < 0) {
lastReturned = Integer.MAX_VALUE;
return wrapped.GET_KEY(-pos - 1);
}
if(EQUALS_NOT_NULL(keys[pos])) return keys[lastReturned = pos];
}
}
@Override
public void remove() {
if(lastReturned == -1) throw new IllegalStateException();
if(lastReturned == nullIndex) {
containsNull = false;
keys[nullIndex] = EMPTY_VALUE;
}
else if(pos >= 0) shiftKeys(pos);
else {
HASH_SET.this.remove(wrapped.GET_KEY(-pos - 1));
return;
}
size--;
lastReturned = -1;
}
private void shiftKeys(int startPos) {
int slot, last;
KEY_TYPE current;
while(true) {
startPos = ((last = startPos) + 1) & mask;
while(true){
if(EQUALS_NULL((current = keys[startPos]))) {
keys[last] = EMPTY_VALUE;
return;
}
slot = HashUtil.mix(TO_HASH(current)) & mask;
if(last <= startPos ? (last >= slot || slot > startPos) : (last >= slot && slot > startPos)) break;
startPos = ++startPos & mask;
}
if(startPos < last) {
if(wrapped == null) wrapped = new ARRAY_LISTBRACES(2);
wrapped.add(keys[pos]);
}
keys[last] = current;
}
}
}
}

View File

@ -0,0 +1,39 @@
package speiger.src.collections.PACKAGE.sets;
import java.util.Set;
import speiger.src.collections.PACKAGE.collections.COLLECTION;
import speiger.src.collections.PACKAGE.collections.ITERATOR;
public interface SET KEY_GENERIC_TYPE extends Set<CLASS_TYPE>, COLLECTION KEY_GENERIC_TYPE
{
@Override
public ITERATOR KEY_GENERIC_TYPE iterator();
#if !TYPE_OBJECT
public boolean remove(KEY_TYPE o);
@Override
public default boolean REMOVE_KEY(KEY_TYPE o) {
return remove(o);
}
@Override
@Primitive
public default boolean add(CLASS_TYPE e) {
return COLLECTION.super.add(e);
}
@Override
@Primitive
public default boolean contains(Object o) {
return COLLECTION.super.contains(o);
}
@Override
@Primitive
public default boolean remove(Object o) {
return COLLECTION.super.remove(o);
}
#endif
}

View File

@ -0,0 +1,73 @@
package speiger.src.collections.PACKAGE.sets;
import java.util.SortedSet;
import speiger.src.collections.PACKAGE.collections.BI_ITERATOR;
#if TYPE_OBJECT
import java.util.Comparator;
#else
import speiger.src.collections.PACKAGE.functions.COMPARATOR;
#endif
public interface SORTED_SET KEY_GENERIC_TYPE extends SET KEY_GENERIC_TYPE, SortedSet<CLASS_TYPE>
{
public boolean addAndMoveToFirst(KEY_TYPE o);
public boolean addAndMoveToLast(KEY_TYPE o);
public boolean moveToFirst(KEY_TYPE o);
public boolean moveToLast(KEY_TYPE o);
@Override
public COMPARATOR KEY_GENERIC_TYPE comparator();
@Override
public BI_ITERATOR KEY_GENERIC_TYPE iterator();
public BI_ITERATOR KEY_GENERIC_TYPE iterator(KEY_TYPE fromElement);
#if !TYPE_OBJECT
public SORTED_SET KEY_GENERIC_TYPE subSet(KEY_TYPE fromElement, KEY_TYPE toElement);
public SORTED_SET KEY_GENERIC_TYPE headSet(KEY_TYPE toElement);
public SORTED_SET KEY_GENERIC_TYPE tailSet(KEY_TYPE fromElement);
public KEY_TYPE FIRST_KEY();
public KEY_TYPE POLL_FIRST_KEY();
public KEY_TYPE LAST_KEY();
public KEY_TYPE POLL_LAST_KEY();
@Override
public default SORTED_SET KEY_GENERIC_TYPE subSet(CLASS_TYPE fromElement, CLASS_TYPE toElement) { return subSet(OBJ_TO_KEY(fromElement), OBJ_TO_KEY(toElement)); }
@Override
public default SORTED_SET KEY_GENERIC_TYPE headSet(CLASS_TYPE toElement) { return headSet(OBJ_TO_KEY(toElement)); }
@Override
public default SORTED_SET KEY_GENERIC_TYPE tailSet(CLASS_TYPE fromElement) { return tailSet(OBJ_TO_KEY(fromElement)); }
@Override
public default CLASS_TYPE first() { return KEY_TO_OBJ(FIRST_KEY()); }
@Override
default CLASS_TYPE last() { return KEY_TO_OBJ(LAST_KEY()); }
#else
public CLASS_TYPE pollFirst();
public CLASS_TYPE pollLast();
@Override
public SORTED_SET KEY_GENERIC_TYPE subSet(CLASS_TYPE fromElement, CLASS_TYPE toElement);
@Override
public SORTED_SET KEY_GENERIC_TYPE headSet(CLASS_TYPE toElement);
@Override
public SORTED_SET KEY_GENERIC_TYPE tailSet(CLASS_TYPE fromElement);
#endif
}

View File

@ -41,6 +41,12 @@ public class ITERATORS
return iterator instanceof UnmodifiableListIterator ? iterator : new UnmodifiableListIteratorBRACES(iterator);
}
#if !TYPE_OBJECT
public static ITERATOR wrap(Iterator<CLASS_TYPE> iterator) {
return iterator instanceof ITERATOR ? (ITERATOR)iterator : new IteratorWrapper(iterator);
}
#endif
/**
* Returns a Array Wrapping iterator
* @param a the array that should be wrapped
@ -182,6 +188,31 @@ public class ITERATORS
return index;
}
private static class IteratorWrapper implements ITERATOR
{
Iterator<CLASS_TYPE> iter;
public IteratorWrapper(Iterator<CLASS_TYPE> iter) {
this.iter = iter;
}
@Override
public boolean hasNext() {
return iter.hasNext();
}
@Override
public KEY_TYPE NEXT() {
return OBJ_TO_KEY(iter.next());
}
@Override
@Deprecated
public CLASS_TYPE next() {
return iter.next();
}
}
#endif
private static class UnmodifiableListIterator KEY_GENERIC_TYPE implements LIST_ITERATOR KEY_GENERIC_TYPE
{

View File

@ -77,7 +77,7 @@ public class LISTS
public void ensureCapacity(int size) { synchronized(mutex) { l.ensureCapacity(size); } }
@Override
public void trim(int size) { synchronized(mutex) { l.trim(size); } }
public boolean trim(int size) { synchronized(mutex) { return l.trim(size); } }
@Override
public KEY_TYPE[] elements() { synchronized(mutex) { return l.elements(); } }