diff --git a/rosjava/src/main/java/org/ros/concurrent/CircularBlockingQueue.java b/rosjava/src/main/java/org/ros/concurrent/CircularBlockingQueue.java index 5bd5b26e7705d082b807e2595d9c80c370cd0cec..ae011a260bd6140f0eefe46f514172f4b9fede26 100644 --- a/rosjava/src/main/java/org/ros/concurrent/CircularBlockingQueue.java +++ b/rosjava/src/main/java/org/ros/concurrent/CircularBlockingQueue.java @@ -16,16 +16,17 @@ package org.ros.concurrent; +import java.util.Iterator; import java.util.Queue; /** - * A {@link Queue} that removes the old elements when the number of elements - * exceeds the limit and blocks on {@link #take()} when there are no elements - * available. + * A {@link Queue}-like data structure that removes the old elements when the + * number of elements exceeds the limit and blocks on {@link #take()} when there + * are no elements available. * * @author damonkohler@google.com (Damon Kohler) */ -public class CircularBlockingQueue<T> { +public class CircularBlockingQueue<T> implements Iterable<T> { private final T[] queue; private final Object mutex; @@ -65,8 +66,9 @@ public class CircularBlockingQueue<T> { * * @param entry * the entry to add + * @return {@code true} */ - public void add(T entry) { + public boolean add(T entry) { synchronized (mutex) { queue[(start + length) % limit] = entry; if (length == limit) { @@ -76,6 +78,7 @@ public class CircularBlockingQueue<T> { } mutex.notify(); } + return true; } /** @@ -101,10 +104,39 @@ public class CircularBlockingQueue<T> { return entry; } - /** - * @return {@code true} if the queue is empty, {@code false} otherwise - */ public boolean isEmpty() { return length == 0; } + + /** + * Returns an iterator over the queue. + * <p> + * Note that this is not thread-safe and that {@link Iterator#remove()} is + * unsupported. + * + * @see java.lang.Iterable#iterator() + */ + @Override + public Iterator<T> iterator() { + return new Iterator<T>() { + int offset = 0; + + @Override + public boolean hasNext() { + return offset < length; + } + + @Override + public T next() { + T entry = queue[start + offset]; + offset++; + return entry; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } } diff --git a/rosjava/src/test/java/org/ros/concurrent/CircularBlockingQueueTest.java b/rosjava/src/test/java/org/ros/concurrent/CircularBlockingQueueTest.java index 1a517ec8f38abb3c9599745240de58b3cf083854..d8f973fe43952b233c48cd0ba9eb2f12495a8ea7 100644 --- a/rosjava/src/test/java/org/ros/concurrent/CircularBlockingQueueTest.java +++ b/rosjava/src/test/java/org/ros/concurrent/CircularBlockingQueueTest.java @@ -17,12 +17,14 @@ package org.ros.concurrent; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import org.junit.Before; import org.junit.Test; +import java.util.Iterator; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -41,7 +43,7 @@ public class CircularBlockingQueueTest { } @Test - public void testPutAndTake() throws InterruptedException { + public void testAddAndTake() throws InterruptedException { CircularBlockingQueue<String> queue = new CircularBlockingQueue<String>(10); String expectedString1 = "Hello, world!"; String expectedString2 = "Goodbye, world!"; @@ -61,6 +63,23 @@ public class CircularBlockingQueueTest { assertEquals(expectedString, queue.take()); } + @Test + public void testIterator() throws InterruptedException { + CircularBlockingQueue<String> queue = new CircularBlockingQueue<String>(10); + String expectedString1 = "Hello, world!"; + String expectedString2 = "Goodbye, world!"; + queue.add(expectedString1); + queue.add(expectedString2); + Iterator<String> iterator = queue.iterator(); + assertEquals(expectedString1, iterator.next()); + assertEquals(expectedString2, iterator.next()); + assertFalse(iterator.hasNext()); + queue.take(); + iterator = queue.iterator(); + assertEquals(expectedString2, iterator.next()); + assertFalse(iterator.hasNext()); + } + @Test public void testBlockingTake() throws InterruptedException { final CircularBlockingQueue<String> queue = new CircularBlockingQueue<String>(1);