package com.jenkov.nioserver; /** * Same as QueueFillCount, except that QueueFlip uses a flip flag to keep track * of when the internal writePos has "overflowed" (meaning it goes back to 0). * Other than that, the two implementations are very similar in * functionality.
*
* One additional difference is that QueueFlip has an available() method, where * this is a public variable in QueueFillCount.
*
* Project: java-nio-server
* File: QueueIntFlip.java
* Created: 18 Oct 2015
* * @author jjenkov */ public class QueueIntFlip { public int[] elements; public int capacity; public int writePos; public int readPos; public boolean flipped; public QueueIntFlip(int capacity) { this.capacity = capacity; elements = new int[capacity]; // TODO: get from TypeAllocator ? } public void reset() { writePos = 0; readPos = 0; flipped = false; } public int available() { return flipped ? capacity - readPos + writePos : writePos - readPos; } public int remainingCapacity() { return flipped ? readPos - writePos : capacity - writePos; } public boolean put(int element) { if (!flipped) { if (writePos == capacity) { writePos = 0; flipped = true; if (writePos < readPos) { elements[writePos++] = element; return true; } else return false; } else { elements[writePos++] = element; return true; } } else { if (writePos < readPos) { elements[writePos++] = element; return true; } else return false; } } public int put(int[] newElements, int length) { int newElementsReadPos = 0; if (!flipped) { // readPos lower than writePos - free sections are: // 1) from writePos to capacity // 2) from 0 to readPos if (length <= capacity - writePos) { // new elements fit into top of elements array - copy directly for (; newElementsReadPos < length; newElementsReadPos++) elements[writePos++] = newElements[newElementsReadPos]; return newElementsReadPos; } else { // new elements must be divided between top and bottom of elements array // writing to top for (; writePos < capacity; writePos++) elements[writePos] = newElements[newElementsReadPos++]; // writing to bottom this.writePos = 0; this.flipped = true; int endPos = Math.min(readPos, length - newElementsReadPos); for (; writePos < endPos; writePos++) this.elements[writePos] = newElements[newElementsReadPos++]; return newElementsReadPos; } } else { // readPos higher than writePos - free sections are: // 1) from writePos to readPos int endPos = Math.min(readPos, writePos + length); for (; writePos < endPos; writePos++) elements[writePos] = newElements[newElementsReadPos++]; return newElementsReadPos; } } public int take() { if (!flipped) return readPos < writePos ? elements[readPos++] : -1; else { if (readPos == capacity) { readPos = 0; flipped = false; return readPos < writePos ? elements[readPos++] : -1; } else return elements[readPos++]; } } public int take(int[] into, int length) { int intoWritePos = 0; if (!flipped) { // writePos higher than readPos - available section is writePos - readPos int endPos = Math.min(writePos, readPos + length); for (; readPos < endPos; readPos++) into[intoWritePos++] = elements[readPos]; return intoWritePos; } else { // readPos higher than writePos - available sections are top + bottom of // elements array if (length <= capacity - readPos) { // length is lower than the elements available at the top of the elements array // - copy directly for (; intoWritePos < length; intoWritePos++) into[intoWritePos] = elements[readPos++]; return intoWritePos; } else { // length is higher than elements available at the top of the elements array // split copy into a copy from both top and bottom of elements array. // copy from top for (; readPos < capacity; readPos++) into[intoWritePos++] = elements[readPos]; // copy from bottom readPos = 0; flipped = false; int endPos = Math.min(writePos, length - intoWritePos); for (; readPos < endPos; readPos++) into[intoWritePos++] = elements[readPos]; return intoWritePos; } } } }