io.craft.atom.util.ByteArrayBuffer Maven / Gradle / Ivy
package io.craft.atom.util;
import java.io.Serializable;
import lombok.ToString;
/**
* A resizable byte array.
*
* NOTE: it's not thread safe.
*
* @author mindwind
* @version 1.0, 2011-10-26
*/
@ToString
public final class ByteArrayBuffer implements Serializable {
private static final long serialVersionUID = -5219299551050201309L;
private byte[] buffer;
private int len ;
// ~ -------------------------------------------------------------------------------------------------------------
/**
* Creates an instance of {@link ByteArrayBuffer} with default(2048) initial capacity.
*/
public ByteArrayBuffer() {
this(2048);
}
/**
* Creates an instance of {@link ByteArrayBuffer} with the given initial capacity.
*
* @param capacity
* the capacity
*/
public ByteArrayBuffer(int capacity) {
checkCapacity(capacity);
this.buffer = new byte[capacity];
}
/**
* Creates an instance of {@link ByteArrayBuffer} with the given byte array.
*
* @param bytes
*/
public ByteArrayBuffer(final byte[] bytes) {
super();
if (bytes == null) {
throw new NullPointerException("bytes is null");
}
this.buffer = bytes;
this.len = bytes.length;
}
// ~ -------------------------------------------------------------------------------------------------------------
private void checkCapacity(int capacity) {
if (capacity < 0) {
throw new IllegalArgumentException("Buffer capacity may not be negative");
}
}
/**
* Appends len
bytes to this buffer from the given source array starting at index off
.
* The capacity of the buffer is increased, if necessary, to accommodate all len
bytes.
*
* @param b
* the bytes to be appended.
* @param off
* the index of the first byte to append.
* @param len
* the number of bytes to append.
* @throws IndexOutOfBoundsException
* if off
if out of range, len
is negative, or off
+ len
is out of range.
* @return a reference to this object.
*/
public ByteArrayBuffer append(final byte[] b, int off, int len) {
if (b == null) {
return this;
}
if ((off | len | (b.length - off) | (off + len) | (b.length - off - len)) < 0) {
throw new IndexOutOfBoundsException("off: " + off + " len: " + len + " b.length: " + b.length);
}
if (len == 0) {
return this;
}
int newlen = this.len + len;
if (newlen > this.buffer.length) {
expand(newlen);
}
System.arraycopy(b, off, this.buffer, this.len, len);
this.len = newlen;
return this;
}
/**
* Appends b
byte to this buffer. The capacity of the buffer is increased, if necessary, to accommodate the additional byte.
*
* @param b
* the byte to be appended.
* @return a reference to this object.
*/
public ByteArrayBuffer append(byte b) {
int newlen = this.len + 1;
if (newlen > this.buffer.length) {
expand(newlen);
}
this.buffer[this.len] = b;
this.len = newlen;
return this;
}
/**
* Appends b
byte to this buffer. The capacity of the buffer is increased, if necessary, to accommodate the additional byte.
*
* @param b
* the byte to be appended.
* @return a reference to this object.
*/
public ByteArrayBuffer append(final byte[] b) {
if (b == null) {
return this;
}
return append(b, 0, b.length);
}
/**
* Clears content of the buffer. The underlying byte array is not resized.
*/
public void clear() {
this.len = 0;
}
/**
* Reset buffer with new capacity
*
* @param capacity
*/
public void reset(int capacity) {
checkCapacity(capacity);
clear();
this.buffer = new byte[capacity];
}
/**
* Return an new array of bytes from the buffer.
*
* @return byte array
*/
public byte[] array() {
return array0(0, this.len);
}
/**
* Return an new sub array of bytes from the buffer, with the boundary from start to end, if start==end return a zero byte array.
*
* @param start The beginning index, inclusive
* @param end The ending index, exclusive.
* @return byte array
*/
public byte[] array(int start, int end) {
if (start < 0 || end < 0 || start > end || end > length()) {
throw new IllegalArgumentException("start=" + start + ", end=" + end + ", len=" + length());
}
int len = end - start;
if (len == 0) {
return new byte[0];
}
return array0(start, len);
}
private byte[] array0(int start, int len) {
if (start < 0 || len < 0 || start + len > length()) {
throw new IllegalArgumentException("start=" + start + ", len=" + len);
}
byte[] b = new byte[len];
System.arraycopy(this.buffer, start, b, 0, len);
return b;
}
/**
* Returns the byte
value in this buffer at the specified index.
* The index argument must be greater than or equal to 0
, and less than the length of this buffer.
*
* @param i the index of the desired byte value.
* @return the byte value at the specified index.
* @throws IndexOutOfBoundsException if index
is negative or greater than or equal to {@link #length()}.
*/
public byte byteAt(int i) {
return this.buffer[i];
}
/**
* Returns the current capacity. The capacity is the amount of storage available for newly appended bytes,
* beyond which an allocation will occur.
*
* @return the current capacity
*/
public int capacity() {
return this.buffer.length;
}
/**
* Returns the length of the buffer (byte count).
*
* @return the length of the buffer
*/
public int length() {
return this.len;
}
/**
* Returns reference to the underlying byte array.
*
* @return the byte array.
*/
public byte[] buffer() {
return this.buffer;
}
/**
* Returns true
if this buffer is empty, that is, its {@link #length()} is equal to 0
.
*
* @return true
if this buffer is empty, false
otherwise.
*/
public boolean isEmpty() {
return this.len == 0;
}
/**
* Returns true
if this buffer is full, that is, its {@link #length()} is equal to its {@link #capacity()}.
*
* @return true
if this buffer is full, false
otherwise.
*/
public boolean isFull() {
return this.len == this.buffer.length;
}
/**
* Returns the first occurence position of the specified byte in backing byte array
*
* @param b
* @return if occurs, return the index of the first byte; if it does not occur, -1
is returned.
*/
public int indexOf(byte b) {
return ByteUtil.indexOf(this.buffer, b);
}
/**
* Returns the index within this buffer of the first occurrence of the specified byte, starting the search at the specified
* beginIndex
and finishing at endIndex
. If no such byte occurs in this buffer within the specified bounds,
* -1
is returned.
*
* There is no restriction on the value of beginIndex
and endIndex
.
* If beginIndex
is negative, it has the same effect as if it were zero.
* If endIndex
is greater than {@link #length()}, it has the same effect as if it were {@link #length()}.
* If the beginIndex
is greater than the endIndex
, -1
is returned.
*
* @param b the byte to search for.
* @param beginIndex the index to start the search from, inclusive
* @param endIndex the index to finish the search at, exclusive
* @return the index of the first occurrence of the byte in the buffer within the given bounds, or -1
if the bytes does not occur.
*
*/
public int indexOf(byte b, int beginIndex, int endIndex) {
if (beginIndex < 0) {
beginIndex = 0;
}
if (endIndex > this.len) {
endIndex = this.len;
}
if (beginIndex >= endIndex) {
return -1;
}
for (int i = beginIndex; i < endIndex; i++) {
if (this.buffer[i] == b) {
return i;
}
}
return -1;
}
/**
* Returns the first occurrence position of the specified bytes in backing byte array
*
* @param bytes
* @return if occurs, return the index of the first byte; if it does not occur, -1
is returned.
*/
public int indexOf(byte[] bytes) {
return ByteUtil.indexOf(this.buffer, bytes);
}
/**
* Returns the index within this buffer of the first occurrence of the specified bytes, starting the search at the specified
* beginIndex
and finishing buffer end. If no such byte occurs in this buffer within the specified bounds, -1
is returned.
*
* There is no restriction on the value of beginIndex
.
* If beginIndex
is negative, it has the same effect as if it were zero.
*
* @param bytes the bytes to search for.
* @param beginIndex the index to start the search from, inclusive.
* @return the index of the first occurrence of the byte in the buffer within the given bounds, or -1
if the byte does not occur.
*/
public int indexOf(byte[] bytes, int beginIndex) {
if(bytes == null || beginIndex >= length()) {
return -1;
}
if (beginIndex < 0) {
beginIndex = 0;
}
return ByteUtil.indexOf(this.buffer, bytes, beginIndex, length());
}
/**
* Returns the index within this buffer of the first occurrence of the specified bytes, starting the search at the specified
* beginIndex
and finishing at endIndex
. If no such byte occurs in this buffer within the specified bounds,
* -1
is returned.
*
* There is no restriction on the value of beginIndex
and endIndex
.
* If beginIndex
is negative, it has the same effect as if it were zero.
* If endIndex
is greater than {@link #length()}, it has the same effect as if it were {@link #length()}.
* If the beginIndex
is greater than the endIndex
, -1
is returned.
*
* @param bytes the bytes to search for.
* @param beginIndex the index to start the search from, inclusive
* @param endIndex the index to finish the search at, exclusive
* @return the index of the first occurrence of the byte in the buffer within the given bounds, or -1
if the byte does not occur.
*
*/
public int indexOf(byte[] bytes, int beginIndex, int endIndex) {
if(bytes == null || beginIndex >= endIndex) {
return -1;
}
if (beginIndex < 0) {
beginIndex = 0;
}
if (endIndex > length()) {
endIndex = length();
}
return ByteUtil.indexOf(this.buffer, bytes, beginIndex, endIndex);
}
private void expand(int newlen) {
byte newbuffer[] = new byte[Math.max(this.buffer.length << 1, newlen)];
System.arraycopy(this.buffer, 0, newbuffer, 0, this.len);
this.buffer = newbuffer;
}
}