/* * Copyright 2012 Real Logic Ltd. * * 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 uk.co.real_logic.queues; import java.util.Collection; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.Queue; import java.util.concurrent.atomic.AtomicLong; public final class OneToOneConcurrentArrayQueue3<E> implements Queue<E> { private final int capacity; private final int mask; private final E[] buffer; private final AtomicLong tail = new PaddedAtomicLong(0); private final AtomicLong head = new PaddedAtomicLong(0); public static class PaddedLong { public long value = 0, p1, p2, p3, p4, p5, p6; } private final PaddedLong tailCache = new PaddedLong(); private final PaddedLong headCache = new PaddedLong(); @SuppressWarnings("unchecked") public OneToOneConcurrentArrayQueue3(final int capacity) { this.capacity = findNextPositivePowerOfTwo(capacity); mask = this.capacity - 1; buffer = (E[])new Object[this.capacity]; } public static int findNextPositivePowerOfTwo(final int value) { return 1 << (32 - Integer.numberOfLeadingZeros(value - 1)); } public boolean add(final E e) { if (offer(e)) { return true; } throw new IllegalStateException("Queue is full"); } public boolean offer(final E e) { if (null == e) { throw new NullPointerException("Null is not a valid element"); } final long currentTail = tail.get(); final long wrapPoint = currentTail - capacity; if (headCache.value <= wrapPoint) { headCache.value = head.get(); if (headCache.value <= wrapPoint) { return false; } } buffer[(int)currentTail & mask] = e; tail.lazySet(currentTail + 1); return true; } public E poll() { final long currentHead = head.get(); if (currentHead >= tailCache.value) { tailCache.value = tail.get(); if (currentHead >= tailCache.value) { return null; } } final int index = (int)currentHead & mask; final E e = buffer[index]; buffer[index] = null; head.lazySet(currentHead + 1); return e; } public E remove() { final E e = poll(); if (null == e) { throw new NoSuchElementException("Queue is empty"); } return e; } public E element() { final E e = peek(); if (null == e) { throw new NoSuchElementException("Queue is empty"); } return e; } public E peek() { return buffer[(int)head.get() & mask]; } public int size() { return (int)(tail.get() - head.get()); } public boolean isEmpty() { return tail.get() == head.get(); } public boolean contains(final Object o) { if (null == o) { return false; } for (long i = head.get(), limit = tail.get(); i < limit; i++) { final E e = buffer[(int)i & mask]; if (o.equals(e)) { return true; } } return false; } public Iterator<E> iterator() { throw new UnsupportedOperationException(); } public Object[] toArray() { throw new UnsupportedOperationException(); } public <T> T[] toArray(final T[] a) { throw new UnsupportedOperationException(); } public boolean remove(final Object o) { throw new UnsupportedOperationException(); } public boolean containsAll(final Collection<?> c) { for (final Object o : c) { if (!contains(o)) { return false; } } return true; } public boolean addAll(final Collection<? extends E> c) { for (final E e : c) { add(e); } return true; } public boolean removeAll(final Collection<?> c) { throw new UnsupportedOperationException(); } public boolean retainAll(final Collection<?> c) { throw new UnsupportedOperationException(); } public void clear() { Object value; do { value = poll(); } while (null != value); } }