Added over 6k tests...

- 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
This commit is contained in:
Speiger 2021-12-10 10:55:16 +01:00
parent 362838c434
commit eaa45976c7
10 changed files with 484 additions and 101 deletions

View File

@ -18,11 +18,16 @@
- Fixed: Map.Entry toString wasn't writing values not like it should do. - Fixed: Map.Entry toString wasn't writing values not like it should do.
- Fixed: Set.hashCode now is the sum of the elements instead of a Unique HashCode based on the elements. - Fixed: Set.hashCode now is the sum of the elements instead of a Unique HashCode based on the elements.
- Fixed: Added missing NonNull Checks. - Fixed: Added missing NonNull Checks.
- Fixed: OpenHashMap.containsValue implementation was wrong. - Fixed: Custom/OpenHashMap.containsValue implementation was wrong.
- Fixed: OpenHashMap.compute/present/absent now works how it is specified in the Java Documentation - Fixed: Custom/OpenHashMap.compute/present/absent now works how it is specified in the Java Documentation
- Fixed: OpenHashMap.merge/BulkMerge now works how it is specified in the Java Documentation - Fixed: Custom/OpenHashMap.merge/BulkMerge now works how it is specified in the Java Documentation
- Fixed: OpenHashMap.keySet.remove was causing a infinite loop. - Fixed: Custom/Linked/OpenHashMap.keySet.remove was causing a infinite loop.
- Fixed: OpenHashMap.mapIterator now no longer crashes in certain cases. - Fixed: Custom/Linked/OpenHashMap.entrySet.contains was not correctly comparing the entry.
- Fixed: Custom/OpenHashMap.mapIterator now no longer crashes in certain cases.
- Added: Custom/LinkedOpenHashMap now takes use of the improved Iterator it has for containsValue
- 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: RB/AVLTreeMaps issues. Roughly the same as the rest of the maps
### 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

@ -820,8 +820,19 @@ public class LINKED_CUSTOM_HASH_MAP KEY_VALUE_GENERIC_TYPE extends CUSTOM_HASH_M
@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_CUSTOM_HASH_MAP.this.containsKey(((MAP.Entry KEY_VALUE_GENERIC_TYPE)o).ENTRY_KEY()); if(o instanceof MAP.Entry) {
return LINKED_CUSTOM_HASH_MAP.this.containsKey(((Map.Entry<?, ?>)o).getKey()); MAP.Entry KEY_VALUE_GENERIC_TYPE entry = (MAP.Entry KEY_VALUE_GENERIC_TYPE)o;
int index = LINKED_CUSTOM_HASH_MAP.this.findIndex(entry.ENTRY_KEY());
if(index >= 0) return VALUE_EQUALS(entry.ENTRY_VALUE(), LINKED_CUSTOM_HASH_MAP.this.values[index]);
}
else {
Map.Entry<?, ?> entry = (Map.Entry<?, ?>)o;
#if !TYPE_OBJECT
if(!(entry.getKey() instanceof CLASS_TYPE)) return false;
#endif
int index = LINKED_CUSTOM_HASH_MAP.this.findIndex((CLASS_TYPE)entry.getKey());
if(index >= 0) return Objects.equals(entry.getValue(), VALUE_TO_OBJ(LINKED_CUSTOM_HASH_MAP.this.values[index]));
}
} }
return false; return false;
} }
@ -873,7 +884,7 @@ public class LINKED_CUSTOM_HASH_MAP KEY_VALUE_GENERIC_TYPE extends CUSTOM_HASH_M
@Override @Override
public boolean remove(Object o) { public boolean remove(Object o) {
int oldSize = size; int oldSize = size;
remove(o); LINKED_CUSTOM_HASH_MAP.this.remove(o);
return size != oldSize; return size != oldSize;
} }
@ -886,7 +897,7 @@ public class LINKED_CUSTOM_HASH_MAP KEY_VALUE_GENERIC_TYPE extends CUSTOM_HASH_M
@Override @Override
public boolean remove(KEY_TYPE o) { public boolean remove(KEY_TYPE o) {
int oldSize = size; int oldSize = size;
remove(o); LINKED_CUSTOM_HASH_MAP.this.remove(o);
return size != oldSize; return size != oldSize;
} }

View File

