All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ajjpj.abase.collection.immutable.AHashSet Maven / Gradle / Ivy

Go to download

a-base is a library of basic (hence the name) classes, most notably immutable collection classes with copy-on-write operations

There is a newer version: 1.0-pre11
Show newest version
package com.ajjpj.abase.collection.immutable;

import com.ajjpj.abase.collection.ACollectionHelper;
import com.ajjpj.abase.collection.AEquality;
import com.ajjpj.abase.collection.AEqualsWrapper;
import com.ajjpj.abase.function.AFunction1;
import com.ajjpj.abase.function.APredicate;

import java.util.Collection;
import java.util.Iterator;
import java.util.Map;


/**
 * This is an immutable hash set implementation. It has mutator methods that return a modified copy of the set. It
 *  does not implement java.util.Set because that interface is inherently mutable. It does however
 *  provide a method to return an immutable view implementing java.util.Set.

* * It provides uniqueness guarantees based on a configurable equality strategy which defaults to "equals-based". * * @author arno */ public class AHashSet implements ACollection> { private final AHashMap inner; private static final AHashSet emptyEquals = new AHashSet<>(AHashMap.empty(AEquality.EQUALS)); private static final AHashSet emptyIdentity = new AHashSet<>(AHashMap.empty(AEquality.IDENTITY)); /** * Returns an empty AHashSet instance with default (i.e. equals-based) equality. Using a factory method instead of * a constructor allows AHashSet to return a cached implementation. */ @SuppressWarnings("unchecked") public static AHashSet empty() { return (AHashSet) emptyEquals; } /** * Returns an empty AHashSet instance with a given equality strategy. Using a factory method instead of * a constructor allows AHashSet to return a cached implementation. */ @SuppressWarnings("unchecked") public static AHashSet empty(AEquality equality) { if(equality == AEquality.EQUALS) return (AHashSet) emptyEquals; if(equality == AEquality.IDENTITY) return (AHashSet) emptyIdentity; return new AHashSet<>(AHashMap.empty(equality)); } /** * Creates an AHashSet instance with default (i.e. equals-based) equality that is initialized with the elements from a given collection. */ public static AHashSet create(Iterable elements) { return create(AEquality.EQUALS, elements); } /** * Creates an AHashSet instance with a given equality strategy that is initialized with the elements from a given collection. */ public static AHashSet create(AEquality equality, Iterable elements) { AHashSet result = empty(equality); for(T el: elements) { result = result.added(el); } return result; } /** * Creates an AHashSet instance with default (i.e. equals-based) equality that is initialized with the elements from a given collection. */ public static AHashSet create(T... elements) { return create(AEquality.EQUALS, elements); } /** * Creates an AHashSet instance with a given equality strategy that is initialized with the elements from a given collection. */ public static AHashSet create(AEquality equality, T... elements) { AHashSet result = empty(equality); for(T el: elements) { result = result.added(el); } return result; } private AHashSet(AHashMap inner) { this.inner = inner; } public int size() { return inner.size(); } public boolean isEmpty() { return inner.isEmpty(); } public boolean nonEmpty() { return inner.nonEmpty(); } public boolean contains(T el) { return inner.containsKey(el); } /** * This method creates and returns a new AHashSet instance that is guaranteed to contain the given new element. * 'Containment' is relative to the configured equality strategy - if e.g. the set uses AEquality.IDENTITY, it * can contain two objects that are equal without being the same.

* * This is the only method to add elements to the set. */ public AHashSet added(T el) { final AHashMap newInner = inner.updated(el, true); if(newInner == inner) { return this; } return new AHashSet<> (newInner); } /** * This method creates and returns a new AHashSet instance that is guaranteed not to contain the given element. * 'Containment' is relative to the configured equality strategy - if e.g. the set uses AEquality.IDENTITY, it * might not remove an element that is equal to the object that is passed to the removed() method * if they are not the same.

* * This is the only method to remove elements from the set. */ public AHashSet removed(T el) { final AHashMap newInner = inner.removed(el); if(newInner == inner) { return this; } return new AHashSet<> (newInner); } /** * Returns a read-only java.util.Set view of this set. The view is read-through, and creation has * constant time complexity. */ public java.util.Set asJavaUtilSet() { return inner.asJavaUtilMap().keySet(); } @Override public Iterator iterator() { return asJavaUtilSet().iterator(); } @Override public int hashCode() { return inner.hashCode(); } @SuppressWarnings("SimplifiableIfStatement") @Override public boolean equals(Object o) { if(o == this) { return true; } if(! (o instanceof AHashSet)) { return false; } return inner.equals(((AHashSet)o).inner); } public AList toList() { return AList.create(this); } @Override public String mkString() { return ACollectionHelper.mkString(this); } @Override public String mkString(String prefix, String separator, String suffix) { return ACollectionHelper.mkString(this, prefix, separator, suffix); } @Override public String mkString(String separator) { return ACollectionHelper.mkString(this, separator); } @Override public boolean forAll(APredicate pred) throws E { //TODO junit test return ACollectionHelper.forAll(this, pred); } @Override public boolean exists(APredicate pred) throws E { //TODO junit return ACollectionHelper.exists(this, pred); } @Override public AHashSet toSet() { return this; } @Override public AHashSet toSet(AEquality equality) { if(equality == inner.equality) { return this; } return AHashSet.create(equality, this); } @Override public AOption find(APredicate pred) throws E { return ACollectionHelper.find(this, pred); } @Override public AHashSet map(AFunction1 f) throws E { // list instead of set to support arbitrary equality implementations return create(inner.equality, ACollectionHelper.map(this, f)); } @Override public AFilterMonadic> flatMap(AFunction1, T, E> f) throws E { return create(inner.equality, ACollectionHelper.flatMap(this, f)); } @SuppressWarnings("unchecked") @Override public AHashSet flatten() { return (AHashSet) create(inner.equality, ACollectionHelper.flatten((Iterable>) this)); } @Override public AHashSet filter(APredicate pred) throws E { return create(inner.equality, ACollectionHelper.filter(this, pred)); } @Override public AMap> groupBy(AFunction1 f) throws E { //TODO javadoc: *equals* based (and *not* the same as here!) return groupBy(f, AEquality.EQUALS); } @Override public AMap> groupBy(AFunction1 f, AEquality keyEquality) throws E { final Map, Collection> raw = ACollectionHelper.groupBy(this, f, keyEquality); AMap> result = AHashMap.empty(keyEquality); for(Map.Entry, Collection> entry: raw.entrySet()) { result = result.updated(entry.getKey().value, AHashSet.create(entry.getValue())); } return result; } }