package com.snowcattle.game.common.util;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import java.nio.charset.CodingErrorAction;
import java.util.ArrayList;
import java.util.List;
/**
*
* 简单的用于连接字符串操作的对象,相对于StringBuilder有以下改进:
* <ul>
* <li>
* append方法,延迟组装结果(在调用{@link #end()}
* 的时候才进行内存拷贝操作),避免使用StringBuilder时如果字符串较长时造成的较多的重复内存拷贝</li>
* <li>
* getBytes方法,直接对value进行编码,避免String.getBytes的内存拷贝操作</li>
* </ul>
* 该类适用于将字符串作为网络数据包发送的场合(即只需要得到byte[]数据,而不需要连接完成后的String对象),同时每次append时字符串较长
*
*
*
*/
public class ConactString {
private List<String> buffers;
private int length;
private char[] value;
private String valueStr;
private boolean isEnd = false;
public ConactString() {
buffers = new ArrayList<String>();
}
public ConactString(int capacity) {
buffers = new ArrayList<String>(capacity);
}
public ConactString append(String str) {
if (str == null) {
return this;
}
this.buffers.add(str);
length += str.length();
return this;
}
public ByteBuffer getBytes(String charsetName) {
if (!isEnd) {
throw new IllegalStateException("The conact has not been end.");
}
final CharsetEncoder encoder = Charset.forName(charsetName).newEncoder().onMalformedInput(
CodingErrorAction.REPLACE).onUnmappableCharacter(CodingErrorAction.REPLACE);
final CharBuffer cb = CharBuffer.wrap(this.value, 0, this.value.length);
try {
encoder.reset();
final int len = (int) (this.length * (double) encoder.maxBytesPerChar());
final ByteBuffer bb = ByteBuffer.allocate(len);
CoderResult cr = encoder.encode(cb, bb, true);
if (!cr.isUnderflow())
cr.throwException();
cr = encoder.flush(bb);
if (!cr.isUnderflow())
cr.throwException();
return bb;
} catch (Exception x) {
throw new Error(x);
}
}
public int length() {
return this.length;
}
public void end() {
value = new char[this.length];
int _dest = 0;
final int _size = this.buffers.size();
for (int i = 0; i < _size; i++) {
final String _str = this.buffers.get(i);
final int _len = _str.length();
_str.getChars(0, _len, value, _dest);
_dest = _dest + _len;
}
isEnd = true;
this.buffers = null;
}
public String toString() {
if (valueStr == null) {
valueStr = new String(value);
}
return valueStr;
}
}