@ -307,8 +307,7 @@ public class CUSTOM_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VAL
#if !VALUE_OBJECT #if !VALUE_OBJECT
@Override @Override
public boolean containsValue(VALUE_TYPE value) { public boolean containsValue(VALUE_TYPE value) {
if(VALUE_EQUALS(value, values[nullIndex])) return true; for(int i = nullIndex;i >= 0;i--)
for(int i = nullIndex-1;i >= 0;i--)
if(!strategy.equals(keys[i], EMPTY_KEY_VALUE) && VALUE_EQUALS(values[i], value)) return true; if(!strategy.equals(keys[i], EMPTY_KEY_VALUE) && VALUE_EQUALS(values[i], value)) return true;
return false; return false;
} }
@ -317,9 +316,12 @@ public class CUSTOM_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VAL
@Override @Override
@ValuePrimitive @ValuePrimitive
public boolean containsValue(Object value) { public boolean containsValue(Object value) {
if((value == null && VALUE_EQUALS(values[nullIndex], getDefaultReturnValue())) || EQUALS_VALUE_TYPE(values[nullIndex], value)) return true; for(int i = nullIndex;i >= 0;i--)
for(int i = nullIndex-1;i >= 0;i--) #if VALUE_OBJECT
if(!strategy.equals(keys[i], EMPTY_KEY_VALUE) && EQUALS_VALUE_TYPE(values[i], value)) return true;
#else
if(!strategy.equals(keys[i], EMPTY_KEY_VALUE) && ((value == null && values[i] == getDefaultReturnValue()) || EQUALS_VALUE_TYPE(values[i], value))) return true; if(!strategy.equals(keys[i], EMPTY_KEY_VALUE) && ((value == null && values[i] == getDefaultReturnValue()) || EQUALS_VALUE_TYPE(values[i], value))) return true;
#endif
return false; return false;
} }
@ -338,7 +340,6 @@ public class CUSTOM_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VAL
} }
@Override @Override
@Deprecated
public CLASS_VALUE_TYPE remove(Object key) { public CLASS_VALUE_TYPE remove(Object key) {
#if !TYPE_OBJECT #if !TYPE_OBJECT
if(!(key instanceof CLASS_TYPE)) return getDefaultReturnValue(); if(!(key instanceof CLASS_TYPE)) return getDefaultReturnValue();
@ -495,6 +496,7 @@ public class CUSTOM_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VAL
@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 < 0) { if(index < 0) {
VALUE_TYPE newValue = mappingFunction.APPLY_VALUE(key, getDefaultReturnValue()); VALUE_TYPE newValue = mappingFunction.APPLY_VALUE(key, getDefaultReturnValue());
@ -513,6 +515,7 @@ public class CUSTOM_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VAL
@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 < 0) { if(index < 0) {
VALUE_TYPE newValue = mappingFunction.GET_VALUE(key); VALUE_TYPE newValue = mappingFunction.GET_VALUE(key);
@ -520,11 +523,18 @@ public class CUSTOM_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VAL
insert(-index-1, key, newValue); insert(-index-1, 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 < 0) { if(index < 0) {
VALUE_TYPE newValue = valueProvider.VALUE_GET_KEY(); VALUE_TYPE newValue = valueProvider.VALUE_GET_KEY();
@ -532,13 +542,20 @@ public class CUSTOM_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VAL
insert(-index-1, key, newValue); insert(-index-1, 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 < 0) return getDefaultReturnValue(); if(index < 0 || 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);
@ -550,8 +567,12 @@ public class CUSTOM_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VAL
@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 < 0 ? value : mappingFunction.APPLY_VALUE(values[index], value); VALUE_TYPE newValue = index < 0 || 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);
@ -567,7 +588,7 @@ public class CUSTOM_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VAL
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 < 0 ? entry.ENTRY_VALUE() : mappingFunction.APPLY_VALUE(values[index], entry.ENTRY_VALUE()); VALUE_TYPE newValue = index < 0 || 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);
@ -784,7 +805,7 @@ public class CUSTOM_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VAL
@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]);
} }
} }
@ -968,8 +989,19 @@ public class CUSTOM_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VAL
@Override @Override
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 CUSTOM_HASH_MAP.this.containsKey(((MAP.Entry KEY_VALUE_GENERIC_TYPE)o).ENTRY_KEY()); if(o instanceof MAP.Entry) {
return CUSTOM_HASH_MAP.this.containsKey(((Map.Entry<?, ?>)o).getKey()); MAP.Entry KEY_VALUE_GENERIC_TYPE entry = (MAP.Entry KEY_VALUE_GENERIC_TYPE)o;
int index = CUSTOM_HASH_MAP.this.findIndex(entry.ENTRY_KEY());
if(index >= 0) return VALUE_EQUALS(entry.ENTRY_VALUE(), CUSTOM_HASH_MAP.this.values[index]);
}
else {
Map.Entry<?, ?> entry = (Map.Entry<?, ?>)o;
#if !TYPE_OBJECT
if(!(entry.getKey() instanceof CLASS_TYPE)) return false;
#endif
int index = CUSTOM_HASH_MAP.this.findIndex((CLASS_TYPE)entry.getKey());
if(index >= 0) return Objects.equals(entry.getValue(), VALUE_TO_OBJ(CUSTOM_HASH_MAP.this.values[index]));
}
} }
return false; return false;
} }
@ -998,7 +1030,7 @@ public class CUSTOM_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VAL
@Override @Override
public boolean remove(Object o) { public boolean remove(Object o) {
int oldSize = size; int oldSize = size;
remove(o); CUSTOM_HASH_MAP.this.remove(o);
return size != oldSize; return size != oldSize;
} }
@ -1011,7 +1043,7 @@ public class CUSTOM_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VAL
@Override @Override
public boolean remove(KEY_TYPE o) { public boolean remove(KEY_TYPE o) {
int oldSize = size; int oldSize = size;
remove(o); CUSTOM_HASH_MAP.this.remove(o);
return size != oldSize; return size != oldSize;
} }
@ -1041,9 +1073,10 @@ public class CUSTOM_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VAL
@Override @Override
public void forEach(CONSUMER KEY_SUPER_GENERIC_TYPE action) { public void forEach(CONSUMER KEY_SUPER_GENERIC_TYPE action) {
Objects.requireNonNull(action);
if(containsNull) action.accept(keys[nullIndex]); if(containsNull) action.accept(keys[nullIndex]);
for(int i = nullIndex-1;i>=0;i--) for(int i = nullIndex-1;i>=0;i--)
if(strategy.equals(keys[i], EMPTY_KEY_VALUE)) action.accept(keys[i]); if(!strategy.equals(keys[i], EMPTY_KEY_VALUE)) action.accept(keys[i]);
} }
@Override @Override
@ -1406,9 +1439,9 @@ 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(pos >= 0) shiftKeys(pos); else if(lastReturned >= 0) shiftKeys(lastReturned);
else { else {
CUSTOM_HASH_MAP.this.remove(wrapped.GET_KEY(-pos - 1)); CUSTOM_HASH_MAP.this.remove(wrapped.GET_KEY(-lastReturned - 1));
return; return;
} }
size--; size--;

View File

@ -323,6 +323,33 @@ public class LINKED_HASH_MAP KEY_VALUE_GENERIC_TYPE extends HASH_MAP KEY_VALUE_G
return values[index]; return values[index];
} }
#if !VALUE_OBJECT
@Override
public boolean containsValue(VALUE_TYPE value) {
int index = firstIndex;
while(index != -1) {
if(VALUE_EQUALS(values[index], value)) return true;
index = (int)links[index];
}
return false;
}
#endif
@Override
@ValuePrimitive
public boolean containsValue(Object value) {
int index = firstIndex;
while(index != -1) {
#if VALUE_OBJECT
if(VALUE_EQUALS(values[index], value)) return true;
#else
if((value == null && values[index] == getDefaultReturnValue()) || EQUALS_VALUE_TYPE(values[index], value)) return true;
#endif
index = (int)links[index];
}
return false;
}
@Override @Override
public LINKED_HASH_MAP KEY_VALUE_GENERIC_TYPE copy() { public LINKED_HASH_MAP KEY_VALUE_GENERIC_TYPE copy() {
LINKED_HASH_MAP KEY_VALUE_GENERIC_TYPE map = new LINKED_HASH_MAPKV_BRACES(0, loadFactor); LINKED_HASH_MAP KEY_VALUE_GENERIC_TYPE map = new LINKED_HASH_MAPKV_BRACES(0, loadFactor);
@ -797,8 +824,16 @@ public class LINKED_HASH_MAP KEY_VALUE_GENERIC_TYPE extends HASH_MAP KEY_VALUE_G
@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_HASH_MAP.this.containsKey(((MAP.Entry KEY_VALUE_GENERIC_TYPE)o).ENTRY_KEY()); if(o instanceof MAP.Entry) {
return LINKED_HASH_MAP.this.containsKey(((Map.Entry<?, ?>)o).getKey()); MAP.Entry KEY_VALUE_GENERIC_TYPE entry = (MAP.Entry KEY_VALUE_GENERIC_TYPE)o;
int index = LINKED_HASH_MAP.this.findIndex(entry.ENTRY_KEY());
if(index >= 0) return VALUE_EQUALS(entry.ENTRY_VALUE(), LINKED_HASH_MAP.this.values[index]);
}
else {
Map.Entry<?, ?> entry = (Map.Entry<?, ?>)o;
int index = LINKED_HASH_MAP.this.findIndex(entry.getKey());
if(index >= 0) return Objects.equals(entry.getValue(), VALUE_TO_OBJ(LINKED_HASH_MAP.this.values[index]));
}
} }
return false; return false;
} }
@ -850,7 +885,7 @@ public class LINKED_HASH_MAP KEY_VALUE_GENERIC_TYPE extends HASH_MAP KEY_VALUE_G
@Override @Override
public boolean remove(Object o) { public boolean remove(Object o) {
int oldSize = size; int oldSize = size;
remove(o); LINKED_HASH_MAP.this.remove(o);
return size != oldSize; return size != oldSize;
} }
@ -863,7 +898,7 @@ public class LINKED_HASH_MAP KEY_VALUE_GENERIC_TYPE extends HASH_MAP KEY_VALUE_G
@Override @Override
public boolean remove(KEY_TYPE o) { public boolean remove(KEY_TYPE o) {
int oldSize = size; int oldSize = size;
remove(o); LINKED_HASH_MAP.this.remove(o);
return size != oldSize; return size != oldSize;
} }

View File

