ArraySet.java
package org.klojang.collections;
import org.klojang.check.Check;
import org.klojang.util.ArrayMethods;
import org.klojang.util.InvokeMethods;
import java.util.*;
import static org.klojang.check.CommonChecks.lt;
import static org.klojang.util.ArrayMethods.EMPTY_OBJECT_ARRAY;
import static org.klojang.util.ArrayMethods.implode;
final class ArraySet<E> extends ImmutableSet<E> {
@SuppressWarnings({"rawtypes"})
private static final ArraySet EMPTY = new ArraySet(EMPTY_OBJECT_ARRAY);
@SuppressWarnings({"unchecked"})
private static <E> ArraySet<E> empty() {
return (ArraySet<E>) EMPTY;
}
/*
* If trusted, the provided array is supposed to be internally generated, going out
* of scope immediately, and known to contain unique values only. All bets are off
* if this is not the case!!!! In that case the array will be swallowed rather than
* copied into the ArraySet.
*/
static <E> ArraySet<E> of(E[] values) {
return values.length != 0 ? new ArraySet<>(values) : empty();
}
static <E> ArraySet<E> copyOf(Collection<E> values) {
return values.size() != 0 ? new ArraySet<>(values.toArray()) : empty();
}
private final Object[] elems;
private ArraySet(Object[] elems) {
this.elems = elems;
}
@Override
public int size() {
return elems.length;
}
@Override
public boolean isEmpty() {
return elems.length == 0;
}
@Override
public boolean contains(Object o) {
return ArrayMethods.isElementOf(o, elems);
}
@Override
public boolean containsAll(Collection<?> c) {
return new HashSet<>(this).containsAll(c);
}
@Override
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
Check.notNull(a);
int sz = elems.length;
if (a.length < sz) {
a = (T[]) InvokeMethods.newArray(a.getClass(), sz);
}
int i = 0;
Object[] result = a;
for (E val : this) {
result[i++] = val;
}
if (a.length > sz) {
a[sz] = null;
}
return a;
}
@Override
public Iterator<E> iterator() {
return new Iterator<>() {
private int i = 0;
@Override
public boolean hasNext() {
return i < elems.length;
}
@Override
@SuppressWarnings({"unchecked"})
public E next() {
Check.that(i).is(lt(), size(), NoSuchElementException::new);
return (E) elems[i++];
}
};
}
@Override
public Object[] toArray() {
if (this == EMPTY) {
return EMPTY_OBJECT_ARRAY;
}
Object[] objs = new Object[elems.length];
System.arraycopy(elems, 0, objs, 0, elems.length);
return objs;
}
private int hash;
private String str;
@Override
public int hashCode() {
if (hash == 0) {
hash = Arrays.hashCode(elems);
}
return hash;
}
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o instanceof ArraySet<?> other) {
int len = other.elems.length;
if (elems.length == len) {
for (int i = 0; i < len; ++i) {
if (!elems[i].equals(other.elems[i])) {
return false;
}
}
return true;
}
return false;
}
if (o instanceof Set s) {
Iterator<E> itr = s.iterator();
for (Object e : elems) {
if (!itr.hasNext() || !e.equals(itr.next())) {
return false;
}
}
return !itr.hasNext();
}
return false;
}
@Override
public String toString() {
if (str == null) {
str = '[' + implode(elems) + ']';
}
return str;
}
}