--- /dev/null
+package org.apache.lucene.analysis.tokenattributes;
+
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.io.Serializable;
+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.RamUsageEstimator;
+
+/**
+ * The term text of a Token.
+ */
+public class CharTermAttributeImpl extends AttributeImpl implements CharTermAttribute, TermAttribute, Cloneable, Serializable {
+ private static int MIN_BUFFER_SIZE = 10;
+
+ private char[] termBuffer = new char[ArrayUtil.oversize(MIN_BUFFER_SIZE, RamUsageEstimator.NUM_BYTES_CHAR)];
+ private int termLength = 0;
+
+ @Deprecated
+ public String term() {
+ // don't delegate to toString() here!
+ return new String(termBuffer, 0, termLength);
+ }
+
+ public final void copyBuffer(char[] buffer, int offset, int length) {
+ growTermBuffer(length);
+ System.arraycopy(buffer, offset, termBuffer, 0, length);
+ termLength = length;
+ }
+
+ @Deprecated
+ public void setTermBuffer(char[] buffer, int offset, int length) {
+ copyBuffer(buffer, offset, length);
+ }
+
+ @Deprecated
+ public void setTermBuffer(String buffer) {
+ int length = buffer.length();
+ growTermBuffer(length);
+ buffer.getChars(0, length, termBuffer, 0);
+ termLength = length;
+ }
+
+ @Deprecated
+ public void setTermBuffer(String buffer, int offset, int length) {
+ assert offset <= buffer.length();
+ assert offset + length <= buffer.length();
+ growTermBuffer(length);
+ buffer.getChars(offset, offset + length, termBuffer, 0);
+ termLength = length;
+ }
+
+ public final char[] buffer() {
+ return termBuffer;
+ }
+
+ @Deprecated
+ public char[] termBuffer() {
+ return termBuffer;
+ }
+
+ public final char[] resizeBuffer(int newSize) {
+ if(termBuffer.length < newSize){
+ // Not big enough; create a new array with slight
+ // over allocation and preserve content
+ final char[] newCharBuffer = new char[ArrayUtil.oversize(newSize, RamUsageEstimator.NUM_BYTES_CHAR)];
+ System.arraycopy(termBuffer, 0, newCharBuffer, 0, termBuffer.length);
+ termBuffer = newCharBuffer;
+ }
+ return termBuffer;
+ }
+
+ @Deprecated
+ public char[] resizeTermBuffer(int newSize) {
+ return resizeBuffer(newSize);
+ }
+
+ private void growTermBuffer(int newSize) {
+ if(termBuffer.length < newSize){
+ // Not big enough; create a new array with slight
+ // over allocation:
+ termBuffer = new char[ArrayUtil.oversize(newSize, RamUsageEstimator.NUM_BYTES_CHAR)];
+ }
+ }
+
+ @Deprecated
+ public int termLength() {
+ return termLength;
+ }
+
+ public final CharTermAttribute setLength(int length) {
+ if (length > termBuffer.length)
+ throw new IllegalArgumentException("length " + length + " exceeds the size of the termBuffer (" + termBuffer.length + ")");
+ termLength = length;
+ return this;
+ }
+
+ public final CharTermAttribute setEmpty() {
+ termLength = 0;
+ return this;
+ }
+
+ @Deprecated
+ public void setTermLength(int length) {
+ setLength(length);
+ }
+
+ // *** CharSequence interface ***
+ public final int length() {
+ return termLength;
+ }
+
+ public final char charAt(int index) {
+ if (index >= termLength)
+ throw new IndexOutOfBoundsException();
+ return termBuffer[index];
+ }
+
+ public final CharSequence subSequence(final int start, final int end) {
+ if (start > termLength || end > termLength)
+ throw new IndexOutOfBoundsException();
+ return new String(termBuffer, start, end - start);
+ }
+
+ // *** Appendable interface ***
+
+ public final CharTermAttribute append(CharSequence csq) {
+ if (csq == null) // needed for Appendable compliance
+ return appendNull();
+ return append(csq, 0, csq.length());
+ }
+
+ public final CharTermAttribute append(CharSequence csq, int start, int end) {
+ if (csq == null) // needed for Appendable compliance
+ csq = "null";
+ final int len = end - start, csqlen = csq.length();
+ if (len < 0 || start > csqlen || end > csqlen)
+ throw new IndexOutOfBoundsException();
+ if (len == 0)
+ return this;
+ resizeBuffer(termLength + len);
+ if (len > 4) { // only use instanceof check series for longer CSQs, else simply iterate
+ 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++);
+ // no fall-through here, as termLength is updated!
+ return this;
+ }
+ termLength += len;
+ return this;
+ } else {
+ while (start < end)
+ termBuffer[termLength++] = csq.charAt(start++);
+ return this;
+ }
+ }
+
+ public final CharTermAttribute append(char c) {
+ resizeBuffer(termLength + 1)[termLength++] = c;
+ return this;
+ }
+
+ // *** For performance some convenience methods in addition to CSQ's ***
+
+ public final CharTermAttribute append(String s) {
+ if (s == null) // needed for Appendable compliance
+ return appendNull();
+ final int len = s.length();
+ s.getChars(0, len, resizeBuffer(termLength + len), termLength);
+ termLength += len;
+ return this;
+ }
+
+ public final CharTermAttribute append(StringBuilder s) {
+ if (s == null) // needed for Appendable compliance
+ return appendNull();
+ final int len = s.length();
+ s.getChars(0, len, resizeBuffer(termLength + len), termLength);
+ termLength += len;
+ return this;
+ }
+
+ public final CharTermAttribute append(CharTermAttribute ta) {
+ if (ta == null) // needed for Appendable compliance
+ 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;
+ }
+
+ // *** AttributeImpl ***
+
+ @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 Object clone() {
+ CharTermAttributeImpl t = (CharTermAttributeImpl)super.clone();
+ // Do a deep clone
+ t.termBuffer = new char[this.termLength];
+ System.arraycopy(this.termBuffer, 0, t.termBuffer, 0, this.termLength);
+ 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;
+ }
+
+ /**
+ * Returns solely the term text as specified by the
+ * {@link CharSequence} interface.
+ * <p>This method changed the behavior with Lucene 3.1,
+ * before it returned a String representation of the whole
+ * term with all attributes.
+ * This affects especially the
+ * {@link org.apache.lucene.analysis.Token} subclass.
+ */
+ @Override
+ public String toString() {
+ // CharSequence requires that only the contents are returned, but this is orginal code: "term=" + new String(termBuffer, 0, termLength)
+ return new String(termBuffer, 0, termLength);
+ }
+
+ @Override
+ public void reflectWith(AttributeReflector reflector) {
+ reflector.reflect(CharTermAttribute.class, "term", toString());
+ }
+
+ @Override
+ public void copyTo(AttributeImpl target) {
+ if (target instanceof CharTermAttribute) {
+ CharTermAttribute t = (CharTermAttribute) target;
+ t.copyBuffer(termBuffer, 0, termLength);
+ } else {
+ TermAttribute t = (TermAttribute) target;
+ t.setTermBuffer(termBuffer, 0, termLength);
+ }
+ }
+
+}