@ -288,7 +288,7 @@ public class HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GENE
@ValuePrimitive @ValuePrimitive
public boolean containsValue(Object value) { public boolean containsValue(Object value) {
for(int i = nullIndex;i >= 0;i--) for(int i = nullIndex;i >= 0;i--)
#if TYPE_OBJECT #if VALUE_OBJECT
if(KEY_EQUALS_NOT_NULL(keys[i]) && EQUALS_VALUE_TYPE(values[i], value)) return true; if(KEY_EQUALS_NOT_NULL(keys[i]) && EQUALS_VALUE_TYPE(values[i], value)) return true;
#else #else
if(KEY_EQUALS_NOT_NULL(keys[i]) && ((value == null && values[i] == getDefaultReturnValue()) || EQUALS_VALUE_TYPE(values[i], value))) return true; if(KEY_EQUALS_NOT_NULL(keys[i]) && ((value == null && values[i] == getDefaultReturnValue()) || EQUALS_VALUE_TYPE(values[i], value))) return true;
@ -311,7 +311,6 @@ public class HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GENE
} }
@Override @Override
@Deprecated
public CLASS_VALUE_TYPE remove(Object key) { public CLASS_VALUE_TYPE remove(Object key) {
int slot = findIndex(key); int slot = findIndex(key);
if(slot < 0) return VALUE_TO_OBJ(getDefaultReturnValue()); if(slot < 0) return VALUE_TO_OBJ(getDefaultReturnValue());
@ -458,6 +457,7 @@ public class HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GENE
@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 < 0) { if(index < 0) {
VALUE_TYPE newValue = mappingFunction.APPLY_VALUE(key, getDefaultReturnValue()); VALUE_TYPE newValue = mappingFunction.APPLY_VALUE(key, getDefaultReturnValue());
@ -476,6 +476,7 @@ public class HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GENE
@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 < 0) { if(index < 0) {
VALUE_TYPE newValue = mappingFunction.GET_VALUE(key); VALUE_TYPE newValue = mappingFunction.GET_VALUE(key);
@ -494,6 +495,7 @@ public class HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GENE
@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 < 0) { if(index < 0) {
VALUE_TYPE newValue = valueProvider.VALUE_GET_KEY(); VALUE_TYPE newValue = valueProvider.VALUE_GET_KEY();
@ -501,11 +503,18 @@ public class HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GENE
insert(-index-1, key, newValue); insert(-index-1, 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 < 0 || VALUE_EQUALS(values[index], getDefaultReturnValue())) return getDefaultReturnValue(); if(index < 0 || 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]);

View File

@ -237,18 +237,34 @@ public class IMMUTABLE_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_
{ {
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;
newValues[newSize] = b[i];
continue; continue;
} }
boolean found = true; boolean found = true;
int pos = HashUtil.mix(KEY_TO_HASH(o)) & newMask; int pos = HashUtil.mix(KEY_TO_HASH(o)) & newMask;
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)) {
newValues[pos] = b[i];
continue;
}
while(KEY_EQUALS_NOT_NULL((current = newKeys[pos = (++pos & mask)]))) { while(KEY_EQUALS_NOT_NULL((current = newKeys[pos = (++pos & mask)]))) {
if(KEY_EQUALS(current, o)) { if(KEY_EQUALS(current, o)) {
found = false; found = false;
newValues[pos] = b[i];
break; break;
} }
} }
@ -256,7 +272,7 @@ public class IMMUTABLE_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_
if(found) { if(found) {
size++; size++;
newKeys[pos] = o; newKeys[pos] = o;
values[pos] = b[i]; newValues[pos] = b[i];
if(prev != -1) { if(prev != -1) {
newLinks[prev] ^= ((newLinks[prev] ^ (pos & 0xFFFFFFFFL)) & 0xFFFFFFFFL); newLinks[prev] ^= ((newLinks[prev] ^ (pos & 0xFFFFFFFFL)) & 0xFFFFFFFFL);
newLinks[pos] ^= ((newLinks[pos] ^ ((prev & 0xFFFFFFFFL) << 32)) & 0xFFFFFFFF00000000L); newLinks[pos] ^= ((newLinks[pos] ^ ((prev & 0xFFFFFFFFL) << 32)) & 0xFFFFFFFF00000000L);
@ -268,7 +284,7 @@ public class IMMUTABLE_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_
} }
} }
} }
nullIndex = size; nullIndex = newSize;
mask = newMask; mask = newMask;
keys = newKeys; keys = newKeys;
values = newValues; values = newValues;
@ -316,9 +332,11 @@ public class IMMUTABLE_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_
#if !VALUE_OBJECT #if !VALUE_OBJECT
@Override @Override
public boolean containsValue(VALUE_TYPE value) { public boolean containsValue(VALUE_TYPE value) {
if(VALUE_EQUALS(value, values[nullIndex])) return true; int index = firstIndex;
for(int i = nullIndex-1;i >= 0;i--) while(index != -1) {
if(KEY_EQUALS_NOT_NULL(keys[i]) && VALUE_EQUALS(values[i], value)) return true; if(VALUE_EQUALS(values[index], value)) return true;
index = (int)links[index];
}
return false; return false;
} }
@ -326,9 +344,15 @@ public class IMMUTABLE_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_
@Override @Override
@ValuePrimitive @ValuePrimitive
public boolean containsValue(Object value) { public boolean containsValue(Object value) {
if((value == null && VALUE_EQUALS(values[nullIndex], getDefaultReturnValue())) || EQUALS_VALUE_TYPE(values[nullIndex], value)) return true; int index = firstIndex;
for(int i = nullIndex-1;i >= 0;i--) while(index != -1) {
if(KEY_EQUALS_NOT_NULL(keys[i]) && ((value == null && values[i] == getDefaultReturnValue()) || EQUALS_VALUE_TYPE(values[i], value))) return true; #if VALUE_OBJECT
if(VALUE_EQUALS(values[index], value)) return true;
#else
if((value == null && values[index] == getDefaultReturnValue()) || EQUALS_VALUE_TYPE(values[index], value)) return true;
#endif
index = (int)links[index];
}
return false; return false;
} }
@ -544,6 +568,9 @@ public class IMMUTABLE_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_
} }
Map.Entry<?, ?> entry = (Map.Entry<?, ?>)obj; Map.Entry<?, ?> entry = (Map.Entry<?, ?>)obj;
Object key = entry.getKey(); Object key = entry.getKey();
#if !TYPE_OBJECT
if(!(key instanceof CLASS_TYPE)) return false;
#endif
Object value = entry.getValue(); Object value = entry.getValue();
#if TYPE_OBJECT && VALUE_OBJECT #if TYPE_OBJECT && VALUE_OBJECT
return KEY_EQUALS(keys[index], key) && VALUE_EQUALS(values[index], value); return KEY_EQUALS(keys[index], key) && VALUE_EQUALS(values[index], value);
@ -565,7 +592,7 @@ public class IMMUTABLE_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_
@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]);
} }
} }
@ -757,8 +784,16 @@ public class IMMUTABLE_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_
@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 IMMUTABLE_HASH_MAP.this.containsKey(((MAP.Entry KEY_VALUE_GENERIC_TYPE)o).ENTRY_KEY()); if(o instanceof MAP.Entry) {
return IMMUTABLE_HASH_MAP.this.containsKey(((Map.Entry<?, ?>)o).getKey()); MAP.Entry KEY_VALUE_GENERIC_TYPE entry = (MAP.Entry KEY_VALUE_GENERIC_TYPE)o;
int index = IMMUTABLE_HASH_MAP.this.findIndex(entry.ENTRY_KEY());
if(index >= 0) return VALUE_EQUALS(entry.ENTRY_VALUE(), IMMUTABLE_HASH_MAP.this.values[index]);
}
else {
Map.Entry<?, ?> entry = (Map.Entry<?, ?>)o;
int index = IMMUTABLE_HASH_MAP.this.findIndex(entry.getKey());
if(index >= 0) return Objects.equals(entry.getValue(), VALUE_TO_OBJ(IMMUTABLE_HASH_MAP.this.values[index]));
}
} }
return false; return false;
} }

View File

@ -233,6 +233,9 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_
#endif #endif
@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
Objects.requireNonNull(key);
#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);
size++; size++;
@ -267,6 +270,9 @@ 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
Objects.requireNonNull(key);
#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);
size++; size++;
@ -302,6 +308,9 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_
#if VALUE_PRIMITIVES #if VALUE_PRIMITIVES
@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
Objects.requireNonNull(key);
#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);
size++; size++;
@ -510,6 +519,10 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_
@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);
#if TYPE_OBJECT
Objects.requireNonNull(key);
#endif
Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key); Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key);
if(entry == null) { if(entry == null) {
VALUE_TYPE newValue = mappingFunction.APPLY_VALUE(key, getDefaultReturnValue()); VALUE_TYPE newValue = mappingFunction.APPLY_VALUE(key, getDefaultReturnValue());
@ -528,6 +541,10 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_
@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);
#if TYPE_OBJECT
Objects.requireNonNull(key);
#endif
Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key); Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key);
if(entry == null) { if(entry == null) {
VALUE_TYPE newValue = mappingFunction.GET_VALUE(key); VALUE_TYPE newValue = mappingFunction.GET_VALUE(key);
@ -535,11 +552,20 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_
put(key, newValue); put(key, newValue);
return newValue; return newValue;
} }
if(VALUE_EQUALS(entry.value, getDefaultReturnValue())) {
VALUE_TYPE newValue = mappingFunction.GET_VALUE(key);
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) return newValue;
entry.value = newValue;
}
return entry.value; return entry.value;
} }
@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);
#if TYPE_OBJECT
Objects.requireNonNull(key);
#endif
Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key); Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key);
if(entry == null) { if(entry == null) {
VALUE_TYPE newValue = valueProvider.VALUE_GET_KEY(); VALUE_TYPE newValue = valueProvider.VALUE_GET_KEY();
@ -547,13 +573,22 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_
put(key, newValue); put(key, newValue);
return newValue; return newValue;
} }
if(VALUE_EQUALS(entry.value, getDefaultReturnValue())) {
VALUE_TYPE newValue = valueProvider.VALUE_GET_KEY();
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) return newValue;
entry.value = newValue;
}
return entry.value; return entry.value;
} }
@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);
#if TYPE_OBJECT
Objects.requireNonNull(key);
#endif
Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key); Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key);
if(entry == null) return getDefaultReturnValue(); if(entry == null || VALUE_EQUALS(entry.value, getDefaultReturnValue())) return getDefaultReturnValue();
VALUE_TYPE newValue = mappingFunction.APPLY_VALUE(key, entry.value); VALUE_TYPE newValue = mappingFunction.APPLY_VALUE(key, entry.value);
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) { if(VALUE_EQUALS(newValue, getDefaultReturnValue())) {
removeNode(entry); removeNode(entry);
@ -565,8 +600,12 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_
@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 TYPE_OBJECT
Objects.requireNonNull(key);
#endif
Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key); Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key);
VALUE_TYPE newValue = entry == null ? value : mappingFunction.APPLY_VALUE(entry.value, value); VALUE_TYPE newValue = entry == null || VALUE_EQUALS(entry.value, getDefaultReturnValue()) ? value : mappingFunction.APPLY_VALUE(entry.value, value);
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) { if(VALUE_EQUALS(newValue, getDefaultReturnValue())) {
if(entry != null) if(entry != null)
removeNode(entry); removeNode(entry);
@ -582,7 +621,7 @@ public class AVL_TREE_MAP KEY_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)) {
KEY_TYPE key = entry.ENTRY_KEY(); KEY_TYPE key = entry.ENTRY_KEY();
Entry KEY_VALUE_GENERIC_TYPE subEntry = findNode(key); Entry KEY_VALUE_GENERIC_TYPE subEntry = findNode(key);
VALUE_TYPE newValue = subEntry == null ? entry.ENTRY_VALUE() : mappingFunction.APPLY_VALUE(subEntry.value, entry.ENTRY_VALUE()); VALUE_TYPE newValue = subEntry == null || VALUE_EQUALS(subEntry.value, getDefaultReturnValue()) ? entry.ENTRY_VALUE() : mappingFunction.APPLY_VALUE(subEntry.value, entry.ENTRY_VALUE());
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) { if(VALUE_EQUALS(newValue, getDefaultReturnValue())) {
if(subEntry != null) if(subEntry != null)
removeNode(subEntry); removeNode(subEntry);
@ -1491,8 +1530,21 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_
@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 NavigableSubMap.this.containsKey(((MAP.Entry KEY_VALUE_GENERIC_TYPE)o).ENTRY_KEY()); if(o instanceof MAP.Entry) {
return NavigableSubMap.this.containsKey(((Map.Entry<?, ?>)o).getKey()); MAP.Entry KEY_VALUE_GENERIC_TYPE entry = (MAP.Entry KEY_VALUE_GENERIC_TYPE)o;
if(entry.getKey() == null) return false;
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);
}
else {
Map.Entry<?, ?> entry = (Map.Entry<?, ?>)o;
if(entry.getKey() == null) return false;
#if !TYPE_OBJECT
if(!(entry.getKey() instanceof CLASS_TYPE)) return false;
#endif
AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE subEntry = m.findNode((CLASS_TYPE)entry.getKey());
if(subEntry != null) return Objects.equals(entry.getValue(), VALUE_TO_OBJ(subEntry.value));
}
} }
return false; return false;
} }
@ -1884,8 +1936,21 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_
@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 AVL_TREE_MAP.this.containsKey(((MAP.Entry KEY_VALUE_GENERIC_TYPE)o).ENTRY_KEY()); if(o instanceof MAP.Entry) {
return AVL_TREE_MAP.this.containsKey(((Map.Entry<?, ?>)o).getKey()); MAP.Entry KEY_VALUE_GENERIC_TYPE entry = (MAP.Entry KEY_VALUE_GENERIC_TYPE)o;
if(entry.getKey() == null) return false;
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);
}
else {
Map.Entry<?, ?> entry = (Map.Entry<?, ?>)o;
if(entry.getKey() == null) return false;
#if !TYPE_OBJECT
if(!(entry.getKey() instanceof CLASS_TYPE)) return false;
#endif
AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE subEntry = AVL_TREE_MAP.this.findNode((CLASS_TYPE)entry.getKey());
if(subEntry != null) return Objects.equals(entry.getValue(), VALUE_TO_OBJ(subEntry.value));
}
} }
return false; return false;
} }
@ -2551,6 +2616,43 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_
} }
#endif #endif
@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;
#if TYPE_OBJECT
if(entry.ENTRY_KEY() == null) return false;
#endif
return KEY_EQUALS(key, entry.ENTRY_KEY()) && VALUE_EQUALS(value, entry.ENTRY_VALUE());
}
Map.Entry<?, ?> entry = (Map.Entry<?, ?>)obj;
Object otherKey = entry.getKey();
if(otherKey == null) return false;
Object otherValue = entry.getValue();
#if TYPE_OBJECT && VALUE_OBJECT
return KEY_EQUALS(key, otherKey) && VALUE_EQUALS(value, otherValue);
#else if TYPE_OBJECT
return otherValue instanceof CLASS_VALUE_TYPE && KEY_EQUALS(key, otherKey) && VALUE_EQUALS(value, CLASS_TO_VALUE(otherValue));
#else if VALUE_OBJECT
return otherKey instanceof CLASS_TYPE && KEY_EQUALS(key, CLASS_TO_KEY(otherKey)) && VALUE_EQUALS(value, otherValue);
#else
return otherKey instanceof CLASS_TYPE && otherValue instanceof CLASS_VALUE_TYPE && KEY_EQUALS(key, CLASS_TO_KEY(otherKey)) && VALUE_EQUALS(value, CLASS_TO_VALUE(otherValue));
#endif
}
return false;
}
@Override
public int hashCode() {
return KEY_TO_HASH(key) ^ VALUE_TO_HASH(value);
}
@Override
public String toString() {
return KEY_TO_STRING(key) + "=" + VALUE_TO_STRING(value);
}
int getHeight() { return state; } int getHeight() { return state; }
void updateHeight() { state = (1 + Math.max(left == null ? -1 : left.getHeight(), right == null ? -1 : right.getHeight())); } void updateHeight() { state = (1 + Math.max(left == null ? -1 : left.getHeight(), right == null ? -1 : right.getHeight())); }

