We are now to 16k tests. Fixed loads of issues.

-Added: Tests for Lists and Sets.
-Fixed: SubLists are now stable (they weren't before)
-Fixed: All the bugs that the unit tests found so far.
-Updated: ReadMe/Changelog
This commit is contained in:
Speiger 2021-12-11 12:53:58 +01:00
parent eaa45976c7
commit e1df59d512
24 changed files with 747 additions and 219 deletions

View File

@ -28,6 +28,9 @@
- Fixed: CustomOpenHashMap.keySet.forEach was basically putting out keys even if they were present - Fixed: CustomOpenHashMap.keySet.forEach was basically putting out keys even if they were present
- Fixed: ImmutableMaps issues thanks to the tests. Roughly the same as the rest of the maps - Fixed: ImmutableMaps issues thanks to the tests. Roughly the same as the rest of the maps
- Fixed: RB/AVLTreeMaps issues. Roughly the same as the rest of the maps - Fixed: RB/AVLTreeMaps issues. Roughly the same as the rest of the maps
- Fixed: SubLists are now properly implemented.
- Fixed: HashSet Iterator bugs now fixed... That was Painful.
- Added: Tests for Lists and Sets
### Version 0.4.5 ### Version 0.4.5
- Added: removeAll/retainAll(Collection c, Consumer r) which receives all the elements that got deleted from the collection - Added: removeAll/retainAll(Collection c, Consumer r) which receives all the elements that got deleted from the collection

View File

@ -19,6 +19,21 @@ But its focus is a different one.
- Suppliers - Suppliers
- Bi/Consumers - Bi/Consumers
## Current Level of Stability
Since this is a relatively new Library, stability was not perfect and some areas are not perfect yet.
Thanks to @ben-manes we now have Roughly 16000 test covering Maps/Sets/Lists.
These tests cover Javas Collection API completely and ensuring a Stable implementation.
These freshly added tests allowed me to squash thousands of issues according to Googles Test Library (Guava-Tests).
These will be expanded on as time goes on.
One know aspect of Instability is SubSets and SubMaps. They require full rewrites to be fully stable.
So it is not advised to use them until these issues are addressed.
PriorityQueues are tested separately and ensure basic functionality though GuavaTests are planned.
They just require a custom implementation to run.
As a summary: Stability is good/excellent, unless you need SubSets/SubMaps
## Specialized Functions ## Specialized Functions
New Specialized functions that were added to increase performance or reduce allocations or Quality Of life. New Specialized functions that were added to increase performance or reduce allocations or Quality Of life.
To highlight things that may be wanted. To highlight things that may be wanted.
@ -121,5 +136,5 @@ to build the jar:
do not combine the commands because they can not be executed at the same time. do not combine the commands because they can not be executed at the same time.
## Current Down Sides (Random order) ## Current Down Sides (Random order)
- Testing for Sub Maps/Sets/Lists are only in a very basic way tested - SubMaps/Set implementation isn't perfect right now. This will be addressed slowly due to rewrites required.
- Documentation is only present at the lowest level for most cases and needs a typo fixing. - Documentation is only present at the lowest level for most cases and needs a typo fixing.

View File

@ -3,11 +3,15 @@ package speiger.src.collections.PACKAGE.lists;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.ListIterator; import java.util.ListIterator;
import java.util.NoSuchElementException;
import java.util.Objects; import java.util.Objects;
import speiger.src.collections.PACKAGE.collections.ABSTRACT_COLLECTION; import speiger.src.collections.PACKAGE.collections.ABSTRACT_COLLECTION;
import speiger.src.collections.PACKAGE.collections.COLLECTION; import speiger.src.collections.PACKAGE.collections.COLLECTION;
import speiger.src.collections.PACKAGE.collections.ITERATOR; import speiger.src.collections.PACKAGE.collections.ITERATOR;
import speiger.src.collections.PACKAGE.collections.SPLIT_ITERATOR;
import speiger.src.collections.PACKAGE.utils.SPLIT_ITERATORS;
import speiger.src.collections.utils.SanityChecks;
/** /**
* Abstract implementation of the {@link LIST} interface. * Abstract implementation of the {@link LIST} interface.
@ -15,9 +19,8 @@ import speiger.src.collections.PACKAGE.collections.ITERATOR;
*/ */
public abstract class ABSTRACT_LIST KEY_GENERIC_TYPE extends ABSTRACT_COLLECTION KEY_GENERIC_TYPE implements LIST KEY_GENERIC_TYPE public abstract class ABSTRACT_LIST KEY_GENERIC_TYPE extends ABSTRACT_COLLECTION KEY_GENERIC_TYPE implements LIST KEY_GENERIC_TYPE
{ {
#if !TYPE_OBJECT
/** /**
* A Type-Specific implementation of add function that delegates to {@link #add(int, KEY_TYPE)} * A Type-Specific implementation of add function that delegates to {@link List#add(int, Object)}
*/ */
@Override @Override
public boolean add(KEY_TYPE e) { public boolean add(KEY_TYPE e) {
@ -25,6 +28,7 @@ public abstract class ABSTRACT_LIST KEY_GENERIC_TYPE extends ABSTRACT_COLLECTION
return true; return true;
} }
#if !TYPE_OBJECT
/** {@inheritDoc} /** {@inheritDoc}
* <p>This default implementation delegates to the corresponding type-specific function. * <p>This default implementation delegates to the corresponding type-specific function.
* @deprecated Please use the corresponding type-specific function instead. * @deprecated Please use the corresponding type-specific function instead.
@ -213,7 +217,8 @@ public abstract class ABSTRACT_LIST KEY_GENERIC_TYPE extends ABSTRACT_COLLECTION
@Override @Override
public LIST KEY_GENERIC_TYPE subList(int fromIndex, int toIndex) { public LIST KEY_GENERIC_TYPE subList(int fromIndex, int toIndex) {
return new SUB_LIST(this, fromIndex, toIndex); SanityChecks.checkArrayCapacity(size(), fromIndex, toIndex-fromIndex);
return new SubList(this, 0, fromIndex, toIndex);
} }
@Override @Override
@ -228,6 +233,7 @@ public abstract class ABSTRACT_LIST KEY_GENERIC_TYPE extends ABSTRACT_COLLECTION
@Override @Override
public LIST_ITERATOR KEY_GENERIC_TYPE listIterator(int index) { public LIST_ITERATOR KEY_GENERIC_TYPE listIterator(int index) {
if(index < 0 || index > size()) throw new IndexOutOfBoundsException();
return new LIST_ITER(index); return new LIST_ITER(index);
} }
@ -239,134 +245,128 @@ public abstract class ABSTRACT_LIST KEY_GENERIC_TYPE extends ABSTRACT_COLLECTION
public ABSTRACT_LIST KEY_GENERIC_TYPE copy() { throw new UnsupportedOperationException(); } public ABSTRACT_LIST KEY_GENERIC_TYPE copy() { throw new UnsupportedOperationException(); }
private class SUB_LIST extends ABSTRACT_LIST KEY_GENERIC_TYPE { private class SubList extends ABSTRACT_LIST KEY_GENERIC_TYPE
ABSTRACT_LIST KEY_GENERIC_TYPE l; {
int offset; final ABSTRACT_LIST KEY_GENERIC_TYPE list;
final int parentOffset;
final int offset;
int size; int size;
SUB_LIST(ABSTRACT_LIST KEY_GENERIC_TYPE l, int from, int to) { public SubList(ABSTRACT_LIST KEY_GENERIC_TYPE list, int offset, int from, int to) {
if (from < 0) throw new IndexOutOfBoundsException("fromIndex = " + from); this.list = list;
else if (to > l.size()) throw new IndexOutOfBoundsException("toIndex = " + to); this.parentOffset = from;
else if (from > to) throw new IllegalArgumentException("fromIndex(" + from + ") > toIndex(" + to + ")"); this.offset = offset + from;
this.l = l; this.size = to - from;
offset = from;
size = to - from;
} }
@Override @Override
public void add(int index, KEY_TYPE e) { public void add(int index, KEY_TYPE element) {
checkAddRange(index); checkAddSubRange(index);
l.add(index+offset, e); list.add(parentOffset+index, element);
size++; size++;
} }
@Override @Override
public boolean addAll(int index, Collection<? extends CLASS_TYPE> c) { public boolean addAll(int index, Collection<? extends CLASS_TYPE> c) {
checkAddRange(index); checkAddSubRange(index);
int size = c.size(); int add = c.size();
if(size == 0) return false; if(add <= 0) return false;
l.addAll(index + offset, l); list.addAll(parentOffset+index, c);
offset += size; this.size += add;
return true; return true;
} }
@Override @Override
public boolean addAll(int index, COLLECTION KEY_GENERIC_TYPE c) { public boolean addAll(int index, COLLECTION KEY_GENERIC_TYPE c) {
checkAddRange(index); checkAddSubRange(index);
int size = c.size(); int add = c.size();
if(size == 0) return false; if(add <= 0) return false;
l.addAll(index + offset, l); list.addAll(parentOffset+index, c);
offset += size; this.size += add;
return true; return true;
} }
@Override @Override
public boolean addAll(int index, LIST KEY_GENERIC_TYPE c) { public boolean addAll(int index, LIST KEY_GENERIC_TYPE c) {
checkAddRange(index); checkAddSubRange(index);
int size = c.size(); int add = c.size();
if(size == 0) return false; if(add <= 0) return false;
l.addAll(index + offset, l); list.addAll(parentOffset+index, c);
offset += size; this.size += add;
return true;
}
@Override
public boolean addAll(KEY_TYPE[] e, int offset, int length) {
if(length <= 0) return false;
l.addElements(this.offset, e, offset, length);
offset += length;
return true; return true;
} }
@Override @Override
public void addElements(int from, KEY_TYPE[] a, int offset, int length) { public void addElements(int from, KEY_TYPE[] a, int offset, int length) {
checkRange(from); checkAddSubRange(from);
l.addElements(from + this.offset, a, offset, length); if(length <= 0) return;
size += length; list.addElements(parentOffset+from, a, offset, length);
this.size += length;
} }
@Override @Override
public KEY_TYPE[] getElements(int from, KEY_TYPE[] a, int offset, int length) { public KEY_TYPE[] getElements(int from, KEY_TYPE[] a, int offset, int length) {
checkRange(from); SanityChecks.checkArrayCapacity(size, from, length);
return l.getElements(from + this.offset, a, offset, length); SanityChecks.checkArrayCapacity(a.length, offset, length);
return list.getElements(from+this.offset, a, offset, length);
} }
@Override @Override
public void removeElements(int from, int to) { public void removeElements(int from, int to) {
checkRange(from); if(to-from <= 0) return;
checkRange(to); checkSubRange(from);
l.removeElements(from + offset, to + offset); checkSubRange(to);
list.removeElements(from+parentOffset, to+parentOffset);
size -= to - from; size -= to - from;
} }
#if TYPE_OBJECT #if TYPE_OBJECT
@Override @Override
public <K> K[] extractElements(int from, int to, Class<K> clz) { public <K> K[] extractElements(int from, int to, Class<K> type) {
checkRange(from); checkSubRange(from);
checkRange(to); checkSubRange(to);
K[] a = l.extractElements(from + offset, to + offset, clz); K[] result = list.extractElements(from+parentOffset, to+parentOffset, type);
size -= to - from; size -= to - from;
return a; return result;
} }
#else #else
@Override @Override
public KEY_TYPE[] extractElements(int from, int to) { public KEY_TYPE[] extractElements(int from, int to) {
checkRange(from); checkSubRange(from);
checkRange(to); checkSubRange(to);
KEY_TYPE[] a = l.extractElements(from + offset, to + offset); KEY_TYPE[] result = list.extractElements(from+parentOffset, to+parentOffset);
size -= to - from; size -= to - from;
return a; return result;
} }
#endif #endif
@Override @Override
public KEY_TYPE GET_KEY(int index) { public KEY_TYPE GET_KEY(int index) {
checkRange(index); checkSubRange(index);
return l.GET_KEY(index + offset); return list.GET_KEY(offset+index);
} }
@Override @Override
public KEY_TYPE set(int index, KEY_TYPE e) { public KEY_TYPE set(int index, KEY_TYPE element) {
checkRange(index); checkSubRange(index);
return l.set(index + offset, e); return list.set(offset+index, element);
}
@Override
public KEY_TYPE swapRemove(int index) {
checkSubRange(index);
KEY_TYPE result = list.swapRemove(index+parentOffset);
size--;
return result;
} }
@Override @Override
public KEY_TYPE REMOVE(int index) { public KEY_TYPE REMOVE(int index) {
checkRange(index); checkSubRange(index);
int temp = l.size(); KEY_TYPE result = list.REMOVE(index+parentOffset);
KEY_TYPE type = l.REMOVE(index + offset); size--;
if(l.size() != temp) size--; return result;
return type;
}
public KEY_TYPE swapRemove(int index) {
checkRange(index);
int temp = l.size();
KEY_TYPE type = l.swapRemove(index + offset);
if(l.size() != temp) size--;
return type;
} }
@Override @Override
@ -374,15 +374,112 @@ public abstract class ABSTRACT_LIST KEY_GENERIC_TYPE extends ABSTRACT_COLLECTION
return size; return size;
} }
private void checkRange(int index) { @Override
public SPLIT_ITERATOR KEY_GENERIC_TYPE spliterator() { return SPLIT_ITERATORS.createSplititerator(this, 16464); }
@Override
public LIST_ITERATOR KEY_GENERIC_TYPE listIterator(int index) {
if(index < 0 || index > size()) throw new IndexOutOfBoundsException();
return new SubListIterator(this, index);
}
@Override
public LIST KEY_GENERIC_TYPE subList(int fromIndex, int toIndex) {
SanityChecks.checkArrayCapacity(size, fromIndex, toIndex-fromIndex);
return new SubList(list, offset, fromIndex, toIndex);
}
protected void checkSubRange(int index) {
if (index < 0 || index >= size) if (index < 0 || index >= size)
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
} }
private void checkAddRange(int index) { protected void checkAddSubRange(int index) {
if (index < 0 || index > size) if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
} }
private class SubListIterator implements LIST_ITERATOR KEY_GENERIC_TYPE
{
ABSTRACT_LIST KEY_GENERIC_TYPE list;
int index;
int lastReturned = -1;
SubListIterator(ABSTRACT_LIST KEY_GENERIC_TYPE list, int index) {
this.list = list;
this.index = index;
}
@Override
public boolean hasNext() {
return index < list.size();
}
@Override
public KEY_TYPE NEXT() {
if(!hasNext()) throw new NoSuchElementException();
int i = index++;
return list.GET_KEY((lastReturned = i));
}
@Override
public boolean hasPrevious() {
return index > 0;
}
@Override
public KEY_TYPE PREVIOUS() {
if(!hasPrevious()) throw new NoSuchElementException();
index--;
return list.GET_KEY((lastReturned = index));
}
@Override
public int nextIndex() {
return index;
}
@Override
public int previousIndex() {
return index-1;
}
@Override
public void remove() {
if(lastReturned == -1) throw new IllegalStateException();
list.REMOVE(lastReturned);
index = lastReturned;
lastReturned = -1;
}
@Override
public void set(KEY_TYPE e) {
if(lastReturned == -1) throw new IllegalStateException();
list.set(lastReturned, e);
}
@Override
public void add(KEY_TYPE e) {
list.add(index++, e);
lastReturned = -1;
}
@Override
public int skip(int amount) {
if(amount < 0) throw new IllegalStateException("Negative Numbers are not allowed");
int steps = Math.min(amount, (list.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;
}
}
} }
private class LIST_ITER implements LIST_ITERATOR KEY_GENERIC_TYPE { private class LIST_ITER implements LIST_ITERATOR KEY_GENERIC_TYPE {
@ -400,8 +497,9 @@ public abstract class ABSTRACT_LIST KEY_GENERIC_TYPE extends ABSTRACT_COLLECTION
@Override @Override
public KEY_TYPE NEXT() { public KEY_TYPE NEXT() {
lastReturned = index; if(!hasNext()) throw new NoSuchElementException();
return GET_KEY(index++); int i = index++;
return GET_KEY((lastReturned = i));
} }
@Override @Override
@ -411,8 +509,9 @@ public abstract class ABSTRACT_LIST KEY_GENERIC_TYPE extends ABSTRACT_COLLECTION
@Override @Override
public KEY_TYPE PREVIOUS() { public KEY_TYPE PREVIOUS() {
lastReturned = index; if(!hasPrevious()) throw new NoSuchElementException();
return GET_KEY(index--); index--;
return GET_KEY((lastReturned = index));
} }
@Override @Override
@ -427,25 +526,20 @@ public abstract class ABSTRACT_LIST KEY_GENERIC_TYPE extends ABSTRACT_COLLECTION
@Override @Override
public void remove() { public void remove() {
if(lastReturned == -1) if(lastReturned == -1) throw new IllegalStateException();
throw new IllegalStateException();
ABSTRACT_LIST.this.REMOVE(lastReturned); ABSTRACT_LIST.this.REMOVE(lastReturned);
if(lastReturned < index) index = lastReturned;
index--;
lastReturned = -1; lastReturned = -1;
} }
@Override @Override
public void set(KEY_TYPE e) { public void set(KEY_TYPE e) {
if(lastReturned == -1) if(lastReturned == -1) throw new IllegalStateException();
throw new IllegalStateException();
ABSTRACT_LIST.this.set(lastReturned, e); ABSTRACT_LIST.this.set(lastReturned, e);
} }
@Override @Override
public void add(KEY_TYPE e) { public void add(KEY_TYPE e) {
if(lastReturned == -1)
throw new IllegalStateException();
ABSTRACT_LIST.this.add(index++, e); ABSTRACT_LIST.this.add(index++, e);
lastReturned = -1; lastReturned = -1;
} }

View File

@ -1029,6 +1029,7 @@ public class ARRAY_LIST KEY_GENERIC_TYPE extends ABSTRACT_LIST KEY_GENERIC_TYPE
for(int i = 0;i<size;i++) for(int i = 0;i<size;i++)
a[i] = (E)KEY_TO_OBJ(data[i]); a[i] = (E)KEY_TO_OBJ(data[i]);
#endif #endif
if (a.length > size) a[size] = null;
return a; return a;
} }
@ -1037,6 +1038,7 @@ public class ARRAY_LIST KEY_GENERIC_TYPE extends ABSTRACT_LIST KEY_GENERIC_TYPE
public KEY_TYPE[] TO_ARRAY(KEY_TYPE[] a) { public KEY_TYPE[] TO_ARRAY(KEY_TYPE[] a) {
if(a.length < size) a = new KEY_TYPE[size]; if(a.length < size) a = new KEY_TYPE[size];
System.arraycopy(data, 0, a, 0, size); System.arraycopy(data, 0, a, 0, size);
if (a.length > size) a[size] = EMPTY_KEY_VALUE;
return a; return a;
} }
@ -1138,6 +1140,7 @@ public class ARRAY_LIST KEY_GENERIC_TYPE extends ABSTRACT_LIST KEY_GENERIC_TYPE
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
} }
#if PRIMITIVES #if PRIMITIVES
/** /**
* Returns a Java-Type-Specific Stream to reduce boxing/unboxing. * Returns a Java-Type-Specific Stream to reduce boxing/unboxing.

View File

@ -5,6 +5,7 @@ import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
#endif #endif
import java.util.Collection; import java.util.Collection;
import java.util.NoSuchElementException;
import java.util.Objects; import java.util.Objects;
#if TYPE_OBJECT #if TYPE_OBJECT
import java.util.function.BiFunction; import java.util.function.BiFunction;
@ -381,6 +382,12 @@ public class IMMUTABLE_LIST KEY_GENERIC_TYPE extends ABSTRACT_LIST KEY_GENERIC_T
return result; return result;
} }
@Override
public LIST_ITERATOR KEY_GENERIC_TYPE listIterator(int index) {
if(index < 0 || index > size()) throw new IndexOutOfBoundsException();
return new LIST_ITER(index);
}
@Override @Override
public KEY_TYPE set(int index, KEY_TYPE e) { throw new UnsupportedOperationException(); } public KEY_TYPE set(int index, KEY_TYPE e) { throw new UnsupportedOperationException(); }
@Override @Override
@ -447,6 +454,7 @@ public class IMMUTABLE_LIST KEY_GENERIC_TYPE extends ABSTRACT_LIST KEY_GENERIC_T
else if(a.length < data.length) a = (E[])ObjectArrays.newArray(a.getClass().getComponentType(), data.length); else if(a.length < data.length) a = (E[])ObjectArrays.newArray(a.getClass().getComponentType(), data.length);
for(int i = 0,m=data.length;i<m;i++) for(int i = 0,m=data.length;i<m;i++)
a[i] = (E)KEY_TO_OBJ(data[i]); a[i] = (E)KEY_TO_OBJ(data[i]);
if (a.length > data.length) a[data.length] = null;
return a; return a;
} }
@ -455,6 +463,7 @@ public class IMMUTABLE_LIST KEY_GENERIC_TYPE extends ABSTRACT_LIST KEY_GENERIC_T
public KEY_TYPE[] TO_ARRAY(KEY_TYPE[] a) { public KEY_TYPE[] TO_ARRAY(KEY_TYPE[] a) {
if(a.length < data.length) a = new KEY_TYPE[data.length]; if(a.length < data.length) a = new KEY_TYPE[data.length];
System.arraycopy(data, 0, a, 0, data.length); System.arraycopy(data, 0, a, 0, data.length);
if (a.length > data.length) a[data.length] = EMPTY_KEY_VALUE;
return a; return a;
} }
@ -495,4 +504,69 @@ public class IMMUTABLE_LIST KEY_GENERIC_TYPE extends ABSTRACT_LIST KEY_GENERIC_T
*/ */
@Override @Override
public SPLIT_ITERATOR KEY_GENERIC_TYPE spliterator() { return SPLIT_ITERATORS.createArraySplititerator(data, data.length, 16464); } public SPLIT_ITERATOR KEY_GENERIC_TYPE spliterator() { return SPLIT_ITERATORS.createArraySplititerator(data, data.length, 16464); }
private class LIST_ITER implements LIST_ITERATOR KEY_GENERIC_TYPE {
int index;
LIST_ITER(int index) {
this.index = index;
}
@Override
public boolean hasNext() {
return index < size();
}
@Override
public KEY_TYPE NEXT() {
if(!hasNext()) throw new NoSuchElementException();
return GET_KEY(index++);
}
@Override
public boolean hasPrevious() {
return index > 0;
}
@Override
public KEY_TYPE PREVIOUS() {
if(!hasPrevious()) throw new NoSuchElementException();
return GET_KEY(--index);
}
@Override
public int nextIndex() {
return index;
}
@Override
public int previousIndex() {
return index-1;
}
@Override
public void remove() { throw new UnsupportedOperationException(); }
@Override
public void set(KEY_TYPE e) { throw new UnsupportedOperationException(); }
@Override
public void add(KEY_TYPE e) { throw new UnsupportedOperationException(); }
@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;
}
}
} }

