Fix CircularBuffer and add unit tests (#3411)

This commit is contained in:
Narek Karapetian
2022-10-06 12:51:10 +04:00
committed by GitHub
parent e96f567bfc
commit 471d2c0b5d
2 changed files with 165 additions and 109 deletions

View File

@ -1,132 +1,61 @@
package com.thealgorithms.datastructures.buffers;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
public class CircularBuffer {
public class CircularBuffer<Item> {
private final Item[] buffer;
private final CircularPointer putPointer;
private final CircularPointer getPointer;
private final AtomicInteger size = new AtomicInteger(0);
private char[] _buffer;
public final int _buffer_size;
private int _write_index = 0;
private int _read_index = 0;
private AtomicInteger _readable_data = new AtomicInteger(0);
public CircularBuffer(int buffer_size) {
if (!IsPowerOfTwo(buffer_size)) {
throw new IllegalArgumentException();
}
this._buffer_size = buffer_size;
_buffer = new char[buffer_size];
public CircularBuffer(int size) {
//noinspection unchecked
this.buffer = (Item[]) new Object[size];
this.putPointer = new CircularPointer(0, size);
this.getPointer = new CircularPointer(0, size);
}
private boolean IsPowerOfTwo(int i) {
return (i & (i - 1)) == 0;
public boolean isEmpty() {
return size.get() == 0;
}
private int getTrueIndex(int i) {
return i % _buffer_size;
public boolean isFull() {
return size.get() == buffer.length;
}
public Character readOutChar() {
Character result = null;
public Item get() {
if (isEmpty())
return null;
// if we have data to read
if (_readable_data.get() > 0) {
result = Character.valueOf(_buffer[getTrueIndex(_read_index)]);
_readable_data.decrementAndGet();
_read_index++;
}
return result;
Item item = buffer[getPointer.getAndIncrement()];
size.decrementAndGet();
return item;
}
public boolean writeToCharBuffer(char c) {
boolean result = false;
public boolean put(Item item) {
if (isFull())
return false;
// if we can write to the buffer
if (_readable_data.get() < _buffer_size) {
// write to buffer
_buffer[getTrueIndex(_write_index)] = c;
_readable_data.incrementAndGet();
_write_index++;
result = true;
}
return result;
buffer[putPointer.getAndIncrement()] = item;
size.incrementAndGet();
return true;
}
private static class TestWriteWorker implements Runnable {
private static class CircularPointer {
private int pointer;
private final int max;
String _alphabet = "abcdefghijklmnopqrstuvwxyz0123456789";
Random _random = new Random();
CircularBuffer _buffer;
public TestWriteWorker(CircularBuffer cb) {
this._buffer = cb;
public CircularPointer(int pointer, int max) {
this.pointer = pointer;
this.max = max;
}
private char getRandomChar() {
return _alphabet.charAt(_random.nextInt(_alphabet.length()));
public int getAndIncrement() {
if (pointer == max)
pointer = 0;
int tmp = pointer;
pointer++;
return tmp;
}
public void run() {
while (!Thread.interrupted()) {
if (!_buffer.writeToCharBuffer(getRandomChar())) {
Thread.yield();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
return;
}
}
}
}
}
private static class TestReadWorker implements Runnable {
CircularBuffer _buffer;
public TestReadWorker(CircularBuffer cb) {
this._buffer = cb;
}
@Override
public void run() {
System.out.println("Printing Buffer:");
while (!Thread.interrupted()) {
Character c = _buffer.readOutChar();
if (c != null) {
System.out.print(c.charValue());
} else {
Thread.yield();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
System.out.println();
return;
}
}
}
}
}
public static void main(String[] args) throws InterruptedException {
int buffer_size = 1024;
// create circular buffer
CircularBuffer cb = new CircularBuffer(buffer_size);
// create threads that read and write the buffer.
Thread write_thread = new Thread(new TestWriteWorker(cb));
Thread read_thread = new Thread(new TestReadWorker(cb));
read_thread.start();
write_thread.start();
// wait some amount of time
Thread.sleep(10000);
// interrupt threads and exit
write_thread.interrupt();
read_thread.interrupt();
}
}