forked from Speiger/Primitive-Collections
New Sets
-Added: Custom HashSet (Normal, Linked) -Added: ArraySet -Fixed: A bug in AbstractList.SubList
This commit is contained in:
parent
16efec5ca4
commit
c8fc84bf88
|
@ -73,13 +73,16 @@ public class GlobalVariables
|
|||
|
||||
//Final Classes
|
||||
addClassMapper("ARRAY_LIST", "ArrayList");
|
||||
addClassMapper("LINKED_CUSTOM_HASH_SET", "LinkedOpenCustomHashSet");
|
||||
addClassMapper("LINKED_HASH_SET", "LinkedOpenHashSet");
|
||||
addClassMapper("CUSTOM_HASH_SET", "OpenCustomHashSet");
|
||||
addClassMapper("HASH_SET", "OpenHashSet");
|
||||
addClassMapper("ARRAY_SET", "ArraySet");
|
||||
|
||||
//Abstract Classes
|
||||
addClassMapper("ABSTRACT_COLLECTION", "AbstractCollection");
|
||||
addClassMapper("ABSTRACT_SET", "AbstractSet");
|
||||
addClassMapper("ABSTRACT_LIST", "AbstractList");
|
||||
addAbstractMapper("ABSTRACT_COLLECTION", "Abstract%sCollection");
|
||||
addAbstractMapper("ABSTRACT_SET", "Abstract%sSet");
|
||||
addAbstractMapper("ABSTRACT_LIST", "Abstract%sList");
|
||||
addClassMapper("SUB_LIST", "SubList");
|
||||
|
||||
//Helper Classes
|
||||
|
@ -94,9 +97,11 @@ public class GlobalVariables
|
|||
addClassMapper("ITERATOR", "Iterator");
|
||||
addClassMapper("ITERABLE", "Iterable");
|
||||
addClassMapper("COLLECTION", "Collection");
|
||||
addClassMapper("LIST_ITER", "ListIter");
|
||||
addClassMapper("LIST", "List");
|
||||
addClassMapper("SORTED_SET", "SortedSet");
|
||||
addClassMapper("SET", "Set");
|
||||
addClassMapper("STRATEGY", "Strategy");
|
||||
addClassMapper("STACK", "Stack");
|
||||
if(type.isObject())
|
||||
{
|
||||
|
@ -111,7 +116,6 @@ public class GlobalVariables
|
|||
addFunctionMappers("IARRAY", "I%sArray");
|
||||
}
|
||||
//Dependency
|
||||
addClassMapper("LIST_ITER", "ListIter");
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -169,6 +173,11 @@ public class GlobalVariables
|
|||
operators.add(new SimpleMapper(pattern, type.getFileType()+replacement));
|
||||
}
|
||||
|
||||
private void addAbstractMapper(String pattern, String replacement)
|
||||
{
|
||||
operators.add(new SimpleMapper(pattern, String.format(replacement, type.getFileType())));
|
||||
}
|
||||
|
||||
private void addFunctionMapper(String pattern, String replacement)
|
||||
{
|
||||
operators.add(new SimpleMapper(pattern, replacement+type.getNonFileType()));
|
||||
|
|
|
@ -53,6 +53,9 @@ public class TestBuilder extends TemplateProcessor
|
|||
varibles.add(type);
|
||||
}
|
||||
nameRemapper.put("IArray", "I%sArray");
|
||||
nameRemapper.put("AbstractCollection", "Abstract%sCollection");
|
||||
nameRemapper.put("AbstractSet", "Abstract%sSet");
|
||||
nameRemapper.put("AbstractList", "Abstract%sList");
|
||||
blocked.put("Consumer", EnumSet.of(ClassType.OBJECT));
|
||||
blocked.put("Comparator", EnumSet.of(ClassType.OBJECT));
|
||||
blocked.put("Stack", EnumSet.of(ClassType.OBJECT));
|
||||
|
|
|
@ -366,6 +366,7 @@ public abstract class ABSTRACT_LIST KEY_GENERIC_TYPE extends ABSTRACT_COLLECTION
|
|||
|
||||
@Override
|
||||
public KEY_TYPE NEXT() {
|
||||
lastReturned = index;
|
||||
return GET_KEY(index++);
|
||||
}
|
||||
|
||||
|
@ -376,6 +377,7 @@ public abstract class ABSTRACT_LIST KEY_GENERIC_TYPE extends ABSTRACT_COLLECTION
|
|||
|
||||
@Override
|
||||
public KEY_TYPE PREVIOUS() {
|
||||
lastReturned = index;
|
||||
return GET_KEY(index--);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,567 @@
|
|||
package speiger.src.collections.PACKAGE.sets;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
#if TYPE_OBJECT
|
||||
import java.util.Comparator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
#else
|
||||
import java.util.NoSuchElementException;
|
||||
#endif
|
||||
import java.util.Set;
|
||||
|
||||
import speiger.src.collections.PACKAGE.collections.BI_ITERATOR;
|
||||
import speiger.src.collections.PACKAGE.collections.COLLECTION;
|
||||
#if !TYPE_OBJECT
|
||||
import speiger.src.collections.PACKAGE.functions.COMPARATOR;
|
||||
#endif
|
||||
import speiger.src.collections.PACKAGE.lists.LIST_ITERATOR;
|
||||
import speiger.src.collections.PACKAGE.utils.ARRAYS;
|
||||
|
||||
public class ARRAY_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE implements SORTED_SET KEY_GENERIC_TYPE
|
||||
{
|
||||
protected transient KEY_TYPE[] data;
|
||||
protected int size = 0;
|
||||
|
||||
public ARRAY_SET() {
|
||||
#if TYPE_OBJECT
|
||||
data = (KEY_TYPE[])ARRAYS.EMPTY_ARRAY;
|
||||
#else
|
||||
data = ARRAYS.EMPTY_ARRAY;
|
||||
#endif
|
||||
}
|
||||
|
||||
public ARRAY_SET(int capacity) {
|
||||
#if TYPE_OBJECT
|
||||
data = (KEY_TYPE[])new Object[capacity];
|
||||
#else
|
||||
data = new KEY_TYPE[capacity];
|
||||
#endif
|
||||
}
|
||||
|
||||
public ARRAY_SET(KEY_TYPE[] array) {
|
||||
this(array, array.length);
|
||||
}
|
||||
|
||||
public ARRAY_SET(KEY_TYPE[] array, int length) {
|
||||
data = array;
|
||||
size = length;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public ARRAY_SET(Collection<? extends CLASS_TYPE> c) {
|
||||
this(c.size());
|
||||
addAll(c);
|
||||
}
|
||||
|
||||
public ARRAY_SET(COLLECTION KEY_GENERIC_TYPE c) {
|
||||
this(c.size());
|
||||
addAll(c);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public ARRAY_SET(Set<? extends CLASS_TYPE> s) {
|
||||
this(s.size());
|
||||
for(CLASS_TYPE e : s)
|
||||
data[size++] = OBJ_TO_KEY(e);
|
||||
}
|
||||
|
||||
public ARRAY_SET(SET KEY_GENERIC_TYPE s) {
|
||||
this(s.size());
|
||||
for(KEY_TYPE e : s)
|
||||
data[size++] = e;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(KEY_TYPE o) {
|
||||
int index = findIndex(o);
|
||||
if(index == -1) {
|
||||
if(data.length == size) data = Arrays.copyOf(data, size == 0 ? 2 : size * 2);
|
||||
data[size++] = o;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAndMoveToFirst(KEY_TYPE o) {
|
||||
int index = findIndex(o);
|
||||
if(index == -1) {
|
||||
if(data.length == size) data = Arrays.copyOf(data, size == 0 ? 2 : size * 2);
|
||||
System.arraycopy(data, 0, data, 1, size++);
|
||||
data[0] = o;
|
||||
return true;
|
||||
}
|
||||
else if(index != 0) {
|
||||
o = data[index];
|
||||
System.arraycopy(data, 0, data, 1, index);
|
||||
data[index] = o;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAndMoveToLast(KEY_TYPE o) {
|
||||
int index = findIndex(o);
|
||||
if(index == -1) {
|
||||
if(data.length == size) data = Arrays.copyOf(data, size == 0 ? 2 : size * 2);
|
||||
data[size++] = o;
|
||||
return true;
|
||||
}
|
||||
else if(index != size - 1) {
|
||||
o = data[index];
|
||||
System.arraycopy(data, index+1, data, index, size - index);
|
||||
data[size] = o;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean moveToFirst(KEY_TYPE o) {
|
||||
int index = findIndex(o);
|
||||
if(index > 0) {
|
||||
o = data[index];
|
||||
System.arraycopy(data, 0, data, 1, index);
|
||||
data[index] = o;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean moveToLast(KEY_TYPE o) {
|
||||
int index = findIndex(o);
|
||||
if(index != -1 && index != size - 1) {
|
||||
o = data[index];
|
||||
System.arraycopy(data, index+1, data, index, size - index);
|
||||
data[size] = o;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#if !TYPE_OBJECT
|
||||
@Override
|
||||
public boolean contains(KEY_TYPE e) {
|
||||
return findIndex(e) != -1;
|
||||
}
|
||||
|
||||
#else
|
||||
@Override
|
||||
public boolean contains(Object e) {
|
||||
return findIndex((KEY_TYPE)e) != -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
@Override
|
||||
public KEY_TYPE FIRST_KEY() {
|
||||
if(size == 0) throw new NoSuchElementException();
|
||||
return data[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public KEY_TYPE LAST_KEY() {
|
||||
if(size == 0) throw new NoSuchElementException();
|
||||
return data[size - 1];
|
||||
}
|
||||
|
||||
#if !TYPE_OBJECT
|
||||
@Override
|
||||
public boolean remove(KEY_TYPE o) {
|
||||
int index = findIndex(o);
|
||||
if(index != -1) {
|
||||
System.arraycopy(data, index+1, data, index, size - index);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#else
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
int index = findIndex((KEY_TYPE)o);
|
||||
if(index != -1) {
|
||||
System.arraycopy(data, index+1, data, index, size - index);
|
||||
data[size-1] = EMPTY_VALUE;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
@Override
|
||||
public KEY_TYPE POLL_FIRST_KEY() {
|
||||
if(size == 0) throw new NoSuchElementException();
|
||||
KEY_TYPE result = data[0];
|
||||
System.arraycopy(data, 1, data, 0, size);
|
||||
#if TYPE_OBJECT
|
||||
data[size-1] = EMPTY_VALUE;
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KEY_TYPE POLL_LAST_KEY() {
|
||||
if(size == 0) throw new NoSuchElementException();
|
||||
#if TYPE_OBJECT
|
||||
KEY_TYPE result = data[size-1];
|
||||
data[size-1] = EMPTY_VALUE;
|
||||
return result;
|
||||
#else
|
||||
return data[--size];
|
||||
#endif
|
||||
}
|
||||
|
||||
protected int findIndex(KEY_TYPE o) {
|
||||
for(int i = size-1;i>=0;i--)
|
||||
if(EQUALS(data[i], o)) return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BI_ITERATOR KEY_GENERIC_TYPE iterator() {
|
||||
return new SetIterator(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BI_ITERATOR KEY_GENERIC_TYPE iterator(KEY_TYPE fromElement) {
|
||||
int index = findIndex(fromElement);
|
||||
if(index != -1) return new SetIterator(index);
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SORTED_SET KEY_GENERIC_TYPE subSet(KEY_TYPE fromElement, KEY_TYPE toElement) {
|
||||
int fromIndex = findIndex(fromElement);
|
||||
int toIndex = findIndex(toElement);
|
||||
if(fromIndex == -1 || toIndex == -1) throw new NoSuchElementException();
|
||||
return new SubSet(fromIndex, toIndex - fromIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SORTED_SET KEY_GENERIC_TYPE headSet(KEY_TYPE toElement) {
|
||||
int toIndex = findIndex(toElement);
|
||||
if(toIndex == -1) throw new NoSuchElementException();
|
||||
return new SubSet(0, toIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SORTED_SET KEY_GENERIC_TYPE tailSet(KEY_TYPE fromElement) {
|
||||
int fromIndex = findIndex(fromElement);
|
||||
if(fromIndex == -1) throw new NoSuchElementException();
|
||||
return new SubSet(fromIndex, size - fromIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public COMPARATOR KEY_GENERIC_TYPE comparator() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
size = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
private class SubSet extends ABSTRACT_SET KEY_GENERIC_TYPE implements SORTED_SET KEY_GENERIC_TYPE {
|
||||
int offset;
|
||||
int length;
|
||||
|
||||
SubSet(int offset, int length) {
|
||||
this.offset = offset;
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(KEY_TYPE o) {
|
||||
int index = findIndex(o);
|
||||
if(index != -1) {
|
||||
if(data.length == size) data = Arrays.copyOf(data, size == 0 ? 2 : size * 2);
|
||||
System.arraycopy(data, (offset+length), data, (offset+length)+1, size-(offset+length));
|
||||
data[offset+length] = o;
|
||||
size++;
|
||||
length++;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAndMoveToFirst(KEY_TYPE o) {
|
||||
int index = findIndex(o);
|
||||
if(index == -1) {
|
||||
if(data.length == size) data = Arrays.copyOf(data, size == 0 ? 2 : size * 2);
|
||||
System.arraycopy(data, offset, data, offset+1, size-offset);
|
||||
data[offset] = o;
|
||||
size++;
|
||||
length++;
|
||||
return true;
|
||||
}
|
||||
else if(index != 0) {
|
||||
o = data[index];
|
||||
System.arraycopy(data, offset, data, offset+1, index-offset);
|
||||
data[offset] = o;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAndMoveToLast(KEY_TYPE o) {
|
||||
int index = findIndex(o);
|
||||
if(index == -1) {
|
||||
if(data.length == size) data = Arrays.copyOf(data, size == 0 ? 2 : size * 2);
|
||||
System.arraycopy(data, (offset+length)+1, data, (offset+length), size-(offset+length));
|
||||
data[offset+length] = o;
|
||||
size++;
|
||||
length++;
|
||||
return true;
|
||||
}
|
||||
else if(index != 0) {
|
||||
o = data[index];
|
||||
System.arraycopy(data, offset+1, data, offset, index-offset);
|
||||
data[offset+length] = o;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean moveToFirst(KEY_TYPE o) {
|
||||
int index = findIndex(o);
|
||||
if(index != -1 && index != offset) {
|
||||
o = data[index];
|
||||
System.arraycopy(data, offset, data, offset+1, index-offset);
|
||||
data[offset] = o;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean moveToLast(KEY_TYPE o) {
|
||||
int index = findIndex(o);
|
||||
if(index != -1 && index != (offset+length) - 1) {
|
||||
o = data[index];
|
||||
System.arraycopy(data, offset+1, data, offset, index-offset);
|
||||
data[offset+length] = o;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#if !TYPE_OBJECT
|
||||
@Override
|
||||
public boolean contains(KEY_TYPE e) {
|
||||
return findIndex(e) != -1;
|
||||
}
|
||||
|
||||
#else
|
||||
@Override
|
||||
public boolean contains(Object e) {
|
||||
return findIndex((KEY_TYPE)e) != -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
@Override
|
||||
public KEY_TYPE FIRST_KEY() {
|
||||
if(length == 0) throw new NoSuchElementException();
|
||||
return data[offset];
|
||||
}
|
||||
|
||||
@Override
|
||||
public KEY_TYPE LAST_KEY() {
|
||||
if(length == 0) throw new NoSuchElementException();
|
||||
return data[(offset + length) - 1];
|
||||
}
|
||||
|
||||
#if !TYPE_OBJECT
|
||||
@Override
|
||||
public boolean remove(KEY_TYPE o) {
|
||||
int index = findIndex(o);
|
||||
if(index != -1) {
|
||||
System.arraycopy(data, index+1, data, index, size - index);
|
||||
size--;
|
||||
length--;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#else
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
int index = findIndex((KEY_TYPE)o);
|
||||
if(index != -1) {
|
||||
System.arraycopy(data, index+1, data, index, size - index);
|
||||
data[size-1] = EMPTY_VALUE;
|
||||
size--;
|
||||
length--;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
@Override
|
||||
public KEY_TYPE POLL_FIRST_KEY() {
|
||||
if(length == 0) throw new NoSuchElementException();
|
||||
KEY_TYPE result = data[offset];
|
||||
System.arraycopy(data, offset+1, data, offset, size-offset);
|
||||
#if TYPE_OBJECT
|
||||
data[size-1] = EMPTY_VALUE;
|
||||
#endif
|
||||
size--;
|
||||
length--;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KEY_TYPE POLL_LAST_KEY() {
|
||||
if(length == 0) throw new NoSuchElementException();
|
||||
KEY_TYPE result = data[offset+length];
|
||||
System.arraycopy(data, (offset+length)+1, data, (offset+length), size-(offset+length));
|
||||
#if TYPE_OBJECT
|
||||
data[size-1] = EMPTY_VALUE;
|
||||
#endif
|
||||
size--;
|
||||
length--;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public COMPARATOR KEY_GENERIC_TYPE comparator() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BI_ITERATOR KEY_GENERIC_TYPE iterator() {
|
||||
return new SetIterator(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BI_ITERATOR KEY_GENERIC_TYPE iterator(KEY_TYPE fromElement) {
|
||||
int index = findIndex(fromElement);
|
||||
if(index != -1) return new SetIterator(index);
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SORTED_SET KEY_GENERIC_TYPE subSet(KEY_TYPE fromElement, KEY_TYPE toElement) {
|
||||
int fromIndex = findIndex(fromElement);
|
||||
int toIndex = findIndex(toElement);
|
||||
if(fromIndex == -1 || toIndex == -1) throw new NoSuchElementException();
|
||||
return new SubSet(fromIndex, toIndex - fromIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SORTED_SET KEY_GENERIC_TYPE headSet(KEY_TYPE toElement) {
|
||||
int toIndex = findIndex(toElement);
|
||||
if(toIndex == -1) throw new NoSuchElementException();
|
||||
return new SubSet(0, toIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SORTED_SET KEY_GENERIC_TYPE tailSet(KEY_TYPE fromElement) {
|
||||
int fromIndex = findIndex(fromElement);
|
||||
if(fromIndex == -1) throw new NoSuchElementException();
|
||||
return new SubSet(fromIndex, size - fromIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return length;
|
||||
}
|
||||
|
||||
private int findIndex(KEY_TYPE o) {
|
||||
for(int i = length-1;i>=0;i--)
|
||||
if(data[offset+i] == o) return i + offset;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private class SetIterator implements LIST_ITERATOR KEY_GENERIC_TYPE {
|
||||
int index;
|
||||
int lastReturned = -1;
|
||||
|
||||
public SetIterator(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return index < size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public KEY_TYPE NEXT() {
|
||||
lastReturned = index;
|
||||
return data[index++];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPrevious() {
|
||||
return index > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KEY_TYPE PREVIOUS() {
|
||||
lastReturned = index;
|
||||
return data[index--];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int nextIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int previousIndex() {
|
||||
return index-1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
if(lastReturned == -1)
|
||||
throw new IllegalStateException();
|
||||
ARRAY_SET.this.remove(data[lastReturned]);
|
||||
if(lastReturned < index)
|
||||
index--;
|
||||
lastReturned = -1;
|
||||
}
|
||||
|
||||
#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
|
||||
@Override
|
||||
public int skip(int amount) {
|
||||
if(amount < 0) throw new IllegalStateException("Negative Numbers are not allowed");
|
||||
int steps = Math.min(amount, (size() - 1) - index);
|
||||
index += steps;
|
||||
return steps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int back(int amount) {
|
||||
if(amount < 0) throw new IllegalStateException("Negative Numbers are not allowed");
|
||||
int steps = Math.min(amount, index);
|
||||
index -= steps;
|
||||
return steps;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,560 @@
|
|||
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;
|
||||
|
||||
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.PACKAGE.utils.STRATEGY;
|
||||
import speiger.src.collections.utils.HashUtil;
|
||||
import speiger.src.collections.utils.SanityChecks;
|
||||
|
||||
public class LINKED_CUSTOM_HASH_SET KEY_GENERIC_TYPE extends CUSTOM_HASH_SET KEY_GENERIC_TYPE implements SORTED_SET KEY_GENERIC_TYPE
|
||||
{
|
||||
protected long[] links;
|
||||
protected int firstIndex = -1;
|
||||
protected int lastIndex = -1;
|
||||
|
||||
public LINKED_CUSTOM_HASH_SET(STRATEGY KEY_SUPER_GENERIC_TYPE strategy) {
|
||||
this(HashUtil.DEFAULT_MIN_CAPACITY, HashUtil.DEFAULT_LOAD_FACTOR, strategy);
|
||||
}
|
||||
|
||||
public LINKED_CUSTOM_HASH_SET(int minCapacity, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) {
|
||||
this(minCapacity, HashUtil.DEFAULT_LOAD_FACTOR, strategy);
|
||||
}
|
||||
|
||||
public LINKED_CUSTOM_HASH_SET(int minCapacity, float loadFactor, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) {
|
||||
super(minCapacity, loadFactor, strategy);
|
||||
links = new long[nullIndex + 1];
|
||||
}
|
||||
|
||||
public LINKED_CUSTOM_HASH_SET(KEY_TYPE[] array, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) {
|
||||
this(array, 0, array.length, HashUtil.DEFAULT_LOAD_FACTOR, strategy);
|
||||
}
|
||||
|
||||
public LINKED_CUSTOM_HASH_SET(KEY_TYPE[] array, float loadFactor, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) {
|
||||
this(array, 0, array.length, loadFactor, strategy);
|
||||
}
|
||||
|
||||
public LINKED_CUSTOM_HASH_SET(KEY_TYPE[] array, int offset, int length, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) {
|
||||
this(array, offset, length, HashUtil.DEFAULT_LOAD_FACTOR, strategy);
|
||||
}
|
||||
|
||||
public LINKED_CUSTOM_HASH_SET(KEY_TYPE[] array, int offset, int length, float loadFactor, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) {
|
||||
this(length < 0 ? 0 : length, strategy);
|
||||
SanityChecks.checkArrayCapacity(array.length, offset, length);
|
||||
for(int i = 0;i<length;i++) add(array[offset+i]);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public LINKED_CUSTOM_HASH_SET(Collection<? extends CLASS_TYPE> collection, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) {
|
||||
this(collection, HashUtil.DEFAULT_LOAD_FACTOR, strategy);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public LINKED_CUSTOM_HASH_SET(Collection<? extends CLASS_TYPE> collection, float loadFactor, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) {
|
||||
this(collection.size(), loadFactor, strategy);
|
||||
addAll(collection);
|
||||
}
|
||||
|
||||
public LINKED_CUSTOM_HASH_SET(COLLECTION KEY_GENERIC_TYPE collection, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) {
|
||||
this(collection, HashUtil.DEFAULT_LOAD_FACTOR, strategy);
|
||||
}
|
||||
|
||||
public LINKED_CUSTOM_HASH_SET(COLLECTION KEY_GENERIC_TYPE collection, float loadFactor, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) {
|
||||
this(collection.size(), strategy);
|
||||
addAll(collection);
|
||||
}
|
||||
|
||||
public LINKED_CUSTOM_HASH_SET(Iterator<CLASS_TYPE> iterator, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) {
|
||||
this(iterator, HashUtil.DEFAULT_LOAD_FACTOR, strategy);
|
||||
}
|
||||
|
||||
public LINKED_CUSTOM_HASH_SET(Iterator<CLASS_TYPE> iterator, float loadFactor, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) {
|
||||
#if !TYPE_OBJECT
|
||||
this(ITERATORS.wrap(iterator), loadFactor, strategy);
|
||||
#else
|
||||
this(HashUtil.DEFAULT_MIN_CAPACITY, loadFactor, strategy);
|
||||
while(iterator.hasNext()) add(iterator.next());
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !TYPE_OBJECT
|
||||
public LINKED_CUSTOM_HASH_SET(ITERATOR KEY_GENERIC_TYPE iterator, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) {
|
||||
this(iterator, HashUtil.DEFAULT_LOAD_FACTOR, strategy);
|
||||
}
|
||||
|
||||
public LINKED_CUSTOM_HASH_SET(ITERATOR KEY_GENERIC_TYPE iterator, float loadFactor, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) {
|
||||
this(HashUtil.DEFAULT_MIN_CAPACITY, loadFactor, strategy);
|
||||
while(iterator.hasNext()) add(iterator.NEXT());
|
||||
}
|
||||
|
||||
#endif
|
||||
@Override
|
||||
public boolean addAndMoveToFirst(KEY_TYPE o) {
|
||||
if(strategy.equals(o, EMPTY_VALUE)) {
|
||||
if(containsNull) {
|
||||
moveToFirstIndex(nullIndex);
|
||||
return false;
|
||||
}
|
||||
containsNull = true;
|
||||
onNodeAdded(nullIndex);
|
||||
}
|
||||
else {
|
||||
int pos = HashUtil.mix(strategy.hashCode(o)) & mask;
|
||||
while(!strategy.equals(keys[pos], EMPTY_VALUE)) {
|
||||
if(strategy.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(strategy.equals(o, EMPTY_VALUE)) {
|
||||
if(containsNull) {
|
||||
moveToLastIndex(nullIndex);
|
||||
return false;
|
||||
}
|
||||
containsNull = true;
|
||||
onNodeAdded(nullIndex);
|
||||
}
|
||||
else {
|
||||
int pos = HashUtil.mix(strategy.hashCode(o)) & mask;
|
||||
while(!strategy.equals(keys[pos], EMPTY_VALUE)) {
|
||||
if(strategy.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(strategy.equals(o, EMPTY_VALUE)) {
|
||||
if(containsNull) {
|
||||
moveToFirstIndex(nullIndex);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
int pos = HashUtil.mix(strategy.hashCode(o)) & mask;
|
||||
while(!strategy.equals(keys[pos], EMPTY_VALUE)) {
|
||||
if(strategy.equals(keys[pos], o)) {
|
||||
moveToFirstIndex(pos);
|
||||
return true;
|
||||
}
|
||||
pos = ++pos & mask;
|
||||
}
|
||||
keys[pos] = o;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean moveToLast(KEY_TYPE o) {
|
||||
if(strategy.equals(o, EMPTY_VALUE)) {
|
||||
if(containsNull) {
|
||||
moveToLastIndex(nullIndex);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
int pos = HashUtil.mix(strategy.hashCode(o)) & mask;
|
||||
while(!strategy.equals(keys[pos], EMPTY_VALUE)) {
|
||||
if(strategy.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] = 0xFFFFFFFF00000000L | (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) | 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(strategy.equals(result, EMPTY_VALUE)) {
|
||||
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(strategy.equals(result, EMPTY_VALUE)) {
|
||||
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(strategy.equals(keys[i], EMPTY_VALUE)) pos = newSize;
|
||||
else {
|
||||
pos = HashUtil.mix(strategy.hashCode(keys[i])) & newMask;
|
||||
while(!strategy.equals(newKeys[pos], EMPTY_VALUE)) 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(strategy.equals(from, EMPTY_VALUE)) {
|
||||
if(containsNull) {
|
||||
next = (int) links[nullIndex];
|
||||
previous = nullIndex;
|
||||
}
|
||||
else throw new NoSuchElementException("The null element is not in the set");
|
||||
}
|
||||
else if(strategy.equals(keys[lastIndex], from)) {
|
||||
previous = lastIndex;
|
||||
index = size;
|
||||
}
|
||||
else {
|
||||
int pos = HashUtil.mix(strategy.hashCode(from)) & mask;
|
||||
while(!strategy.equals(keys[pos], EMPTY_VALUE)) {
|
||||
if(strategy.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(strategy.equals((current = keys[startPos]), EMPTY_VALUE)) {
|
||||
keys[last] = EMPTY_VALUE;
|
||||
return;
|
||||
}
|
||||
slot = HashUtil.mix(strategy.hashCode(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
|
||||
}
|
||||
}
|
|
@ -210,13 +210,13 @@ public class LINKED_HASH_SET KEY_GENERIC_TYPE extends HASH_SET KEY_GENERIC_TYPE
|
|||
}
|
||||
else {
|
||||
long link = links[startPos];
|
||||
int prev = (int) ( link >>> 32 );
|
||||
int next = (int) link;
|
||||
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);
|
||||
links[startPos] = 0xFFFFFFFF00000000L | (firstIndex & 0xFFFFFFFFL);
|
||||
firstIndex = startPos;
|
||||
}
|
||||
|
||||
|
@ -234,7 +234,7 @@ public class LINKED_HASH_SET KEY_GENERIC_TYPE extends HASH_SET KEY_GENERIC_TYPE
|
|||
links[next] ^= ((links[next] ^ (link & 0xFFFFFFFF00000000L)) & 0xFFFFFFFF00000000L);
|
||||
}
|
||||
links[lastIndex] ^= ((links[lastIndex] ^ (startPos & 0xFFFFFFFFL)) & 0xFFFFFFFFL);
|
||||
links[startPos] = ((lastIndex & 0xFFFFFFFFL) << 32) | (-1 & 0xFFFFFFFFL);
|
||||
links[startPos] = ((lastIndex & 0xFFFFFFFFL) << 32) | 0xFFFFFFFFL;
|
||||
lastIndex = startPos;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,384 @@
|
|||
package speiger.src.collections.PACKAGE.sets;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
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.PACKAGE.utils.STRATEGY;
|
||||
|
||||
import speiger.src.collections.utils.HashUtil;
|
||||
import speiger.src.collections.utils.ITrimmable;
|
||||
import speiger.src.collections.utils.SanityChecks;
|
||||
|
||||
public class CUSTOM_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;
|
||||
protected final STRATEGY KEY_SUPER_GENERIC_TYPE strategy;
|
||||
|
||||
public CUSTOM_HASH_SET(STRATEGY KEY_SUPER_GENERIC_TYPE strategy) {
|
||||
this(HashUtil.DEFAULT_MIN_CAPACITY, HashUtil.DEFAULT_LOAD_FACTOR, strategy);
|
||||
}
|
||||
|
||||
public CUSTOM_HASH_SET(int minCapacity, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) {
|
||||
this(minCapacity, HashUtil.DEFAULT_LOAD_FACTOR, strategy);
|
||||
}
|
||||
|
||||
public CUSTOM_HASH_SET(int minCapacity, float loadFactor, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) {
|
||||
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
|
||||
this.strategy = strategy;
|
||||
}
|
||||
|
||||
public CUSTOM_HASH_SET(KEY_TYPE[] array, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) {
|
||||
this(array, 0, array.length, HashUtil.DEFAULT_LOAD_FACTOR, strategy);
|
||||
}
|
||||
|
||||
public CUSTOM_HASH_SET(KEY_TYPE[] array, float loadFactor, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) {
|
||||
this(array, 0, array.length, loadFactor, strategy);
|
||||
}
|
||||
|
||||
public CUSTOM_HASH_SET(KEY_TYPE[] array, int offset, int length, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) {
|
||||
this(array, offset, length, HashUtil.DEFAULT_LOAD_FACTOR, strategy);
|
||||
}
|
||||
|
||||
public CUSTOM_HASH_SET(KEY_TYPE[] array, int offset, int length, float loadFactor, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) {
|
||||
this(length < 0 ? 0 : length, strategy);
|
||||
SanityChecks.checkArrayCapacity(array.length, offset, length);
|
||||
for(int i = 0;i<length;i++) add(array[offset+i]);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public CUSTOM_HASH_SET(Collection<? extends CLASS_TYPE> collection, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) {
|
||||
this(collection, HashUtil.DEFAULT_LOAD_FACTOR, strategy);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public CUSTOM_HASH_SET(Collection<? extends CLASS_TYPE> collection, float loadFactor, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) {
|
||||
this(collection.size(), loadFactor, strategy);
|
||||
addAll(collection);
|
||||
}
|
||||
|
||||
public CUSTOM_HASH_SET(COLLECTION KEY_GENERIC_TYPE collection, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) {
|
||||
this(collection, HashUtil.DEFAULT_LOAD_FACTOR, strategy);
|
||||
}
|
||||
|
||||
public CUSTOM_HASH_SET(COLLECTION KEY_GENERIC_TYPE collection, float loadFactor, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) {
|
||||
this(collection.size(), strategy);
|
||||
addAll(collection);
|
||||
}
|
||||
|
||||
public CUSTOM_HASH_SET(Iterator<CLASS_TYPE> iterator, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) {
|
||||
this(iterator, HashUtil.DEFAULT_LOAD_FACTOR, strategy);
|
||||
}
|
||||
|
||||
public CUSTOM_HASH_SET(Iterator<CLASS_TYPE> iterator, float loadFactor, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) {
|
||||
#if !TYPE_OBJECT
|
||||
this(ITERATORS.wrap(iterator), loadFactor, strategy);
|
||||
#else
|
||||
this(HashUtil.DEFAULT_MIN_CAPACITY, loadFactor, strategy);
|
||||
while(iterator.hasNext()) add(iterator.next());
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !TYPE_OBJECT
|
||||
public CUSTOM_HASH_SET(ITERATOR KEY_GENERIC_TYPE iterator, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) {
|
||||
this(iterator, HashUtil.DEFAULT_LOAD_FACTOR, strategy);
|
||||
}
|
||||
|
||||
public CUSTOM_HASH_SET(ITERATOR KEY_GENERIC_TYPE iterator, float loadFactor, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) {
|
||||
this(HashUtil.DEFAULT_MIN_CAPACITY, loadFactor, strategy);
|
||||
while(iterator.hasNext()) add(iterator.NEXT());
|
||||
}
|
||||
|
||||
#endif
|
||||
public STRATEGY KEY_SUPER_GENERIC_TYPE getStrategy() {
|
||||
return strategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(KEY_TYPE o) {
|
||||
if(strategy.equals(o, EMPTY_VALUE)) {
|
||||
if(containsNull) return false;
|
||||
containsNull = true;
|
||||
onNodeAdded(nullIndex);
|
||||
}
|
||||
else {
|
||||
int pos = HashUtil.mix(strategy.hashCode(o)) & mask;
|
||||
KEY_TYPE current = keys[pos];
|
||||
if(!strategy.equals(current, EMPTY_VALUE)) {
|
||||
if(strategy.equals(current, o)) return false;
|
||||
while(!strategy.equals((current = keys[++pos & mask]), EMPTY_VALUE))
|
||||
if(strategy.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(strategy.equals((KEY_TYPE)o, EMPTY_VALUE)) return containsNull;
|
||||
int pos = HashUtil.mix(strategy.hashCode((KEY_TYPE)o)) & mask;
|
||||
KEY_TYPE current = keys[pos];
|
||||
if(!strategy.equals(current, EMPTY_VALUE)) return false;
|
||||
if(strategy.equals(current, (KEY_TYPE)o)) return true;
|
||||
while(true) {
|
||||
if(strategy.equals((current = keys[++pos & mask]), EMPTY_VALUE)) return false;
|
||||
else if(strategy.equals(current, (KEY_TYPE)o)) return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
if(strategy.equals((KEY_TYPE)o, EMPTY_VALUE)) return (containsNull ? removeNullIndex() : false);
|
||||
int pos = HashUtil.mix(strategy.hashCode((KEY_TYPE)o)) & mask;
|
||||
KEY_TYPE current = keys[pos];
|
||||
if(!strategy.equals(current, EMPTY_VALUE)) return false;
|
||||
if(strategy.equals(current, (KEY_TYPE)o)) return removeIndex(pos);
|
||||
while(true) {
|
||||
if(strategy.equals((current = keys[++pos & mask]), EMPTY_VALUE)) return false;
|
||||
else if(strategy.equals(current, (KEY_TYPE)o)) return removeIndex(pos);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
@Override
|
||||
public boolean contains(KEY_TYPE o) {
|
||||
if(strategy.equals(o, EMPTY_VALUE)) return containsNull;
|
||||
int pos = HashUtil.mix(strategy.hashCode(o)) & mask;
|
||||
KEY_TYPE current = keys[pos];
|
||||
if(!strategy.equals(current, EMPTY_VALUE)) return false;
|
||||
if(strategy.equals(current, o)) return true;
|
||||
while(true) {
|
||||
if(strategy.equals((current = keys[++pos & mask]), EMPTY_VALUE)) return false;
|
||||
else if(strategy.equals(current, o)) return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(KEY_TYPE o) {
|
||||
if(strategy.equals(o, EMPTY_VALUE)) return (containsNull ? removeNullIndex() : false);
|
||||
int pos = HashUtil.mix(strategy.hashCode(o)) & mask;
|
||||
KEY_TYPE current = keys[pos];
|
||||
if(!strategy.equals(current, EMPTY_VALUE)) return false;
|
||||
if(strategy.equals(current, o)) return removeIndex(pos);
|
||||
while(true) {
|
||||
if(strategy.equals((current = keys[++pos & mask]), EMPTY_VALUE)) return false;
|
||||
else if(strategy.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(strategy.equals((current = keys[startPos]), EMPTY_VALUE)) {
|
||||
keys[last] = EMPTY_VALUE;
|
||||
return;
|
||||
}
|
||||
slot = HashUtil.mix(strategy.hashCode(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(strategy.equals(keys[--i], EMPTY_VALUE));
|
||||
if(!strategy.equals(newKeys[pos = HashUtil.mix(TO_HASH(keys[i])) & newMask], EMPTY_VALUE))
|
||||
while(!strategy.equals(newKeys[++pos & newMask], EMPTY_VALUE));
|
||||
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(!strategy.equals(keys[pos], EMPTY_VALUE)) 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 {
|
||||
CUSTOM_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(strategy.equals((current = keys[startPos]), EMPTY_VALUE)) {
|
||||
keys[last] = EMPTY_VALUE;
|
||||
return;
|
||||
}
|
||||
slot = HashUtil.mix(strategy.hashCode(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package speiger.src.collections.PACKAGE.utils;
|
||||
|
||||
public interface STRATEGY KEY_GENERIC_TYPE
|
||||
{
|
||||
public int hashCode(KEY_TYPE o);
|
||||
|
||||
public boolean equals(KEY_TYPE key, KEY_TYPE value);
|
||||
}
|
Loading…
Reference in New Issue