// ----------------------------------------------------------------------- // // // 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. // // // ----------------------------------------------------------------------- namespace Lucene.Net.Analysis.TokenAttributes { using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; using Support; using Util; /// /// The term text of a Token /// /// /// /// /// Java File: /// lucene/src/java/org/apache/lucene/analysis/tokenattributes/CharTermAttributeImpl.java /// /// /// /// C# File: /// src/Lucene.Net/Analysis/TokenAttributes/CharTermAttribute.cs /// /// /// /// C# Tests: /// test/Lucene.Net.Test/Analysis/TokenAttributes/CharTermAttributeTest.cs /// /// /// /// /// The java version has extra methods to work with Java's /// CharSequence. /// Java's version of string, StringBuilder, StringBuffer, and CharBuffer /// all implement this interface. C# does not have a known equivalent. /// /// [SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix", Justification = "The class was called Attribute in Java. It would be fun to call it Annotation. However, " + "its probably best to try to honor the correlating names when possible.")] public class CharTermAttribute : AttributeBase, ICharTermAttribute { private const int MinBufferSize = 10; private int termLength; private char[] buffer; /// /// Initializes a new instance of the class. /// public CharTermAttribute() { this.buffer = CreateBuffer(MinBufferSize); } /// /// Gets or sets the internal termBuffer character array which you can then /// directly alter. /// /// The buffer. /// /// /// You may cast this to a char[] rather than calling the ToArray() /// on . /// /// /// If the array is too small for the token, use /// to increase the size. After altering the buffer be sure to call /// to record the valid characters that /// were placed into the termBuffer. /// /// public IEnumerable Buffer { get { return this.buffer; } protected set { this.buffer = value.ToArray(); } } /// /// Gets or sets the number of valid characters, the length of the term, in /// the termBuffer array. /// /// /// /// /// Use this to truncate the termBuffer or to synchronize any external /// manipulation of the termBuffer. /// /// /// To grow the size of the array, use first. /// /// public int Length { get { return this.termLength; } set { this.SetLength(value); } } /// /// Appends the specified value. /// /// The value. /// /// An instance of for fluent interface /// chaining purposes. /// public ICharTermAttribute Append(char value) { int newLength = this.termLength + 1; this.ResizeBuffer(newLength); this.buffer[newLength] = value; return this; } /// /// Appends the specified to internal buffer or character sequence. /// /// The value. /// /// An instance of for fluent interface /// chaining purposes. /// public ICharTermAttribute Append(string value) { return Append(value, 0, value == null ? 0 : value.Length); } /// /// Appends the specified to internal buffer or character sequence. /// /// The value. /// the index of string to start the copy. /// The length of the string that is to be copied. /// /// An instance of for fluent interface /// chaining purposes. /// public ICharTermAttribute Append(string value, int startingIndex, int length) { if (value == null) return this.AppendNull(); value.CopyTo(startingIndex, this.InternalResizeBuffer(this.termLength + length), this.termLength, length); this.Length += length; return this; } /// /// Appends the specified . /// /// The value. /// /// An instance of for fluent interface /// chaining purposes. /// public ICharTermAttribute Append(StringBuilder value) { if (value == null) return this.AppendNull(); return this.Append(value.ToString()); } /// /// Appends the specified . /// /// The value. /// /// An instance of for fluent interface /// chaining purposes. /// public ICharTermAttribute Append(ICharTermAttribute value) { if (value == null) return this.AppendNull(); int length = value.Length; CharTermAttribute innerValue = value as CharTermAttribute; char[] array = (innerValue == null) ? value.Buffer.ToArray() : innerValue.buffer; Array.Copy(array, 0, this.InternalResizeBuffer(this.termLength + length), this.termLength, length); this.termLength += length; return this; } /// /// Returns the character at the specified index index. /// /// The position of the character. /// An instance of . /// /// Throws when the index is equal or greater than the current buffer length /// public char CharAt(int index) { if (index >= this.termLength) throw new ArgumentOutOfRangeException("index"); return this.buffer[index]; } /// /// Clears the instance. /// public override void Clear() { this.termLength = 0; } /// /// Creates a clone of the object, generally shallow. /// /// an the clone of the current instance. public override AttributeBase Clone() { CharTermAttribute clone = (CharTermAttribute)this.MemberwiseClone(); clone.Buffer = new char[this.termLength]; Array.Copy(this.buffer, 0, clone.buffer, 0, this.termLength); return clone; } /// /// Copies the contents of the buffer, starting at the offset to the specified length. /// /// The buffer to copy. /// The index of the first character to copy inside the buffer. /// The number of characters to copy. public void CopyBuffer(char[] buffer, int offset = 0, int length = -1) { if (length == -1) length = buffer.Length; this.GrowBuffer(length); Array.Copy(buffer, offset, this.buffer, 0, length); this.termLength = length; } /// /// Copies to. /// /// The attribute base. public override void CopyTo(AttributeBase attributeBase) { ICharTermAttribute attribute = (ICharTermAttribute)attributeBase; attribute.CopyBuffer(this.buffer, 0, this.termLength); } /// /// Sets the length of the internal buffer to zero. User this /// method before appending content using Append methods. /// /// /// An instance of for fluent interface /// chaining purposes. /// public ICharTermAttribute Empty() { this.termLength = 0; return this; } /// /// Determines whether the specified is equal to this instance. /// /// The to compare with this instance. /// /// true if the specified is equal to this instance; otherwise, false. /// public override bool Equals(object obj) { if (this == obj) return true; CharTermAttribute attribute = obj as CharTermAttribute; if (attribute == null) return false; if (this.termLength != attribute.termLength) return false; for (int i = 0; i < this.termLength; i++) { if (this.buffer[i] != attribute.buffer[i]) return false; } return true; } /// /// Returns a hash code for this instance. /// /// /// A hash code for this instance, suitable for use in /// hashing algorithms and data structures like a hash table. /// public override int GetHashCode() { int code = this.termLength; code = (code * 31) + this.buffer.CreateHashCode(); return code; } /// /// Resizes the length of the internal buffer to the new value and preserves the /// existing content. /// /// The length to re-buffer to. /// The array. public IEnumerable ResizeBuffer(int length) { return this.InternalResizeBuffer(length); } /// /// Gets or sets the number of valid characters, the length of the term, in /// the termBuffer array. /// /// The length. /// /// /// Use this to truncate the termBuffer or to synchronize any external /// manipulation of the termBuffer. /// /// /// To grow the size of the array, use first. /// /// /// /// An instance of for fluent interface /// chaining purposes. /// public ICharTermAttribute SetLength(int length) { if (length > this.buffer.Length) { string message = "The given length '{0}' needs to be less than current the internal buffer length '{1}'" .Inject(length, this.buffer.Length); throw new ArgumentOutOfRangeException("length", message); } this.termLength = length; return this; } /// /// Returns a that represents this instance. /// /// /// A that represents this instance. /// public override string ToString() { return new string(this.buffer).Substring(0, this.termLength); } private static char[] CreateBuffer(int length) { return new char[ArrayUtil.Oversize(length, RamUsageEstimator.NumberOfBytesChar)]; } private CharTermAttribute AppendNull() { this.ResizeBuffer(this.termLength + 4); this.buffer[this.termLength++] = 'n'; this.buffer[this.termLength++] = 'u'; this.buffer[this.termLength++] = 'l'; this.buffer[this.termLength++] = 'l'; return this; } private void GrowBuffer(int length) { if (this.buffer.Length < length) this.Buffer = CreateBuffer(length); } private char[] InternalResizeBuffer(int length) { if (this.buffer.Length < length) { char[] newBuffer = CreateBuffer(length); Array.Copy(this.buffer, 0, newBuffer, 0, this.buffer.Length); this.buffer = newBuffer; } return this.buffer; } } }