package com.ericsson.tic.vi; /** * This is a buffer which stores char arrays. Buffer overflow leads to the * oldest data beeing overwritten. The buffer is synchronized for writing only. * Only one consumer is allowed. Consumer is assumed to read the full contents * of the buffer before making another call to swap. * * @author Sami Matilainen * @version 1.0 (2008-12-04) */ public class RawBuffer { /** The write side of the buffer. */ private char[][] writeSide; /** The read side of the buffer. */ private char[][] readSide; /** A temp. buffer used for swaps. */ private char[][] temp; /** The width of the buffer. */ private int width; /** The capacity/height of the buffer. Actual capacity is capacity-1 */ private int capacity; /** Pointer. */ private int readRear, writeRear, writeFront, readFront; /** Lock used for synchronizing the buffer while writing and swapping */ private Object lock = new Object(); /** * Creates a new double-sided, circular, buffer. * Buffer overflow leads to the oldest data beeing overwritten. * * @param width The width of the buffer. * @param capacity Capacity of the buffer. */ public RawBuffer(int width, int capacity) { this.width = width; this.capacity = capacity; writeSide = new char[capacity][width]; readSide = new char[capacity][width]; temp = new char[capacity][width]; readRear = 0; writeRear = 0; readFront = 0; writeFront = 0; } /** * Get the width of this buffer. * * @return The width of this buffer. */ public int getWidth() { return width; } /** * Swaps the buffer. */ public void swap() { synchronized(lock) { temp = readSide; readSide = writeSide; writeSide = temp; readRear = writeRear; readFront = writeFront; writeRear = 0; writeFront = 0; } } /** * Fetches a line of text from the read side of the buffer. * * @return A line from the buffer. * @throws If the buffer is empty. */ public char[] fetch() throws Exception { char[] ret = new char[width]; if (empty()) { throw new Exception("EmptyBuffer"); } else { int i = 0; while(readSide[readRear][i] != '\u0000') { ret[i] = readSide[readRear][i]; i++; } readRear = (readRear + 1) % capacity; } return ret; } /** * Determine wheter the buffer is empty or not. * * @return True if and only if the read side of the buffer is empty. */ public boolean empty() { return (readFront == readRear); } /** * Deposits a line of text into the buffer on the write side. * * @param line The line of text to be deposited. */ public void deposit(char[] line) { synchronized(lock) { for(int i = 0; i < line.length && i < width; i++) { writeSide[writeFront][i] = line[i]; } if (line.length < (width-1)) { writeSide[writeFront][line.length] = '\u0000'; } else { writeSide[writeFront][width-1] = '\u0000'; } writeFront = (writeFront + 1) % capacity; if (writeFront == writeRear) { writeRear = (writeRear + 1) % capacity; } } } /** * Deposits a line of text into the buffer on the write side. * This version is optimized to read only relevant chars. * * @param line The line of text to be deposited. * @param dataLength The amount of characters to be read */ public void deposit(char[] line, int dataLength) { synchronized(lock) { for(int i = 0; i < dataLength && i < width; i++) { writeSide[writeFront][i] = line[i]; } if (dataLength < (width-1)) { writeSide[writeFront][dataLength] = '\u0000'; } else { writeSide[writeFront][width-1] = '\u0000'; } writeFront = (writeFront + 1) % capacity; if (writeFront == writeRear) { writeRear = (writeRear + 1) % capacity; } } } }