From 4448eca78713f343dc710987033065b6ac0be780 Mon Sep 17 00:00:00 2001 From: Speiger Date: Tue, 12 Apr 2022 06:06:18 +0200 Subject: [PATCH] Finishing ConcurrentHashMap implementation, next tests --- .../speiger/src/builder/GlobalVariables.java | 3 +- .../builder/PrimitiveCollectionsBuilder.java | 4 +- .../concurrent/ConcurrentOpenHashMap.template | 376 ++++++++++++++---- .../maps/interfaces/ConcurrentMap.template | 95 +++++ .../templates/maps/interfaces/Map.template | 9 + .../src/collections/utils/HashUtil.java | 2 + 6 files changed, 411 insertions(+), 78 deletions(-) create mode 100644 src/builder/resources/speiger/assets/collections/templates/maps/interfaces/ConcurrentMap.template diff --git a/src/builder/java/speiger/src/builder/GlobalVariables.java b/src/builder/java/speiger/src/builder/GlobalVariables.java index cf6c1bb9..59a88c79 100644 --- a/src/builder/java/speiger/src/builder/GlobalVariables.java +++ b/src/builder/java/speiger/src/builder/GlobalVariables.java @@ -174,7 +174,7 @@ public class GlobalVariables addBiClassMapper("LINKED_CUSTOM_HASH_MAP", "LinkedOpenCustomHashMap", "2"); addBiClassMapper("LINKED_HASH_MAP", "LinkedOpenHashMap", "2"); addBiClassMapper("CUSTOM_HASH_MAP", "OpenCustomHashMap", "2"); - addBiClassMapper("CONCURRENT_MAP", "ConcurrentOpenHashMap", "2"); + addBiClassMapper("CONCURRENT_HASH_MAP", "ConcurrentOpenHashMap", "2"); addBiClassMapper("AVL_TREE_MAP", "AVLTreeMap", "2"); addBiClassMapper("RB_TREE_MAP", "RBTreeMap", "2"); addFunctionValueMappers("LINKED_ENUM_MAP", valueType.isObject() ? "LinkedEnum2ObjectMap" : "LinkedEnum2%sMap"); @@ -224,6 +224,7 @@ public class GlobalVariables addBiClassMapper("NAVIGABLE_MAP", "NavigableMap", "2"); addBiClassMapper("ORDERED_MAP", "OrderedMap", "2"); addBiClassMapper("SORTED_MAP", "SortedMap", "2"); + addBiClassMapper("CONCURRENT_MAP", "ConcurrentMap", "2"); addBiClassMapper("MAP", "Map", "2"); addClassMapper("NAVIGABLE_SET", "NavigableSet"); addBiClassMapper("PAIR", "Pair", ""); diff --git a/src/builder/java/speiger/src/builder/PrimitiveCollectionsBuilder.java b/src/builder/java/speiger/src/builder/PrimitiveCollectionsBuilder.java index 1066531e..c2454921 100644 --- a/src/builder/java/speiger/src/builder/PrimitiveCollectionsBuilder.java +++ b/src/builder/java/speiger/src/builder/PrimitiveCollectionsBuilder.java @@ -83,7 +83,7 @@ public class PrimitiveCollectionsBuilder extends TemplateProcessor biRequired.put("Pair", ""); biRequired.put("MutablePair", ""); biRequired.put("ImmutablePair", ""); - addBiClass("Function", "Maps", "Map", "SortedMap", "OrderedMap", "NavigableMap", "AbstractMap", "ConcurrentOpenHashMap", "ImmutableOpenHashMap", "OpenHashMap", "LinkedOpenHashMap", "OpenCustomHashMap", "LinkedOpenCustomHashMap", "ArrayMap", "RBTreeMap", "AVLTreeMap"); + addBiClass("Function", "Maps", "Map", "SortedMap", "OrderedMap", "NavigableMap", "ConcurrentMap", "AbstractMap", "ConcurrentOpenHashMap", "ImmutableOpenHashMap", "OpenHashMap", "LinkedOpenHashMap", "OpenCustomHashMap", "LinkedOpenCustomHashMap", "ArrayMap", "RBTreeMap", "AVLTreeMap"); nameRemapper.put("BiConsumer", "%sConsumer"); nameRemapper.put("IArray", "I%sArray"); nameRemapper.put("AbstractMap", "Abstract%sMap"); @@ -100,7 +100,7 @@ public class PrimitiveCollectionsBuilder extends TemplateProcessor addBlockage(ClassType.OBJECT, "Consumer", "Comparator", "Stack"); addBlockage(ClassType.BOOLEAN, "ArraySet", "AVLTreeSet", "RBTreeSet", "SortedSet", "OrderedSet", "NavigableSet", "OpenHashSet", "OpenCustomHashSet", "LinkedOpenHashSet", "LinkedOpenCustomHashSet"); - addBlockage(ClassType.BOOLEAN, "ConcurrentOpenHashMap", "ImmutableOpenHashMap", "ImmutableOpenHashSet", "SortedMap", "OrderedMap", "NavigableMap", "OpenHashMap", "LinkedOpenHashMap", "OpenCustomHashMap", "LinkedOpenCustomHashMap", "ArrayMap", "RBTreeMap", "AVLTreeMap"); + addBlockage(ClassType.BOOLEAN, "ConcurrentOpenHashMap", "ImmutableOpenHashMap", "ImmutableOpenHashSet", "SortedMap", "OrderedMap", "NavigableMap", "ConcurrentMap", "OpenHashMap", "LinkedOpenHashMap", "OpenCustomHashMap", "LinkedOpenCustomHashMap", "ArrayMap", "RBTreeMap", "AVLTreeMap"); } protected void create(ClassType mainType, ClassType subType) diff --git a/src/builder/resources/speiger/assets/collections/templates/maps/impl/concurrent/ConcurrentOpenHashMap.template b/src/builder/resources/speiger/assets/collections/templates/maps/impl/concurrent/ConcurrentOpenHashMap.template index db48b3c2..3d67c022 100644 --- a/src/builder/resources/speiger/assets/collections/templates/maps/impl/concurrent/ConcurrentOpenHashMap.template +++ b/src/builder/resources/speiger/assets/collections/templates/maps/impl/concurrent/ConcurrentOpenHashMap.template @@ -6,6 +6,7 @@ import java.util.NoSuchElementException; import java.util.Objects; import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; + import java.util.function.BiFunction; #if !TYPE_OBJECT @@ -27,6 +28,7 @@ import speiger.src.collections.PACKAGE.functions.function.PREDICATE; #endif import speiger.src.collections.PACKAGE.maps.abstracts.ABSTRACT_MAP; import speiger.src.collections.PACKAGE.maps.interfaces.MAP; +import speiger.src.collections.PACKAGE.maps.interfaces.CONCURRENT_MAP; #if !TYPE_OBJECT import speiger.src.collections.PACKAGE.sets.ABSTRACT_SET; import speiger.src.collections.PACKAGE.sets.SET; @@ -72,13 +74,23 @@ import speiger.src.collections.objects.sets.AbstractObjectSet; import speiger.src.collections.objects.sets.ObjectSet; import speiger.src.collections.utils.HashUtil; -@SuppressWarnings("javadoc") -public class CONCURRENT_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GENERIC_TYPE +/** + * A TypeSpecific ConcurrentHashMap implementation that is based on Guavas approach and backing array implementations. + * Like Guavas implementation this solution can be accessed by multiple threads, but it is not as flexible as Javas implementation. + * The concurrencyLevel decides how many pools exist, and each pool can be accessed by 1 thread for writing and as many threads for reading. + * + * @Type(T) + * @ValueType(V) + */ +public class CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GENERIC_TYPE implements CONCURRENT_MAP KEY_VALUE_GENERIC_TYPE { + /** Segment Limit */ private static final int MAX_SEGMENTS = 1 << 16; - + /** Buckets of the ConcurrentMap */ protected transient Segment KEY_VALUE_GENERIC_TYPE[] segments; + /** Bitshift of the HashCode */ protected transient int segmentShift; + /** Max Bits thats used in the segments */ protected transient int segmentMask; /** EntrySet cache */ protected transient FastEntrySet KEY_VALUE_GENERIC_TYPE entrySet; @@ -87,12 +99,74 @@ public class CONCURRENT_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALU /** Values cache */ protected transient VALUE_COLLECTION VALUE_GENERIC_TYPE values; - protected CONCURRENT_MAP(boolean unused) {} + /** + * Copy constructor that doesn't trigger the building of segments and allows to copy it faster. + * @param unused not used, Just to keep all constructors accessible. + */ + protected CONCURRENT_HASH_MAP(boolean unused) {} - public CONCURRENT_MAP(int minCapacity, float loadFactor, int concurrencyLevel) { + /** + * Default Constructor + */ + public CONCURRENT_HASH_MAP() { + this(HashUtil.DEFAULT_MIN_CAPACITY, HashUtil.DEFAULT_LOAD_FACTOR, HashUtil.DEFAULT_MIN_CONCURRENCY); + } + + /** + * Constructor that defines the minimum capacity + * @param minCapacity the minimum capacity the HashMap is allowed to be. + * @throws IllegalStateException if the minimum capacity is negative + */ + public CONCURRENT_HASH_MAP(int minCapacity) { + this(minCapacity, HashUtil.DEFAULT_LOAD_FACTOR, HashUtil.DEFAULT_MIN_CONCURRENCY); + } + + /** + * Constructor that defines the minimum capacity and load factor + * @param minCapacity the minimum capacity the HashMap is allowed to be. + * @param loadFactor the percentage of how full the backing array can be before they resize + * @throws IllegalStateException if the minimum capacity is negative + * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1 + */ + public CONCURRENT_HASH_MAP(int minCapacity, float loadFactor) { + this(minCapacity, loadFactor, HashUtil.DEFAULT_MIN_CONCURRENCY); + } + + /** + * Constructor that defines the minimum capacity and concurrencyLevel + * @param minCapacity the minimum capacity the HashMap is allowed to be. + * @param concurrencyLevel decides how many operations can be performed at once. + * @throws IllegalStateException if the minimum capacity is negative + * @throws IllegalStateException if the concurrencyLevel is either below/equal to 0 or above/equal to 65535 + */ + public CONCURRENT_HASH_MAP(int minCapacity, int concurrencyLevel) { + this(minCapacity, HashUtil.DEFAULT_LOAD_FACTOR, concurrencyLevel); + } + + /** + * Constructor that defines the load factor and concurrencyLevel + * @param loadFactor the percentage of how full the backing array can be before they resize + * @param concurrencyLevel decides how many operations can be performed at once. + * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1 + * @throws IllegalStateException if the concurrencyLevel is either below/equal to 0 or above/equal to 65535 + */ + public CONCURRENT_HASH_MAP(float loadFactor, int concurrencyLevel) { + this(HashUtil.DEFAULT_MIN_CAPACITY, loadFactor, concurrencyLevel); + } + + /** + * Constructor that defines the minimum capacity, load factor and concurrencyLevel + * @param minCapacity the minimum capacity the HashMap is allowed to be. + * @param loadFactor the percentage of how full the backing array can be before they resize + * @param concurrencyLevel decides how many operations can be performed at once. + * @throws IllegalStateException if the minimum capacity is negative + * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1 + * @throws IllegalStateException if the concurrencyLevel is either below/equal to 0 or above/equal to 65535 + */ + public CONCURRENT_HASH_MAP(int minCapacity, float loadFactor, int concurrencyLevel) { if(minCapacity < 0) throw new IllegalStateException("Minimum Capacity is negative. This is not allowed"); if(loadFactor <= 0 || loadFactor >= 1F) throw new IllegalStateException("Load Factor is not between 0 and 1"); - if(concurrencyLevel < 0 || concurrencyLevel >= MAX_SEGMENTS) throw new IllegalStateException("concurrencyLevel has to be between 0 and 65536"); + if(concurrencyLevel <= 0 || concurrencyLevel >= MAX_SEGMENTS) throw new IllegalStateException("concurrencyLevel has to be between 0 and 65536"); int segmentCount = HashUtil.nextPowerOfTwo(concurrencyLevel); int shift = Integer.numberOfTrailingZeros(segmentCount); segments = new Segment[segmentCount]; @@ -108,6 +182,190 @@ public class CONCURRENT_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALU } } +#if !TYPE_OBJECT || !VALUE_OBJECT + /** + * Helper constructor that allow to create a map from boxed values (it will unbox them) + * @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 CONCURRENT_HASH_MAP(CLASS_TYPE[] keys, CLASS_VALUE_TYPE[] values) { + this(keys, values, HashUtil.DEFAULT_LOAD_FACTOR, HashUtil.DEFAULT_MIN_CONCURRENCY); + } + + /** + * Helper constructor that allow to create a map from boxed values (it will unbox them) + * @param keys the keys that should be put into the map + * @param values the values that should be put into the map. + * @param loadFactor the percentage of how full the backing array can be before they resize + * @throws IllegalStateException if the keys and values do not match in lenght + * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1 + */ + public CONCURRENT_HASH_MAP(CLASS_TYPE[] keys, CLASS_VALUE_TYPE[] values, float loadFactor) { + this(keys, values, loadFactor, HashUtil.DEFAULT_MIN_CONCURRENCY); + } + + /** + * Helper constructor that allow to create a map from boxed values (it will unbox them) + * @param keys the keys that should be put into the map + * @param values the values that should be put into the map. + * @param concurrencyLevel decides how many operations can be performed at once. + * @throws IllegalStateException if the keys and values do not match in lenght + * @throws IllegalStateException if the concurrencyLevel is either below/equal to 0 or above/equal to 65535 + */ + public CONCURRENT_HASH_MAP(CLASS_TYPE[] keys, CLASS_VALUE_TYPE[] values, int concurrencyLevel) { + this(keys, values, HashUtil.DEFAULT_LOAD_FACTOR, concurrencyLevel); + } + + /** + * Helper constructor that allow to create a map from boxed values (it will unbox them) + * @param keys the keys that should be put into the map + * @param values the values that should be put into the map. + * @param loadFactor the percentage of how full the backing array can be before they resize + * @param concurrencyLevel decides how many operations can be performed at once. + * @throws IllegalStateException if the keys and values do not match in lenght + * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1 + * @throws IllegalStateException if the concurrencyLevel is either below/equal to 0 or above/equal to 65535 + */ + public CONCURRENT_HASH_MAP(CLASS_TYPE[] keys, CLASS_VALUE_TYPE[] values, float loadFactor, int concurrencyLevel) { + this(keys.length, loadFactor, concurrencyLevel); + if(keys.length != values.length) throw new IllegalStateException("Input Arrays are not equal size"); + for(int i = 0,m=keys.length;i map) { + this(map, HashUtil.DEFAULT_LOAD_FACTOR, HashUtil.DEFAULT_MIN_CONCURRENCY); + } + + /** + * A Helper constructor that allows to create a Map with exactly the same values as the provided map. + * @param map the values that should be present in the map + * @param loadFactor the percentage of how full the backing array can be before they resize + * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1 + */ + public CONCURRENT_HASH_MAP(Map map, float loadFactor) { + this(map, loadFactor, HashUtil.DEFAULT_MIN_CONCURRENCY); + } + + /** + * A Helper constructor that allows to create a Map with exactly the same values as the provided map. + * @param map the values that should be present in the map + * @param concurrencyLevel decides how many operations can be performed at once. + * @throws IllegalStateException if the concurrencyLevel is either below/equal to 0 or above/equal to 65535 + */ + public CONCURRENT_HASH_MAP(Map map, int concurrencyLevel) { + this(map, HashUtil.DEFAULT_LOAD_FACTOR, concurrencyLevel); + } + + /** + * A Helper constructor that allows to create a Map with exactly the same values as the provided map. + * @param map the values that should be present in the map + * @param loadFactor the percentage of how full the backing array can be before they resize + * @param concurrencyLevel decides how many operations can be performed at once. + * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1 + * @throws IllegalStateException if the concurrencyLevel is either below/equal to 0 or above/equal to 65535 + */ + public CONCURRENT_HASH_MAP(Map map, float loadFactor, int concurrencyLevel) { + this(map.size(), loadFactor, concurrencyLevel); + putAll(map); + } + + /** + * A Type Specific Helper function that allows to create a new Map with exactly the same values as the provided map. + * @param map the values that should be present in the map + */ + public CONCURRENT_HASH_MAP(MAP KEY_VALUE_GENERIC_TYPE map) { + this(map, HashUtil.DEFAULT_LOAD_FACTOR, HashUtil.DEFAULT_MIN_CONCURRENCY); + } + + /** + * A Type Specific Helper function that allows to create a new Map with exactly the same values as the provided map. + * @param map the values that should be present in the map + * @param loadFactor the percentage of how full the backing array can be before they resize + * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1 + */ + public CONCURRENT_HASH_MAP(MAP KEY_VALUE_GENERIC_TYPE map, float loadFactor) { + this(map, loadFactor, HashUtil.DEFAULT_MIN_CONCURRENCY); + } + + /** + * A Type Specific Helper function that allows to create a new Map with exactly the same values as the provided map. + * @param map the values that should be present in the map + * @param concurrencyLevel decides how many operations can be performed at once. + * @throws IllegalStateException if the concurrencyLevel is either below/equal to 0 or above/equal to 65535 + */ + public CONCURRENT_HASH_MAP(MAP KEY_VALUE_GENERIC_TYPE map, int concurrencyLevel) { + this(map, HashUtil.DEFAULT_LOAD_FACTOR, concurrencyLevel); + } + + /** + * A Type Specific Helper function that allows to create a new Map with exactly the same values as the provided map. + * @param map the values that should be present in the map + * @param loadFactor the percentage of how full the backing array can be before they resize + * @param concurrencyLevel decides how many operations can be performed at once. + * @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1 + * @throws IllegalStateException if the concurrencyLevel is either below/equal to 0 or above/equal to 65535 + */ + public CONCURRENT_HASH_MAP(MAP KEY_VALUE_GENERIC_TYPE map, float loadFactor, int concurrencyLevel) { + this(map.size(), loadFactor, concurrencyLevel); + putAll(map); + } + @Override public VALUE_TYPE put(KEY_TYPE key, VALUE_TYPE value) { int hash = getHashCode(key); @@ -196,8 +454,8 @@ public class CONCURRENT_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALU } @Override - public CONCURRENT_MAP KEY_VALUE_GENERIC_TYPE copy() { - CONCURRENT_MAP KEY_VALUE_GENERIC_TYPE copy = new CONCURRENT_MAPKV_BRACES(false); + public CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE copy() { + CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE copy = new CONCURRENT_HASH_MAPKV_BRACES(false); copy.segmentShift = segmentShift; copy.segmentMask = segmentMask; copy.segments = new Segment[segments.length]; @@ -331,31 +589,17 @@ public class CONCURRENT_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALU return HashUtil.mix(Objects.hashCode(obj)); } - public void test() { - - } - private class MapEntrySet extends AbstractObjectSet implements MAP.FastEntrySet KEY_VALUE_GENERIC_TYPE { @Override public ObjectBidirectionalIterator iterator() { return new EntryIterator(); } - //TODO implement? - public ObjectBidirectionalIterator iterator(MAP.Entry KEY_VALUE_GENERIC_TYPE fromElement) { - return new EntryIterator(fromElement.ENTRY_KEY()); - } - @Override public ObjectBidirectionalIterator fastIterator() { return new FastEntryIterator(); } - //TODO implement? - public ObjectBidirectionalIterator fastIterator(KEY_TYPE fromElement) { - return new FastEntryIterator(fromElement); - } - @Override public MapEntrySet copy() { throw new UnsupportedOperationException(); } @@ -546,22 +790,22 @@ public class CONCURRENT_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALU 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 CONCURRENT_MAP.this.remove(entry.ENTRY_KEY(), entry.ENTRY_VALUE()); + return CONCURRENT_HASH_MAP.this.remove(entry.ENTRY_KEY(), entry.ENTRY_VALUE()); } Map.Entry entry = (Map.Entry)o; - return CONCURRENT_MAP.this.remove(entry.getKey(), entry.getValue()); + return CONCURRENT_HASH_MAP.this.remove(entry.getKey(), entry.getValue()); } return false; } @Override public int size() { - return CONCURRENT_MAP.this.size(); + return CONCURRENT_HASH_MAP.this.size(); } @Override public void clear() { - CONCURRENT_MAP.this.clear(); + CONCURRENT_HASH_MAP.this.clear(); } } @@ -580,7 +824,7 @@ public class CONCURRENT_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALU @Override public boolean remove(Object o) { int oldSize = size(); - CONCURRENT_MAP.this.remove(o); + CONCURRENT_HASH_MAP.this.remove(o); return size() != oldSize; } @@ -593,7 +837,7 @@ public class CONCURRENT_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALU @Override public boolean remove(KEY_TYPE o) { int oldSize = size(); - CONCURRENT_MAP.this.remove(o); + CONCURRENT_HASH_MAP.this.remove(o); return size() != oldSize; } @@ -603,22 +847,17 @@ public class CONCURRENT_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALU return new KeyIterator(); } - //TODO implement into interface? - public BI_ITERATOR KEY_GENERIC_TYPE iterator(KEY_TYPE fromElement) { - return new KeyIterator(fromElement); - } - @Override public KeySet copy() { throw new UnsupportedOperationException(); } @Override public int size() { - return CONCURRENT_MAP.this.size(); + return CONCURRENT_HASH_MAP.this.size(); } @Override public void clear() { - CONCURRENT_MAP.this.clear(); + CONCURRENT_HASH_MAP.this.clear(); } @Override @@ -801,12 +1040,12 @@ public class CONCURRENT_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALU @Override public int size() { - return CONCURRENT_MAP.this.size(); + return CONCURRENT_HASH_MAP.this.size(); } @Override public void clear() { - CONCURRENT_MAP.this.clear(); + CONCURRENT_HASH_MAP.this.clear(); } @Override @@ -967,9 +1206,6 @@ public class CONCURRENT_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALU MapEntry entry = new MapEntry(); public FastEntryIterator() {} - public FastEntryIterator(KEY_TYPE from) { - super(from); - } @Override public MAP.Entry KEY_VALUE_GENERIC_TYPE next() { @@ -988,9 +1224,6 @@ public class CONCURRENT_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALU MapEntry entry; public EntryIterator() {} - public EntryIterator(KEY_TYPE from) { - super(from); - } @Override public MAP.Entry KEY_VALUE_GENERIC_TYPE next() { @@ -1030,9 +1263,6 @@ public class CONCURRENT_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALU private class KeyIterator extends MapIterator implements BI_ITERATOR KEY_GENERIC_TYPE { public KeyIterator() {} - public KeyIterator(KEY_TYPE from) { - super(from); - } @Override public KEY_TYPE PREVIOUS() { @@ -1062,17 +1292,6 @@ public class CONCURRENT_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALU if(nextSegment != -1) next = segments[nextSegment].firstIndex; } - MapIterator(KEY_TYPE from) { - int hash = getHashCode(from); - previousSegment = currentSegment = nextSegment = getSegmentIndex(hash); - Segment KEY_VALUE_GENERIC_TYPE seg = segments[currentSegment]; - current = previous = seg.findIndex(hash, from); - if(current == -1) throw new NoSuchElementException("The element was not found"); - findNextIndex(); - current = -1; - currentSegment = -1; - } - public boolean hasNext() { return next != -1; } @@ -1267,7 +1486,7 @@ public class CONCURRENT_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALU protected static class Segment KEY_VALUE_GENERIC_TYPE extends ReentrantLock { private static final long serialVersionUID = -446894977795760975L; - protected final CONCURRENT_MAP KEY_VALUE_GENERIC_TYPE map; + protected final CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE map; /** The Backing keys array */ protected transient KEY_TYPE[] keys; /** The Backing values array */ @@ -1293,11 +1512,11 @@ public class CONCURRENT_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALU /** How full the Arrays are allowed to get before resize */ protected float loadFactor; - protected Segment(CONCURRENT_MAP KEY_VALUE_GENERIC_TYPE map) { + protected Segment(CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE map) { this.map = map; } - protected Segment(CONCURRENT_MAP KEY_VALUE_GENERIC_TYPE map, int minCapacity, float loadFactor, boolean isNullContainer) { + protected Segment(CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE map, int minCapacity, float loadFactor, boolean isNullContainer) { this.map = map; this.minCapacity = minCapacity; this.loadFactor = loadFactor; @@ -1310,21 +1529,28 @@ public class CONCURRENT_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALU links = new long[arraySize]; } - protected Segment KEY_VALUE_GENERIC_TYPE copy(CONCURRENT_MAP KEY_VALUE_GENERIC_TYPE newMap) { - Segment KEY_VALUE_GENERIC_TYPE copy = new SegmentKV_BRACES(newMap); - copy.keys = Arrays.copyOf(keys, keys.length); - copy.values = Arrays.copyOf(values, values.length); - copy.links = Arrays.copyOf(links, links.length); - copy.firstIndex = firstIndex; - copy.lastIndex = lastIndex; - copy.containsNull = containsNull; - copy.nullIndex = nullIndex; - copy.maxFill = maxFill; - copy.mask = mask; - copy.size = size; - copy.minCapacity = minCapacity; - copy.loadFactor = loadFactor; - return copy; + protected Segment KEY_VALUE_GENERIC_TYPE copy(CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE newMap) { + lock(); + try + { + Segment KEY_VALUE_GENERIC_TYPE copy = new SegmentKV_BRACES(newMap); + copy.keys = Arrays.copyOf(keys, keys.length); + copy.values = Arrays.copyOf(values, values.length); + copy.links = Arrays.copyOf(links, links.length); + copy.firstIndex = firstIndex; + copy.lastIndex = lastIndex; + copy.containsNull = containsNull; + copy.nullIndex = nullIndex; + copy.maxFill = maxFill; + copy.mask = mask; + copy.size = size; + copy.minCapacity = minCapacity; + copy.loadFactor = loadFactor; + return copy; + } + finally { + unlock(); + } } protected VALUE_TYPE getDefaultReturnValue() { diff --git a/src/builder/resources/speiger/assets/collections/templates/maps/interfaces/ConcurrentMap.template b/src/builder/resources/speiger/assets/collections/templates/maps/interfaces/ConcurrentMap.template new file mode 100644 index 00000000..f38524c2 --- /dev/null +++ b/src/builder/resources/speiger/assets/collections/templates/maps/interfaces/ConcurrentMap.template @@ -0,0 +1,95 @@ +package speiger.src.collections.PACKAGE.maps.interfaces; + +import java.util.concurrent.ConcurrentMap; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Function; + +/** + * A type specific ConcurrentMap interface that reduces boxing/unboxing. + * Since the interface adds nothing new. It is there just for completion sake. + * @Type(T) + * @ValueType(V) + */ +public interface CONCURRENT_MAP KEY_VALUE_GENERIC_TYPE extends ConcurrentMap, MAP KEY_VALUE_GENERIC_TYPE +{ + @Override + @Primitive + public default CLASS_VALUE_TYPE compute(CLASS_TYPE key, BiFunction mappingFunction) { + return MAP.super.compute(key, mappingFunction); + } + + @Override + @Primitive + public default CLASS_VALUE_TYPE computeIfAbsent(CLASS_TYPE key, Function mappingFunction) { + return MAP.super.computeIfAbsent(key, mappingFunction); + } + + @Override + @Primitive + public default CLASS_VALUE_TYPE computeIfPresent(CLASS_TYPE key, BiFunction mappingFunction) { + return MAP.super.computeIfPresent(key, mappingFunction); + } + + @Override + @Primitive + public default void forEach(BiConsumer action) { + MAP.super.forEach(action); + } + + @Override + @Primitive + public default CLASS_VALUE_TYPE merge(CLASS_TYPE key, CLASS_VALUE_TYPE value, BiFunction mappingFunction) { + return MAP.super.merge(key, value, mappingFunction); + } + +#if TYPE_OBJECT && VALUE_OBJECT + @Override + public CLASS_VALUE_TYPE getOrDefault(Object key, CLASS_VALUE_TYPE defaultValue); + @Override + public CLASS_VALUE_TYPE putIfAbsent(CLASS_TYPE key, CLASS_VALUE_TYPE value); + @Override + public boolean remove(Object key, Object value); + @Override + public boolean replace(CLASS_TYPE key, CLASS_VALUE_TYPE oldValue, CLASS_VALUE_TYPE newValue); + @Override + public CLASS_VALUE_TYPE replace(CLASS_TYPE key, CLASS_VALUE_TYPE value); + +#else + @Primitive + @Override + public default CLASS_VALUE_TYPE getOrDefault(Object key, CLASS_VALUE_TYPE defaultValue) { + return MAP.super.getOrDefault(key, defaultValue); + } + + @Override + @Primitive + public default CLASS_VALUE_TYPE putIfAbsent(CLASS_TYPE key, CLASS_VALUE_TYPE value) { + return MAP.super.putIfAbsent(key, value); + } + + @Override + @Deprecated + public default boolean remove(Object key, Object value) { + return MAP.super.remove(key, value); + } + + @Override + @Deprecated + public default boolean replace(CLASS_TYPE key, CLASS_VALUE_TYPE oldValue, CLASS_VALUE_TYPE newValue) { + return MAP.super.replace(key, oldValue, newValue); + } + + @Override + @Deprecated + public default CLASS_VALUE_TYPE replace(CLASS_TYPE key, CLASS_VALUE_TYPE value) { + return MAP.super.replace(key, value); + } + +#endif + @Override + @Deprecated + public default void replaceAll(BiFunction mappingFunction) { + MAP.super.replaceAll(mappingFunction); + } +} \ No newline at end of file diff --git a/src/builder/resources/speiger/assets/collections/templates/maps/interfaces/Map.template b/src/builder/resources/speiger/assets/collections/templates/maps/interfaces/Map.template index 3af9b47e..80f96a3e 100644 --- a/src/builder/resources/speiger/assets/collections/templates/maps/interfaces/Map.template +++ b/src/builder/resources/speiger/assets/collections/templates/maps/interfaces/Map.template @@ -31,6 +31,7 @@ import speiger.src.collections.PACKAGE.maps.impl.immutable.IMMUTABLE_HASH_MAP; import speiger.src.collections.PACKAGE.maps.impl.tree.AVL_TREE_MAP; import speiger.src.collections.PACKAGE.maps.impl.tree.RB_TREE_MAP; import speiger.src.collections.PACKAGE.maps.impl.misc.ARRAY_MAP; +import speiger.src.collections.PACKAGE.maps.impl.concurrent.CONCURRENT_HASH_MAP; #if TYPE_OBJECT import speiger.src.collections.PACKAGE.maps.impl.misc.ENUM_MAP; import speiger.src.collections.PACKAGE.maps.impl.misc.LINKED_ENUM_MAP; @@ -1508,6 +1509,14 @@ public interface MAP KEY_VALUE_GENERIC_TYPE extends Map