package com.colloquial.arithcode; /** <P>Stores a queue of bytes in a buffer with a maximum size. New * bytes are added to the tail of the queue, and if the size exceeds * the maximum, bytes are removed from the front of the queue. Used * to model a sliding window of a fixed width over a stream of bytes * presented a byte at a time. The bytes in the current window are * accessed through an array of bytes, an offset and a length. * * <P>For instance, with a maximum length of 2, beginning with an * empty buffer and adding bytes 1, 2, 3, and 4 in that order leads to * queues <code>{1}</code>, <code>{1,2}</code>, <code>{2,3}</code> and * <code>{3,4}</code>. * * @author <a href="http://www.colloquial.com/carp/">Bob Carpenter</a> * @version 1.0 * @since 1.0 */ public final class ByteBuffer { /** Construct a context buffer of given maximum size. * @param maxWidth Maximum number of bytes in a context. */ public ByteBuffer(int maxWidth) { _maxWidth = maxWidth; _bytes = new byte[BUFFER_SIZE_MULTIPLIER * maxWidth]; } /** Current array of bytes backing this byte buffer. The returned * bytes are not a copy and should not be modified. * @return Array of bytes backing this buffer. */ public byte[] bytes() { return _bytes; } /** Current offset of this buffer into the byte array. * @return Offset of the buffer into the byte array. */ public int offset() { return _offset; } /** Current length of this buffer. * @return Length of this buffer. */ public int length() { return _length; } /** Add a byte to the end of the context, removing first element if * necessary. * @param b Byte to push onto the tail of the context. */ public void buffer(byte b) { if (nextFreeIndex() > maxIndex()) tampDown(); _bytes[nextFreeIndex()] = b; if (_length < _maxWidth) ++_length; else ++_offset; } /** Return a string representation of this context using * the current localization to convert bytes to characters. * @return String representation of this context. */ public String toString() { return new String(_bytes,_offset,_length); } /** Array of bytes used to buffer incoming bytes. */ final byte[] _bytes; /** Maximum number of bytes in queue before adding pushes one off. */ private final int _maxWidth; /** Offset of first byte of current context in buffer. */ int _offset = 0; /** Number of bytes in the context. Maximum will be given during construction. */ int _length = 0; /** Index in the buffer for next element. May point beyond the * maximum index if there is no more space. * @return Index for next element. */ private int nextFreeIndex() { return _offset+_length; } /** The maximum index in the buffer. * @param Index of last element in the buffer. */ private int maxIndex() { return _bytes.length-1; } /** Moves bytes in context down to start of buffer. */ private void tampDown() { for (int i = 0; i < _length-1; ++i) { _bytes[i] = _bytes[_offset+i+1]; } _offset = 0; } /** Number of contexts that fit in the buffer without shifting. */ private static final int BUFFER_SIZE_MULTIPLIER = 32; }