org.apache.lucene.analysis.tokenattributes.CharTermAttributeImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.lucene.analysis.tokenattributes.CharTermAttributeImpl.java

Source

/*
 * 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.
 */
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;

/** Default implementation of {@link CharTermAttribute}. */
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;

    /** May be used by subclasses to convert to different charsets / encodings for implementing {@link #getBytesRef()}. */
    protected BytesRefBuilder builder = new BytesRefBuilder();

    /** Initialize this attribute with empty term text */
    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) {
            // Not big enough; create a new array with slight
            // over allocation and preserve content
            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) {
            // Not big enough; create a new array with slight
            // over allocation:
            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;
    }

    // *** TermToBytesRefAttribute interface ***

    @Override
    public BytesRef getBytesRef() {
        builder.copyChars(termBuffer, 0, termLength);
        return builder.get();
    }

    // *** CharSequence interface ***
    @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);
    }

    // *** Appendable interface ***

    @Override
    public final CharTermAttribute append(CharSequence csq) {
        if (csq == null) // needed for Appendable compliance
            return appendNull();
        return append(csq, 0, csq.length());
    }

    @Override
    public final CharTermAttribute append(CharSequence csq, int start, int end) {
        if (csq == null) // needed for Appendable compliance
            csq = "null";
        // TODO: the optimized cases (jdk methods) will already do such checks, maybe re-organize this?
        FutureObjects.checkFromToIndex(start, end, csq.length());
        final int len = end - start;
        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;
        }
    }

    @Override
    public final CharTermAttribute append(char c) {
        resizeBuffer(termLength + 1)[termLength++] = c;
        return this;
    }

    // *** For performance some convenience methods in addition to CSQ's ***

    @Override
    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;
    }

    @Override
    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;
    }

    @Override
    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 CharTermAttributeImpl 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);
        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;
    }

    /** 
     * Returns solely the term text as specified by the
     * {@link CharSequence} interface.
     */
    @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);
    }

}