View File

@ -233,6 +233,9 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_G
#endif #endif
@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
Objects.requireNonNull(key);
#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);
size++; size++;
@ -267,6 +270,10 @@ 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
Objects.requireNonNull(key);
#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);
size++; size++;
@ -302,6 +309,9 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_G
#if VALUE_PRIMITIVES #if VALUE_PRIMITIVES
@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
Objects.requireNonNull(key);
#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);
size++; size++;
@ -509,6 +519,10 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_G
@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);
#if TYPE_OBJECT
Objects.requireNonNull(key);
#endif
Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key); Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key);
if(entry == null) { if(entry == null) {
VALUE_TYPE newValue = mappingFunction.APPLY_VALUE(key, getDefaultReturnValue()); VALUE_TYPE newValue = mappingFunction.APPLY_VALUE(key, getDefaultReturnValue());
@ -527,6 +541,10 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_G
@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);
#if TYPE_OBJECT
Objects.requireNonNull(key);
#endif
Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key); Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key);
if(entry == null) { if(entry == null) {
VALUE_TYPE newValue = mappingFunction.GET_VALUE(key); VALUE_TYPE newValue = mappingFunction.GET_VALUE(key);
@ -534,11 +552,20 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_G
put(key, newValue); put(key, newValue);
return newValue; return newValue;
} }
if(VALUE_EQUALS(entry.value, getDefaultReturnValue())) {
VALUE_TYPE newValue = mappingFunction.GET_VALUE(key);
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) return newValue;
entry.value = newValue;
}
return entry.value; return entry.value;
} }
@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);
#if TYPE_OBJECT
Objects.requireNonNull(key);
#endif
Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key); Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key);
if(entry == null) { if(entry == null) {
VALUE_TYPE newValue = valueProvider.VALUE_GET_KEY(); VALUE_TYPE newValue = valueProvider.VALUE_GET_KEY();
@ -546,13 +573,22 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_G
put(key, newValue); put(key, newValue);
return newValue; return newValue;
} }
if(VALUE_EQUALS(entry.value, getDefaultReturnValue())) {
VALUE_TYPE newValue = valueProvider.VALUE_GET_KEY();
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) return newValue;
entry.value = newValue;
}
return entry.value; return entry.value;
} }
@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);
#if TYPE_OBJECT
Objects.requireNonNull(key);
#endif
Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key); Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key);
if(entry == null) return getDefaultReturnValue(); if(entry == null || VALUE_EQUALS(entry.value, getDefaultReturnValue())) return getDefaultReturnValue();
VALUE_TYPE newValue = mappingFunction.APPLY_VALUE(key, entry.value); VALUE_TYPE newValue = mappingFunction.APPLY_VALUE(key, entry.value);
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) { if(VALUE_EQUALS(newValue, getDefaultReturnValue())) {
removeNode(entry); removeNode(entry);
@ -564,8 +600,12 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_G
@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 TYPE_OBJECT
Objects.requireNonNull(key);
#endif
Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key); Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key);
VALUE_TYPE newValue = entry == null ? value : mappingFunction.APPLY_VALUE(entry.value, value); VALUE_TYPE newValue = entry == null || VALUE_EQUALS(entry.value, getDefaultReturnValue()) ? value : mappingFunction.APPLY_VALUE(entry.value, value);
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) { if(VALUE_EQUALS(newValue, getDefaultReturnValue())) {
if(entry != null) if(entry != null)
removeNode(entry); removeNode(entry);
@ -581,7 +621,7 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_G
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();
Entry KEY_VALUE_GENERIC_TYPE subEntry = findNode(key); Entry KEY_VALUE_GENERIC_TYPE subEntry = findNode(key);
VALUE_TYPE newValue = subEntry == null ? entry.ENTRY_VALUE() : mappingFunction.APPLY_VALUE(subEntry.value, entry.ENTRY_VALUE()); VALUE_TYPE newValue = subEntry == null || VALUE_EQUALS(subEntry.value, getDefaultReturnValue()) ? entry.ENTRY_VALUE() : mappingFunction.APPLY_VALUE(subEntry.value, entry.ENTRY_VALUE());
if(VALUE_EQUALS(newValue, getDefaultReturnValue())) { if(VALUE_EQUALS(newValue, getDefaultReturnValue())) {
if(subEntry != null) if(subEntry != null)
removeNode(subEntry); removeNode(subEntry);
@ -1545,8 +1585,21 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_G
@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 NavigableSubMap.this.containsKey(((MAP.Entry KEY_VALUE_GENERIC_TYPE)o).ENTRY_KEY()); if(o instanceof MAP.Entry) {
return NavigableSubMap.this.containsKey(((Map.Entry<?, ?>)o).getKey()); MAP.Entry KEY_VALUE_GENERIC_TYPE entry = (MAP.Entry KEY_VALUE_GENERIC_TYPE)o;
if(entry.getKey() == null) return false;
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);
}
else {
Map.Entry<?, ?> entry = (Map.Entry<?, ?>)o;
if(entry.getKey() == null) return false;
#if !TYPE_OBJECT
if(!(entry.getKey() instanceof CLASS_TYPE)) return false;
#endif
RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE subEntry = m.findNode((CLASS_TYPE)entry.getKey());
if(subEntry != null) return Objects.equals(entry.getValue(), VALUE_TO_OBJ(subEntry.value));
}
} }
return false; return false;
} }
@ -1938,8 +1991,21 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_G
@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 RB_TREE_MAP.this.containsKey(((MAP.Entry KEY_VALUE_GENERIC_TYPE)o).ENTRY_KEY()); if(o instanceof MAP.Entry) {
return RB_TREE_MAP.this.containsKey(((Map.Entry<?, ?>)o).getKey()); MAP.Entry KEY_VALUE_GENERIC_TYPE entry = (MAP.Entry KEY_VALUE_GENERIC_TYPE)o;
if(entry.getKey() == null) return false;
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);
}
else {
Map.Entry<?, ?> entry = (Map.Entry<?, ?>)o;
if(entry.getKey() == null) return false;
#if !TYPE_OBJECT
if(!(entry.getKey() instanceof CLASS_TYPE)) return false;
#endif
RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE subEntry = RB_TREE_MAP.this.findNode((CLASS_TYPE)entry.getKey());
if(subEntry != null) return Objects.equals(entry.getValue(), VALUE_TO_OBJ(subEntry.value));
}
} }
return false; return false;
} }
@ -2620,6 +2686,43 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_G
} }
#endif #endif
@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;
#if TYPE_OBJECT
if(entry.ENTRY_KEY() == null) return false;
#endif
return KEY_EQUALS(key, entry.ENTRY_KEY()) && VALUE_EQUALS(value, entry.ENTRY_VALUE());
}
Map.Entry<?, ?> entry = (Map.Entry<?, ?>)obj;
Object otherKey = entry.getKey();
if(otherKey == null) return false;
Object otherValue = entry.getValue();
#if TYPE_OBJECT && VALUE_OBJECT
return KEY_EQUALS(key, otherKey) && VALUE_EQUALS(value, otherValue);
#else if TYPE_OBJECT
return otherValue instanceof CLASS_VALUE_TYPE && KEY_EQUALS(key, otherKey) && VALUE_EQUALS(value, CLASS_TO_VALUE(otherValue));
#else if VALUE_OBJECT
return otherKey instanceof CLASS_TYPE && KEY_EQUALS(key, CLASS_TO_KEY(otherKey)) && VALUE_EQUALS(value, otherValue);
#else
return otherKey instanceof CLASS_TYPE && otherValue instanceof CLASS_VALUE_TYPE && KEY_EQUALS(key, CLASS_TO_KEY(otherKey)) && VALUE_EQUALS(value, CLASS_TO_VALUE(otherValue));
#endif
}
return false;
}
@Override
public int hashCode() {
return KEY_TO_HASH(key) ^ VALUE_TO_HASH(value);
}
@Override
public String toString() {
return KEY_TO_STRING(key) + "=" + VALUE_TO_STRING(value);
}
boolean isBlack() { boolean isBlack() {
return (state & BLACK) != 0; return (state & BLACK) != 0;
} }

