package jane.core;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
/**
* 用于存储可扩展字节序列的类型
* <p>
* 一个Octets及其子类的实例不能同时由多个线程同时访问
* @formatter:off
*/
public class Octets implements Cloneable, Comparable<Octets>
{
private static final char[] HEX = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
public static final byte[] EMPTY = new byte[0]; // 共享的空缓冲区
public static final int DEFAULT_SIZE = 16; // 默认的缓冲区
private static Charset _defaultCharset = Const.stringCharset; // 本类的默认字符集
protected byte[] _buffer = EMPTY; // 数据缓冲区. 注意此变量名字和类型的改变要和leveldb中的jni.cc对应
protected int _count; // 当前有效的数据缓冲区大小. 注意此变量名字和类型的改变要和leveldb中的jni.cc对应
public static void setDefaultEncoding(Charset charset)
{
_defaultCharset = (charset != null ? charset : Const.stringCharset);
}
public static Octets wrap(byte[] data, int size)
{
Octets o = new Octets();
o._buffer = data;
if(size > data.length) o._count = data.length;
else if(size < 0) o._count = 0;
else o._count = size;
return o;
}
public static Octets wrap(byte[] data)
{
if(data == null) throw new NullPointerException();
Octets o = new Octets();
o._buffer = data;
o._count = data.length;
return o;
}
public static Octets wrap(String str)
{
return wrap(str.getBytes(_defaultCharset));
}
public static Octets wrap(String str, Charset charset)
{
return wrap(str.getBytes(charset));
}
public static Octets wrap(String str, String encoding) throws UnsupportedEncodingException
{
return wrap(str.getBytes(encoding));
}
public static Octets createSpace(int size)
{
Octets o = new Octets();
if(size > 0)
{
o._buffer = new byte[size];
o._count = size;
}
return o;
}
public Octets()
{
}
public Octets(int size)
{
reserveSpace(size);
}
public Octets(Octets o)
{
replace(o);
}
public Octets(byte[] data)
{
replace(data);
}
public Octets(byte[] data, int pos, int size)
{
replace(data, pos, size);
}
public byte[] array()
{
return _buffer;
}
public boolean empty()
{
return _count <= 0;
}
public int size()
{
return _count;
}
public int capacity()
{
return _buffer.length;
}
@SuppressWarnings("static-method")
public int position()
{
return 0;
}
public int remain()
{
return _count;
}
public byte getByte(int p)
{
return _buffer[p];
}
public void setByte(int p, byte b)
{
_buffer[p] = b;
}
public void clear()
{
_count = 0;
}
public void reset()
{
_buffer = EMPTY;
_count = 0;
}
public byte[] getBytes()
{
int n = _count;
if(n <= 0) return EMPTY;
byte[] buf = new byte[n];
System.arraycopy(_buffer, 0, buf, 0, n);
return buf;
}
public byte[] getBytes(int pos, int len)
{
if(pos < 0) pos = 0;
if(pos >= _count || len <= 0) return EMPTY;
int n = pos + len;
n = (n < 0 || n > _count ? _count - pos : len);
byte[] buf = new byte[n];
System.arraycopy(_buffer, pos, buf, 0, n);
return buf;
}
public Octets wraps(byte[] data, int size)
{
_buffer = data;
if(size > data.length) _count = data.length;
else if(size < 0) _count = 0;
else _count = size;
return this;
}
public Octets wraps(byte[] data)
{
_buffer = data;
_count = data.length;
return this;
}
/**
* @param size 期望缩小的空间. 如果比当前数据小,则缩小的当前数据大小
*/
public void shrink(int size)
{
int n = _count;
if(n <= 0)
{
reset();
return;
}
if(size < n) size = n;
byte[] buffer = _buffer;
if(size >= buffer.length) return;
byte[] buf = new byte[size];
System.arraycopy(buffer, 0, buf, 0, n);
_buffer = buf;
}
public void shrink()
{
shrink(0);
}
public void reserve(int size)
{
byte[] buffer = _buffer;
if(size > buffer.length)
{
int cap = DEFAULT_SIZE;
while(size > cap) cap <<= 1;
byte[] buf = new byte[cap];
int n = _count;
if(n > 0) System.arraycopy(buffer, 0, buf, 0, n);
_buffer = buf;
}
}
/**
* 类似reserve, 但不保证原数据的有效
*/
public final void reserveSpace(int size)
{
if(size > _buffer.length)
{
int cap = DEFAULT_SIZE;
while(size > cap) cap <<= 1;
_buffer = new byte[cap];
}
}
public void resize(int size)
{
if(size < 0) size = 0;
else reserve(size);
_count = size;
}
public final void replace(byte[] data, int pos, int size)
{
if(size <= 0) { _count = 0; return; }
int len = data.length;
if(pos < 0) pos = 0;
if(pos >= len) { _count = 0; return; }
len -= pos;
if(size > len) size = len;
reserveSpace(size);
System.arraycopy(data, pos, _buffer, 0, size);
_count = size;
}
public final void replace(byte[] data)
{
replace(data, 0, data.length);
}
public final void replace(Octets o)
{
replace(o._buffer, 0, o._count);
}
public void swap(Octets o)
{
int size = _count; _count = o._count; o._count = size;
byte[] buf = o._buffer; o._buffer = _buffer; _buffer = buf;
}
public Octets append(byte b)
{
int n = _count;
int nNew = n + 1;
reserve(nNew);
_buffer[n] = b;
_count = nNew;
return this;
}
public Octets append(byte[] data, int pos, int size)
{
if(size <= 0) return this;
int len = data.length;
if(pos < 0) pos = 0;
if(pos >= len) return this;
len -= pos;
if(size > len) size = len;
int n = _count;
reserve(n + size);
System.arraycopy(data, pos, _buffer, n, size);
_count = n + size;
return this;
}
public Octets append(byte[] data)
{
return append(data, 0, data.length);
}
public Octets append(Octets o)
{
return append(o._buffer, 0, o._count);
}
public Octets insert(int from, byte[] data, int pos, int size)
{
int n = _count;
if(from < 0) from = 0;
if(from >= n) return append(data, pos, size);
if(size <= 0) return this;
int len = data.length;
if(pos < 0) pos = 0;
if(pos >= len) return this;
len -= pos;
if(size > len) size = len;
reserve(n + size);
byte[] buf = _buffer;
System.arraycopy(buf, from, buf, from + size, n - from);
System.arraycopy(data, pos, buf, from, size);
_count = n + size;
return this;
}
public Octets insert(int from, byte[] data)
{
return insert(from, data, 0, data.length);
}
public Octets insert(int from, Octets o)
{
return insert(from, o._buffer, 0, o._count);
}
public Octets erase(int from, int to)
{
int n = _count;
if(from < 0) from = 0;
if(from >= n || from >= to) return this;
if(to >= n) _count = from;
else
{
n -= to;
System.arraycopy(_buffer, to, _buffer, from, n);
_count = n + from;
}
return this;
}
public Octets eraseFront(int size)
{
int n = _count;
if(size >= n) _count = 0;
else if(size > 0)
{
n -= size;
System.arraycopy(_buffer, size, _buffer, 0, n);
_count = n;
}
return this;
}
public int find(int pos, int end, byte b)
{
if(pos < 0) pos = 0;
int n = _count;
if(end > n) end = n;
byte[] buf = _buffer;
for(; pos < end; ++pos)
if(buf[pos] == b) return pos;
return -1;
}
public int find(int pos, byte b)
{
return find(pos, _count, b);
}
public int find(byte b)
{
return find(0, _count, b);
}
public int find(int pos, int end, byte[] b, int p, int s)
{
if(p < 0) p = 0;
if(p + s > b.length) s = b.length - p;
if(s <= 0) return 0;
if(pos < 0) pos = 0;
int e = _count - s + 1;
if(end > e) end = e;
byte[] buf = _buffer;
byte c = b[0];
for(; pos < end; ++pos)
{
if(buf[pos] == c)
{
for(int n = 1;; ++n)
{
if(n == s) return pos;
if(buf[pos + n] != b[n]) break;
}
}
}
return -1;
}
public int find(int pos, byte[] b, int p, int s)
{
return find(pos, _count, b, p, s);
}
public int find(byte[] b, int p, int s)
{
return find(0, _count, b, p, s);
}
public int find(int pos, int end, byte[] b)
{
return find(pos, end, b, 0, b.length);
}
public int find(int pos, byte[] b)
{
return find(pos, _count, b, 0, b.length);
}
public int find(byte[] b)
{
return find(0, _count, b, 0, b.length);
}
public void setString(String str)
{
byte[] buf;
_buffer = buf = str.getBytes(_defaultCharset);
_count = buf.length;
}
public void setString(String str, Charset charset)
{
byte[] buf;
_buffer = buf = str.getBytes(charset);
_count = buf.length;
}
public void setString(String str, String encoding) throws UnsupportedEncodingException
{
byte[] buf;
_buffer = buf = str.getBytes(encoding);
_count = buf.length;
}
public String getString()
{
return new String(_buffer, 0, _count, _defaultCharset);
}
public String getString(Charset charset)
{
return new String(_buffer, 0, _count, charset);
}
public String getString(String encoding) throws UnsupportedEncodingException
{
return new String(_buffer, 0, _count, encoding);
}
@Override
public Octets clone()
{
return new Octets(this);
}
@Override
public int hashCode()
{
byte[] buf = _buffer;
int n = _count;
int result = n;
if(n <= 32)
{
for(int i = 0; i < n; ++i)
result = 31 * result + buf[i];
}
else
{
for(int i = 0; i < 16; ++i)
result = 31 * result + buf[i];
for(int i = n - 16; i < n; ++i)
result = 31 * result + buf[i];
}
return result;
}
@Override
public int compareTo(Octets o)
{
if(o == null) return 1;
int n0 = _count, n1 = o._count;
int n = (n0 < n1 ? n0 : n1);
byte[] buf = _buffer;
byte[] data = o._buffer;
for(int i = 0; i < n; ++i)
{
int c = ((buf[i] & 0xff) - (data[i] & 0xff));
if(c != 0) return c;
}
return n0 - n1;
}
@Override
public boolean equals(Object o)
{
if(this == o) return true;
if(!(o instanceof Octets)) return false;
Octets oct = (Octets)o;
int n = _count;
if(n != oct._count) return false;
byte[] buf = _buffer;
byte[] data = oct._buffer;
for(int i = 0; i < n; ++i)
if(buf[i] != data[i]) return false;
return true;
}
public final boolean equals(Octets oct)
{
if(this == oct) return true;
if(oct == null) return false;
int n = _count;
if(n != oct._count) return false;
byte[] buf = _buffer;
byte[] data = oct._buffer;
for(int i = 0; i < n; ++i)
if(buf[i] != data[i]) return false;
return true;
}
@Override
public String toString()
{
return "[" + _count + '/' + _buffer.length + ']';
}
public static char toHexNumber(int v)
{
return HEX[v & 15];
}
public StringBuilder dump(StringBuilder s)
{
int n = _count;
if(s == null) s = new StringBuilder(n * 3 + 4);
s.append('[');
if(n <= 0) return s.append(']');
byte[] buf = _buffer;
for(int i = 0;;)
{
int b = buf[i];
s.append(HEX[(b >> 4) & 15]);
s.append(HEX[b & 15]);
if(++i >= n) return s.append(']');
s.append(' ');
}
}
public StringBuilder dump()
{
return dump(null);
}
public StringBuilder dumpJStr(StringBuilder s)
{
int n = _count;
if(s == null) s = new StringBuilder(n * 4 + 4);
s.append('"');
if(n <= 0) return s.append('"');
byte[] buf = _buffer;
for(int i = 0;;)
{
int b = buf[i];
s.append('\\').append('x');
s.append(HEX[(b >> 4) & 15]);
s.append(HEX[b & 15]);
if(++i >= n) return s.append('"');
}
}
public StringBuilder dumpJStr()
{
return dumpJStr(null);
}
}