Primitive-Collections/src/builder/resources/speiger/assets/collections/templates/maps/impl/misc/EnumMap.template

861 lines
25 KiB
Plaintext

package speiger.src.collections.PACKAGE.maps.impl.misc;
import java.util.Arrays;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.function.Consumer;
#if VALUE_BOOLEAN
import java.util.function.Predicate;
#endif
import speiger.src.collections.VALUE_PACKAGE.collections.VALUE_ABSTRACT_COLLECTION;
import speiger.src.collections.VALUE_PACKAGE.collections.VALUE_COLLECTION;
import speiger.src.collections.VALUE_PACKAGE.collections.VALUE_ITERATOR;
#if !VALUE_OBJECT
import speiger.src.collections.objects.collections.ObjectIterator;
#endif
import speiger.src.collections.VALUE_PACKAGE.functions.VALUE_SUPPLIER;
import speiger.src.collections.VALUE_PACKAGE.functions.function.VALUE_UNARY_OPERATOR;
import speiger.src.collections.PACKAGE.functions.consumer.BI_CONSUMER;
#if !VALUE_OBJECT
import speiger.src.collections.PACKAGE.functions.function.UNARY_OPERATOR;
#endif
#if !VALUE_BOOLEAN
import speiger.src.collections.PACKAGE.functions.function.FUNCTION;
#endif
import speiger.src.collections.objects.maps.abstracts.ABSTRACT_MAP;
import speiger.src.collections.objects.maps.interfaces.MAP;
import speiger.src.collections.objects.sets.AbstractObjectSet;
import speiger.src.collections.objects.sets.ObjectSet;
/**
* A Type Specific EnumMap implementation that allows for Primitive Values.
* Unlike javas implementation this one does not jump around between a single long or long array implementation based around the enum size
* This will cause a bit more memory usage but allows for a simpler implementation.
* @Type(T)
* @ValueType(V)
*/
public class ENUM_MAP KEY_ENUM_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GENERIC_TYPE
{
/** Enum Type that is being used */
protected Class<T> keyType;
/** The Backing keys array. */
protected transient T[] keys;
/** The Backing values array */
protected transient VALUE_TYPE[] values;
/** The Backing array that indicates which index is present or not */
protected transient long[] present;
/** Amount of Elements stored in the ArrayMap */
protected int size = 0;
/** EntrySet cache */
protected transient ObjectSet<MAP.Entry KEY_VALUE_GENERIC_TYPE> entrySet;
/** KeySet cache */
protected transient ObjectSet<T> keySet;
/** Values cache */
protected transient VALUE_COLLECTION VALUE_GENERIC_TYPE valuesC;
protected ENUM_MAP() {
}
/**
* Default Constructor
* @param keyType the type of Enum that should be used
*/
public ENUM_MAP(Class<T> keyType) {
this.keyType = keyType;
keys = getKeyUniverse(keyType);
values = NEW_VALUE_ARRAY(keys.length);
present = new long[((keys.length - 1) >> 6) + 1];
}
#if !VALUE_OBJECT
/**
* Helper constructor that allow to create a EnumMap from boxed values (it will unbox them)
* @param keys the keys that should be put into the EnumMap
* @param values the values that should be put into the EnumMap.
* @throws IllegalStateException if the keys and values do not match in lenght
*/
public ENUM_MAP(T[] keys, CLASS_VALUE_TYPE[] values) {
if(keys.length <= 0) throw new IllegalArgumentException("Empty Array are not allowed");
if(keys.length != values.length) throw new IllegalArgumentException("Keys and Values have to be the same size");
keyType = keys[0].getDeclaringClass();
this.keys = getKeyUniverse(keyType);
this.values = NEW_VALUE_ARRAY(this.keys.length);
present = new long[((this.keys.length - 1) >> 6) + 1];
putAll(keys, values);
}
#endif
/**
* Helper constructor that allow to create a EnumMap from unboxed values
* @param keys the keys that should be put into the map
* @param values the values that should be put into the map.
* @throws IllegalStateException if the keys and values do not match in lenght
*/
public ENUM_MAP(T[] keys, VALUE_TYPE[] values) {
if(keys.length <= 0) throw new IllegalArgumentException("Empty Array are not allowed");
if(keys.length != values.length) throw new IllegalArgumentException("Keys and Values have to be the same size");
keyType = keys[0].getDeclaringClass();
this.keys = getKeyUniverse(keyType);
this.values = NEW_VALUE_ARRAY(this.keys.length);
present = new long[((this.keys.length - 1) >> 6) + 1];
putAll(keys, values);
}
/**
* A Helper constructor that allows to create a EnumMap with exactly the same values as the provided map.
* @param map the values that should be present in the map
*/
public ENUM_MAP(Map<? extends CLASS_TYPE, ? extends CLASS_VALUE_TYPE> map) {
if(map instanceof ENUM_MAP) {
ENUM_MAP KEY_VALUE_GENERIC_TYPE enumMap = (ENUM_MAP KEY_VALUE_GENERIC_TYPE)map;
keyType = enumMap.keyType;
keys = enumMap.keys;
values = enumMap.values.clone();
present = enumMap.present.clone();
size = enumMap.size;
}
else if(map.isEmpty()) throw new IllegalArgumentException("Empty Maps are not allowed");
else {
keyType = map.keySet().iterator().next().getDeclaringClass();
this.keys = getKeyUniverse(keyType);
this.values = NEW_VALUE_ARRAY(keys.length);
present = new long[((keys.length - 1) >> 6) + 1];
putAll(map);
}
}
/**
* A Type Specific Helper function that allows to create a new EnumMap with exactly the same values as the provided map.
* @param map the values that should be present in the map
*/
public ENUM_MAP(MAP KEY_VALUE_GENERIC_TYPE map) {
if(map instanceof ENUM_MAP) {
ENUM_MAP KEY_VALUE_GENERIC_TYPE enumMap = (ENUM_MAP KEY_VALUE_GENERIC_TYPE)map;
keyType = enumMap.keyType;
keys = enumMap.keys;
values = enumMap.values.clone();
present = enumMap.present.clone();
size = enumMap.size;
}
else if(map.isEmpty()) throw new IllegalArgumentException("Empty Maps are not allowed");
else {
keyType = map.keySet().iterator().next().getDeclaringClass();
this.keys = getKeyUniverse(keyType);
this.values = NEW_VALUE_ARRAY(keys.length);
present = new long[((keys.length - 1) >> 6) + 1];
putAll(map);
}
}
@Override
public VALUE_TYPE put(T key, VALUE_TYPE value) {
int index = key.ordinal();
if(isSet(index)) {
VALUE_TYPE result = values[index];
values[index] = value;
return result;
}
set(index);
values[index] = value;
return getDefaultReturnValue();
}
@Override
public VALUE_TYPE putIfAbsent(T key, VALUE_TYPE value) {
int index = key.ordinal();
if(isSet(index)) {
if(VALUE_EQUALS(values[index], getDefaultReturnValue())) {
VALUE_TYPE oldValue = values[index];
values[index] = value;
return oldValue;
}
return values[index];
}
set(index);
values[index] = value;
return getDefaultReturnValue();
}
#if VALUE_PRIMITIVES
@Override
public VALUE_TYPE addTo(T key, VALUE_TYPE value) {
int index = key.ordinal();
if(isSet(index)) {
VALUE_TYPE result = values[index];
values[index] += value;
return result;
}
set(index);
values[index] = value;
return getDefaultReturnValue();
}
@Override
public VALUE_TYPE subFrom(T key, VALUE_TYPE value) {
int index = key.ordinal();
if(!isSet(index)) return getDefaultReturnValue();
VALUE_TYPE oldValue = values[index];
values[index] -= value;
if(value < 0 ? (values[index] >= getDefaultReturnValue()) : (values[index] <= getDefaultReturnValue())) {
clear(index);
values[index] = EMPTY_VALUE;
}
return oldValue;
}
#endif
@Override
public boolean containsKey(Object key) {
if(!keyType.isInstance(key)) return false;
return isSet(((T)key).ordinal());
}
#if VALUE_OBJECT
@Override
public boolean containsValue(Object value) {
for(int i = 0;i<values.length;i++)
if(isSet(i) && VALUE_EQUALS(value, values[i])) return true;
return false;
}
#else
@Override
public boolean containsValue(VALUE_TYPE value) {
for(int i = 0;i<values.length;i++)
if(isSet(i) && VALUE_EQUALS(value, values[i])) return true;
return false;
}
#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
public VALUE_TYPE rem(T key) {
if(!keyType.isInstance(key)) return getDefaultReturnValue();
int index = key.ordinal();
if(!isSet(index)) return getDefaultReturnValue();
clear(index);
VALUE_TYPE result = values[index];
values[index] = EMPTY_VALUE;
return result;
}
@Override
public VALUE_TYPE remOrDefault(T key, VALUE_TYPE defaultValue) {
int index = key.ordinal();
if(!isSet(index)) return defaultValue;
clear(index);
VALUE_TYPE result = values[index];
values[index] = EMPTY_VALUE;
return result;
}
#if VALUE_OBJECT
@Override
public boolean remove(Object key, Object value) {
int index = ((T)key).ordinal();
if(!isSet(index) || VALUE_EQUALS_NOT(value, values[index])) return false;
clear(index);
values[index] = EMPTY_VALUE;
return true;
}
#else
@Override
public boolean remove(T key, VALUE_TYPE value) {
int index = key.ordinal();
if(!isSet(index) || VALUE_EQUALS_NOT(value, values[index])) return false;
clear(index);
values[index] = EMPTY_VALUE;
return true;
}
#endif
@Override
public VALUE_TYPE GET_VALUE(T key) {
if(!keyType.isInstance(key)) return getDefaultReturnValue();
int index = key.ordinal();
return isSet(index) ? values[index] : getDefaultReturnValue();
}
#if VALUE_OBJECT
@Override
public VALUE_TYPE getOrDefault(Object key, VALUE_TYPE defaultValue) {
if(!keyType.isInstance(key)) return defaultValue;
int index = ((T)key).ordinal();
return isSet(index) ? values[index] : defaultValue;
}
#else
@Override
public VALUE_TYPE getOrDefault(T key, VALUE_TYPE defaultValue) {
if(!keyType.isInstance(key)) return defaultValue;
int index = key.ordinal();
return isSet(index) ? values[index] : defaultValue;
}
#endif
@Override
public ENUM_MAP KEY_VALUE_GENERIC_TYPE copy() {
ENUM_MAP KEY_VALUE_GENERIC_TYPE map = new ENUM_MAPKV_BRACES(keyType);
map.size = size;
System.arraycopy(present, 0, map.present, 0, Math.min(present.length, map.present.length));
System.arraycopy(values, 0, map.values, 0, Math.min(values.length, map.values.length));
return map;
}
@Override
public ObjectSet<MAP.Entry KEY_VALUE_GENERIC_TYPE> ENTRY_SET() {
if(entrySet == null) entrySet = new EntrySet();
return entrySet;
}
@Override
public ObjectSet<T> keySet() {
if(keySet == null) keySet = new KeySet();
return keySet;
}
@Override
public VALUE_COLLECTION VALUE_GENERIC_TYPE values() {
if(valuesC == null) valuesC = new Values();
return valuesC;
}
@Override
public void forEach(BI_CONSUMER KEY_VALUE_GENERIC_TYPE action) {
if(size() <= 0) return;
for(int i = 0,m=keys.length;i<m;i++) {
if(isSet(i)) action.accept(keys[i], values[i]);
}
}
@Override
public boolean replace(T key, VALUE_TYPE oldValue, VALUE_TYPE newValue) {
int index = key.ordinal();
if(!isSet(index) || values[index] != oldValue) return false;
values[index] = newValue;
return true;
}
@Override
public VALUE_TYPE replace(T key, VALUE_TYPE value) {
int index = key.ordinal();
if(!isSet(index)) return getDefaultReturnValue();
VALUE_TYPE oldValue = values[index];
values[index] = value;
return oldValue;
}
@Override
public VALUE_TYPE COMPUTE(T key, UNARY_OPERATOR KEY_VALUE_GENERIC_TYPE mappingFunction) {
int index = key.ordinal();
if(!isSet(index)) {
VALUE_TYPE newValue = mappingFunction.APPLY_VALUE(key, getDefaultReturnValue());
#if VALUE_OBJECT
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) return newValue;
#endif
set(index);
values[index] = newValue;
return newValue;
}
VALUE_TYPE newValue = mappingFunction.APPLY_VALUE(key, values[index]);
#if VALUE_OBJECT
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) {
clear(index);
values[index] = EMPTY_VALUE;
return newValue;
}
#endif
values[index] = newValue;
return newValue;
}
@Override
public VALUE_TYPE COMPUTE_IF_ABSENT(T key, FUNCTION KEY_VALUE_GENERIC_TYPE mappingFunction) {
int index = key.ordinal();
if(!isSet(index)) {
VALUE_TYPE newValue = mappingFunction.APPLY(key);
#if VALUE_OBJECT
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) return newValue;
#endif
set(index);
values[index] = newValue;
return newValue;
}
VALUE_TYPE newValue = values[index];
#if VALUE_OBJECT
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) {
newValue = mappingFunction.APPLY(key);
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) return newValue;
values[index] = newValue;
}
#endif
return newValue;
}
@Override
public VALUE_TYPE SUPPLY_IF_ABSENT(T key, VALUE_SUPPLIER VALUE_GENERIC_TYPE valueProvider) {
int index = key.ordinal();
if(!isSet(index)) {
VALUE_TYPE newValue = valueProvider.VALUE_SUPPLY_GET();
#if VALUE_OBJECT
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) return newValue;
#endif
set(index);
values[index] = newValue;
return newValue;
}
VALUE_TYPE newValue = values[index];
#if VALUE_OBJECT
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) {
newValue = valueProvider.VALUE_SUPPLY_GET();
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) return newValue;
values[index] = newValue;
}
#endif
return newValue;
}
@Override
public VALUE_TYPE COMPUTE_IF_PRESENT(T key, UNARY_OPERATOR KEY_VALUE_GENERIC_TYPE mappingFunction) {
int index = key.ordinal();
#if !VALUE_OBJECT
if(!isSet(index)) return getDefaultReturnValue();
VALUE_TYPE newValue = mappingFunction.APPLY_VALUE(key, values[index]);
#else
if(!isSet(index) || VALUE_EQUALS(values[index], getDefaultReturnValue())) return getDefaultReturnValue();
VALUE_TYPE newValue = mappingFunction.APPLY_VALUE(key, values[index]);
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) {
clear(index);
values[index] = EMPTY_VALUE;
return newValue;
}
#endif
values[index] = newValue;
return newValue;
}
#if !VALUE_OBJECT
@Override
public VALUE_TYPE COMPUTENonDefault(T key, UNARY_OPERATOR KEY_VALUE_GENERIC_TYPE mappingFunction) {
int index = key.ordinal();
if(!isSet(index)) {
VALUE_TYPE newValue = mappingFunction.APPLY_VALUE(key, getDefaultReturnValue());
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) return newValue;
set(index);
values[index] = newValue;
return newValue;
}
VALUE_TYPE newValue = mappingFunction.APPLY_VALUE(key, values[index]);
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) {
clear(index);
values[index] = EMPTY_VALUE;
return newValue;
}
values[index] = newValue;
return newValue;
}
@Override
public VALUE_TYPE COMPUTE_IF_ABSENTNonDefault(T key, FUNCTION KEY_VALUE_GENERIC_TYPE mappingFunction) {
int index = key.ordinal();
if(!isSet(index)) {
VALUE_TYPE newValue = mappingFunction.APPLY(key);
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) return newValue;
set(index);
values[index] = newValue;
return newValue;
}
VALUE_TYPE newValue = values[index];
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) {
newValue = mappingFunction.APPLY(key);
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) return newValue;
values[index] = newValue;
}
return newValue;
}
@Override
public VALUE_TYPE SUPPLY_IF_ABSENTNonDefault(T key, VALUE_SUPPLIER VALUE_GENERIC_TYPE valueProvider) {
int index = key.ordinal();
if(!isSet(index)) {
VALUE_TYPE newValue = valueProvider.VALUE_SUPPLY_GET();
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) return newValue;
set(index);
values[index] = newValue;
return newValue;
}
VALUE_TYPE newValue = values[index];
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) {
newValue = valueProvider.VALUE_SUPPLY_GET();
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) return newValue;
values[index] = newValue;
}
return newValue;
}
@Override
public VALUE_TYPE COMPUTE_IF_PRESENTNonDefault(T key, UNARY_OPERATOR KEY_VALUE_GENERIC_TYPE mappingFunction) {
int index = key.ordinal();
if(!isSet(index) || VALUE_EQUALS(values[index], getDefaultReturnValue())) return getDefaultReturnValue();
VALUE_TYPE newValue = mappingFunction.APPLY_VALUE(key, values[index]);
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) {
clear(index);
values[index] = EMPTY_VALUE;
return newValue;
}
values[index] = newValue;
return newValue;
}
#endif
@Override
public VALUE_TYPE MERGE(T key, VALUE_TYPE value, VALUE_UNARY_OPERATOR VALUE_VALUE_GENERIC_TYPE mappingFunction) {
int index = key.ordinal();
#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(isSet(index)) {
clear(index);
values[index] = EMPTY_VALUE;
}
}
else if(!isSet(index)) {
set(index);
values[index] = newValue;
}
else values[index] = newValue;
return newValue;
}
@Override
public void BULK_MERGE(MAP KEY_VALUE_GENERIC_TYPE m, VALUE_UNARY_OPERATOR VALUE_VALUE_GENERIC_TYPE mappingFunction) {
Objects.requireNonNull(mappingFunction);
for(MAP.Entry KEY_VALUE_GENERIC_TYPE entry : getFastIterable(m)) {
T key = entry.ENTRY_KEY();
int index = key.ordinal();
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(isSet(index)) {
clear(index);
values[index] = EMPTY_VALUE;
}
}
else if(!isSet(index)) {
set(index);
values[index] = newValue;
}
else values[index] = newValue;
}
}
@Override
public void clear() {
if(size == 0) return;
size = 0;
Arrays.fill(present, 0L);
Arrays.fill(values, EMPTY_VALUE);
}
@Override
public int size() {
return size;
}
protected void onNodeAdded(int index) {
}
protected void onNodeRemoved(int index) {
}
protected void set(int index) {
onNodeAdded(index);
present[index >> 6] |= (1L << index);
size++;
}
protected void clear(int index) {
size--;
present[index >> 6] &= ~(1L << index);
onNodeRemoved(index);
}
protected boolean isSet(int index) { return (present[index >> 6] & (1L << index)) != 0; }
protected static <K extends Enum<K>> K[] getKeyUniverse(Class<K> keyType) {
return keyType.getEnumConstants();
}
class EntrySet extends AbstractObjectSet<MAP.Entry KEY_VALUE_GENERIC_TYPE> {
@Override
public boolean contains(Object o) {
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;
}
@Override
public boolean remove(Object o) {
if(o instanceof Map.Entry) {
if(o instanceof MAP.Entry) {
MAP.Entry KEY_VALUE_GENERIC_TYPE entry = (MAP.Entry KEY_VALUE_GENERIC_TYPE)o;
return ENUM_MAP.this.remove(entry.getKey(), entry.ENTRY_VALUE());
}
Map.Entry<?, ?> entry = (java.util.Map.Entry<?, ?>)o;
return ENUM_MAP.this.remove(entry.getKey(), entry.getValue());
}
return false;
}
@Override
public void forEach(Consumer<? super MAP.Entry KEY_VALUE_GENERIC_TYPE> action) {
if(size() <= 0) return;
for(int i = 0,m=keys.length;i<m;i++) {
if(isSet(i)) action.accept(new ValueMapEntry(i));
}
}
@Override
public ObjectIterator<MAP.Entry KEY_VALUE_GENERIC_TYPE> iterator() {
return new EntryIterator();
}
@Override
public int size() {
return ENUM_MAP.this.size();
}
@Override
public void clear() {
ENUM_MAP.this.clear();
}
}
class KeySet extends AbstractObjectSet<T> {
@Override
public boolean contains(Object o) {
return containsKey(o);
}
@Override
public boolean remove(Object o) {
int size = size();
ENUM_MAP.this.remove(o);
return size != size();
}
@Override
public ObjectIterator<T> iterator() {
return new KeyIterator();
}
@Override
public int size() {
return ENUM_MAP.this.size();
}
@Override
public void clear() {
ENUM_MAP.this.clear();
}
}
class Values extends VALUE_ABSTRACT_COLLECTION VALUE_GENERIC_TYPE {
@Override
public boolean add(VALUE_TYPE o) { throw new UnsupportedOperationException(); }
#if TYPE_OBJECT
@Override
public boolean contains(Object e) { return containsValue(e); }
#else
@Override
public boolean contains(VALUE_TYPE e) { return containsValue(e); }
#endif
@Override
public VALUE_ITERATOR VALUE_GENERIC_TYPE iterator() {
return new ValueIterator();
}
@Override
public int size() {
return ENUM_MAP.this.size();
}
@Override
public void clear() {
ENUM_MAP.this.clear();
}
}
class EntryIterator extends MapIterator implements ObjectIterator<MAP.Entry KEY_VALUE_GENERIC_TYPE> {
@Override
public MAP.Entry KEY_VALUE_GENERIC_TYPE next() {
return new ValueMapEntry(nextEntry());
}
}
class KeyIterator extends MapIterator implements ObjectIterator<T> {
@Override
public T next() {
return keys[nextEntry()];
}
}
class ValueIterator extends MapIterator implements VALUE_ITERATOR VALUE_GENERIC_TYPE {
@Override
public VALUE_TYPE VALUE_NEXT() {
return values[nextEntry()];
}
}
class MapIterator {
int index;
int lastReturnValue = -1;
int nextIndex = -1;
public boolean hasNext() {
if(nextIndex == -1 && index < values.length) {
while(index < values.length && !isSet(index++));
nextIndex = index-1;
if(!isSet(nextIndex)) nextIndex = -1;
}
return nextIndex != -1;
}
public int nextEntry() {
if(!hasNext()) throw new NoSuchElementException();
lastReturnValue = nextIndex;
nextIndex = -1;
return lastReturnValue;
}
public void remove() {
if(lastReturnValue == -1) throw new IllegalStateException();
clear(lastReturnValue);
values[lastReturnValue] = EMPTY_VALUE;
lastReturnValue = -1;
}
}
protected class ValueMapEntry extends MapEntry {
protected KEY_TYPE key;
protected VALUE_TYPE value;
public ValueMapEntry(int index) {
super(index);
key = keys[index];
value = values[index];
}
@Override
public KEY_TYPE ENTRY_KEY() {
return key;
}
@Override
public VALUE_TYPE ENTRY_VALUE() {
return value;
}
@Override
public VALUE_TYPE setValue(VALUE_TYPE value) {
this.value = value;
return super.setValue(value);
}
}
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;
}
void set(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(ENTRY_KEY(), entry.ENTRY_KEY()) && VALUE_EQUALS(ENTRY_VALUE(), 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(ENTRY_KEY(), key) && VALUE_EQUALS(ENTRY_VALUE(), value);
#else if TYPE_OBJECT
return value instanceof CLASS_VALUE_TYPE && KEY_EQUALS(ENTRY_KEY(), key) && VALUE_EQUALS(ENTRY_VALUE(), CLASS_TO_VALUE(value));
#else if VALUE_OBJECT
return key instanceof CLASS_TYPE && KEY_EQUALS(ENTRY_KEY(), CLASS_TO_KEY(key)) && VALUE_EQUALS(ENTRY_VALUE(), value);
#else
return key instanceof CLASS_TYPE && value instanceof CLASS_VALUE_TYPE && KEY_EQUALS(ENTRY_KEY(), CLASS_TO_KEY(key)) && VALUE_EQUALS(ENTRY_VALUE(), CLASS_TO_VALUE(value));
#endif
}
return false;
}
@Override
public int hashCode() {
return KEY_TO_HASH(ENTRY_KEY()) ^ VALUE_TO_HASH(ENTRY_VALUE());
}
@Override
public String toString() {
return KEY_TO_STRING(ENTRY_KEY()) + "=" + VALUE_TO_STRING(ENTRY_VALUE());
}
}
}