View File

@ -9,6 +9,7 @@ import java.nio.JAVA_BUFFER;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.Objects; import java.util.Objects;
import java.util.NoSuchElementException;
import java.util.Spliterator; import java.util.Spliterator;
#if PRIMITIVES #if PRIMITIVES
import java.util.Spliterator.JAVA_SPLIT_ITERATOR; import java.util.Spliterator.JAVA_SPLIT_ITERATOR;
@ -326,9 +327,8 @@ public class LINKED_LIST KEY_GENERIC_TYPE extends ABSTRACT_LIST KEY_GENERIC_TYPE
@Override @Override
@Primitive @Primitive
public int indexOf(Object o) { public int indexOf(Object o) {
if(o == null) return -1;
Entry KEY_GENERIC_TYPE entry = first; Entry KEY_GENERIC_TYPE entry = first;
for(int i = 0;entry != null;entry = entry.next) { for(int i = 0;entry != null;entry = entry.next,i++) {
if(Objects.equals(KEY_TO_OBJ(entry.value), o)) return i; if(Objects.equals(KEY_TO_OBJ(entry.value), o)) return i;
} }
return -1; return -1;
@ -337,9 +337,8 @@ public class LINKED_LIST KEY_GENERIC_TYPE extends ABSTRACT_LIST KEY_GENERIC_TYPE
@Override @Override
@Primitive @Primitive
public int lastIndexOf(Object o) { public int lastIndexOf(Object o) {
if(o == null) return -1;
Entry KEY_GENERIC_TYPE entry = last; Entry KEY_GENERIC_TYPE entry = last;
for(int i = size-1;entry != null;entry = entry.prev) { for(int i = size-1;entry != null;entry = entry.prev,i--) {
if(Objects.equals(KEY_TO_OBJ(entry.value), o)) return i; if(Objects.equals(KEY_TO_OBJ(entry.value), o)) return i;
} }
return -1; return -1;
@ -354,7 +353,7 @@ public class LINKED_LIST KEY_GENERIC_TYPE extends ABSTRACT_LIST KEY_GENERIC_TYPE
@Override @Override
public int indexOf(KEY_TYPE e) { public int indexOf(KEY_TYPE e) {
Entry entry = first; Entry entry = first;
for(int i = 0;entry != null;entry = entry.next) { for(int i = 0;entry != null;entry = entry.next,i++) {
if(KEY_EQUALS(entry.value, e)) return i; if(KEY_EQUALS(entry.value, e)) return i;
} }
return -1; return -1;
@ -363,26 +362,17 @@ public class LINKED_LIST KEY_GENERIC_TYPE extends ABSTRACT_LIST KEY_GENERIC_TYPE
@Override @Override
public int lastIndexOf(KEY_TYPE e) { public int lastIndexOf(KEY_TYPE e) {
Entry entry = last; Entry entry = last;
for(int i = size-1;entry != null;entry = entry.prev) { for(int i = size-1;entry != null;entry = entry.prev,i--) {
if(KEY_EQUALS(entry.value, e)) return i; if(KEY_EQUALS(entry.value, e)) return i;
} }
return -1; return -1;
} }
#endif #endif
@Override
public ITERATOR KEY_GENERIC_TYPE iterator() {
return new ListIter(first, 0);
}
@Override
public LIST_ITERATOR KEY_GENERIC_TYPE listIterator() {
return new ListIter(first, 0);
}
@Override @Override
public LIST_ITERATOR KEY_GENERIC_TYPE listIterator(int index) { public LIST_ITERATOR KEY_GENERIC_TYPE listIterator(int index) {
if(index == size-1) return new ListIter(last, index); if(index < 0 || index > size()) throw new IndexOutOfBoundsException();
if(index == size) return new ListIter(null, index);
if(index == 0) return new ListIter(first, index); if(index == 0) return new ListIter(first, index);
return new ListIter(getNode(index), index); return new ListIter(getNode(index), index);
} }
@ -564,7 +554,7 @@ public class LINKED_LIST KEY_GENERIC_TYPE extends ABSTRACT_LIST KEY_GENERIC_TYPE
@Override @Override
public boolean removeFirst(KEY_TYPE e) { public boolean removeFirst(KEY_TYPE e) {
if(size == 0) return false; if(size == 0) return false;
for(Entry KEY_GENERIC_TYPE entry = first;entry.next != null;entry = entry.next) { for(Entry KEY_GENERIC_TYPE entry = first;entry != null;entry = entry.next) {
if(KEY_EQUALS(entry.value, e)) { if(KEY_EQUALS(entry.value, e)) {
unlink(entry); unlink(entry);
return true; return true;
@ -576,7 +566,7 @@ public class LINKED_LIST KEY_GENERIC_TYPE extends ABSTRACT_LIST KEY_GENERIC_TYPE
@Override @Override
public boolean removeLast(KEY_TYPE e) { public boolean removeLast(KEY_TYPE e) {
if(size == 0) return false; if(size == 0) return false;
for(Entry KEY_GENERIC_TYPE entry = last;entry.prev != null;entry = entry.prev) { for(Entry KEY_GENERIC_TYPE entry = last;entry != null;entry = entry.prev) {
if(KEY_EQUALS(entry.value, e)) { if(KEY_EQUALS(entry.value, e)) {
unlink(entry); unlink(entry);
return true; return true;
@ -615,7 +605,7 @@ public class LINKED_LIST KEY_GENERIC_TYPE extends ABSTRACT_LIST KEY_GENERIC_TYPE
@Override @Override
public boolean REMOVE_SWAP(KEY_TYPE e) { public boolean REMOVE_SWAP(KEY_TYPE e) {
if(size == 0) return false; if(size == 0) return false;
for(Entry KEY_GENERIC_TYPE entry = last;entry.prev != null;entry = entry.prev) { for(Entry KEY_GENERIC_TYPE entry = last;entry != null;entry = entry.prev) {
if(KEY_EQUALS(entry.value, e)) { if(KEY_EQUALS(entry.value, e)) {
if(entry.next == null) { if(entry.next == null) {
unlinkLast(entry); unlinkLast(entry);
@ -649,7 +639,7 @@ public class LINKED_LIST KEY_GENERIC_TYPE extends ABSTRACT_LIST KEY_GENERIC_TYPE
@Override @Override
public boolean remove(Object e) { public boolean remove(Object e) {
if(size <= 0) return false; if(size <= 0) return false;
for(Entry KEY_GENERIC_TYPE entry = first;entry.next != null;entry = entry.next) { for(Entry KEY_GENERIC_TYPE entry = first;entry != null;entry = entry.next) {
if(KEY_EQUALS(entry.value, e)) { if(KEY_EQUALS(entry.value, e)) {
unlink(entry); unlink(entry);
return true; return true;
@ -949,6 +939,7 @@ public class LINKED_LIST KEY_GENERIC_TYPE extends ABSTRACT_LIST KEY_GENERIC_TYPE
for(Entry KEY_GENERIC_TYPE entry = first;entry != null;entry = entry.next) { for(Entry KEY_GENERIC_TYPE entry = first;entry != null;entry = entry.next) {
a[i++] = (E)KEY_TO_OBJ(entry.value); a[i++] = (E)KEY_TO_OBJ(entry.value);
} }
if (a.length > size) a[size] = null;
return a; return a;
} }
@ -958,8 +949,9 @@ public class LINKED_LIST KEY_GENERIC_TYPE extends ABSTRACT_LIST KEY_GENERIC_TYPE
if(a.length < size) a = new KEY_TYPE[size]; if(a.length < size) a = new KEY_TYPE[size];
int i = 0; int i = 0;
for(Entry KEY_GENERIC_TYPE entry = first;entry != null;entry = entry.next) { for(Entry KEY_GENERIC_TYPE entry = first;entry != null;entry = entry.next) {
a[i++] = KEY_TO_OBJ(entry.value); a[i++] = entry.value;
} }
if (a.length > size) a[size] = EMPTY_KEY_VALUE;
return a; return a;
} }
@ -1118,23 +1110,23 @@ public class LINKED_LIST KEY_GENERIC_TYPE extends ABSTRACT_LIST KEY_GENERIC_TYPE
private class ListIter implements LIST_ITERATOR KEY_GENERIC_TYPE private class ListIter implements LIST_ITERATOR KEY_GENERIC_TYPE
{ {
Entry KEY_GENERIC_TYPE node; Entry KEY_GENERIC_TYPE next;
Entry KEY_GENERIC_TYPE lastReturned; Entry KEY_GENERIC_TYPE lastReturned;
int index; int index;
ListIter(Entry KEY_GENERIC_TYPE node, int index) { ListIter(Entry KEY_GENERIC_TYPE next, int index) {
this.node = node; this.next = next;
this.index = index; this.index = index;
} }
@Override @Override
public boolean hasNext() { public boolean hasNext() {
return node != null; return index < size;
} }
@Override @Override
public boolean hasPrevious() { public boolean hasPrevious() {
return node != null; return index > 0;
} }
@Override @Override
@ -1150,23 +1142,26 @@ public class LINKED_LIST KEY_GENERIC_TYPE extends ABSTRACT_LIST KEY_GENERIC_TYPE
@Override @Override
public void remove() { public void remove() {
if(lastReturned == null) throw new IllegalStateException(); if(lastReturned == null) throw new IllegalStateException();
if(lastReturned.next == node) index--; Entry KEY_GENERIC_TYPE lastNext = lastReturned.next;
unlink(lastReturned); unlink(lastReturned);
if (next == lastReturned) next = lastNext;
else index--;
lastReturned = null; lastReturned = null;
} }
@Override @Override
public KEY_TYPE PREVIOUS() { public KEY_TYPE PREVIOUS() {
lastReturned = node; if(!hasPrevious()) throw new NoSuchElementException();
node = node.prev; lastReturned = next = (next == null) ? last : next.prev;
index--; index--;
return lastReturned.value; return lastReturned.value;
} }
@Override @Override
public KEY_TYPE NEXT() { public KEY_TYPE NEXT() {
lastReturned = node; if(!hasNext()) throw new NoSuchElementException();
node = node.next; lastReturned = next;
next = next.next;
index++; index++;
return lastReturned.value; return lastReturned.value;
} }
@ -1179,10 +1174,9 @@ public class LINKED_LIST KEY_GENERIC_TYPE extends ABSTRACT_LIST KEY_GENERIC_TYPE
@Override @Override
public void add(KEY_TYPE e) { public void add(KEY_TYPE e) {
if(lastReturned == null) throw new IllegalStateException();
if(node.next == null) linkLast(e);
else linkBefore(e, node);
lastReturned = null; lastReturned = null;
if (next == null) linkLast(e);
else linkBefore(e, next);
index++; index++;
} }
} }

View File

@ -1389,6 +1389,7 @@ public class CUSTOM_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VAL
private class MapIterator { private class MapIterator {
int pos = nullIndex; int pos = nullIndex;
int returnedPos = -1;
int lastReturned = -1; int lastReturned = -1;
int nextIndex = Integer.MIN_VALUE; int nextIndex = Integer.MIN_VALUE;
boolean returnNull = containsNull; boolean returnNull = containsNull;
@ -1420,6 +1421,7 @@ public class CUSTOM_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VAL
public int nextEntry() { public int nextEntry() {
if(!hasNext()) throw new NoSuchElementException(); if(!hasNext()) throw new NoSuchElementException();
returnedPos = pos;
if(nextIndex < 0){ if(nextIndex < 0){
lastReturned = Integer.MAX_VALUE; lastReturned = Integer.MAX_VALUE;
int value = findIndex(wrapped.GET_KEY(nextIndex)); int value = findIndex(wrapped.GET_KEY(nextIndex));
@ -1439,9 +1441,10 @@ public class CUSTOM_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VAL
keys[nullIndex] = EMPTY_KEY_VALUE; keys[nullIndex] = EMPTY_KEY_VALUE;
values[nullIndex] = EMPTY_VALUE; values[nullIndex] = EMPTY_VALUE;
} }
else if(lastReturned >= 0) shiftKeys(lastReturned); else if(returnedPos >= 0) shiftKeys(returnedPos);
else { else {
CUSTOM_HASH_MAP.this.remove(wrapped.GET_KEY(-lastReturned - 1)); CUSTOM_HASH_MAP.this.remove(wrapped.GET_KEY(-returnedPos - 1));
lastReturned = -1;
return; return;
} }
size--; size--;

View File

@ -1345,6 +1345,7 @@ public class HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GENE
private class MapIterator { private class MapIterator {
int pos = nullIndex; int pos = nullIndex;
int returnedPos = -1;
int lastReturned = -1; int lastReturned = -1;
int nextIndex = Integer.MIN_VALUE; int nextIndex = Integer.MIN_VALUE;
boolean returnNull = containsNull; boolean returnNull = containsNull;
@ -1376,6 +1377,7 @@ public class HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GENE
public int nextEntry() { public int nextEntry() {
if(!hasNext()) throw new NoSuchElementException(); if(!hasNext()) throw new NoSuchElementException();
returnedPos = pos;
if(nextIndex < 0){ if(nextIndex < 0){
lastReturned = Integer.MAX_VALUE; lastReturned = Integer.MAX_VALUE;
int value = findIndex(wrapped.GET_KEY(nextIndex)); int value = findIndex(wrapped.GET_KEY(nextIndex));
@ -1395,9 +1397,10 @@ public class HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GENE
keys[nullIndex] = EMPTY_KEY_VALUE; keys[nullIndex] = EMPTY_KEY_VALUE;
values[nullIndex] = EMPTY_VALUE; values[nullIndex] = EMPTY_VALUE;
} }
else if(lastReturned >= 0) shiftKeys(lastReturned); else if(returnedPos >= 0) shiftKeys(returnedPos);
else { else {
HASH_MAP.this.remove(wrapped.GET_KEY(-lastReturned - 1)); HASH_MAP.this.remove(wrapped.GET_KEY(-returnedPos - 1));
lastReturned = -1;
return; return;
} }
size--; size--;

View File

@ -261,7 +261,7 @@ public class IMMUTABLE_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_
newValues[pos] = b[i]; newValues[pos] = b[i];
continue; continue;
} }
while(KEY_EQUALS_NOT_NULL((current = newKeys[pos = (++pos & mask)]))) { while(KEY_EQUALS_NOT_NULL((current = newKeys[pos = (++pos & newMask)]))) {
if(KEY_EQUALS(current, o)) { if(KEY_EQUALS(current, o)) {
found = false; found = false;
newValues[pos] = b[i]; newValues[pos] = b[i];

View File

@ -202,9 +202,12 @@ public class ARRAY_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GEN
@Override @Override
public VALUE_TYPE putIfAbsent(KEY_TYPE key, VALUE_TYPE value) { public VALUE_TYPE putIfAbsent(KEY_TYPE key, VALUE_TYPE value) {
int index = findIndex(key); int index = findIndex(key);
if(index >= 0) insertIndex(size++, key, value); if(index < 0) {
insertIndex(size++, key, value);
return getDefaultReturnValue(); return getDefaultReturnValue();
} }
return values[index];
}
#if VALUE_PRIMITIVES #if VALUE_PRIMITIVES
@Override @Override
@ -463,6 +466,7 @@ public class ARRAY_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GEN
@Override @Override
public VALUE_TYPE COMPUTE(KEY_TYPE key, UNARY_OPERATOR KEY_VALUE_GENERIC_TYPE mappingFunction) { public VALUE_TYPE COMPUTE(KEY_TYPE key, UNARY_OPERATOR KEY_VALUE_GENERIC_TYPE mappingFunction) {
Objects.requireNonNull(mappingFunction);
int index = findIndex(key); int index = findIndex(key);
if(index == -1) { if(index == -1) {
VALUE_TYPE newValue = mappingFunction.APPLY_VALUE(key, getDefaultReturnValue()); VALUE_TYPE newValue = mappingFunction.APPLY_VALUE(key, getDefaultReturnValue());
@ -481,6 +485,7 @@ public class ARRAY_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GEN
@Override @Override
public VALUE_TYPE COMPUTE_IF_ABSENT(KEY_TYPE key, FUNCTION KEY_VALUE_GENERIC_TYPE mappingFunction) { public VALUE_TYPE COMPUTE_IF_ABSENT(KEY_TYPE key, FUNCTION KEY_VALUE_GENERIC_TYPE mappingFunction) {
Objects.requireNonNull(mappingFunction);
int index = findIndex(key); int index = findIndex(key);
if(index == -1) { if(index == -1) {
VALUE_TYPE newValue = mappingFunction.GET_VALUE(key); VALUE_TYPE newValue = mappingFunction.GET_VALUE(key);
@ -488,11 +493,18 @@ public class ARRAY_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GEN
insertIndex(size++, key, newValue); insertIndex(size++, key, newValue);
return newValue; return newValue;
} }
return values[index]; VALUE_TYPE newValue = values[index];
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) {
newValue = mappingFunction.GET_VALUE(key);
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) return newValue;
values[index] = newValue;
}
return newValue;
} }
@Override @Override
public VALUE_TYPE SUPPLY_IF_ABSENT(KEY_TYPE key, VALUE_SUPPLIER VALUE_GENERIC_TYPE valueProvider) { public VALUE_TYPE SUPPLY_IF_ABSENT(KEY_TYPE key, VALUE_SUPPLIER VALUE_GENERIC_TYPE valueProvider) {
Objects.requireNonNull(valueProvider);
int index = findIndex(key); int index = findIndex(key);
if(index == -1) { if(index == -1) {
VALUE_TYPE newValue = valueProvider.VALUE_GET_KEY(); VALUE_TYPE newValue = valueProvider.VALUE_GET_KEY();
@ -500,13 +512,20 @@ public class ARRAY_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GEN
insertIndex(size++, key, newValue); insertIndex(size++, key, newValue);
return newValue; return newValue;
} }
return values[index]; VALUE_TYPE newValue = values[index];
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) {
newValue = valueProvider.VALUE_GET_KEY();
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) return newValue;
values[index] = newValue;
}
return newValue;
} }
@Override @Override
public VALUE_TYPE COMPUTE_IF_PRESENT(KEY_TYPE key, UNARY_OPERATOR KEY_VALUE_GENERIC_TYPE mappingFunction) { public VALUE_TYPE COMPUTE_IF_PRESENT(KEY_TYPE key, UNARY_OPERATOR KEY_VALUE_GENERIC_TYPE mappingFunction) {
Objects.requireNonNull(mappingFunction);
int index = findIndex(key); int index = findIndex(key);
if(index == -1) return getDefaultReturnValue(); if(index == -1 || VALUE_EQUALS(values[index], getDefaultReturnValue())) return getDefaultReturnValue();
VALUE_TYPE newValue = mappingFunction.APPLY_VALUE(key, values[index]); VALUE_TYPE newValue = mappingFunction.APPLY_VALUE(key, values[index]);
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) { if(VALUE_EQUALS(newValue, getDefaultReturnValue())) {
removeIndex(index); removeIndex(index);
@ -518,8 +537,12 @@ public class ARRAY_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GEN
@Override @Override
public VALUE_TYPE MERGE(KEY_TYPE key, VALUE_TYPE value, VALUE_UNARY_OPERATOR VALUE_VALUE_GENERIC_TYPE mappingFunction) { public VALUE_TYPE MERGE(KEY_TYPE key, VALUE_TYPE value, VALUE_UNARY_OPERATOR VALUE_VALUE_GENERIC_TYPE mappingFunction) {
Objects.requireNonNull(mappingFunction);
#if VALUE_OBJECT
Objects.requireNonNull(value);
#endif
int index = findIndex(key); int index = findIndex(key);
VALUE_TYPE newValue = index == -1 ? value : mappingFunction.APPLY_VALUE(values[index], value); VALUE_TYPE newValue = index == -1 || VALUE_EQUALS(values[index], getDefaultReturnValue()) ? value : mappingFunction.APPLY_VALUE(values[index], value);
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) { if(VALUE_EQUALS(newValue, getDefaultReturnValue())) {
if(index >= 0) if(index >= 0)
removeIndex(index); removeIndex(index);
@ -535,7 +558,7 @@ public class ARRAY_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GEN
for(MAP.Entry KEY_VALUE_GENERIC_TYPE entry : MAPS.fastIterable(m)) { for(MAP.Entry KEY_VALUE_GENERIC_TYPE entry : MAPS.fastIterable(m)) {
KEY_TYPE key = entry.ENTRY_KEY(); KEY_TYPE key = entry.ENTRY_KEY();
int index = findIndex(key); int index = findIndex(key);
VALUE_TYPE newValue = index == -1 ? entry.ENTRY_VALUE() : mappingFunction.APPLY_VALUE(values[index], entry.ENTRY_VALUE()); VALUE_TYPE newValue = index == -1 || VALUE_EQUALS(values[index], getDefaultReturnValue()) ? entry.ENTRY_VALUE() : mappingFunction.APPLY_VALUE(values[index], entry.ENTRY_VALUE());
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) { if(VALUE_EQUALS(newValue, getDefaultReturnValue())) {
if(index >= 0) if(index >= 0)
removeIndex(index); removeIndex(index);
@ -683,21 +706,18 @@ public class ARRAY_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GEN
#endif #endif
protected int findIndex(Object key, Object value) { protected int findIndex(Object key, Object value) {
if(key == null || value == null) return -1;
for(int i = size-1;i>=0;i--) for(int i = size-1;i>=0;i--)
if(EQUALS_KEY_TYPE(keys[i], key) && EQUALS_VALUE_TYPE(values[i], value)) return i; if(EQUALS_KEY_TYPE(keys[i], key) && EQUALS_VALUE_TYPE(values[i], value)) return i;
return -1; return -1;
} }
protected int findIndex(Object key) { protected int findIndex(Object key) {
if(key == null) return -1;
for(int i = size-1;i>=0;i--) for(int i = size-1;i>=0;i--)
if(EQUALS_KEY_TYPE(keys[i], key)) return i; if(EQUALS_KEY_TYPE(keys[i], key)) return i;
return -1; return -1;
} }
protected int findValue(Object value) { protected int findValue(Object value) {
if(value == null) return -1;
for(int i = size-1;i>=0;i--) for(int i = size-1;i>=0;i--)
if(EQUALS_VALUE_TYPE(values[i], value)) return i; if(EQUALS_VALUE_TYPE(values[i], value)) return i;
return -1; return -1;
@ -1069,21 +1089,18 @@ public class ARRAY_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GEN
#endif #endif
protected int findIndex(Object key, Object value) { protected int findIndex(Object key, Object value) {
if(key == null || value == null) return -1;
for(int i = length-1;i>=0;i--) for(int i = length-1;i>=0;i--)
if(EQUALS_KEY_TYPE(keys[offset+i], key) && EQUALS_VALUE_TYPE(values[offset+i], value)) return i+offset; if(EQUALS_KEY_TYPE(keys[offset+i], key) && EQUALS_VALUE_TYPE(values[offset+i], value)) return i+offset;
return -1; return -1;
} }
protected int findIndex(Object key) { protected int findIndex(Object key) {
if(key == null) return -1;
for(int i = length-1;i>=0;i--) for(int i = length-1;i>=0;i--)
if(EQUALS_KEY_TYPE(keys[offset+i], key)) return i+offset; if(EQUALS_KEY_TYPE(keys[offset+i], key)) return i+offset;
return -1; return -1;
} }
protected int findValue(Object value) { protected int findValue(Object value) {
if(value == null) return -1;
for(int i = length-1;i>=0;i--) for(int i = length-1;i>=0;i--)
if(EQUALS_VALUE_TYPE(values[offset+i], value)) return i+offset; if(EQUALS_VALUE_TYPE(values[offset+i], value)) return i+offset;
return -1; return -1;
@ -1268,8 +1285,14 @@ public class ARRAY_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GEN
@Deprecated @Deprecated
public boolean contains(Object o) { public boolean contains(Object o) {
if(o instanceof Map.Entry) { if(o instanceof Map.Entry) {
if(o instanceof MAP.Entry) return SubMap.this.containsKey(((MAP.Entry KEY_VALUE_GENERIC_TYPE)o).ENTRY_KEY()); if(o instanceof MAP.Entry) {
return SubMap.this.containsKey(((Map.Entry<?, ?>)o).getKey()); MAP.Entry KEY_VALUE_GENERIC_TYPE entry = (MAP.Entry KEY_VALUE_GENERIC_TYPE)o;
return SubMap.this.findIndex(entry.ENTRY_KEY(), entry.ENTRY_VALUE()) >= 0;
}
else {
Map.Entry<?, ?> entry = (Map.Entry<?, ?>)o;
return ARRAY_MAP.this.findIndex(entry.getKey(), entry.getValue()) >= 0;
}
} }
return false; return false;
} }
@ -1318,7 +1341,7 @@ public class ARRAY_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GEN
@Override @Override
public boolean remove(Object o) { public boolean remove(Object o) {
int oldSize = length; int oldSize = length;
remove(o); SubMap.this.remove(o);
return length != oldSize; return length != oldSize;
} }
@ -1329,7 +1352,7 @@ public class ARRAY_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GEN
@Override @Override
public boolean remove(KEY_TYPE o) { public boolean remove(KEY_TYPE o) {
int oldSize = length; int oldSize = length;
remove(o); SubMap.this.remove(o);
return length != oldSize; return length != oldSize;
} }
@ -1737,12 +1760,14 @@ public class ARRAY_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GEN
} }
public int previousEntry() { public int previousEntry() {
if(!hasPrevious()) throw new NoSuchElementException();
int returnIndex = offset+index; int returnIndex = offset+index;
lastReturned = index--; lastReturned = index--;
return returnIndex; return returnIndex;
} }
public int nextEntry() { public int nextEntry() {
if(!hasNext()) throw new NoSuchElementException();
int returnIndex = offset+index; int returnIndex = offset+index;
lastReturned = index++; lastReturned = index++;
return returnIndex; return returnIndex;
@ -1944,8 +1969,16 @@ public class ARRAY_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GEN
@Deprecated @Deprecated
public boolean contains(Object o) { public boolean contains(Object o) {
if(o instanceof Map.Entry) { if(o instanceof Map.Entry) {
if(o instanceof MAP.Entry) return ARRAY_MAP.this.containsKey(((MAP.Entry KEY_VALUE_GENERIC_TYPE)o).ENTRY_KEY()); if(o instanceof MAP.Entry) {
return ARRAY_MAP.this.containsKey(((Map.Entry<?, ?>)o).getKey()); MAP.Entry KEY_VALUE_GENERIC_TYPE entry = (MAP.Entry KEY_VALUE_GENERIC_TYPE)o;
int index = ARRAY_MAP.this.findIndex(entry.ENTRY_KEY());
if(index >= 0) return VALUE_EQUALS(entry.ENTRY_VALUE(), ARRAY_MAP.this.values[index]);
}
else {
Map.Entry<?, ?> entry = (Map.Entry<?, ?>)o;
int index = ARRAY_MAP.this.findIndex(entry.getKey());
if(index >= 0) return Objects.equals(entry.getValue(), VALUE_TO_OBJ(ARRAY_MAP.this.values[index]));
}
} }
return false; return false;
} }
@ -1994,7 +2027,7 @@ public class ARRAY_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GEN
@Override @Override
public boolean remove(Object o) { public boolean remove(Object o) {
int oldSize = size; int oldSize = size;
remove(o); ARRAY_MAP.this.remove(o);
return size != oldSize; return size != oldSize;
} }
@ -2005,7 +2038,7 @@ public class ARRAY_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GEN
@Override @Override
public boolean remove(KEY_TYPE o) { public boolean remove(KEY_TYPE o) {
int oldSize = size; int oldSize = size;
remove(o); ARRAY_MAP.this.remove(o);
return size != oldSize; return size != oldSize;
} }
@ -2401,11 +2434,13 @@ public class ARRAY_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GEN
} }
public int previousEntry() { public int previousEntry() {
if(!hasPrevious()) throw new NoSuchElementException();
lastReturned = index; lastReturned = index;
return index--; return index--;
} }
public int nextEntry() { public int nextEntry() {
if(!hasNext()) throw new NoSuchElementException();
lastReturned = index; lastReturned = index;
return index++; return index++;
} }
@ -2480,7 +2515,7 @@ public class ARRAY_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GEN
@Override @Override
public String toString() { public String toString() {
return KEY_TO_STRING(keys[index]) + "->" + VALUE_TO_STRING(values[index]); return KEY_TO_STRING(keys[index]) + "=" + VALUE_TO_STRING(values[index]);
} }
} }
} }

View File

@ -183,6 +183,7 @@ public class ENUM_MAP KEY_ENUM_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE
#endif #endif
@Override @Override
public boolean containsKey(Object key) { public boolean containsKey(Object key) {
if(!keyType.isInstance(key)) return false;
return isSet(((T)key).ordinal()); return isSet(((T)key).ordinal());
} }
@ -190,7 +191,7 @@ public class ENUM_MAP KEY_ENUM_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE
@Override @Override
public boolean containsValue(Object value) { public boolean containsValue(Object value) {
for(int i = 0;i<values.length;i++) for(int i = 0;i<values.length;i++)
if(VALUE_EQUALS(value, values[i])) return true; if(isSet(i) && VALUE_EQUALS(value, values[i])) return true;
return false; return false;
} }
@ -198,13 +199,25 @@ public class ENUM_MAP KEY_ENUM_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE
@Override @Override
public boolean containsValue(VALUE_TYPE value) { public boolean containsValue(VALUE_TYPE value) {
for(int i = 0;i<values.length;i++) for(int i = 0;i<values.length;i++)
if(VALUE_EQUALS(value, values[i])) return true; if(isSet(i) && VALUE_EQUALS(value, values[i])) return true;
return false; return false;
} }
#endif #endif
@Override
public CLASS_VALUE_TYPE remove(Object key) {
if(!keyType.isInstance(key)) return getDefaultReturnValue();
int index = ((T)key).ordinal();
if(!isSet(index)) return getDefaultReturnValue();
clear(index);
VALUE_TYPE result = values[index];
values[index] = EMPTY_VALUE;
return result;
}
@Override @Override
public VALUE_TYPE rem(T key) { public VALUE_TYPE rem(T key) {
if(!keyType.isInstance(key)) return getDefaultReturnValue();
int index = key.ordinal(); int index = key.ordinal();
if(!isSet(index)) return getDefaultReturnValue(); if(!isSet(index)) return getDefaultReturnValue();
clear(index); clear(index);
@ -246,6 +259,7 @@ public class ENUM_MAP KEY_ENUM_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE
#endif #endif
@Override @Override
public VALUE_TYPE GET_VALUE(T key) { public VALUE_TYPE GET_VALUE(T key) {
if(!keyType.isInstance(key)) return getDefaultReturnValue();
int index = key.ordinal(); int index = key.ordinal();
return isSet(index) ? values[index] : getDefaultReturnValue(); return isSet(index) ? values[index] : getDefaultReturnValue();
} }
@ -253,6 +267,7 @@ public class ENUM_MAP KEY_ENUM_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE
#if VALUE_OBJECT #if VALUE_OBJECT
@Override @Override
public VALUE_TYPE getOrDefault(Object key, VALUE_TYPE defaultValue) { public VALUE_TYPE getOrDefault(Object key, VALUE_TYPE defaultValue) {
if(!keyType.isInstance(key)) return defaultValue;
int index = ((T)key).ordinal(); int index = ((T)key).ordinal();
return isSet(index) ? values[index] : defaultValue; return isSet(index) ? values[index] : defaultValue;
} }
@ -260,6 +275,7 @@ public class ENUM_MAP KEY_ENUM_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE
#else #else
@Override @Override
public VALUE_TYPE getOrDefault(T key, VALUE_TYPE defaultValue) { public VALUE_TYPE getOrDefault(T key, VALUE_TYPE defaultValue) {
if(!keyType.isInstance(key)) return defaultValue;
int index = key.ordinal(); int index = key.ordinal();
return isSet(index) ? values[index] : defaultValue; return isSet(index) ? values[index] : defaultValue;
} }
@ -347,7 +363,13 @@ public class ENUM_MAP KEY_ENUM_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE
values[index] = newValue; values[index] = newValue;
return newValue; return newValue;
} }
return values[index]; VALUE_TYPE newValue = values[index];
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) {
newValue = mappingFunction.GET_VALUE(key);
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) return newValue;
values[index] = newValue;
}
return newValue;
} }
@Override @Override
@ -360,13 +382,19 @@ public class ENUM_MAP KEY_ENUM_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE
values[index] = newValue; values[index] = newValue;
return newValue; return newValue;
} }
return values[index]; VALUE_TYPE newValue = values[index];
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) {
newValue = valueProvider.VALUE_GET_KEY();
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) return newValue;
values[index] = newValue;
}
return newValue;
} }
@Override @Override
public VALUE_TYPE COMPUTE_IF_PRESENT(T key, UNARY_OPERATOR KEY_VALUE_GENERIC_TYPE mappingFunction) { public VALUE_TYPE COMPUTE_IF_PRESENT(T key, UNARY_OPERATOR KEY_VALUE_GENERIC_TYPE mappingFunction) {
int index = key.ordinal(); int index = key.ordinal();
if(!isSet(index)) return getDefaultReturnValue(); if(!isSet(index) || VALUE_EQUALS(values[index], getDefaultReturnValue())) return getDefaultReturnValue();
VALUE_TYPE newValue = mappingFunction.APPLY_VALUE(key, values[index]); VALUE_TYPE newValue = mappingFunction.APPLY_VALUE(key, values[index]);
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) { if(VALUE_EQUALS(newValue, getDefaultReturnValue())) {
clear(index); clear(index);
@ -380,7 +408,10 @@ public class ENUM_MAP KEY_ENUM_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE
@Override @Override
public VALUE_TYPE MERGE(T key, VALUE_TYPE value, VALUE_UNARY_OPERATOR VALUE_VALUE_GENERIC_TYPE mappingFunction) { public VALUE_TYPE MERGE(T key, VALUE_TYPE value, VALUE_UNARY_OPERATOR VALUE_VALUE_GENERIC_TYPE mappingFunction) {
int index = key.ordinal(); int index = key.ordinal();
VALUE_TYPE newValue = !isSet(index) ? value : mappingFunction.APPLY_VALUE(values[index], value); #if VALUE_OBJECT
Objects.requireNonNull(value);
#endif
VALUE_TYPE newValue = !isSet(index) || VALUE_EQUALS(values[index], getDefaultReturnValue()) ? value : mappingFunction.APPLY_VALUE(values[index], value);
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) { if(VALUE_EQUALS(newValue, getDefaultReturnValue())) {
if(isSet(index)) { if(isSet(index)) {
clear(index); clear(index);
@ -401,7 +432,7 @@ public class ENUM_MAP KEY_ENUM_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE
for(MAP.Entry KEY_VALUE_GENERIC_TYPE entry : MAPS.fastIterable(m)) { for(MAP.Entry KEY_VALUE_GENERIC_TYPE entry : MAPS.fastIterable(m)) {
T key = entry.ENTRY_KEY(); T key = entry.ENTRY_KEY();
int index = key.ordinal(); int index = key.ordinal();
VALUE_TYPE newValue = !isSet(index) ? entry.ENTRY_VALUE() : mappingFunction.APPLY_VALUE(values[index], entry.ENTRY_VALUE()); VALUE_TYPE newValue = !isSet(index) || VALUE_EQUALS(values[index], getDefaultReturnValue()) ? entry.ENTRY_VALUE() : mappingFunction.APPLY_VALUE(values[index], entry.ENTRY_VALUE());
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) { if(VALUE_EQUALS(newValue, getDefaultReturnValue())) {
if(isSet(index)) { if(isSet(index)) {
clear(index); clear(index);
@ -424,6 +455,11 @@ public class ENUM_MAP KEY_ENUM_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE
Arrays.fill(values, EMPTY_VALUE); Arrays.fill(values, EMPTY_VALUE);
} }
@Override
public int size() {
return size;
}
protected void onNodeAdded(int index) { protected void onNodeAdded(int index) {
} }
@ -433,9 +469,9 @@ public class ENUM_MAP KEY_ENUM_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE
} }
protected void set(int index) { protected void set(int index) {
size++;
present[index >> 6] |= (1L << index);
onNodeAdded(index); onNodeAdded(index);
present[index >> 6] |= (1L << index);
size++;
} }
protected void clear(int index) { protected void clear(int index) {
size--; size--;
@ -452,7 +488,20 @@ public class ENUM_MAP KEY_ENUM_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE
@Override @Override
public boolean contains(Object o) { public boolean contains(Object o) {
if(o instanceof Map.Entry) return containsKey(((Map.Entry<?, ?>)o).getKey()); if(o instanceof Map.Entry) {
if(o instanceof MAP.Entry) {
MAP.Entry KEY_VALUE_GENERIC_TYPE entry = (MAP.Entry KEY_VALUE_GENERIC_TYPE)o;
if(!keyType.isInstance(entry.ENTRY_KEY())) return false;
int index = ((T)entry.ENTRY_KEY()).ordinal();
if(index >= 0 && ENUM_MAP.this.isSet(index)) return VALUE_EQUALS(entry.ENTRY_VALUE(), ENUM_MAP.this.values[index]);
}
else {
Map.Entry<?, ?> entry = (Map.Entry<?, ?>)o;
if(!keyType.isInstance(entry.getKey())) return false;
int index = ((T)entry.getKey()).ordinal();
if(index >= 0 && ENUM_MAP.this.isSet(index)) return Objects.equals(entry.getValue(), VALUE_TO_OBJ(ENUM_MAP.this.values[index]));
}
}
return false; return false;
} }
@ -548,8 +597,7 @@ public class ENUM_MAP KEY_ENUM_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE
class EntryIterator extends MapIterator implements ObjectIterator<MAP.Entry KEY_VALUE_GENERIC_TYPE> { class EntryIterator extends MapIterator implements ObjectIterator<MAP.Entry KEY_VALUE_GENERIC_TYPE> {
@Override @Override
public MAP.Entry KEY_VALUE_GENERIC_TYPE next() { public MAP.Entry KEY_VALUE_GENERIC_TYPE next() {
int index = nextEntry(); return new MapEntry(nextEntry());
return new BasicEntry<>(keys[index], values[index]);
} }
} }
@ -584,13 +632,74 @@ public class ENUM_MAP KEY_ENUM_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE
public int nextEntry() { public int nextEntry() {
if(!hasNext()) throw new NoSuchElementException(); if(!hasNext()) throw new NoSuchElementException();
lastReturnValue = nextIndex; lastReturnValue = nextIndex;
return nextIndex; nextIndex = -1;
return lastReturnValue;
} }
public void remove() { public void remove() {
if(lastReturnValue == -1) throw new IllegalStateException(); if(lastReturnValue == -1) throw new IllegalStateException();
clear(lastReturnValue); clear(lastReturnValue);
values[lastReturnValue] = EMPTY_VALUE; values[lastReturnValue] = EMPTY_VALUE;
lastReturnValue = -1;
}
}
protected class MapEntry implements MAP.Entry KEY_VALUE_GENERIC_TYPE, Map.Entry<CLASS_TYPE, CLASS_VALUE_TYPE> {
public int index = -1;
public MapEntry() {}
public MapEntry(int index) {
this.index = index;
}
@Override
public KEY_TYPE ENTRY_KEY() {
return keys[index];
}
@Override
public VALUE_TYPE ENTRY_VALUE() {
return values[index];
}
@Override
public VALUE_TYPE setValue(VALUE_TYPE value) {
VALUE_TYPE oldValue = values[index];
values[index] = value;
return oldValue;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof Map.Entry) {
if(obj instanceof MAP.Entry) {
MAP.Entry KEY_VALUE_GENERIC_TYPE entry = (MAP.Entry KEY_VALUE_GENERIC_TYPE)obj;
return KEY_EQUALS(keys[index], entry.ENTRY_KEY()) && VALUE_EQUALS(values[index], entry.ENTRY_VALUE());
}
Map.Entry<?, ?> entry = (Map.Entry<?, ?>)obj;
Object key = entry.getKey();
Object value = entry.getValue();
#if TYPE_OBJECT && VALUE_OBJECT
return KEY_EQUALS(keys[index], key) && VALUE_EQUALS(values[index], value);
#else if TYPE_OBJECT
return value instanceof CLASS_VALUE_TYPE && KEY_EQUALS(keys[index], key) && VALUE_EQUALS(values[index], CLASS_TO_VALUE(value));
#else if VALUE_OBJECT
return key instanceof CLASS_TYPE && KEY_EQUALS(keys[index], CLASS_TO_KEY(key)) && VALUE_EQUALS(values[index], value);
#else
return key instanceof CLASS_TYPE && value instanceof CLASS_VALUE_TYPE && KEY_EQUALS(keys[index], CLASS_TO_KEY(key)) && VALUE_EQUALS(values[index], CLASS_TO_VALUE(value));
#endif
}
return false;
}
@Override
public int hashCode() {
return KEY_TO_HASH(keys[index]) ^ VALUE_TO_HASH(values[index]);
}
@Override
public String toString() {
return KEY_TO_STRING(keys[index]) + "=" + VALUE_TO_STRING(values[index]);
} }
} }
} }

View File

@ -109,7 +109,7 @@ public class LINKED_ENUM_MAP KEY_ENUM_VALUE_GENERIC_TYPE extends ENUM_MAP KEY_VA
links = enumMap.links.clone(); links = enumMap.links.clone();
size = enumMap.size; size = enumMap.size;
} }
if(map instanceof ENUM_MAP) { else if(map instanceof ENUM_MAP) {
ENUM_MAP KEY_VALUE_GENERIC_TYPE enumMap = (ENUM_MAP KEY_VALUE_GENERIC_TYPE)map; ENUM_MAP KEY_VALUE_GENERIC_TYPE enumMap = (ENUM_MAP KEY_VALUE_GENERIC_TYPE)map;
keyType = enumMap.keyType; keyType = enumMap.keyType;
keys = enumMap.keys; keys = enumMap.keys;
@ -156,7 +156,7 @@ public class LINKED_ENUM_MAP KEY_ENUM_VALUE_GENERIC_TYPE extends ENUM_MAP KEY_VA
links = enumMap.links.clone(); links = enumMap.links.clone();
size = enumMap.size; size = enumMap.size;
} }
if(map instanceof ENUM_MAP) { else if(map instanceof ENUM_MAP) {
ENUM_MAP KEY_VALUE_GENERIC_TYPE enumMap = (ENUM_MAP KEY_VALUE_GENERIC_TYPE)map; ENUM_MAP KEY_VALUE_GENERIC_TYPE enumMap = (ENUM_MAP KEY_VALUE_GENERIC_TYPE)map;
keyType = enumMap.keyType; keyType = enumMap.keyType;
keys = enumMap.keys; keys = enumMap.keys;
@ -519,8 +519,18 @@ public class LINKED_ENUM_MAP KEY_ENUM_VALUE_GENERIC_TYPE extends ENUM_MAP KEY_VA
@Deprecated @Deprecated
public boolean contains(Object o) { public boolean contains(Object o) {
if(o instanceof Map.Entry) { if(o instanceof Map.Entry) {
if(o instanceof MAP.Entry) return LINKED_ENUM_MAP.this.containsKey(((MAP.Entry KEY_VALUE_GENERIC_TYPE)o).ENTRY_KEY()); if(o instanceof MAP.Entry) {
return LINKED_ENUM_MAP.this.containsKey(((Map.Entry<?, ?>)o).getKey()); MAP.Entry KEY_VALUE_GENERIC_TYPE entry = (MAP.Entry KEY_VALUE_GENERIC_TYPE)o;
if(!keyType.isInstance(entry.ENTRY_KEY())) return false;
int index = ((T)entry.ENTRY_KEY()).ordinal();
if(index >= 0 && LINKED_ENUM_MAP.this.isSet(index)) return VALUE_EQUALS(entry.ENTRY_VALUE(), LINKED_ENUM_MAP.this.values[index]);
}
else {
Map.Entry<?, ?> entry = (Map.Entry<?, ?>)o;
if(!keyType.isInstance(entry.getKey())) return false;
int index = ((T)entry.getKey()).ordinal();
if(index >= 0 && LINKED_ENUM_MAP.this.isSet(index)) return Objects.equals(entry.getValue(), VALUE_TO_OBJ(LINKED_ENUM_MAP.this.values[index]));
}
} }
return false; return false;
} }
@ -572,7 +582,7 @@ public class LINKED_ENUM_MAP KEY_ENUM_VALUE_GENERIC_TYPE extends ENUM_MAP KEY_VA
@Override @Override
public boolean remove(Object o) { public boolean remove(Object o) {
int oldSize = size; int oldSize = size;
remove(o); LINKED_ENUM_MAP.this.remove(o);
return size != oldSize; return size != oldSize;
} }
@ -585,7 +595,7 @@ public class LINKED_ENUM_MAP KEY_ENUM_VALUE_GENERIC_TYPE extends ENUM_MAP KEY_VA
@Override @Override
public boolean remove(T o) { public boolean remove(T o) {
int oldSize = size; int oldSize = size;
remove(o); LINKED_ENUM_MAP.this.remove(o);
return size != oldSize; return size != oldSize;
} }
@ -887,6 +897,7 @@ public class LINKED_ENUM_MAP KEY_ENUM_VALUE_GENERIC_TYPE extends ENUM_MAP KEY_VA
previous = (int)(links[current] >>> 32); previous = (int)(links[current] >>> 32);
} }
else next = (int)links[current]; else next = (int)links[current];
size--; size--;
if(previous == -1) firstIndex = next; if(previous == -1) firstIndex = next;
else links[previous] ^= ((links[previous] ^ (next & 0xFFFFFFFFL)) & 0xFFFFFFFFL); else links[previous] ^= ((links[previous] ^ (next & 0xFFFFFFFFL)) & 0xFFFFFFFFL);
@ -894,6 +905,8 @@ public class LINKED_ENUM_MAP KEY_ENUM_VALUE_GENERIC_TYPE extends ENUM_MAP KEY_VA
if (next == -1) lastIndex = previous; if (next == -1) lastIndex = previous;
else links[next] ^= ((links[next] ^ ((previous & 0xFFFFFFFFL) << 32)) & 0xFFFFFFFF00000000L); else links[next] ^= ((links[next] ^ ((previous & 0xFFFFFFFFL) << 32)) & 0xFFFFFFFF00000000L);
values[current] = EMPTY_VALUE; values[current] = EMPTY_VALUE;
present[current >> 6] &= ~(1L << current);
current = -1;
} }
public int previousEntry() { public int previousEntry() {
@ -985,7 +998,7 @@ public class LINKED_ENUM_MAP KEY_ENUM_VALUE_GENERIC_TYPE extends ENUM_MAP KEY_VA
@Override @Override
public String toString() { public String toString() {
return KEY_TO_STRING(keys[index]) + "->" + VALUE_TO_STRING(values[index]); return KEY_TO_STRING(keys[index]) + "=" + VALUE_TO_STRING(values[index]);
} }
} }
} }

View File

@ -234,7 +234,7 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_
@Override @Override
public VALUE_TYPE put(KEY_TYPE key, VALUE_TYPE value) { public VALUE_TYPE put(KEY_TYPE key, VALUE_TYPE value) {
#if TYPE_OBJECT #if TYPE_OBJECT
Objects.requireNonNull(key); validate(key);
#endif #endif
if(tree == null) { if(tree == null) {
tree = first = last = new EntryKV_BRACES(key, value, null); tree = first = last = new EntryKV_BRACES(key, value, null);
@ -271,7 +271,7 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_
@Override @Override
public VALUE_TYPE putIfAbsent(KEY_TYPE key, VALUE_TYPE value) { public VALUE_TYPE putIfAbsent(KEY_TYPE key, VALUE_TYPE value) {
#if TYPE_OBJECT #if TYPE_OBJECT
Objects.requireNonNull(key); validate(key);
#endif #endif
if(tree == null) { if(tree == null) {
tree = first = last = new EntryKV_BRACES(key, value, null); tree = first = last = new EntryKV_BRACES(key, value, null);
@ -309,7 +309,7 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_
@Override @Override
public VALUE_TYPE addTo(KEY_TYPE key, VALUE_TYPE value) { public VALUE_TYPE addTo(KEY_TYPE key, VALUE_TYPE value) {
#if TYPE_OBJECT #if TYPE_OBJECT
Objects.requireNonNull(key); validate(key);
#endif #endif
if(tree == null) { if(tree == null) {
tree = first = last = new EntryKV_BRACES(key, value, null); tree = first = last = new EntryKV_BRACES(key, value, null);
@ -521,7 +521,7 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_
public VALUE_TYPE COMPUTE(KEY_TYPE key, UNARY_OPERATOR KEY_VALUE_GENERIC_TYPE mappingFunction) { public VALUE_TYPE COMPUTE(KEY_TYPE key, UNARY_OPERATOR KEY_VALUE_GENERIC_TYPE mappingFunction) {
Objects.requireNonNull(mappingFunction); Objects.requireNonNull(mappingFunction);
#if TYPE_OBJECT #if TYPE_OBJECT
Objects.requireNonNull(key); validate(key);
#endif #endif
Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key); Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key);
if(entry == null) { if(entry == null) {
@ -543,7 +543,7 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_
public VALUE_TYPE COMPUTE_IF_ABSENT(KEY_TYPE key, FUNCTION KEY_VALUE_GENERIC_TYPE mappingFunction) { public VALUE_TYPE COMPUTE_IF_ABSENT(KEY_TYPE key, FUNCTION KEY_VALUE_GENERIC_TYPE mappingFunction) {
Objects.requireNonNull(mappingFunction); Objects.requireNonNull(mappingFunction);
#if TYPE_OBJECT #if TYPE_OBJECT
Objects.requireNonNull(key); validate(key);
#endif #endif
Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key); Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key);
if(entry == null) { if(entry == null) {
@ -564,7 +564,7 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_
public VALUE_TYPE SUPPLY_IF_ABSENT(KEY_TYPE key, VALUE_SUPPLIER VALUE_GENERIC_TYPE valueProvider) { public VALUE_TYPE SUPPLY_IF_ABSENT(KEY_TYPE key, VALUE_SUPPLIER VALUE_GENERIC_TYPE valueProvider) {
Objects.requireNonNull(valueProvider); Objects.requireNonNull(valueProvider);
#if TYPE_OBJECT #if TYPE_OBJECT
Objects.requireNonNull(key); validate(key);
#endif #endif
Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key); Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key);
if(entry == null) { if(entry == null) {
@ -585,7 +585,7 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_
public VALUE_TYPE COMPUTE_IF_PRESENT(KEY_TYPE key, UNARY_OPERATOR KEY_VALUE_GENERIC_TYPE mappingFunction) { public VALUE_TYPE COMPUTE_IF_PRESENT(KEY_TYPE key, UNARY_OPERATOR KEY_VALUE_GENERIC_TYPE mappingFunction) {
Objects.requireNonNull(mappingFunction); Objects.requireNonNull(mappingFunction);
#if TYPE_OBJECT #if TYPE_OBJECT
Objects.requireNonNull(key); validate(key);
#endif #endif
Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key); Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key);
if(entry == null || VALUE_EQUALS(entry.value, getDefaultReturnValue())) return getDefaultReturnValue(); if(entry == null || VALUE_EQUALS(entry.value, getDefaultReturnValue())) return getDefaultReturnValue();
@ -602,7 +602,7 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_
public VALUE_TYPE MERGE(KEY_TYPE key, VALUE_TYPE value, VALUE_UNARY_OPERATOR VALUE_VALUE_GENERIC_TYPE mappingFunction) { public VALUE_TYPE MERGE(KEY_TYPE key, VALUE_TYPE value, VALUE_UNARY_OPERATOR VALUE_VALUE_GENERIC_TYPE mappingFunction) {
Objects.requireNonNull(mappingFunction); Objects.requireNonNull(mappingFunction);
#if TYPE_OBJECT #if TYPE_OBJECT
Objects.requireNonNull(key); validate(key);
#endif #endif
Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key); Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key);
VALUE_TYPE newValue = entry == null || VALUE_EQUALS(entry.value, getDefaultReturnValue()) ? value : mappingFunction.APPLY_VALUE(entry.value, value); VALUE_TYPE newValue = entry == null || VALUE_EQUALS(entry.value, getDefaultReturnValue()) ? value : mappingFunction.APPLY_VALUE(entry.value, value);
@ -899,6 +899,7 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_
} }
} }
protected void validate(KEY_TYPE k) { compare(k, k); }
protected int compare(KEY_TYPE k, KEY_TYPE v) { return comparator != null ? comparator.compare(k, v) : COMPAREABLE_TO_KEY(k, v);} protected int compare(KEY_TYPE k, KEY_TYPE v) { return comparator != null ? comparator.compare(k, v) : COMPAREABLE_TO_KEY(k, v);}
/** From CLR */ /** From CLR */
@ -1532,13 +1533,13 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_
if(o instanceof Map.Entry) { if(o instanceof Map.Entry) {
if(o instanceof MAP.Entry) { if(o instanceof MAP.Entry) {
MAP.Entry KEY_VALUE_GENERIC_TYPE entry = (MAP.Entry KEY_VALUE_GENERIC_TYPE)o; MAP.Entry KEY_VALUE_GENERIC_TYPE entry = (MAP.Entry KEY_VALUE_GENERIC_TYPE)o;
if(entry.getKey() == null) return false; if(entry.getKey() == null && comparator() == null) return false;
AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE subEntry = m.findNode(entry.ENTRY_KEY()); AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE subEntry = m.findNode(entry.ENTRY_KEY());
if(subEntry != null) return VALUE_EQUALS(entry.ENTRY_VALUE(), subEntry.value); if(subEntry != null) return VALUE_EQUALS(entry.ENTRY_VALUE(), subEntry.value);
} }
else { else {
Map.Entry<?, ?> entry = (Map.Entry<?, ?>)o; Map.Entry<?, ?> entry = (Map.Entry<?, ?>)o;
if(entry.getKey() == null) return false; if(entry.getKey() == null && comparator() == null) return false;
#if !TYPE_OBJECT #if !TYPE_OBJECT
if(!(entry.getKey() instanceof CLASS_TYPE)) return false; if(!(entry.getKey() instanceof CLASS_TYPE)) return false;
#endif #endif
@ -1938,13 +1939,13 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_
if(o instanceof Map.Entry) { if(o instanceof Map.Entry) {
if(o instanceof MAP.Entry) { if(o instanceof MAP.Entry) {
MAP.Entry KEY_VALUE_GENERIC_TYPE entry = (MAP.Entry KEY_VALUE_GENERIC_TYPE)o; MAP.Entry KEY_VALUE_GENERIC_TYPE entry = (MAP.Entry KEY_VALUE_GENERIC_TYPE)o;
if(entry.getKey() == null) return false; if(entry.getKey() == null && comparator() == null) return false;
AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE subEntry = AVL_TREE_MAP.this.findNode(entry.ENTRY_KEY()); AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE subEntry = AVL_TREE_MAP.this.findNode(entry.ENTRY_KEY());
if(subEntry != null) return VALUE_EQUALS(entry.ENTRY_VALUE(), subEntry.value); if(subEntry != null) return VALUE_EQUALS(entry.ENTRY_VALUE(), subEntry.value);
} }
else { else {
Map.Entry<?, ?> entry = (Map.Entry<?, ?>)o; Map.Entry<?, ?> entry = (Map.Entry<?, ?>)o;
if(entry.getKey() == null) return false; if(entry.getKey() == null && comparator() == null) return false;
#if !TYPE_OBJECT #if !TYPE_OBJECT
if(!(entry.getKey() instanceof CLASS_TYPE)) return false; if(!(entry.getKey() instanceof CLASS_TYPE)) return false;
#endif #endif

View File

@ -234,7 +234,7 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_G
@Override @Override
public VALUE_TYPE put(KEY_TYPE key, VALUE_TYPE value) { public VALUE_TYPE put(KEY_TYPE key, VALUE_TYPE value) {
#if TYPE_OBJECT #if TYPE_OBJECT
Objects.requireNonNull(key); validate(key);
#endif #endif
if(tree == null) { if(tree == null) {
tree = first = last = new EntryKV_BRACES(key, value, null); tree = first = last = new EntryKV_BRACES(key, value, null);
@ -271,7 +271,7 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_G
@Override @Override
public VALUE_TYPE putIfAbsent(KEY_TYPE key, VALUE_TYPE value) { public VALUE_TYPE putIfAbsent(KEY_TYPE key, VALUE_TYPE value) {
#if TYPE_OBJECT #if TYPE_OBJECT
Objects.requireNonNull(key); validate(key);
#endif #endif
if(tree == null) { if(tree == null) {
@ -310,7 +310,7 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_G
@Override @Override
public VALUE_TYPE addTo(KEY_TYPE key, VALUE_TYPE value) { public VALUE_TYPE addTo(KEY_TYPE key, VALUE_TYPE value) {
#if TYPE_OBJECT #if TYPE_OBJECT
Objects.requireNonNull(key); validate(key);
#endif #endif
if(tree == null) { if(tree == null) {
tree = first = last = new EntryKV_BRACES(key, value, null); tree = first = last = new EntryKV_BRACES(key, value, null);
@ -521,7 +521,7 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_G
public VALUE_TYPE COMPUTE(KEY_TYPE key, UNARY_OPERATOR KEY_VALUE_GENERIC_TYPE mappingFunction) { public VALUE_TYPE COMPUTE(KEY_TYPE key, UNARY_OPERATOR KEY_VALUE_GENERIC_TYPE mappingFunction) {
Objects.requireNonNull(mappingFunction); Objects.requireNonNull(mappingFunction);
#if TYPE_OBJECT #if TYPE_OBJECT
Objects.requireNonNull(key); validate(key);
#endif #endif
Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key); Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key);
if(entry == null) { if(entry == null) {
@ -543,7 +543,7 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_G
public VALUE_TYPE COMPUTE_IF_ABSENT(KEY_TYPE key, FUNCTION KEY_VALUE_GENERIC_TYPE mappingFunction) { public VALUE_TYPE COMPUTE_IF_ABSENT(KEY_TYPE key, FUNCTION KEY_VALUE_GENERIC_TYPE mappingFunction) {
Objects.requireNonNull(mappingFunction); Objects.requireNonNull(mappingFunction);
#if TYPE_OBJECT #if TYPE_OBJECT
Objects.requireNonNull(key); validate(key);
#endif #endif
Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key); Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key);
if(entry == null) { if(entry == null) {
@ -564,7 +564,7 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_G
public VALUE_TYPE SUPPLY_IF_ABSENT(KEY_TYPE key, VALUE_SUPPLIER VALUE_GENERIC_TYPE valueProvider) { public VALUE_TYPE SUPPLY_IF_ABSENT(KEY_TYPE key, VALUE_SUPPLIER VALUE_GENERIC_TYPE valueProvider) {
Objects.requireNonNull(valueProvider); Objects.requireNonNull(valueProvider);
#if TYPE_OBJECT #if TYPE_OBJECT
Objects.requireNonNull(key); validate(key);
#endif #endif
Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key); Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key);
if(entry == null) { if(entry == null) {
@ -585,7 +585,7 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_G
public VALUE_TYPE COMPUTE_IF_PRESENT(KEY_TYPE key, UNARY_OPERATOR KEY_VALUE_GENERIC_TYPE mappingFunction) { public VALUE_TYPE COMPUTE_IF_PRESENT(KEY_TYPE key, UNARY_OPERATOR KEY_VALUE_GENERIC_TYPE mappingFunction) {
Objects.requireNonNull(mappingFunction); Objects.requireNonNull(mappingFunction);
#if TYPE_OBJECT #if TYPE_OBJECT
Objects.requireNonNull(key); validate(key);
#endif #endif
Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key); Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key);
if(entry == null || VALUE_EQUALS(entry.value, getDefaultReturnValue())) return getDefaultReturnValue(); if(entry == null || VALUE_EQUALS(entry.value, getDefaultReturnValue())) return getDefaultReturnValue();
@ -602,7 +602,7 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_G
public VALUE_TYPE MERGE(KEY_TYPE key, VALUE_TYPE value, VALUE_UNARY_OPERATOR VALUE_VALUE_GENERIC_TYPE mappingFunction) { public VALUE_TYPE MERGE(KEY_TYPE key, VALUE_TYPE value, VALUE_UNARY_OPERATOR VALUE_VALUE_GENERIC_TYPE mappingFunction) {
Objects.requireNonNull(mappingFunction); Objects.requireNonNull(mappingFunction);
#if TYPE_OBJECT #if TYPE_OBJECT
Objects.requireNonNull(key); validate(key);
#endif #endif
Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key); Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key);
VALUE_TYPE newValue = entry == null || VALUE_EQUALS(entry.value, getDefaultReturnValue()) ? value : mappingFunction.APPLY_VALUE(entry.value, value); VALUE_TYPE newValue = entry == null || VALUE_EQUALS(entry.value, getDefaultReturnValue()) ? value : mappingFunction.APPLY_VALUE(entry.value, value);
@ -905,6 +905,7 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_G
} }
} }
protected void validate(KEY_TYPE k) { compare(k, k); }
protected int compare(KEY_TYPE k, KEY_TYPE v) { return comparator != null ? comparator.compare(k, v) : COMPAREABLE_TO_KEY(k, v);} protected int compare(KEY_TYPE k, KEY_TYPE v) { return comparator != null ? comparator.compare(k, v) : COMPAREABLE_TO_KEY(k, v);}
protected static GENERIC_KEY_VALUE_BRACES boolean isBlack(Entry KEY_VALUE_GENERIC_TYPE p) { return p == null || p.isBlack(); } protected static GENERIC_KEY_VALUE_BRACES boolean isBlack(Entry KEY_VALUE_GENERIC_TYPE p) { return p == null || p.isBlack(); }
protected static GENERIC_KEY_VALUE_BRACES Entry KEY_VALUE_GENERIC_TYPE parentOf(Entry KEY_VALUE_GENERIC_TYPE p) { return (p == null ? null : p.parent); } protected static GENERIC_KEY_VALUE_BRACES Entry KEY_VALUE_GENERIC_TYPE parentOf(Entry KEY_VALUE_GENERIC_TYPE p) { return (p == null ? null : p.parent); }
@ -1587,13 +1588,13 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_G
if(o instanceof Map.Entry) { if(o instanceof Map.Entry) {
if(o instanceof MAP.Entry) { if(o instanceof MAP.Entry) {
MAP.Entry KEY_VALUE_GENERIC_TYPE entry = (MAP.Entry KEY_VALUE_GENERIC_TYPE)o; MAP.Entry KEY_VALUE_GENERIC_TYPE entry = (MAP.Entry KEY_VALUE_GENERIC_TYPE)o;
if(entry.getKey() == null) return false; if(entry.getKey() == null && comparator() == null) return false;
RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE subEntry = m.findNode(entry.ENTRY_KEY()); RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE subEntry = m.findNode(entry.ENTRY_KEY());
if(subEntry != null) return VALUE_EQUALS(entry.ENTRY_VALUE(), subEntry.value); if(subEntry != null) return VALUE_EQUALS(entry.ENTRY_VALUE(), subEntry.value);
} }
else { else {
Map.Entry<?, ?> entry = (Map.Entry<?, ?>)o; Map.Entry<?, ?> entry = (Map.Entry<?, ?>)o;
if(entry.getKey() == null) return false; if(entry.getKey() == null && comparator() == null) return false;
#if !TYPE_OBJECT #if !TYPE_OBJECT
if(!(entry.getKey() instanceof CLASS_TYPE)) return false; if(!(entry.getKey() instanceof CLASS_TYPE)) return false;
#endif #endif
@ -1993,13 +1994,13 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_G
if(o instanceof Map.Entry) { if(o instanceof Map.Entry) {
if(o instanceof MAP.Entry) { if(o instanceof MAP.Entry) {
MAP.Entry KEY_VALUE_GENERIC_TYPE entry = (MAP.Entry KEY_VALUE_GENERIC_TYPE)o; MAP.Entry KEY_VALUE_GENERIC_TYPE entry = (MAP.Entry KEY_VALUE_GENERIC_TYPE)o;
if(entry.getKey() == null) return false; if(entry.getKey() == null && comparator() == null) return false;
RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE subEntry = RB_TREE_MAP.this.findNode(entry.ENTRY_KEY()); RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE subEntry = RB_TREE_MAP.this.findNode(entry.ENTRY_KEY());
if(subEntry != null) return VALUE_EQUALS(entry.ENTRY_VALUE(), subEntry.value); if(subEntry != null) return VALUE_EQUALS(entry.ENTRY_VALUE(), subEntry.value);
} }
else { else {
Map.Entry<?, ?> entry = (Map.Entry<?, ?>)o; Map.Entry<?, ?> entry = (Map.Entry<?, ?>)o;
if(entry.getKey() == null) return false; if(entry.getKey() == null && comparator() == null) return false;
#if !TYPE_OBJECT #if !TYPE_OBJECT
if(!(entry.getKey() instanceof CLASS_TYPE)) return false; if(!(entry.getKey() instanceof CLASS_TYPE)) return false;
#endif #endif

View File

@ -213,6 +213,9 @@ public class AVL_TREE_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE
#endif #endif
@Override @Override
public boolean add(KEY_TYPE o) { public boolean add(KEY_TYPE o) {
#if TYPE_OBJECT
validate(o);
#endif
if(tree == null) { if(tree == null) {
tree = first = last = new EntryBRACES(o, null); tree = first = last = new EntryBRACES(o, null);
size++; size++;
@ -242,7 +245,7 @@ public class AVL_TREE_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE
} }
fixAfterInsertion(adding); fixAfterInsertion(adding);
size++; size++;
return false; return true;
} }
@Override @Override
@ -652,6 +655,7 @@ public class AVL_TREE_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE
} }
} }
protected void validate(KEY_TYPE k) { compare(k, k); }
protected int compare(KEY_TYPE k, KEY_TYPE v) { return comparator != null ? comparator.compare(k, v) : COMPAREABLE_TO_KEY(k, v);} protected int compare(KEY_TYPE k, KEY_TYPE v) { return comparator != null ? comparator.compare(k, v) : COMPAREABLE_TO_KEY(k, v);}
/** From CLR */ /** From CLR */

View File

@ -74,8 +74,8 @@ public class ARRAY_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE im
* @throws NegativeArraySizeException if the length is negative * @throws NegativeArraySizeException if the length is negative
*/ */
public ARRAY_SET(KEY_TYPE[] array, int length) { public ARRAY_SET(KEY_TYPE[] array, int length) {
data = Arrays.copyOf(array, length); this(length);
size = length; addAll(array, length);
} }
/** /**
@ -548,6 +548,7 @@ public class ARRAY_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE im
public KEY_TYPE[] TO_ARRAY(KEY_TYPE[] a) { public KEY_TYPE[] TO_ARRAY(KEY_TYPE[] a) {
if(a == null || a.length < size()) return Arrays.copyOf(data, size()); if(a == null || a.length < size()) return Arrays.copyOf(data, size());
System.arraycopy(data, 0, a, 0, size()); System.arraycopy(data, 0, a, 0, size());
if (a.length > size) a[size] = EMPTY_KEY_VALUE;
return a; return a;
} }
@ -568,6 +569,7 @@ public class ARRAY_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE im
else if(a.length < size()) a = (E[])ObjectArrays.newArray(a.getClass().getComponentType(), size()); else if(a.length < size()) a = (E[])ObjectArrays.newArray(a.getClass().getComponentType(), size());
for(int i = 0;i<size();i++) for(int i = 0;i<size();i++)
a[i] = (E)KEY_TO_OBJ(data[i]); a[i] = (E)KEY_TO_OBJ(data[i]);
if (a.length > size) a[size] = null;
return a; return a;
} }
@ -841,6 +843,7 @@ public class ARRAY_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE im
@Override @Override
public KEY_TYPE NEXT() { public KEY_TYPE NEXT() {
if(!hasNext()) throw new NoSuchElementException();
lastReturned = index; lastReturned = index;
return data[index++]; return data[index++];
} }
@ -852,6 +855,7 @@ public class ARRAY_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE im
@Override @Override
public KEY_TYPE PREVIOUS() { public KEY_TYPE PREVIOUS() {
if(!hasPrevious()) throw new NoSuchElementException();
lastReturned = index; lastReturned = index;
return data[index--]; return data[index--];
} }
@ -924,6 +928,7 @@ public class ARRAY_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE im
@Override @Override
public KEY_TYPE NEXT() { public KEY_TYPE NEXT() {
if(!hasNext()) throw new NoSuchElementException();
lastReturned = index; lastReturned = index;
return data[index++]; return data[index++];
} }
@ -935,6 +940,7 @@ public class ARRAY_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE im
@Override @Override
public KEY_TYPE PREVIOUS() { public KEY_TYPE PREVIOUS() {
if(!hasPrevious()) throw new NoSuchElementException();
lastReturned = index; lastReturned = index;
return data[index--]; return data[index--];
} }
@ -951,11 +957,9 @@ public class ARRAY_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE im
@Override @Override
public void remove() { public void remove() {
if(lastReturned == -1) if(lastReturned == -1) throw new IllegalStateException();
throw new IllegalStateException();
ARRAY_SET.this.remove(data[lastReturned]); ARRAY_SET.this.remove(data[lastReturned]);
if(lastReturned < index) if(lastReturned < index) index--;
index--;
lastReturned = -1; lastReturned = -1;
} }

View File

@ -190,7 +190,18 @@ public class IMMUTABLE_HASH_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERI
{ {
KEY_TYPE o = a[i]; KEY_TYPE o = a[i];
if(KEY_EQUALS_NULL(o)) { if(KEY_EQUALS_NULL(o)) {
if(!containsNull) size++; if(!containsNull) {
size++;
if(prev != -1) {
newLinks[prev] ^= ((newLinks[prev] ^ (newSize & 0xFFFFFFFFL)) & 0xFFFFFFFFL);
newLinks[newSize] ^= ((newLinks[newSize] ^ ((prev & 0xFFFFFFFFL) << 32)) & 0xFFFFFFFF00000000L);
prev = newSize;
}
else {
prev = firstIndex = newSize;
newLinks[newSize] = -1L;
}
}
containsNull = true; containsNull = true;
continue; continue;
} }
@ -199,7 +210,7 @@ public class IMMUTABLE_HASH_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERI
KEY_TYPE current = newKeys[pos]; KEY_TYPE current = newKeys[pos];
if(KEY_EQUALS_NOT_NULL(current)) { if(KEY_EQUALS_NOT_NULL(current)) {
if(KEY_EQUALS(current, o)) continue; if(KEY_EQUALS(current, o)) continue;
while(KEY_EQUALS_NOT_NULL((current = newKeys[pos = (++pos & mask)]))) { while(KEY_EQUALS_NOT_NULL((current = newKeys[pos = (++pos & newMask)]))) {
if(KEY_EQUALS(current, o)) { if(KEY_EQUALS(current, o)) {
found = false; found = false;
break; break;
@ -220,7 +231,7 @@ public class IMMUTABLE_HASH_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERI
} }
} }
} }
nullIndex = size; nullIndex = newSize;
mask = newMask; mask = newMask;
keys = newKeys; keys = newKeys;
links = newLinks; links = newLinks;

View File

@ -602,6 +602,7 @@ public class CUSTOM_HASH_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_T
private class SetIterator implements ITERATOR KEY_GENERIC_TYPE { private class SetIterator implements ITERATOR KEY_GENERIC_TYPE {
int pos = nullIndex; int pos = nullIndex;
int returnedPos = -1;
int lastReturned = -1; int lastReturned = -1;
int nextIndex = Integer.MIN_VALUE; int nextIndex = Integer.MIN_VALUE;
boolean returnNull = containsNull; boolean returnNull = containsNull;
@ -634,6 +635,7 @@ public class CUSTOM_HASH_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_T
@Override @Override
public KEY_TYPE NEXT() { public KEY_TYPE NEXT() {
if(!hasNext()) throw new NoSuchElementException(); if(!hasNext()) throw new NoSuchElementException();
returnedPos = pos;
if(nextIndex < 0){ if(nextIndex < 0){
lastReturned = Integer.MAX_VALUE; lastReturned = Integer.MAX_VALUE;
KEY_TYPE value = wrapped.GET_KEY(nextIndex); KEY_TYPE value = wrapped.GET_KEY(nextIndex);
@ -652,9 +654,10 @@ public class CUSTOM_HASH_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_T
containsNull = false; containsNull = false;
keys[nullIndex] = EMPTY_KEY_VALUE; keys[nullIndex] = EMPTY_KEY_VALUE;
} }
else if(pos >= 0) shiftKeys(pos); else if(returnedPos >= 0) shiftKeys(returnedPos);
else { else {
CUSTOM_HASH_SET.this.remove(wrapped.GET_KEY(-pos - 1)); CUSTOM_HASH_SET.this.remove(wrapped.GET_KEY(-returnedPos - 1));
lastReturned = -1;
return; return;
} }
size--; size--;

View File

@ -559,6 +559,7 @@ public class HASH_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE imp
private class SetIterator implements ITERATOR KEY_GENERIC_TYPE { private class SetIterator implements ITERATOR KEY_GENERIC_TYPE {
int pos = nullIndex; int pos = nullIndex;
int returnedPos = -1;
int lastReturned = -1; int lastReturned = -1;
int nextIndex = Integer.MIN_VALUE; int nextIndex = Integer.MIN_VALUE;
boolean returnNull = containsNull; boolean returnNull = containsNull;
@ -592,6 +593,7 @@ public class HASH_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE imp
@Override @Override
public KEY_TYPE NEXT() { public KEY_TYPE NEXT() {
if(!hasNext()) throw new NoSuchElementException(); if(!hasNext()) throw new NoSuchElementException();
returnedPos = pos;
if(nextIndex < 0){ if(nextIndex < 0){
lastReturned = Integer.MAX_VALUE; lastReturned = Integer.MAX_VALUE;
KEY_TYPE value = wrapped.GET_KEY(nextIndex); KEY_TYPE value = wrapped.GET_KEY(nextIndex);
@ -610,9 +612,10 @@ public class HASH_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE imp
containsNull = false; containsNull = false;
keys[nullIndex] = EMPTY_KEY_VALUE; keys[nullIndex] = EMPTY_KEY_VALUE;
} }
else if(pos >= 0) shiftKeys(pos); else if(returnedPos >= 0) shiftKeys(returnedPos);
else { else {
HASH_SET.this.remove(wrapped.GET_KEY(-pos - 1)); HASH_SET.this.remove(wrapped.GET_KEY(-returnedPos - 1));
lastReturned = -1;
return; return;
} }
size--; size--;

View File

@ -213,6 +213,9 @@ public class RB_TREE_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE
#endif #endif
@Override @Override
public boolean add(KEY_TYPE o) { public boolean add(KEY_TYPE o) {
#if TYPE_OBJECT
validate(o);
#endif
if(tree == null) { if(tree == null) {
tree = first = last = new EntryBRACES(o, null); tree = first = last = new EntryBRACES(o, null);
size++; size++;
@ -242,7 +245,7 @@ public class RB_TREE_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE
} }
fixAfterInsertion(adding); fixAfterInsertion(adding);
size++; size++;
return false; return true;
} }
@Override @Override
@ -660,6 +663,7 @@ public class RB_TREE_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE
} }
} }
protected void validate(KEY_TYPE k) { compare(k, k); }
protected int compare(KEY_TYPE k, KEY_TYPE v) { return comparator != null ? comparator.compare(k, v) : COMPAREABLE_TO_KEY(k, v);} protected int compare(KEY_TYPE k, KEY_TYPE v) { return comparator != null ? comparator.compare(k, v) : COMPAREABLE_TO_KEY(k, v);}
protected static GENERIC_KEY_BRACES boolean isBlack(Entry KEY_GENERIC_TYPE p) { return p == null || p.isBlack(); } protected static GENERIC_KEY_BRACES boolean isBlack(Entry KEY_GENERIC_TYPE p) { return p == null || p.isBlack(); }
protected static GENERIC_KEY_BRACES Entry KEY_GENERIC_TYPE parentOf(Entry KEY_GENERIC_TYPE p) { return (p == null ? null : p.parent); } protected static GENERIC_KEY_BRACES Entry KEY_GENERIC_TYPE parentOf(Entry KEY_GENERIC_TYPE p) { return (p == null ? null : p.parent); }

View File

@ -72,8 +72,8 @@ public class SanityChecks
* @throws IllegalStateException if offset or accessSize is negative or the range goes out of the array-size * @throws IllegalStateException if offset or accessSize is negative or the range goes out of the array-size
*/ */
public static void checkArrayCapacity(int arraySize, int offset, int accessSize) { public static void checkArrayCapacity(int arraySize, int offset, int accessSize) {
if(offset < 0) throw new IllegalStateException("Offset is negative ("+offset+")"); if(offset < 0) throw new IndexOutOfBoundsException("Offset is negative ("+offset+")");
else if(accessSize < 0) throw new IllegalStateException("Size is negative ("+accessSize+")"); else if(accessSize < 0) throw new IllegalArgumentException("Size is negative ("+accessSize+")");
else if(arraySize < offset + accessSize) throw new IndexOutOfBoundsException("Index (" + (offset + accessSize) + ") is not in size (" + arraySize + ")"); else if(arraySize < offset + accessSize) throw new IndexOutOfBoundsException("Index (" + (offset + accessSize) + ") is not in size (" + arraySize + ")");
} }

View File

@ -0,0 +1,46 @@
package speiger.src.collections.objects.list;
import java.util.List;
import java.util.function.Function;
import com.google.common.collect.testing.ListTestSuiteBuilder;
import com.google.common.collect.testing.TestStringListGenerator;
import com.google.common.collect.testing.features.CollectionFeature;
import com.google.common.collect.testing.features.CollectionSize;
import com.google.common.collect.testing.features.ListFeature;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import speiger.src.collections.objects.lists.ImmutableObjectList;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.lists.ObjectLinkedList;
@SuppressWarnings("javadoc")
public class ObjectListTests extends TestCase
{
public static Test suite()
{
TestSuite suite = new TestSuite("Lists");
suite.addTest(suite("ArrayList", T -> new ObjectArrayList<>(T)));
suite.addTest(suite("LinkedList", T -> new ObjectLinkedList<>(T)));
suite.addTest(immutableSuite("ImmutableList", T -> new ImmutableObjectList<>(T)));
return suite;
}
public static Test suite(String name, Function<String[], List<String>> factory)
{
return ListTestSuiteBuilder.using(new TestStringListGenerator() {
@Override
protected List<String> create(String[] elements) { return factory.apply(elements); }
}).named(name).withFeatures(ListFeature.GENERAL_PURPOSE, CollectionFeature.ALLOWS_NULL_VALUES, CollectionSize.ANY).createTestSuite();
}
public static Test immutableSuite(String name, Function<String[], List<String>> factory)
{
return ListTestSuiteBuilder.using(new TestStringListGenerator() {
@Override
protected List<String> create(String[] elements) { return factory.apply(elements); }
}).named(name).withFeatures(CollectionFeature.ALLOWS_NULL_VALUES, CollectionSize.ANY).createTestSuite();
}
}

View File

@ -6,7 +6,9 @@ import java.util.Objects;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.function.Supplier; import java.util.function.Supplier;
import com.google.common.collect.testing.AnEnum;
import com.google.common.collect.testing.MapTestSuiteBuilder; import com.google.common.collect.testing.MapTestSuiteBuilder;
import com.google.common.collect.testing.TestEnumMapGenerator;
import com.google.common.collect.testing.TestStringMapGenerator; import com.google.common.collect.testing.TestStringMapGenerator;
import com.google.common.collect.testing.features.CollectionFeature; import com.google.common.collect.testing.features.CollectionFeature;
import com.google.common.collect.testing.features.CollectionSize; import com.google.common.collect.testing.features.CollectionSize;
@ -20,6 +22,9 @@ import speiger.src.collections.objects.maps.impl.customHash.Object2ObjectOpenCus
import speiger.src.collections.objects.maps.impl.hash.Object2ObjectLinkedOpenHashMap; import speiger.src.collections.objects.maps.impl.hash.Object2ObjectLinkedOpenHashMap;
import speiger.src.collections.objects.maps.impl.hash.Object2ObjectOpenHashMap; import speiger.src.collections.objects.maps.impl.hash.Object2ObjectOpenHashMap;
import speiger.src.collections.objects.maps.impl.immutable.ImmutableObject2ObjectOpenHashMap; import speiger.src.collections.objects.maps.impl.immutable.ImmutableObject2ObjectOpenHashMap;
import speiger.src.collections.objects.maps.impl.misc.Enum2ObjectMap;
import speiger.src.collections.objects.maps.impl.misc.LinkedEnum2ObjectMap;
import speiger.src.collections.objects.maps.impl.misc.Object2ObjectArrayMap;
import speiger.src.collections.objects.maps.impl.tree.Object2ObjectAVLTreeMap; import speiger.src.collections.objects.maps.impl.tree.Object2ObjectAVLTreeMap;
import speiger.src.collections.objects.maps.impl.tree.Object2ObjectRBTreeMap; import speiger.src.collections.objects.maps.impl.tree.Object2ObjectRBTreeMap;
import speiger.src.collections.objects.utils.ObjectStrategy; import speiger.src.collections.objects.utils.ObjectStrategy;
@ -34,9 +39,14 @@ public class ObjectMapTests extends TestCase
suite.addTest(suite("LinkedHashMap", Object2ObjectLinkedOpenHashMap::new, true)); suite.addTest(suite("LinkedHashMap", Object2ObjectLinkedOpenHashMap::new, true));
suite.addTest(suite("CustomHashMap", () -> new Object2ObjectOpenCustomHashMap<>(Strategy.INSTANCE), true)); suite.addTest(suite("CustomHashMap", () -> new Object2ObjectOpenCustomHashMap<>(Strategy.INSTANCE), true));
suite.addTest(suite("LinkedCustomHashMap", () -> new Object2ObjectLinkedOpenCustomHashMap<>(Strategy.INSTANCE), true)); suite.addTest(suite("LinkedCustomHashMap", () -> new Object2ObjectLinkedOpenCustomHashMap<>(Strategy.INSTANCE), true));
suite.addTest(suite("RBTreeMap", () -> new Object2ObjectRBTreeMap<String, String>(Comparator.naturalOrder()), false)); suite.addTest(suite("RBTreeMap_NonNull", Object2ObjectRBTreeMap::new, false));
suite.addTest(suite("AVLTreeMap", () -> new Object2ObjectAVLTreeMap<String, String>(Comparator.naturalOrder()), false)); suite.addTest(suite("AVLTreeMap_NonNull", Object2ObjectAVLTreeMap::new, false));
suite.addTest(suite("RBTreeMap_Null", () -> new Object2ObjectRBTreeMap<>(Comparator.nullsFirst(Comparator.naturalOrder())), true));
suite.addTest(suite("AVLTreeMap_Null", () -> new Object2ObjectAVLTreeMap<>(Comparator.nullsFirst(Comparator.naturalOrder())), true));
suite.addTest(immutableSuit("ImmutableMap", ImmutableObject2ObjectOpenHashMap::new)); suite.addTest(immutableSuit("ImmutableMap", ImmutableObject2ObjectOpenHashMap::new));
suite.addTest(suite("ArrayMap", Object2ObjectArrayMap::new, true));
suite.addTest(enumSuite("EnumMap", () -> new Enum2ObjectMap<>(AnEnum.class)));
suite.addTest(enumSuite("LinkedEnumMap", () -> new LinkedEnum2ObjectMap<>(AnEnum.class)));
return suite; return suite;
} }
@ -72,6 +82,21 @@ public class ObjectMapTests extends TestCase
return builder.createTestSuite(); return builder.createTestSuite();
} }
public static Test enumSuite(String name, Supplier<Map<AnEnum, String>> factory)
{
MapTestSuiteBuilder<AnEnum, String> builder = MapTestSuiteBuilder.using(new TestEnumMapGenerator() {
@Override
protected Map<AnEnum, String> create(Map.Entry<AnEnum, String>[] entries) {
Map<AnEnum, String> map = factory.get();
for(Map.Entry<AnEnum, String> entry : entries) {
map.put(entry.getKey(), entry.getValue());
}
return map;
}
}).named(name).withFeatures(CollectionSize.ANY, MapFeature.GENERAL_PURPOSE, MapFeature.ALLOWS_NULL_VALUES, CollectionFeature.SUPPORTS_ITERATOR_REMOVE);
return builder.createTestSuite();
}
private static class Strategy implements ObjectStrategy<String> private static class Strategy implements ObjectStrategy<String>
{ {
static final Strategy INSTANCE = new Strategy(); static final Strategy INSTANCE = new Strategy();

View File

@ -0,0 +1,80 @@
package speiger.src.collections.objects.set;
import java.util.Comparator;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import com.google.common.collect.testing.SetTestSuiteBuilder;
import com.google.common.collect.testing.TestStringSetGenerator;
import com.google.common.collect.testing.features.CollectionFeature;
import com.google.common.collect.testing.features.CollectionSize;
import com.google.common.collect.testing.features.SetFeature;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import speiger.src.collections.objects.sets.ImmutableObjectOpenHashSet;
import speiger.src.collections.objects.sets.ObjectAVLTreeSet;
import speiger.src.collections.objects.sets.ObjectArraySet;
import speiger.src.collections.objects.sets.ObjectLinkedOpenCustomHashSet;
import speiger.src.collections.objects.sets.ObjectLinkedOpenHashSet;
import speiger.src.collections.objects.sets.ObjectOpenCustomHashSet;
import speiger.src.collections.objects.sets.ObjectOpenHashSet;
import speiger.src.collections.objects.sets.ObjectRBTreeSet;
import speiger.src.collections.objects.utils.ObjectStrategy;
@SuppressWarnings("javadoc")
public class ObjectSetTests extends TestCase
{
public static Test suite()
{
TestSuite suite = new TestSuite("Sets");
suite.addTest(suite("HashSet", ObjectOpenHashSet::new, true));
suite.addTest(suite("LinkedHashSet", ObjectLinkedOpenHashSet::new, true));
suite.addTest(suite("CustomHashSet", T -> new ObjectOpenCustomHashSet<>(T, Strategy.INSTANCE), true));
suite.addTest(suite("LinkedCustomHashSet", T -> new ObjectLinkedOpenCustomHashSet<>(T, Strategy.INSTANCE), true));
suite.addTest(immutableSuite("ImmutableHashSet", ImmutableObjectOpenHashSet::new));
suite.addTest(suite("ArraySet", ObjectArraySet::new, true));
suite.addTest(suite("RBTreeSet_NonNull", ObjectRBTreeSet::new, false));
suite.addTest(suite("AVLTreeSet_NonNull", ObjectAVLTreeSet::new, false));
suite.addTest(suite("RBTreeSet_Null", T -> new ObjectRBTreeSet<>(T, Comparator.nullsFirst(Comparator.naturalOrder())), true));
suite.addTest(suite("AVLTreeSet_Null", T -> new ObjectAVLTreeSet<>(T, Comparator.nullsFirst(Comparator.naturalOrder())), true));
return suite;
}
public static Test suite(String name, Function<String[], Set<String>> factory, boolean allowNull)
{
SetTestSuiteBuilder<String> generator = SetTestSuiteBuilder.using(new TestStringSetGenerator() {
@Override
protected Set<String> create(String[] elements) { return factory.apply(elements); }
}).named(name).withFeatures(CollectionSize.ANY, SetFeature.GENERAL_PURPOSE);
if(allowNull) generator.withFeatures(CollectionFeature.ALLOWS_NULL_VALUES);
return generator.createTestSuite();
}
public static Test immutableSuite(String name, Function<String[], Set<String>> factory)
{
return SetTestSuiteBuilder.using(new TestStringSetGenerator() {
@Override
protected Set<String> create(String[] elements) { return factory.apply(elements); }
}).named(name).withFeatures(CollectionSize.ANY, CollectionFeature.ALLOWS_NULL_VALUES).createTestSuite();
}
private static class Strategy implements ObjectStrategy<String>
{
static final Strategy INSTANCE = new Strategy();
@Override
public int hashCode(String o) {
return Objects.hashCode(o);
}
@Override
public boolean equals(String key, String value) {
return Objects.equals(key, value);
}
}
}