/*
* Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.dev.util;
import java.util.Iterator;
import org.h2.mvstore.DataUtils;
/**
* A ring buffer that supports concurrent access.
*
* @param <K> the key type
*/
public class ConcurrentRing<K> {
/**
* The ring buffer.
*/
K[] buffer;
/**
* The read position.
*/
volatile int readPos;
/**
* The write position.
*/
volatile int writePos;
@SuppressWarnings("unchecked")
public ConcurrentRing() {
buffer = (K[]) new Object[4];
}
/**
* Get the first element, or null if none.
*
* @return the first element
*/
public K peekFirst() {
return buffer[getIndex(readPos)];
}
/**
* Get the last element, or null if none.
*
* @return the last element
*/
public K peekLast() {
return buffer[getIndex(writePos - 1)];
}
/**
* Add an element at the end.
*
* @param obj the element
*/
public void add(K obj) {
buffer[getIndex(writePos)] = obj;
writePos++;
if (writePos - readPos >= buffer.length) {
// double the capacity
@SuppressWarnings("unchecked")
K[] b2 = (K[]) new Object[buffer.length * 2];
for (int i = readPos; i < writePos; i++) {
K x = buffer[getIndex(i)];
int i2 = i & b2.length - 1;
b2[i2] = x;
}
buffer = b2;
}
}
/**
* Remove the first element, if it matches.
*
* @param obj the element to remove
* @return true if the element matched and was removed
*/
public boolean removeFirst(K obj) {
int p = readPos;
int idx = getIndex(p);
if (buffer[idx] != obj) {
return false;
}
buffer[idx] = null;
readPos = p + 1;
return true;
}
/**
* Remove the last element, if it matches.
*
* @param obj the element to remove
* @return true if the element matched and was removed
*/
public boolean removeLast(K obj) {
int p = writePos;
int idx = getIndex(p - 1);
if (buffer[idx] != obj) {
return false;
}
buffer[idx] = null;
writePos = p - 1;
return true;
}
/**
* Get the index in the array of the given position.
*
* @param pos the position
* @return the index
*/
int getIndex(int pos) {
return pos & (buffer.length - 1);
}
/**
* Get an iterator over all entries.
*
* @return the iterator
*/
public Iterator<K> iterator() {
return new Iterator<K>() {
int offset;
@Override
public boolean hasNext() {
return readPos + offset < writePos;
}
@Override
public K next() {
if (buffer[getIndex(readPos + offset)] == null) {
System.out.println("" + readPos);
System.out.println("" + getIndex(readPos + offset));
System.out.println("null?");
}
return buffer[getIndex(readPos + offset++)];
}
@Override
public void remove() {
throw DataUtils.newUnsupportedOperationException("remove");
}
};
}
}