// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.collections; import java.util.AbstractSet; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.Set; /** * @author Simon Thoresen Hult */ public abstract class LazySet implements Set { private Set delegate = newEmpty(); @Override public final int size() { return delegate.size(); } @Override public final boolean isEmpty() { return delegate.isEmpty(); } @Override public final boolean contains(Object o) { return delegate.contains(o); } @Override public final Iterator iterator() { return delegate.iterator(); } @Override public final Object[] toArray() { return delegate.toArray(); } @Override public final T[] toArray(T[] a) { // noinspection SuspiciousToArrayCall return delegate.toArray(a); } @Override public final boolean add(E e) { return delegate.add(e); } @Override public final boolean remove(Object o) { return delegate.remove(o); } @Override public final boolean containsAll(Collection c) { return delegate.containsAll(c); } @Override public final boolean addAll(Collection c) { return delegate.addAll(c); } @Override public final boolean retainAll(Collection c) { return delegate.retainAll(c); } @Override public final boolean removeAll(Collection c) { return delegate.removeAll(c); } @Override public final void clear() { delegate.clear(); } @Override public final int hashCode() { return delegate.hashCode(); } @Override public final boolean equals(Object obj) { return obj == this || (obj instanceof Set && delegate.equals(obj)); } private Set newEmpty() { return new EmptySet(); } private Set newSingleton(E e) { return new SingletonSet(e); } protected abstract Set newDelegate(); final Set getDelegate() { return delegate; } class EmptySet extends AbstractSet { @Override public Iterator iterator() { return Collections.emptyIterator(); } @Override public int size() { return 0; } @Override public boolean add(E e) { delegate = newSingleton(e); return true; } @Override public boolean addAll(Collection c) { switch (c.size()) { case 0: return false; case 1: add(c.iterator().next()); return true; default: delegate = newDelegate(); delegate.addAll(c); return true; } } } class SingletonSet extends AbstractSet { final E element; SingletonSet(E e) { this.element = e; } @Override public Iterator iterator() { return new Iterator() { boolean hasNext = true; @Override public boolean hasNext() { return hasNext; } @Override public E next() { if (hasNext) { hasNext = false; return element; } else { throw new NoSuchElementException(); } } @Override public void remove() { if (hasNext) { throw new IllegalStateException(); } else { delegate = newEmpty(); } } }; } @Override public int size() { return 1; } @Override public boolean add(E e) { if (contains(e)) { return false; } else { delegate = newDelegate(); delegate.add(element); delegate.add(e); return true; } } @Override public boolean addAll(Collection c) { switch (c.size()) { case 0: return false; case 1: return add(c.iterator().next()); default: delegate = newDelegate(); delegate.add(element); delegate.addAll(c); return true; } } } public static LazySet newHashSet() { return new LazySet() { @Override protected Set newDelegate() { return new HashSet<>(); } }; } }