861 lines
25 KiB
Plaintext
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());
|
|
}
|
|
}
|
|
}
|