I needed a simple way to run tests on the last n bytes of data received from a socket, and a ring buffer seemed to be the most efficient way to handle it. This is a very basic buffer that stores integers and has an accessible snapshot of its contents as a String
for quick analysis.
public class RingBuffer{ private final int size; private int[] buffer; private volatile int index = 0; public RingBuffer(int size){ this.size = size; this.buffer = new int[size]; } public int feed(int input){ int old = buffer[index]; buffer[index] = input; int nextIndex = index + 1; index = nextIndex % size; return old; } public String toString(){ StringBuilder sb = new StringBuilder(); for(int i=0;i<size;i++) sb.append((char)buffer[(index + i) % size]); return sb.toString(); } }
I’m not worried about limited features or thread safety, since this is being used by an InputStream
wrapper. I’m more concerned about possible consistency issues or any other basic oversight that would keep the result from being consistent, i.e. that the data going out isn’t the same as the data going in.
My use case, for context: trim a Windows newline and period, if present, from the end of the stream.
class GopherInputStream extends InputStream{ private static final int BUFFER_SIZE = 5; private final Pattern TRIM_PATTERN = Pattern.compile(".*\r\n\.(\r\n)?"); private final InputStream is; private final RingBuffer buffer = new RingBuffer(BUFFER_SIZE); private volatile boolean started = false, ended = false; GopherInputStream(InputStream is){ this.is = is; } @Override public int read() throws IOException{ if(!started){ preload(); started = true; } if(ended) return -1; int read = is.read(); if(read == -1){ if(TRIM_PATTERN.matcher(buffer.toString()).matches()){ ended = true; return -1; } } int buffered = buffer.feed(read); if(buffered == -1) ended = true; return buffered; } private void preload() throws IOException{ int i=0, read; while(i++<BUFFER_SIZE && (read = is.read()) != -1) buffer.feed(read); while(i++<BUFFER_SIZE) buffer.feed(-1); } }