View File

@ -1,40 +0,0 @@
package speiger.src.collections.objects.map;
import java.util.Map;
import java.util.function.Supplier;
import com.google.common.collect.testing.MapTestSuiteBuilder;
import com.google.common.collect.testing.TestStringMapGenerator;
import com.google.common.collect.testing.features.CollectionFeature;
import com.google.common.collect.testing.features.CollectionSize;
import com.google.common.collect.testing.features.MapFeature;
import junit.framework.Test;
import junit.framework.TestCase;
import speiger.src.collections.objects.maps.impl.hash.Object2ObjectOpenHashMap;
@SuppressWarnings("javadoc")
public final class MapTest extends TestCase
{
public static Test suite()
{
return suite("Object2ObjectOpenHashMap", Object2ObjectOpenHashMap::new);
}
public static Test suite(String name, Supplier<Map<String, String>> factory)
{
return MapTestSuiteBuilder.using(new TestStringMapGenerator()
{
@Override
protected Map<String, String> create(Map.Entry<String, String>[] entries)
{
Map<String, String> map = factory.get();
for(Map.Entry<String, String> entry : entries)
{
map.put(entry.getKey(), entry.getValue());
}
return map;
}
}).named(name).withFeatures(CollectionSize.ANY, MapFeature.GENERAL_PURPOSE, MapFeature.ALLOWS_NULL_KEYS, MapFeature.ALLOWS_NULL_VALUES, MapFeature.ALLOWS_ANY_NULL_QUERIES, CollectionFeature.SUPPORTS_ITERATOR_REMOVE).createTestSuite();
}
}

