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

ma.vi.base.circular.CircularLongQueue Maven / Gradle / Ivy

/*
 * Copyright (c) 2018 Vikash Madhow
 */

package ma.vi.base.circular;

import java.util.NoSuchElementException;

/**
 * A simple circular queue of longs backed by an array where items
 * are written at the tail of the array and read off the head. When the tail
 * pointer reaches the end of the buffer, it wraps around to the start.
 * 

* This buffer also supports push-back of items through the * {@link #unread()} and {@link #push(long)} methods. * * @author [email protected] */ public class CircularLongQueue { /** * Creates a new circular buffer of the specified size. * * @param size The buffer size. Must be greater than 1. */ @SuppressWarnings("unchecked") public CircularLongQueue(int size) { if (size <= 1) { throw new IllegalArgumentException("Queue size must be greater than 1."); } this.size = size; this.buffer = new long[size]; } /** * Returns true if the buffer is empty. */ public boolean isEmpty() { return start >= end; } /** * Returns true if the buffer is full. */ public boolean isFull() { return end - start >= size; } /** * Returns the first item in the queue and moves the read pointer * by one position. * * @throws NoSuchElementException If there are no more items to read. */ public long pop() { if (isEmpty()) { throw new NoSuchElementException("Queue is empty."); } else { return buffer[modSize(postIncStart())]; } } /** * Returns the first item in the queue and without changing the read pointer. * * @throws NoSuchElementException If there are no more items to read. */ public long peek() { if (isEmpty()) { throw new NoSuchElementException("Queue is empty."); } else { return buffer[modSize(start)]; } } /** * Unread the last item read by decrementing the pointer to the * next item to read in the queue. If this method is called * before any items have been read, null will be returned when * the top of the queue is read next. */ public void unread() { decStart(); } /** * Pushes one item at the front of the buffer such that it will * be the next item read. * * @param item The item to push back. */ public void push(long item) { unread(); buffer[modSize(start)] = item; } /** * Adds an item at the end of the queue, returning the item * previously at that position. This method never throws an * exception, wrapping around at the end of the queue, when * there is no space left. *

* Returns the item which was previously at the position where * the new item is added. */ public long add(long item) { int next = modSize(end); long existing = buffer[next]; buffer[next] = item; end += 1; return existing; } /** * Returns x modulus the size of the buffer. */ private int modSize(int x) { return mod(x, size); } /** * Increment x by 1 taking care of properly wrapping around * {@code Integer.MAX_VALUE} and ensuring that the resulting * after overflowing has the same modulus respective to the * specified modulo value irrespective of whether overflow * happened or not. * * @param x The value to increment. * @param modulo The modulus value. * @return x incremented with possible wrap-around to the negative side * if there was an overflow. */ private int modInc(int x, int modulo) { if (x < Integer.MAX_VALUE) { x++; } else { /* * Wrap around to the negative side ensuring that * the next expected modulus value is preserved * despite the wraparound. */ int remainder = mod(x, modulo); int nextRemainder = remainder == modulo - 1 ? 0 : remainder + 1; x = Integer.MIN_VALUE; while (mod(x, modulo) != nextRemainder) { x++; } } return x; } private int modDec(int x, int modulo) { if (x > Integer.MIN_VALUE) { x--; } else { /* * Wrap around to the positive side ensuring that * the next expected modulus value is preserved * despite the wraparound. */ int remainder = mod(x, modulo); int prevRemainder = remainder == 0 ? modulo - 1 : remainder - 1; x = Integer.MAX_VALUE; while (mod(x, modulo) != prevRemainder) { x--; } } return x; } private int incStart() { return start = modInc(start, size); } private int decStart() { return start = modDec(start, size); } /** * Returns the current value of start and increments it with * {@link #modInc(int, int)} w.r.t to the size of the queue to * cater for overflow wrap-around. */ private int postIncStart() { int value = start; start = modInc(start, size); return value; } private int postDecStart() { int value = start; start = modDec(start, size); return value; } /** * Returns a modulus b. The % operator in Java returns the remainder * between a and b which works fine as modulus unless a is negative. * This method takes care of that possibility. */ public static int mod(int a, int b) { return (a % b + b) % b; } /** * Buffer size. */ private final int size; /** * Buffer. */ private final long[] buffer; /** * Position in buffer where the next character is to be read. */ private int start; /** * end - 1 = position in buffer where the last character to be read * is available. */ private int end; }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy