/*
* Copyright (C) 2015 Jorge Ruesga
*
* 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 com.ruesga.android.wallpapers.photophase;
import java.util.ArrayList;
import java.util.List;
/**
* A class that represent a FIFO queue with a fixed size. When the queue reach the maximum defined
* size then extract the next element from the queue.
* @param <T> The type of object to hold.
*/
@SuppressWarnings("unchecked")
public class FixedQueue<T> {
/**
* An exception thrown when the queue hasn't more elements
*/
public static class EmptyQueueException extends Exception {
private static final long serialVersionUID = 1L;
}
private final Object[] mQueue;
private final int mSize;
private int mHead;
private int mTail;
/**
* Constructor of <code>FixedQueue</code>
*
* @param size The size of the queue. The limit of objects in queue. Beyond this limits
* the older objects are recycled.
*/
public FixedQueue(int size) {
super();
this.mQueue = new Object[size];
this.mSize = size;
this.mHead = 0;
this.mTail = 0;
}
/**
* Method that inserts a new object to the queue.
*
* @param o The object to insert
* @return The object inserted (for concatenation purpose)
*/
public T insert(T o) {
synchronized (this.mQueue) {
if (o == null) throw new NullPointerException();
if (this.mQueue[this.mHead] != null) {
try {
noSynchronizedRemove();
} catch (Throwable ex) {/**NON BLOCK**/}
}
this.mQueue[this.mHead] = o;
this.mHead++;
if (this.mHead >= this.mSize) {
this.mHead = 0;
}
return o;
}
}
/**
* Method that extract the first element in the queue
*
* @return The item extracted
* @throws EmptyQueueException If the queue hasn't element
*/
public T remove() throws EmptyQueueException {
synchronized (this.mQueue) {
return noSynchronizedRemove();
}
}
/**
* Method that extract all the items from the queue
*
* @return The items extracted
* @throws EmptyQueueException If the queue hasn't element
*/
public List<T> removeAll() throws EmptyQueueException {
synchronized (this.mQueue) {
if (isEmpty()) throw new EmptyQueueException();
List<T> l = new ArrayList<>();
while (!isEmpty()) {
l.add(noSynchronizedRemove());
}
return l;
}
}
/**
* Method that retrieves the first element in the queue. This method doesn't remove the item
* from queue.
*
* @return The item retrieved
* @throws EmptyQueueException If the queue hasn't element
*/
public T peek() throws EmptyQueueException {
synchronized (this.mQueue) {
T o = (T)this.mQueue[this.mTail];
if (o == null) throw new EmptyQueueException();
return o;
}
}
/**
* Method that retrieves all the items from the queue. This method doesn't remove any item
* from queue.
*
* @return The items retrieved
* @throws EmptyQueueException If the queue hasn't element
*/
public List<T> peekAll() throws EmptyQueueException {
synchronized (this.mQueue) {
if (isEmpty()) throw new EmptyQueueException();
List<T> l = new ArrayList<>();
int head = this.mHead;
int tail = this.mTail;
do {
l.add((T)this.mQueue[tail]);
tail++;
if (tail >= this.mSize) {
tail = 0;
}
} while (head != tail);
return l;
}
}
/**
* Method that returns if the queue is empty
*
* @return boolean If the queue is empty
*/
public boolean isEmpty() {
synchronized (this.mQueue) {
return this.mQueue[this.mTail] == null;
}
}
/**
* Method that returns the number of items in the queue
*
* @return int The number of items
*/
public int items() {
int cc = 0;
int head = this.mHead;
int tail = this.mTail;
do {
if (this.mQueue[tail] == null) {
return cc;
}
cc++;
tail++;
if (tail >= this.mSize) {
tail = 0;
}
} while (head != tail);
return cc;
}
/**
* Method that remove one item without synchronization (for be called from
* synchronized method).
*
* @return The item extracted
* @throws EmptyQueueException If the queue hasn't element
*/
private T noSynchronizedRemove() throws EmptyQueueException {
T o = (T)this.mQueue[this.mTail];
if (o == null) throw new EmptyQueueException();
this.mQueue[this.mTail] = null;
this.mTail++;
if (this.mTail >= this.mSize) {
this.mTail = 0;
}
return o;
}
/**
* Method that returns the size of this queue.
*
* @return The size of this queue
*/
public int size() {
return mSize;
}
}