View File

@ -0,0 +1,90 @@
package speiger.src.collections.objects.map;
import java.util.Comparator;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Supplier;
import com.google.common.collect.testing.MapTestSuiteBuilder;
import com.google.common.collect.testing.TestStringMapGenerator;
import com.google.common.collect.testing.features.CollectionFeature;
import com.google.common.collect.testing.features.CollectionSize;
import com.google.common.collect.testing.features.MapFeature;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import speiger.src.collections.objects.maps.impl.customHash.Object2ObjectLinkedOpenCustomHashMap;
import speiger.src.collections.objects.maps.impl.customHash.Object2ObjectOpenCustomHashMap;
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.immutable.ImmutableObject2ObjectOpenHashMap;
import speiger.src.collections.objects.maps.impl.tree.Object2ObjectAVLTreeMap;
import speiger.src.collections.objects.maps.impl.tree.Object2ObjectRBTreeMap;
import speiger.src.collections.objects.utils.ObjectStrategy;
@SuppressWarnings("javadoc")
public class ObjectMapTests extends TestCase
{
public static Test suite()
{
TestSuite suite = new TestSuite("Maps");
suite.addTest(suite("HashMap", Object2ObjectOpenHashMap::new, true));
suite.addTest(suite("LinkedHashMap", Object2ObjectLinkedOpenHashMap::new, true));
suite.addTest(suite("CustomHashMap", () -> new Object2ObjectOpenCustomHashMap<>(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("AVLTreeMap", () -> new Object2ObjectAVLTreeMap<String, String>(Comparator.naturalOrder()), false));
suite.addTest(immutableSuit("ImmutableMap", ImmutableObject2ObjectOpenHashMap::new));
return suite;
}
public static Test suite(String name, Supplier<Map<String, String>> factory, boolean allowNull)
{
MapTestSuiteBuilder<String, String> builder = MapTestSuiteBuilder.using(new TestStringMapGenerator() {
@Override
protected Map<String, String> create(Map.Entry<String, String>[] entries) {
Map<String, String> map = factory.get();
for(Map.Entry<String, 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);
if(allowNull) builder.withFeatures(MapFeature.ALLOWS_NULL_KEYS, MapFeature.ALLOWS_ANY_NULL_QUERIES);
return builder.createTestSuite();
}
public static Test immutableSuit(String name, BiFunction<String[], String[], Map<String, String>> factory) {
MapTestSuiteBuilder<String, String> builder = MapTestSuiteBuilder.using(new TestStringMapGenerator() {
@Override
protected Map<String, String> create(Map.Entry<String, String>[] entries) {
String[] keys = new String[entries.length];
String[] values = new String[entries.length];
for(int i = 0;i<entries.length;i++) {
keys[i] = entries[i].getKey();
values[i] = entries[i].getValue();
}
return factory.apply(keys, values);
}
}).named(name).withFeatures(CollectionSize.ANY, MapFeature.ALLOWS_NULL_KEYS, MapFeature.ALLOWS_NULL_VALUES, MapFeature.ALLOWS_ANY_NULL_QUERIES);
return builder.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);
}
}
}