diff --git a/Changelog.md b/Changelog.md index 7be84f8..9725396 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,11 @@ # Changelog of versions +### Version 0.7.1 (Unreleased) +- Added: ISizeProvider interface (Optimization Helper) +- Added: ISizeProvider into most Iterable implementations (Distinct/Filter/FlatMap/ArrayFlatMap don't support it, for obvious reasons) +- Added: ToArray function into Iterable which uses ISizeProvider to reduce overhead of duplicating arrays. +- Fixed: putIfAbsent now replaces defaultValues + ### Version 0.7.0 - Added: Over 11 Million Unit Tests to this library to ensure quality. - Added: ArrayList size constructor now throws IllegalStateException if the size parameter is negative diff --git a/src/builder/resources/speiger/assets/collections/templates/collections/Collection.template b/src/builder/resources/speiger/assets/collections/templates/collections/Collection.template index 6db9129..f3154cb 100644 --- a/src/builder/resources/speiger/assets/collections/templates/collections/Collection.template +++ b/src/builder/resources/speiger/assets/collections/templates/collections/Collection.template @@ -16,13 +16,14 @@ import speiger.src.collections.PACKAGE.functions.CONSUMER; #endif import speiger.src.collections.PACKAGE.utils.SPLIT_ITERATORS; import speiger.src.collections.PACKAGE.utils.COLLECTIONS; +import speiger.src.collections.utils.ISizeProvider; import speiger.src.collections.utils.SanityChecks; /** * A Type-Specific {@link Collection} that reduces (un)boxing * @Type(T) */ -public interface COLLECTION KEY_GENERIC_TYPE extends Collection, ITERABLE KEY_GENERIC_TYPE +public interface COLLECTION KEY_GENERIC_TYPE extends Collection, ITERABLE KEY_GENERIC_TYPE, ISizeProvider { #if !TYPE_OBJECT /** diff --git a/src/builder/resources/speiger/assets/collections/templates/collections/Iterable.template b/src/builder/resources/speiger/assets/collections/templates/collections/Iterable.template index 4d0cfee..38ac229 100644 --- a/src/builder/resources/speiger/assets/collections/templates/collections/Iterable.template +++ b/src/builder/resources/speiger/assets/collections/templates/collections/Iterable.template @@ -10,6 +10,7 @@ import speiger.src.collections.objects.collections.ObjectIterable; #else import java.util.function.BiFunction; import java.util.Comparator; +import speiger.src.collections.ints.functions.function.Int2ObjectFunction; #endif import speiger.src.collections.PACKAGE.functions.function.TO_OBJECT_FUNCTION; @@ -26,6 +27,7 @@ import speiger.src.collections.PACKAGE.utils.ASYNC_BUILDER; import speiger.src.collections.PACKAGE.utils.SPLIT_ITERATORS; import speiger.src.collections.PACKAGE.utils.ITERABLES; import speiger.src.collections.PACKAGE.utils.ITERATORS; +import speiger.src.collections.utils.ISizeProvider; /** * A Type-Specific {@link Iterable} that reduces (un)boxing @@ -117,6 +119,7 @@ public interface ITERABLE KEY_GENERIC_TYPE extends Iterable * @param The return type supplier. * @param The return type. * @return a new Iterable that returns the desired result + * @note does not support TO_ARRAY optimizations. */ default > ObjectIterable flatMap(TO_OBJECT_FUNCTION KKS_GENERIC_TYPE mapper) { return ITERABLES.flatMap(this, mapper); @@ -127,6 +130,7 @@ public interface ITERABLE KEY_GENERIC_TYPE extends Iterable * @param mapper the flatMapping function * @param The return type. * @return a new Iterable that returns the desired result + * @note does not support TO_ARRAY optimizations. */ default ObjectIterable arrayflatMap(TO_OBJECT_FUNCTION KKS_GENERIC_TYPE mapper) { return ITERABLES.arrayFlatMap(this, mapper); @@ -136,6 +140,7 @@ public interface ITERABLE KEY_GENERIC_TYPE extends Iterable * A Helper function to reduce the usage of Streams and allows to filter out unwanted elements * @param filter the elements that should be kept. * @return a Iterable that filtered out all unwanted elements + * @note does not support TO_ARRAY optimizations. */ default ITERABLE KEY_GENERIC_TYPE filter(PREDICATE KEY_GENERIC_TYPE filter) { return ITERABLES.filter(this, filter); @@ -144,6 +149,7 @@ public interface ITERABLE KEY_GENERIC_TYPE extends Iterable /** * A Helper function to reduce the usage of Streams and allows to filter out duplicated elements * @return a Iterable that filtered out all duplicated elements + * @note does not support TO_ARRAY optimizations. */ default ITERABLE KEY_GENERIC_TYPE distinct() { return ITERABLES.distinct(this); @@ -213,6 +219,44 @@ public interface ITERABLE KEY_GENERIC_TYPE extends Iterable return pour(new LINKED_HASH_SETBRACES()); } +#endif + +#if TYPE_OBJECT + /** + * A Helper function that reduces the usage of streams and allows to collect all elements as a Array + * @param action is the creator function of said Array to ensure type is kept. + * @return a new Array of all elements + */ + default KEY_TYPE[] TO_ARRAY(Int2ObjectFunction action) { + ISizeProvider prov = ISizeProvider.of(this); + if(prov != null) { + int size = prov.size(); + if(size >= 0) { + KEY_TYPE[] array = action.get(size); + ITERATORS.unwrap(array, iterator()); + return array; + } + } + return ITERATORS.pour(iterator()).TO_ARRAY(action); + } +#else + /** + * A Helper function that reduces the usage of streams and allows to collect all elements as a Array + * @return a new Array of all elements + */ + default KEY_TYPE[] TO_ARRAY() { + ISizeProvider prov = ISizeProvider.of(this); + if(prov != null) { + int size = prov.size(); + if(size >= 0) { + KEY_TYPE[] array = NEW_KEY_ARRAY(size); + ITERATORS.unwrap(array, iterator()); + return array; + } + } + return ITERATORS.pour(iterator()).TO_ARRAY(); + } + #endif /** * Helper function to reduce stream usage that allows to filter for any matches. 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 c8ba1d7..bc61dcc 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 @@ -1812,6 +1812,11 @@ public class CONCURRENT_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY insert(-slot-1, key, value); return getDefaultReturnValue(); } + else if(VALUE_EQUALS(values[slot], getDefaultReturnValue())) { + VALUE_TYPE oldValue = values[slot]; + values[slot] = value; + return oldValue; + } return values[slot]; } finally { diff --git a/src/builder/resources/speiger/assets/collections/templates/maps/impl/customHash/OpenCustomHashMap.template b/src/builder/resources/speiger/assets/collections/templates/maps/impl/customHash/OpenCustomHashMap.template index b2f4c91..1d67e8b 100644 --- a/src/builder/resources/speiger/assets/collections/templates/maps/impl/customHash/OpenCustomHashMap.template +++ b/src/builder/resources/speiger/assets/collections/templates/maps/impl/customHash/OpenCustomHashMap.template @@ -270,6 +270,11 @@ public class CUSTOM_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VAL insert(-slot-1, key, value); return getDefaultReturnValue(); } + else if(VALUE_EQUALS(values[slot], getDefaultReturnValue())) { + VALUE_TYPE oldValue = values[slot]; + values[slot] = value; + return oldValue; + } return values[slot]; } diff --git a/src/builder/resources/speiger/assets/collections/templates/maps/impl/hash/OpenHashMap.template b/src/builder/resources/speiger/assets/collections/templates/maps/impl/hash/OpenHashMap.template index 7bea7f9..ce26713 100644 --- a/src/builder/resources/speiger/assets/collections/templates/maps/impl/hash/OpenHashMap.template +++ b/src/builder/resources/speiger/assets/collections/templates/maps/impl/hash/OpenHashMap.template @@ -245,6 +245,11 @@ public class HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GENE insert(-slot-1, key, value); return getDefaultReturnValue(); } + else if(VALUE_EQUALS(values[slot], getDefaultReturnValue())) { + VALUE_TYPE oldValue = values[slot]; + values[slot] = value; + return oldValue; + } return values[slot]; } diff --git a/src/builder/resources/speiger/assets/collections/templates/maps/impl/misc/ArrayMap.template b/src/builder/resources/speiger/assets/collections/templates/maps/impl/misc/ArrayMap.template index 6aca5e2..fdc3af2 100644 --- a/src/builder/resources/speiger/assets/collections/templates/maps/impl/misc/ArrayMap.template +++ b/src/builder/resources/speiger/assets/collections/templates/maps/impl/misc/ArrayMap.template @@ -202,6 +202,11 @@ public class ARRAY_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GEN insertIndex(size++, key, value); return getDefaultReturnValue(); } + else if(VALUE_EQUALS(values[index], getDefaultReturnValue())) { + VALUE_TYPE oldValue = values[index]; + values[index] = value; + return oldValue; + } return values[index]; } diff --git a/src/builder/resources/speiger/assets/collections/templates/maps/impl/misc/EnumMap.template b/src/builder/resources/speiger/assets/collections/templates/maps/impl/misc/EnumMap.template index 615e434..eb71035 100644 --- a/src/builder/resources/speiger/assets/collections/templates/maps/impl/misc/EnumMap.template +++ b/src/builder/resources/speiger/assets/collections/templates/maps/impl/misc/EnumMap.template @@ -161,7 +161,14 @@ public class ENUM_MAP KEY_ENUM_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE @Override public VALUE_TYPE putIfAbsent(T key, VALUE_TYPE value) { int index = key.ordinal(); - if(isSet(index)) return values[index]; + 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(); diff --git a/src/builder/resources/speiger/assets/collections/templates/maps/impl/tree/AVLTreeMap.template b/src/builder/resources/speiger/assets/collections/templates/maps/impl/tree/AVLTreeMap.template index 08c5240..f2c57b4 100644 --- a/src/builder/resources/speiger/assets/collections/templates/maps/impl/tree/AVLTreeMap.template +++ b/src/builder/resources/speiger/assets/collections/templates/maps/impl/tree/AVLTreeMap.template @@ -280,7 +280,10 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_ int compare = 0; Node KEY_VALUE_GENERIC_TYPE parent = tree; while(true) { - if((compare = compare(key, parent.key)) == 0) return parent.value; + if((compare = compare(key, parent.key)) == 0) { + if(VALUE_EQUALS(parent.value, getDefaultReturnValue())) return parent.setValue(value); + return parent.value; + } if(compare < 0) { if(parent.left == null) break; parent = parent.left; diff --git a/src/builder/resources/speiger/assets/collections/templates/maps/impl/tree/RBTreeMap.template b/src/builder/resources/speiger/assets/collections/templates/maps/impl/tree/RBTreeMap.template index 09bc91b..d8e94c8 100644 --- a/src/builder/resources/speiger/assets/collections/templates/maps/impl/tree/RBTreeMap.template +++ b/src/builder/resources/speiger/assets/collections/templates/maps/impl/tree/RBTreeMap.template @@ -280,7 +280,10 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_G int compare = 0; Node KEY_VALUE_GENERIC_TYPE parent = tree; while(true) { - if((compare = compare(key, parent.key)) == 0) return parent.value; + if((compare = compare(key, parent.key)) == 0) { + if(VALUE_EQUALS(parent.value, getDefaultReturnValue())) return parent.setValue(value); + return parent.value; + } if(compare < 0) { if(parent.left == null) break; parent = parent.left; 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 1dcce95..1d3e2f5 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 @@ -102,6 +102,26 @@ public interface MAP KEY_VALUE_GENERIC_TYPE extends Map entry) { + return put(entry.getKey(), entry.getValue()); + } + +#endif /** * Type Specific array method to bulk add elements into a map without creating a wrapper and increasing performances * @param keys the keys that should be added diff --git a/src/builder/resources/speiger/assets/collections/templates/utils/Iterables.template b/src/builder/resources/speiger/assets/collections/templates/utils/Iterables.template index 1774452..de74496 100644 --- a/src/builder/resources/speiger/assets/collections/templates/utils/Iterables.template +++ b/src/builder/resources/speiger/assets/collections/templates/utils/Iterables.template @@ -25,6 +25,7 @@ import speiger.src.collections.PACKAGE.functions.function.PREDICATE; import speiger.src.collections.PACKAGE.sets.HASH_SET; import speiger.src.collections.PACKAGE.sets.SET; #endif +import speiger.src.collections.utils.ISizeProvider; /** * A Helper class for Iterables @@ -247,7 +248,7 @@ public class ITERABLES return new WrappedIterableBRACES(iterable); } - private static class WrappedIterable KEY_GENERIC_TYPE implements ITERABLE KEY_GENERIC_TYPE + private static class WrappedIterable KEY_GENERIC_TYPE implements ITERABLE KEY_GENERIC_TYPE, ISizeProvider { Iterable iterable; @@ -259,6 +260,12 @@ public class ITERABLES return ITERATORS.wrap(iterable.iterator()); } + @Override + public int size() { + ISizeProvider prov = ISizeProvider.of(iterable); + return prov == null ? -1 : prov.size(); + } + #if !TYPE_OBJECT @Override public void forEach(CONSUMER action) { @@ -273,7 +280,7 @@ public class ITERABLES #endif } - private static class MappedIterable KSS_GENERIC_TYPE implements ObjectIterable + private static class MappedIterable KSS_GENERIC_TYPE implements ObjectIterable, ISizeProvider { ITERABLE KEY_SPECIAL_GENERIC_TYPE iterable; TO_OBJECT_FUNCTION KSS_GENERIC_TYPE mapper; @@ -287,6 +294,12 @@ public class ITERABLES return ITERATORS.map(iterable.iterator(), mapper); } + @Override + public int size() { + ISizeProvider prov = ISizeProvider.of(this); + return prov == null ? -1 : prov.size(); + } + @Override public void forEach(Consumer action) { Objects.requireNonNull(action); @@ -342,7 +355,7 @@ public class ITERABLES } } - private static class RepeatingIterable KEY_GENERIC_TYPE implements ITERABLE KEY_GENERIC_TYPE + private static class RepeatingIterable KEY_GENERIC_TYPE implements ITERABLE KEY_GENERIC_TYPE, ISizeProvider { ITERABLE KEY_GENERIC_TYPE iterable; int repeats; @@ -357,6 +370,12 @@ public class ITERABLES return ITERATORS.repeat(iterable.iterator(), repeats); } + @Override + public int size() { + ISizeProvider prov = ISizeProvider.of(iterable); + return prov == null ? -1 : prov.size() * (repeats+1); + } + #if !TYPE_OBJECT @Override public void forEach(CONSUMER action) { @@ -407,7 +426,7 @@ public class ITERABLES #endif } - private static class LimitedIterable KEY_GENERIC_TYPE implements ITERABLE KEY_GENERIC_TYPE + private static class LimitedIterable KEY_GENERIC_TYPE implements ITERABLE KEY_GENERIC_TYPE, ISizeProvider { ITERABLE KEY_GENERIC_TYPE iterable; long limit; @@ -422,6 +441,12 @@ public class ITERABLES return ITERATORS.limit(iterable.iterator(), limit); } + @Override + public int size() { + ISizeProvider prov = ISizeProvider.of(iterable); + return prov == null ? -1 : (int)Math.min(prov.size(), limit); + } + #if !TYPE_OBJECT @Override public void forEach(CONSUMER action) { @@ -446,7 +471,7 @@ public class ITERABLES #endif } - private static class SortedIterable KEY_GENERIC_TYPE implements ITERABLE KEY_GENERIC_TYPE + private static class SortedIterable KEY_GENERIC_TYPE implements ITERABLE KEY_GENERIC_TYPE, ISizeProvider { ITERABLE KEY_GENERIC_TYPE iterable; COMPARATOR KEY_GENERIC_TYPE sorter; @@ -461,6 +486,12 @@ public class ITERABLES return ITERATORS.sorted(iterable.iterator(), sorter); } + @Override + public int size() { + ISizeProvider prov = ISizeProvider.of(iterable); + return prov == null ? -1 : prov.size(); + } + #if !TYPE_OBJECT @Override public void forEach(CONSUMER action) { @@ -520,7 +551,7 @@ public class ITERABLES #endif } - private static class PeekIterable KEY_GENERIC_TYPE implements ITERABLE KEY_GENERIC_TYPE + private static class PeekIterable KEY_GENERIC_TYPE implements ITERABLE KEY_GENERIC_TYPE, ISizeProvider { ITERABLE KEY_GENERIC_TYPE iterable; CONSUMER KEY_GENERIC_TYPE action; @@ -535,6 +566,12 @@ public class ITERABLES return ITERATORS.peek(iterable.iterator(), action); } + @Override + public int size() { + ISizeProvider prov = ISizeProvider.of(iterable); + return prov == null ? -1 : prov.size(); + } + #if !TYPE_OBJECT @Override public void forEach(CONSUMER action) { diff --git a/src/main/java/speiger/src/collections/utils/ISizeProvider.java b/src/main/java/speiger/src/collections/utils/ISizeProvider.java new file mode 100644 index 0000000..0833ca3 --- /dev/null +++ b/src/main/java/speiger/src/collections/utils/ISizeProvider.java @@ -0,0 +1,46 @@ +package speiger.src.collections.utils; + +import java.util.Collection; + +/** + * @author Speiger + * + * This Interface is a Helper class to allow transfer the information through Iterators, without forcing a Implementation of a size method through it. + * This is mainly used to optimize the toArray function. + * + */ +public interface ISizeProvider +{ + /** @return the size of the implementing Collection */ + public int size(); + + /** + * Gets a SizeProvider given the Iterable. May return null if it isn't a Collection or a SizeProvider. + * @param iter the Iterable that you want the size of. + * @return a SizeProvider if it is one or if it is a JavaCollection + */ + public static ISizeProvider of(Iterable iter) { + if(iter instanceof ISizeProvider) return (ISizeProvider)iter; + if(iter instanceof Collection) return new CollectionSize((Collection)iter); + return null; + } + + /** + * Collection implementation of the SizeProvider + */ + static class CollectionSize implements ISizeProvider + { + Collection collection; + + public CollectionSize(Collection collection) + { + this.collection = collection; + } + + @Override + public int size() + { + return collection.size(); + } + } +}