package the8472.utils;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;

public class CowSet<E> implements Set<E> {
	
	static final AtomicReferenceFieldUpdater<CowSet,HashMap> u = AtomicReferenceFieldUpdater.newUpdater(CowSet.class, HashMap.class, "backingStore");
	
	volatile HashMap<E,Boolean> backingStore = new HashMap<>();
	
	<T> T update(Function<HashMap<E,Boolean>, ? extends T> c) {
		HashMap<E, Boolean> current;
		final HashMap<E, Boolean> newMap = new HashMap<>();
		T ret;

		do {
			current = u.get(this);
			newMap.clear();
			newMap.putAll(current);
			ret = c.apply(newMap);
		} while(!u.compareAndSet(this, current, newMap));
		
		return ret;
	}
	

	@Override
	public int size() {
		return backingStore.size();
	}

	@Override
	public boolean isEmpty() {
		return backingStore.isEmpty();
	}

	@Override
	public boolean contains(Object o) {
		return backingStore.containsKey(o);
	}

	@Override
	public Iterator<E> iterator() {
		return Collections.unmodifiableCollection(backingStore.keySet()).iterator();
	}

	@Override
	public Object[] toArray() {
		return backingStore.keySet().toArray();
	}

	@Override
	public <T> T[] toArray(T[] a) {
		return backingStore.keySet().toArray(a);
	}

	@Override
	public boolean add(E e) {
		return update(m -> m.putIfAbsent(e, Boolean.TRUE) == null);
	}

	@Override
	public boolean remove(Object o) {
		return update(m -> m.remove(o));
	}

	@Override
	public boolean containsAll(Collection<?> c) {
		throw new UnsupportedOperationException("not implemented");
	}

	@Override
	public boolean addAll(Collection<? extends E> c) {
		throw new UnsupportedOperationException("not implemented");
	}

	@Override
	public boolean retainAll(Collection<?> c) {
		throw new UnsupportedOperationException("not implemented");
	}

	@Override
	public boolean removeAll(Collection<?> c) {
		throw new UnsupportedOperationException("not implemented");
	}

	@Override
	public void clear() {
		backingStore = new HashMap<>();
	}
	
	@Override
	public Stream<E> stream() {
		return backingStore.keySet().stream();
	}
	
	@Override
	public boolean removeIf(Predicate<? super E> filter) {
		return update(m -> {
			return m.keySet().removeIf(filter);
		});
	}
	
	public Set<E> snapshot() {
		return Collections.unmodifiableSet(backingStore.keySet());
	}

}

@@ -1623,16 +1623,25 @@
 (m -%3E m.
+keySet().
 remove(o

fix incorrect return value for CowSet.remove