The circular buffer is an array based queue implementation, widely used for buffering data flows.
Description
The circular buffer consists of one array of fixed length and two pointers. The first pointer points the first stored element, the second one points to the first empty position of the array. When the element is added to the structure, the second index is incremented. When the first element of the array is polled (removed), the first element is incremented and the position is nulled (and the element is destructed). Because both increment operations are performed in a modular fashion (when the last position of the array is occupied, the next element is added at the beginning of the array (if it is empty)), the structure itself forms a circle, hence it is called the circular buffer.
Complexity of operations
The asymptotic complexity of addLast and poll (getFirst) operations is constant – .
001.
/**
002.
* Circular buffer - array based queue
003.
* @author Pavel Micka
004.
*/
005.
public
class
CircularBuffer<ENTITY> {
006.
007.
private
int
size;
008.
private
Object[] array;
009.
private
int
pointer;
//first empty position
010.
011.
/**
012.
* Constructor
013.
* @param length size of the buffer
014.
*/
015.
public
CircularBuffer(
int
length) {
016.
this
.array =
new
Object[length];
017.
this
.size =
0
;
018.
pointer =
0
;
019.
}
020.
021.
/**
022.
* Add an element at the end of the array
023.
* @param i element
024.
*/
025.
public
void
addLast(ENTITY i) {
026.
if
(
this
.size == array.length) {
027.
throw
new
IllegalStateException(
"Buffer is full"
);
028.
}
029.
array[pointer] = i;
030.
031.
pointer = modulo((pointer +
1
), array.length);
032.
size++;
033.
}
034.
035.
/**
036.
* Return and delete the first element (poll)
037.
* @return first element
038.
*/
039.
public
ENTITY getFirst() {
040.
if
(
this
.size ==
0
) {
041.
throw
new
IllegalStateException(
"Buffer is empty"
);
042.
}
043.
ENTITY value = (ENTITY) array[modulo((pointer - size), array.length)];
044.
045.
array[modulo((pointer - size), array.length)] =
null
;
046.
size--;
047.
048.
return
value;
049.
}
050.
051.
/**
052.
* Read the first element (peek)
053.
* @return first element
054.
*/
055.
public
ENTITY readFirst() {
056.
if
(
this
.size ==
0
) {
057.
throw
new
IllegalStateException(
"Buffer is empty"
);
058.
}
059.
ENTITY value = (ENTITY) array[modulo((pointer - size), array.length)];
060.
return
value;
061.
}
062.
063.
/**
064.
* x ≡ number mod(modulo)
065.
* @param number number
066.
* @param modulo modulo
067.
* @return the least nonnegative residuum
068.
*/
069.
private
int
modulo(
int
number,
int
modulo) {
070.
if
(number >=
0
) {
071.
return
number % modulo;
072.
}
073.
int
result = number % modulo;
074.
return
result ==
0
?
0
: result + modulo;
075.
}
076.
077.
@Override
078.
public
String toString() {
079.
StringBuilder builder =
new
StringBuilder();
080.
builder.append(
"Content: "
);
081.
for
(
int
i =
0
; i < size; i++) {
082.
builder.append(array[modulo((pointer - size + i), array.length)]).append(
" "
);
083.
}
084.
builder.append(
"\\nfirst index: "
).append(modulo((pointer - size), array.length)).append(
", last index:"
).append(pointer -
1
).append(
", size: "
).append(size);
085.
return
builder.toString();
086.
}
087.
088.
/**
089.
* Number of occupied positions
090.
* @return number of elements present in the buffer
091.
*/
092.
public
int
getSize() {
093.
return
this
.size;
094.
}
095.
096.
/**
097.
* Size of the buffer
098.
* @return maximal number of elements that could be stored in the buffer
099.
*/
100.
public
int
getLength() {
101.
return
array.length;
102.
}
103.
}