package org.apache.lucene.analysis.tokenattributes;
import java.nio.CharBuffer;
import org.apache.lucene.util.ArrayUtil;
import org.apache.lucene.util.AttributeImpl;
import org.apache.lucene.util.AttributeReflector;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.BytesRefBuilder;
import org.apache.lucene.util.FutureObjects;
public class CharTermAttributeImpl extends AttributeImpl implements CharTermAttribute, TermToBytesRefAttribute, Cloneable {
private static int MIN_BUFFER_SIZE = 10;
private char[] termBuffer = new char[ArrayUtil.oversize(MIN_BUFFER_SIZE, Character.BYTES)];
private int termLength = 0;
protected BytesRefBuilder builder = new BytesRefBuilder();
public CharTermAttributeImpl() {}
@Override
public final void copyBuffer(char[] buffer, int offset, int length) {
growTermBuffer(length);
System.arraycopy(buffer, offset, termBuffer, 0, length);
termLength = length;
}
@Override
public final char[] buffer() {
return termBuffer;
}
@Override
public final char[] resizeBuffer(int newSize) {
if(termBuffer.length < newSize){
final char[] newCharBuffer = new char[ArrayUtil.oversize(newSize, Character.BYTES)];
System.arraycopy(termBuffer, 0, newCharBuffer, 0, termBuffer.length);
termBuffer = newCharBuffer;
}
return termBuffer;
}
private void growTermBuffer(int newSize) {
if(termBuffer.length < newSize){
termBuffer = new char[ArrayUtil.oversize(newSize, Character.BYTES)];
}
}
@Override
public final CharTermAttribute setLength(int length) {
FutureObjects.checkFromIndexSize(0, length, termBuffer.length);
termLength = length;
return this;
}
@Override
public final CharTermAttribute setEmpty() {
termLength = 0;
return this;
}
@Override
public BytesRef getBytesRef() {
builder.copyChars(termBuffer, 0, termLength);
return builder.get();
}
@Override
public final int length() {
return termLength;
}
@Override
public final char charAt(int index) {
FutureObjects.checkIndex(index, termLength);
return termBuffer[index];
}
@Override
public final CharSequence subSequence(final int start, final int end) {
FutureObjects.checkFromToIndex(start, end, termLength);
return new String(termBuffer, start, end - start);
}
@Override
public final CharTermAttribute append(CharSequence csq) {
if (csq == null)
return appendNull();
return append(csq, 0, csq.length());
}
@Override
public final CharTermAttribute append(CharSequence csq, int start, int end) {
if (csq == null)
csq = "null";
FutureObjects.checkFromToIndex(start, end, csq.length());
final int len = end - start;
if (len == 0)
return this;
resizeBuffer(termLength + len);
if (len > 4) {
if (csq instanceof String) {
((String) csq).getChars(start, end, termBuffer, termLength);
} else if (csq instanceof StringBuilder) {
((StringBuilder) csq).getChars(start, end, termBuffer, termLength);
} else if (csq instanceof CharTermAttribute) {
System.arraycopy(((CharTermAttribute) csq).buffer(), start, termBuffer, termLength, len);
} else if (csq instanceof CharBuffer && ((CharBuffer) csq).hasArray()) {
final CharBuffer cb = (CharBuffer) csq;
System.arraycopy(cb.array(), cb.arrayOffset() + cb.position() + start, termBuffer, termLength, len);
} else if (csq instanceof StringBuffer) {
((StringBuffer) csq).getChars(start, end, termBuffer, termLength);
} else {
while (start < end)
termBuffer[termLength++] = csq.charAt(start++);
return this;
}
termLength += len;
return this;
} else {
while (start < end)
termBuffer[termLength++] = csq.charAt(start++);
return this;
}
}
@Override
public final CharTermAttribute append(char c) {
resizeBuffer(termLength + 1)[termLength++] = c;
return this;
}
@Override
public final CharTermAttribute append(String s) {
if (s == null)
return appendNull();
final int len = s.length();
s.getChars(0, len, resizeBuffer(termLength + len), termLength);
termLength += len;
return this;
}
@Override
public final CharTermAttribute append(StringBuilder s) {
if (s == null)
return appendNull();
final int len = s.length();
s.getChars(0, len, resizeBuffer(termLength + len), termLength);
termLength += len;
return this;
}
@Override
public final CharTermAttribute append(CharTermAttribute ta) {
if (ta == null)
return appendNull();
final int len = ta.length();
System.arraycopy(ta.buffer(), 0, resizeBuffer(termLength + len), termLength, len);
termLength += len;
return this;
}
private CharTermAttribute appendNull() {
resizeBuffer(termLength + 4);
termBuffer[termLength++] = 'n';
termBuffer[termLength++] = 'u';
termBuffer[termLength++] = 'l';
termBuffer[termLength++] = 'l';
return this;
}
@Override
public int hashCode() {
int code = termLength;
code = code * 31 + ArrayUtil.hashCode(termBuffer, 0, termLength);
return code;
}
@Override
public void clear() {
termLength = 0;
}
@Override
public CharTermAttributeImpl clone() {
CharTermAttributeImpl t = (CharTermAttributeImpl)super.clone();
t.termBuffer = new char[this.termLength];
System.arraycopy(this.termBuffer, 0, t.termBuffer, 0, this.termLength);
t.builder = new BytesRefBuilder();
t.builder.copyBytes(builder.get());
return t;
}
@Override
public boolean equals(Object other) {
if (other == this) {
return true;
}
if (other instanceof CharTermAttributeImpl) {
final CharTermAttributeImpl o = ((CharTermAttributeImpl) other);
if (termLength != o.termLength)
return false;
for(int i=0;i<termLength;i++) {
if (termBuffer[i] != o.termBuffer[i]) {
return false;
}
}
return true;
}
return false;
}
@Override
public String toString() {
return new String(termBuffer, 0, termLength);
}
@Override
public void reflectWith(AttributeReflector reflector) {
reflector.reflect(CharTermAttribute.class, "term", toString());
reflector.reflect(TermToBytesRefAttribute.class, "bytes", getBytesRef());
}
@Override
public void copyTo(AttributeImpl target) {
CharTermAttribute t = (CharTermAttribute) target;
t.copyBuffer(termBuffer, 0, termLength);
}
}