All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.badlogic.gdx.ai.utils.CircularBuffer Maven / Gradle / Ivy

There is a newer version: 1.8.2
Show newest version
/*******************************************************************************
 * Copyright 2014 See AUTHORS file.
 * 
 * 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.badlogic.gdx.ai.utils;

import com.badlogic.gdx.utils.reflect.ArrayReflection;

/** A circular buffer, possibly resizable.
 * 
 * @author davebaol */
public class CircularBuffer {
	private T[] items;
	private boolean resizable;
	private int head;
	private int tail;
	private int size;

	/** Creates a resizable {@code CircularBuffer}. */
	public CircularBuffer () {
		this(16, true);
	}

	/** Creates a resizable {@code CircularBuffer} with the given initial capacity.
	 * @param initialCapacity the initial capacity of this circular buffer */
	public CircularBuffer (int initialCapacity) {
		this(initialCapacity, true);
	}

	/** Creates a {@code CircularBuffer} with the given initial capacity.
	 * @param initialCapacity the initial capacity of this circular buffer
	 * @param resizable whether this buffer is resizable or has fixed capacity */
	@SuppressWarnings("unchecked")
	public CircularBuffer (int initialCapacity, boolean resizable) {
		this.items = (T[])new Object[initialCapacity];
		this.resizable = resizable;
		this.head = 0;
		this.tail = 0;
		this.size = 0;
	}

	/** Adds the given item to the tail of this circular buffer.
	 * @param item the item to add
	 * @return {@code true} if the item has been successfully added to this circular buffer; {@code false} otherwise. */
	public boolean store (T item) {
		if (size == items.length) {
			if (!resizable) return false;

			// Resize this queue
			resize(Math.max(8, (int)(items.length * 1.75f)));
		}
		size++;
		items[tail++] = item;
		if (tail == items.length) tail = 0;
		return true;
	}

	/** Removes and returns the item at the head of this circular buffer (if any).
	 * @return the item just removed or {@code null} if this circular buffer is empty. */
	public T read () {
		if (size > 0) {
			size--;
			T item = items[head];
			items[head] = null; // Avoid keeping useless references
			if (++head == items.length) head = 0;
			return item;
		}

		return null;
	}

	/** Removes all items from this circular buffer. */
	public void clear () {
		final T[] items = this.items;
		if (tail > head) {
			int i = head, n = tail;
			do {
				items[i++] = null;
			} while (i < n);
		} else if (size > 0) { // NOTE: when head == tail the buffer can be empty or full
			for (int i = head, n = items.length; i < n; i++)
				items[i] = null;
			for (int i = 0, n = tail; i < n; i++)
				items[i] = null;
		}
		this.head = 0;
		this.tail = 0;
		this.size = 0;
	}

	/** Returns {@code true} if this circular buffer is empty; {@code false} otherwise. */
	public boolean isEmpty () {
		return size == 0;
	}

	/** Returns {@code true} if this circular buffer contains as many items as its capacity; {@code false} otherwise. */
	public boolean isFull () {
		return size == items.length;
	}

	/** Returns the number of elements in this circular buffer. */
	public int size () {
		return size;
	}

	/** Returns {@code true} if this circular buffer can be resized; {@code false} otherwise. */
	public boolean isResizable () {
		return resizable;
	}

	/** Sets the flag specifying whether this circular buffer can be resized or not.
	 * @param resizable the flag */
	public void setResizable (boolean resizable) {
		this.resizable = resizable;
	}

	/** Increases the size of the backing array (if necessary) to accommodate the specified number of additional items. Useful
	 * before adding many items to avoid multiple backing array resizes.
	 * @param additionalCapacity the number of additional items */
	public void ensureCapacity (int additionalCapacity) {
		int newCapacity = size + additionalCapacity;
		if (items.length < newCapacity) resize(newCapacity);
	}

	/** Creates a new backing array with the specified capacity containing the current items.
	 * @param newCapacity the new capacity */
	protected void resize (int newCapacity) {
		@SuppressWarnings("unchecked")
		T[] newItems = (T[])ArrayReflection.newInstance(items.getClass().getComponentType(), newCapacity);
		if (tail > head) {
			System.arraycopy(items, head, newItems, 0, size);
		} else if (size > 0) { // NOTE: when head == tail the buffer can be empty or full
			System.arraycopy(items, head, newItems, 0, items.length - head);
			System.arraycopy(items, 0, newItems, items.length - head, tail);
		}
		head = 0;
		tail = size;
		items = newItems;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy