/*
 * Copyright (c) 2011-2016 Pivotal Software Inc, All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package reactor.core.util.concurrent;

import java.util.Collection;
import java.util.Iterator;
import java.util.Objects;
import java.util.Queue;
import java.util.concurrent.atomic.*;

/**
 * A bounded, array backed, single-producer single-consumer queue.
 * 
 * This implementation is based on JCTools' SPSC algorithms:
 * <a href='https://github.com/JCTools/JCTools/blob/master/jctools-core/src/main/java/org/jctools/queues/SpscArrayQueue.java'>SpscArrayQueue</a>
 * and <a href='https://github.com/JCTools/JCTools/blob/master/jctools-core/src/main/java/org/jctools/queues/atomic/SpscAtomicArrayQueue.java'>SpscAtomicArrayQueue</a>
 * of which the {@code SpscAtomicArrayQueue} was contributed by one of the authors of this library. The notable difference
 * is that this class inlines the AtomicReferenceArray directly and there is no lookahead cache involved;
 * item padding has a toll on short lived or bursty uses and lookahead doesn't really matter with small queues.
 * 
 * @param <T> the value type
 */
public final class SpscArrayQueue<T> extends SpscArrayQueueP3<T> implements Queue<T> {
	/** */
	private static final long serialVersionUID = 494623116936946976L;

	public SpscArrayQueue(int capacity) {
		super(QueueSupplier.ceilingNextPowerOfTwo(capacity));
	}
	
	@Override
	public boolean offer(T e) {
		Objects.requireNonNull(e, "e");
		long pi = producerIndex;
		int offset = (int)pi & mask;
		if (get(offset) != null) {
			return false;
		}
		lazySet(offset, e);
		PRODUCER_INDEX.lazySet(this, pi + 1);
		return true;
	}
	
	@Override
	public T poll() {
		long ci = consumerIndex;
		int offset = (int)ci & mask;
		
		T v = get(offset);
		if (v != null) {
			lazySet(offset, null);
			CONSUMER_INDEX.lazySet(this, ci + 1);
		}
		return v;
	}
	
	@Override
	public T peek() {
		int offset = (int)consumerIndex & mask;
		return get(offset);
	}
	
	@Override
	public boolean isEmpty() {
		return producerIndex == consumerIndex;
	}
	
	@Override
	public void clear() {
		while (poll() != null && !isEmpty());
	}

	@Override
	public int size() {
		long ci = consumerIndex;
		for (;;) {
			long pi = producerIndex;
			long ci2 = consumerIndex;
			if (ci == ci2) {
				return (int)(pi - ci);
			}
			ci = ci2;
		}
	}

	@Override
	public boolean contains(Object o) {
		throw new UnsupportedOperationException();
	}

	@Override
	public Iterator<T> iterator() {
		throw new UnsupportedOperationException();
	}

	@Override
	public Object[] toArray() {
		throw new UnsupportedOperationException();
	}

	@Override
	public <R> R[] toArray(R[] a) {
		throw new UnsupportedOperationException();
	}

	@Override
	public boolean remove(Object o) {
		throw new UnsupportedOperationException();
	}

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

	@Override
	public boolean addAll(Collection<? extends T> c) {
		throw new UnsupportedOperationException();
	}

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

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

	@Override
	public boolean add(T e) {
		throw new UnsupportedOperationException();
	}

	@Override
	public T remove() {
		throw new UnsupportedOperationException();
	}

	@Override
	public T element() {
		throw new UnsupportedOperationException();
	}
}

class SpscArrayQueueCold<T> extends AtomicReferenceArray<T> {
	/** */
	private static final long serialVersionUID = 8491797459632447132L;

	final int mask;
	
	public SpscArrayQueueCold(int length) {
		super(length);
		mask = length - 1;
	}
}
class SpscArrayQueueP1<T> extends SpscArrayQueueCold<T> {
	/** */
	private static final long serialVersionUID = -4461305682174876914L;
	
	volatile long p00, p01, p02, p03, p04, p05, p06, p07;
	volatile long p08, p09, p0A, p0B, p0C, p0D, p0E;

	public SpscArrayQueueP1(int length) {
		super(length);
	}
}

class SpscArrayQueueProducer<T> extends SpscArrayQueueP1<T> {

	/** */
	private static final long serialVersionUID = 1657408315616277653L;
	
	public SpscArrayQueueProducer(int length) {
		super(length);
	}

	volatile long producerIndex;
	@SuppressWarnings("rawtypes")
	static final AtomicLongFieldUpdater<SpscArrayQueueProducer> PRODUCER_INDEX =
			AtomicLongFieldUpdater.newUpdater(SpscArrayQueueProducer.class, "producerIndex");

}

class SpscArrayQueueP2<T> extends SpscArrayQueueProducer<T> {
	/** */
	private static final long serialVersionUID = -5400235061461013116L;
	
	volatile long p00, p01, p02, p03, p04, p05, p06, p07;
	volatile long p08, p09, p0A, p0B, p0C, p0D, p0E;

	public SpscArrayQueueP2(int length) {
		super(length);
	}
}

class SpscArrayQueueConsumer<T> extends SpscArrayQueueP2<T> {

	/** */
	private static final long serialVersionUID = 4075549732218321659L;
	
	public SpscArrayQueueConsumer(int length) {
		super(length);
	}

	volatile long consumerIndex;
	@SuppressWarnings("rawtypes")
	static final AtomicLongFieldUpdater<SpscArrayQueueConsumer> CONSUMER_INDEX =
			AtomicLongFieldUpdater.newUpdater(SpscArrayQueueConsumer.class, "consumerIndex");

}

class SpscArrayQueueP3<T> extends SpscArrayQueueConsumer<T> {
	/** */
	private static final long serialVersionUID = -2684922090021364171L;
	
	volatile long p00, p01, p02, p03, p04, p05, p06, p07;
	volatile long p08, p09, p0A, p0B, p0C, p0D, p0E;

	public SpscArrayQueueP3(int length) {
		super(length);
	}
}

@@ -1641,23 +1641,16 @@
 ype%0A */%0A
-public 
 final cl

Exclude Spsc queue from public API