| using J2N.Text; |
| using Lucene.Net.Analysis.TokenAttributes; |
| using System; |
| using System.Reflection; |
| using Attribute = Lucene.Net.Util.Attribute; |
| using AttributeSource = Lucene.Net.Util.AttributeSource; |
| using BytesRef = Lucene.Net.Util.BytesRef; |
| using IAttribute = Lucene.Net.Util.IAttribute; |
| |
| namespace Lucene.Net.Analysis |
| { |
| /* |
| * 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. |
| */ |
| |
| using CharTermAttribute = Lucene.Net.Analysis.TokenAttributes.CharTermAttribute; |
| using IAttributeReflector = Lucene.Net.Util.IAttributeReflector; |
| |
| /// <summary> |
| /// A <see cref="Token"/> is an occurrence of a term from the text of a field. It consists of |
| /// a term's text, the start and end offset of the term in the text of the field, |
| /// and a type string. |
| /// <para/> |
| /// The start and end offsets permit applications to re-associate a token with |
| /// its source text, e.g., to display highlighted query terms in a document |
| /// browser, or to show matching text fragments in a KWIC (KeyWord In Context) |
| /// display, etc. |
| /// <para/> |
| /// The type is a string, assigned by a lexical analyzer |
| /// (a.k.a. tokenizer), naming the lexical or syntactic class that the token |
| /// belongs to. For example an end of sentence marker token might be implemented |
| /// with type "eos". The default token type is "word". |
| /// <para/> |
| /// A Token can optionally have metadata (a.k.a. payload) in the form of a variable |
| /// length byte array. Use <see cref="Index.DocsAndPositionsEnum.GetPayload()"/> to retrieve the |
| /// payloads from the index. |
| /// |
| /// <para/><para/> |
| /// |
| /// <para/><b>NOTE:</b> As of 2.9, Token implements all <see cref="IAttribute"/> interfaces |
| /// that are part of core Lucene and can be found in the <see cref="TokenAttributes"/> namespace. |
| /// Even though it is not necessary to use <see cref="Token"/> anymore, with the new <see cref="TokenStream"/> API it can |
| /// be used as convenience class that implements all <see cref="IAttribute"/>s, which is especially useful |
| /// to easily switch from the old to the new <see cref="TokenStream"/> API. |
| /// |
| /// <para/><para/> |
| /// |
| /// <para><see cref="Tokenizer"/>s and <see cref="TokenFilter"/>s should try to re-use a <see cref="Token"/> |
| /// instance when possible for best performance, by |
| /// implementing the <see cref="TokenStream.IncrementToken()"/> API. |
| /// Failing that, to create a new <see cref="Token"/> you should first use |
| /// one of the constructors that starts with null text. To load |
| /// the token from a char[] use <see cref="ICharTermAttribute.CopyBuffer(char[], int, int)"/>. |
| /// To load from a <see cref="string"/> use <see cref="ICharTermAttribute.SetEmpty()"/> followed by |
| /// <see cref="ICharTermAttribute.Append(string)"/> or <see cref="ICharTermAttribute.Append(string, int, int)"/>. |
| /// Alternatively you can get the <see cref="Token"/>'s termBuffer by calling either <see cref="ICharTermAttribute.Buffer"/>, |
| /// if you know that your text is shorter than the capacity of the termBuffer |
| /// or <see cref="ICharTermAttribute.ResizeBuffer(int)"/>, if there is any possibility |
| /// that you may need to grow the buffer. Fill in the characters of your term into this |
| /// buffer, with <see cref="string.ToCharArray(int, int)"/> if loading from a string, |
| /// or with <see cref="System.Array.Copy(System.Array, int, System.Array, int, int)"/>, |
| /// and finally call <see cref="ICharTermAttribute.SetLength(int)"/> to |
| /// set the length of the term text. See <a target="_top" |
| /// href="https://issues.apache.org/jira/browse/LUCENE-969">LUCENE-969</a> |
| /// for details.</para> |
| /// <para>Typical Token reuse patterns: |
| /// <list type="bullet"> |
| /// <item><description> Copying text from a string (type is reset to <see cref="TypeAttribute.DEFAULT_TYPE"/> if not specified): |
| /// <code> |
| /// return reusableToken.Reinit(string, startOffset, endOffset[, type]); |
| /// </code> |
| /// </description></item> |
| /// <item><description> Copying some text from a string (type is reset to <see cref="TypeAttribute.DEFAULT_TYPE"/> if not specified): |
| /// <code> |
| /// return reusableToken.Reinit(string, 0, string.Length, startOffset, endOffset[, type]); |
| /// </code> |
| /// </description></item> |
| /// <item><description> Copying text from char[] buffer (type is reset to <see cref="TypeAttribute.DEFAULT_TYPE"/> if not specified): |
| /// <code> |
| /// return reusableToken.Reinit(buffer, 0, buffer.Length, startOffset, endOffset[, type]); |
| /// </code> |
| /// </description></item> |
| /// <item><description> Copying some text from a char[] buffer (type is reset to <see cref="TypeAttribute.DEFAULT_TYPE"/> if not specified): |
| /// <code> |
| /// return reusableToken.Reinit(buffer, start, end - start, startOffset, endOffset[, type]); |
| /// </code> |
| /// </description></item> |
| /// <item><description> Copying from one one <see cref="Token"/> to another (type is reset to <see cref="TypeAttribute.DEFAULT_TYPE"/> if not specified): |
| /// <code> |
| /// return reusableToken.Reinit(source.Buffer, 0, source.Length, source.StartOffset, source.EndOffset[, source.Type]); |
| /// </code> |
| /// </description></item> |
| /// </list> |
| /// A few things to note: |
| /// <list type="bullet"> |
| /// <item><description><see cref="Clear()"/> initializes all of the fields to default values. this was changed in contrast to Lucene 2.4, but should affect no one.</description></item> |
| /// <item><description>Because <see cref="TokenStream"/>s can be chained, one cannot assume that the <see cref="Token"/>'s current type is correct.</description></item> |
| /// <item><description>The startOffset and endOffset represent the start and offset in the source text, so be careful in adjusting them.</description></item> |
| /// <item><description>When caching a reusable token, clone it. When injecting a cached token into a stream that can be reset, clone it again.</description></item> |
| /// </list> |
| /// </para> |
| /// <para> |
| /// <b>Please note:</b> With Lucene 3.1, the <see cref="CharTermAttribute.ToString()"/> method had to be changed to match the |
| /// <see cref="ICharSequence"/> interface introduced by the interface <see cref="ICharTermAttribute"/>. |
| /// this method now only prints the term text, no additional information anymore. |
| /// </para> |
| /// </summary> |
| public class Token : CharTermAttribute, ITypeAttribute, IPositionIncrementAttribute, IFlagsAttribute, IOffsetAttribute, IPayloadAttribute, IPositionLengthAttribute |
| { |
| private int startOffset, endOffset; |
| private string type = TypeAttribute.DEFAULT_TYPE; |
| private int flags; |
| private BytesRef payload; |
| private int positionIncrement = 1; |
| private int positionLength = 1; |
| |
| /// <summary> |
| /// Constructs a <see cref="Token"/> will null text. </summary> |
| public Token() |
| { |
| string s = "fooobar"; |
| s.ToCharArray(); |
| } |
| |
| /// <summary> |
| /// Constructs a <see cref="Token"/> with null text and start & end |
| /// offsets. </summary> |
| /// <param name="start"> start offset in the source text </param> |
| /// <param name="end"> end offset in the source text </param> |
| public Token(int start, int end) |
| { |
| CheckOffsets(start, end); |
| startOffset = start; |
| endOffset = end; |
| } |
| |
| /// <summary> |
| /// Constructs a <see cref="Token"/> with null text and start & end |
| /// offsets plus the <see cref="Token"/> type. </summary> |
| /// <param name="start"> start offset in the source text </param> |
| /// <param name="end"> end offset in the source text </param> |
| /// <param name="typ"> the lexical type of this <see cref="Token"/> </param> |
| public Token(int start, int end, string typ) |
| { |
| CheckOffsets(start, end); |
| startOffset = start; |
| endOffset = end; |
| type = typ; |
| } |
| |
| /// <summary> |
| /// Constructs a <see cref="Token"/> with null text and start & end |
| /// offsets plus flags. NOTE: flags is EXPERIMENTAL. </summary> |
| /// <param name="start"> start offset in the source text </param> |
| /// <param name="end"> end offset in the source text </param> |
| /// <param name="flags"> The bits to set for this token </param> |
| public Token(int start, int end, int flags) |
| { |
| CheckOffsets(start, end); |
| startOffset = start; |
| endOffset = end; |
| this.flags = flags; |
| } |
| |
| /// <summary> |
| /// Constructs a <see cref="Token"/> with the given term text, and start |
| /// & end offsets. The type defaults to "word." |
| /// <b>NOTE:</b> for better indexing speed you should |
| /// instead use the char[] termBuffer methods to set the |
| /// term text. </summary> |
| /// <param name="text"> term text </param> |
| /// <param name="start"> start offset in the source text </param> |
| /// <param name="end"> end offset in the source text </param> |
| public Token(string text, int start, int end) |
| { |
| CheckOffsets(start, end); |
| Append(text); |
| startOffset = start; |
| endOffset = end; |
| } |
| |
| /// <summary> |
| /// Constructs a <see cref="Token"/> with the given text, start and end |
| /// offsets, & type. <b>NOTE:</b> for better indexing |
| /// speed you should instead use the char[] termBuffer |
| /// methods to set the term text. </summary> |
| /// <param name="text"> term text </param> |
| /// <param name="start"> start offset in the source text </param> |
| /// <param name="end"> end offset in the source text </param> |
| /// <param name="typ"> token type </param> |
| public Token(string text, int start, int end, string typ) |
| { |
| CheckOffsets(start, end); |
| Append(text); |
| startOffset = start; |
| endOffset = end; |
| type = typ; |
| } |
| |
| /// <summary> |
| /// Constructs a <see cref="Token"/> with the given text, start and end |
| /// offsets, & type. <b>NOTE:</b> for better indexing |
| /// speed you should instead use the char[] termBuffer |
| /// methods to set the term text. </summary> |
| /// <param name="text"> term text </param> |
| /// <param name="start"> start offset in the source text </param> |
| /// <param name="end"> end offset in the source text </param> |
| /// <param name="flags"> token type bits </param> |
| public Token(string text, int start, int end, int flags) |
| { |
| CheckOffsets(start, end); |
| Append(text); |
| startOffset = start; |
| endOffset = end; |
| this.flags = flags; |
| } |
| |
| /// <summary> |
| /// Constructs a <see cref="Token"/> with the given term buffer (offset |
| /// & length), start and end offsets |
| /// </summary> |
| /// <param name="startTermBuffer"> buffer containing term text </param> |
| /// <param name="termBufferOffset"> the index in the buffer of the first character </param> |
| /// <param name="termBufferLength"> number of valid characters in the buffer </param> |
| /// <param name="start"> start offset in the source text </param> |
| /// <param name="end"> end offset in the source text </param> |
| public Token(char[] startTermBuffer, int termBufferOffset, int termBufferLength, int start, int end) |
| { |
| CheckOffsets(start, end); |
| CopyBuffer(startTermBuffer, termBufferOffset, termBufferLength); |
| startOffset = start; |
| endOffset = end; |
| } |
| |
| /// <summary> |
| /// Gets or Sets the position increment (the distance from the prior term). The default value is one. |
| /// </summary> |
| /// <exception cref="ArgumentException"> if value is set to a negative value. </exception> |
| /// <seealso cref="IPositionIncrementAttribute"/> |
| public virtual int PositionIncrement |
| { |
| get => positionIncrement; |
| set |
| { |
| if (value < 0) |
| { |
| throw new ArgumentException("Increment must be zero or greater: " + value); |
| } |
| this.positionIncrement = value; |
| } |
| } |
| |
| /// <summary> |
| /// Gets or Sets the position length of this <see cref="Token"/> (how many positions this token |
| /// spans). |
| /// <para/> |
| /// The default value is one. |
| /// </summary> |
| /// <exception cref="ArgumentException"> if value |
| /// is set to zero or negative. </exception> |
| /// <seealso cref="IPositionLengthAttribute"/> |
| public virtual int PositionLength |
| { |
| get => positionLength; |
| set => this.positionLength = value; |
| } |
| |
| /// <summary> |
| /// Returns this <see cref="Token"/>'s starting offset, the position of the first character |
| /// corresponding to this token in the source text. |
| /// <para/> |
| /// Note that the difference between <see cref="EndOffset"/> and <see cref="StartOffset"/> |
| /// may not be equal to termText.Length, as the term text may have been altered by a |
| /// stemmer or some other filter. |
| /// </summary> |
| /// <seealso cref="SetOffset(int, int)"/> |
| /// <seealso cref="IOffsetAttribute"/> |
| public int StartOffset => startOffset; |
| |
| /// <summary> |
| /// Returns this <see cref="Token"/>'s ending offset, one greater than the position of the |
| /// last character corresponding to this token in the source text. The length |
| /// of the token in the source text is (<code>EndOffset</code> - <see cref="StartOffset"/>). |
| /// </summary> |
| /// <seealso cref="SetOffset(int, int)"/> |
| /// <seealso cref="IOffsetAttribute"/> |
| public int EndOffset => endOffset; |
| |
| /// <summary> |
| /// Set the starting and ending offset. |
| /// </summary> |
| /// <exception cref="ArgumentException"> If <paramref name="startOffset"/> or <paramref name="endOffset"/> |
| /// are negative, or if <paramref name="startOffset"/> is greater than |
| /// <paramref name="endOffset"/> </exception> |
| /// <seealso cref="StartOffset"/> |
| /// <seealso cref="EndOffset"/> |
| /// <seealso cref="IOffsetAttribute"/> |
| public virtual void SetOffset(int startOffset, int endOffset) |
| { |
| CheckOffsets(startOffset, endOffset); |
| this.startOffset = startOffset; |
| this.endOffset = endOffset; |
| } |
| |
| /// <summary>Gets or Sets this <see cref="Token"/>'s lexical type. Defaults to "word". </summary> |
| public string Type |
| { |
| get => type; |
| set => this.type = value; |
| } |
| |
| /// <summary> |
| /// Get the bitset for any bits that have been set. |
| /// <para/> |
| /// This is completely distinct from <see cref="ITypeAttribute.Type" />, although they do share similar purposes. |
| /// The flags can be used to encode information about the token for use by other <see cref="Lucene.Net.Analysis.TokenFilter" />s. |
| /// </summary> |
| /// <seealso cref="IFlagsAttribute"/> |
| public virtual int Flags |
| { |
| get => flags; |
| set => this.flags = value; |
| } |
| |
| /// <summary> |
| /// Gets or Sets this <see cref="Token"/>'s payload. |
| /// </summary> |
| /// <seealso cref="IPayloadAttribute"/> |
| public virtual BytesRef Payload |
| { |
| get => this.payload; |
| set => this.payload = value; |
| } |
| |
| /// <summary> |
| /// Resets the term text, payload, flags, and positionIncrement, |
| /// startOffset, endOffset and token type to default. |
| /// </summary> |
| public override void Clear() |
| { |
| base.Clear(); |
| payload = null; |
| positionIncrement = 1; |
| flags = 0; |
| startOffset = endOffset = 0; |
| type = TokenAttributes.TypeAttribute.DEFAULT_TYPE; |
| } |
| |
| public override object Clone() |
| { |
| var t = (Token)base.Clone(); |
| // Do a deep clone |
| if (payload != null) |
| { |
| t.payload = (BytesRef)payload.Clone(); |
| } |
| return t; |
| } |
| |
| /// <summary> |
| /// Makes a clone, but replaces the term buffer & |
| /// start/end offset in the process. This is more |
| /// efficient than doing a full clone (and then calling |
| /// <see cref="ICharTermAttribute.CopyBuffer"/>) because it saves a wasted copy of the old |
| /// termBuffer. |
| /// </summary> |
| public virtual Token Clone(char[] newTermBuffer, int newTermOffset, int newTermLength, int newStartOffset, int newEndOffset) |
| { |
| var t = new Token(newTermBuffer, newTermOffset, newTermLength, newStartOffset, newEndOffset) |
| { |
| positionIncrement = positionIncrement, |
| flags = flags, |
| type = type |
| }; |
| if (payload != null) |
| { |
| t.payload = (BytesRef)payload.Clone(); |
| } |
| return t; |
| } |
| |
| public override bool Equals(object obj) |
| { |
| if (obj == this) |
| { |
| return true; |
| } |
| |
| |
| if (obj is Token other) |
| { |
| return (startOffset == other.startOffset && |
| endOffset == other.endOffset && |
| flags == other.flags && |
| positionIncrement == other.positionIncrement && |
| (type == null ? other.type == null : type.Equals(other.type, StringComparison.Ordinal)) && |
| (payload == null ? other.payload == null : payload.Equals(other.payload)) && |
| base.Equals(obj) |
| ); |
| } |
| else |
| { |
| return false; |
| } |
| } |
| |
| public override int GetHashCode() |
| { |
| int code = base.GetHashCode(); |
| code = code * 31 + startOffset; |
| code = code * 31 + endOffset; |
| code = code * 31 + flags; |
| code = code * 31 + positionIncrement; |
| if (type != null) |
| { |
| code = code * 31 + type.GetHashCode(); |
| } |
| if (payload != null) |
| { |
| code = code * 31 + payload.GetHashCode(); |
| } |
| return code; |
| } |
| |
| // like clear() but doesn't clear termBuffer/text |
| private void ClearNoTermBuffer() |
| { |
| payload = null; |
| positionIncrement = 1; |
| flags = 0; |
| startOffset = endOffset = 0; |
| type = TokenAttributes.TypeAttribute.DEFAULT_TYPE; |
| } |
| |
| /// <summary> |
| /// Shorthand for calling <see cref="Clear"/>, |
| /// <see cref="ICharTermAttribute.CopyBuffer(char[], int, int)"/>, |
| /// <see cref="SetOffset"/>, |
| /// <see cref="Type"/> (set) </summary> |
| /// <returns> this <see cref="Token"/> instance </returns> |
| public virtual Token Reinit(char[] newTermBuffer, int newTermOffset, int newTermLength, int newStartOffset, int newEndOffset, string newType) |
| { |
| CheckOffsets(newStartOffset, newEndOffset); |
| ClearNoTermBuffer(); |
| CopyBuffer(newTermBuffer, newTermOffset, newTermLength); |
| payload = null; |
| positionIncrement = 1; |
| startOffset = newStartOffset; |
| endOffset = newEndOffset; |
| type = newType; |
| return this; |
| } |
| |
| /// <summary> |
| /// Shorthand for calling <see cref="Clear"/>, |
| /// <see cref="ICharTermAttribute.CopyBuffer(char[], int, int)"/>, |
| /// <see cref="SetOffset"/>, |
| /// <see cref="Type"/> (set) on <see cref="TypeAttribute.DEFAULT_TYPE"/> </summary> |
| /// <returns> this <see cref="Token"/> instance </returns> |
| public virtual Token Reinit(char[] newTermBuffer, int newTermOffset, int newTermLength, int newStartOffset, int newEndOffset) |
| { |
| CheckOffsets(newStartOffset, newEndOffset); |
| ClearNoTermBuffer(); |
| CopyBuffer(newTermBuffer, newTermOffset, newTermLength); |
| startOffset = newStartOffset; |
| endOffset = newEndOffset; |
| type = TokenAttributes.TypeAttribute.DEFAULT_TYPE; |
| return this; |
| } |
| |
| /// <summary> |
| /// Shorthand for calling <see cref="Clear"/>, |
| /// <see cref="ICharTermAttribute.Append(string)"/>, |
| /// <see cref="SetOffset"/>, |
| /// <see cref="Type"/> (set) </summary> |
| /// <returns> this <see cref="Token"/> instance </returns> |
| public virtual Token Reinit(string newTerm, int newStartOffset, int newEndOffset, string newType) |
| { |
| CheckOffsets(newStartOffset, newEndOffset); |
| Clear(); |
| Append(newTerm); |
| startOffset = newStartOffset; |
| endOffset = newEndOffset; |
| type = newType; |
| return this; |
| } |
| |
| /// <summary> |
| /// Shorthand for calling <see cref="Clear"/>, |
| /// <see cref="ICharTermAttribute.Append(string, int, int)"/>, |
| /// <see cref="SetOffset"/>, |
| /// <see cref="Type"/> (set) </summary> |
| /// <returns> this <see cref="Token"/> instance </returns> |
| public virtual Token Reinit(string newTerm, int newTermOffset, int newTermLength, int newStartOffset, int newEndOffset, string newType) |
| { |
| CheckOffsets(newStartOffset, newEndOffset); |
| Clear(); |
| Append(newTerm, newTermOffset, newTermOffset + newTermLength); |
| startOffset = newStartOffset; |
| endOffset = newEndOffset; |
| type = newType; |
| return this; |
| } |
| |
| /// <summary> |
| /// Shorthand for calling <see cref="Clear"/>, |
| /// <see cref="ICharTermAttribute.Append(string)"/>, |
| /// <see cref="SetOffset"/>, |
| /// <see cref="Type"/> (set) on <see cref="TypeAttribute.DEFAULT_TYPE"/> </summary> |
| /// <returns> this <see cref="Token"/> instance </returns> |
| public virtual Token Reinit(string newTerm, int newStartOffset, int newEndOffset) |
| { |
| CheckOffsets(newStartOffset, newEndOffset); |
| Clear(); |
| Append(newTerm); |
| startOffset = newStartOffset; |
| endOffset = newEndOffset; |
| type = TokenAttributes.TypeAttribute.DEFAULT_TYPE; |
| return this; |
| } |
| |
| /// <summary> |
| /// Shorthand for calling <see cref="Clear"/>, |
| /// <see cref="ICharTermAttribute.Append(string, int, int)"/>, |
| /// <see cref="SetOffset"/>, |
| /// <see cref="Type"/> (set) on <see cref="TypeAttribute.DEFAULT_TYPE"/> </summary> |
| /// <returns> this <see cref="Token"/> instance </returns> |
| public virtual Token Reinit(string newTerm, int newTermOffset, int newTermLength, int newStartOffset, int newEndOffset) |
| { |
| CheckOffsets(newStartOffset, newEndOffset); |
| Clear(); |
| Append(newTerm, newTermOffset, newTermOffset + newTermLength); |
| startOffset = newStartOffset; |
| endOffset = newEndOffset; |
| type = TokenAttributes.TypeAttribute.DEFAULT_TYPE; |
| return this; |
| } |
| |
| /// <summary> |
| /// Copy the prototype token's fields into this one. Note: Payloads are shared. </summary> |
| /// <param name="prototype"> source <see cref="Token"/> to copy fields from </param> |
| public virtual void Reinit(Token prototype) |
| { |
| CopyBuffer(prototype.Buffer, 0, prototype.Length); |
| positionIncrement = prototype.positionIncrement; |
| flags = prototype.flags; |
| startOffset = prototype.startOffset; |
| endOffset = prototype.endOffset; |
| type = prototype.type; |
| payload = prototype.payload; |
| } |
| |
| /// <summary> |
| /// Copy the prototype token's fields into this one, with a different term. Note: Payloads are shared. </summary> |
| /// <param name="prototype"> existing <see cref="Token"/> </param> |
| /// <param name="newTerm"> new term text </param> |
| public virtual void Reinit(Token prototype, string newTerm) |
| { |
| SetEmpty().Append(newTerm); |
| positionIncrement = prototype.positionIncrement; |
| flags = prototype.flags; |
| startOffset = prototype.startOffset; |
| endOffset = prototype.endOffset; |
| type = prototype.type; |
| payload = prototype.payload; |
| } |
| |
| /// <summary> |
| /// Copy the prototype token's fields into this one, with a different term. Note: Payloads are shared. </summary> |
| /// <param name="prototype"> existing <see cref="Token"/> </param> |
| /// <param name="newTermBuffer"> buffer containing new term text </param> |
| /// <param name="offset"> the index in the buffer of the first character </param> |
| /// <param name="length"> number of valid characters in the buffer </param> |
| public virtual void Reinit(Token prototype, char[] newTermBuffer, int offset, int length) |
| { |
| CopyBuffer(newTermBuffer, offset, length); |
| positionIncrement = prototype.positionIncrement; |
| flags = prototype.flags; |
| startOffset = prototype.startOffset; |
| endOffset = prototype.endOffset; |
| type = prototype.type; |
| payload = prototype.payload; |
| } |
| |
| public override void CopyTo(IAttribute target) |
| { |
| if (target is Token to) |
| { |
| to.Reinit(this); |
| // reinit shares the payload, so clone it: |
| if (payload != null) |
| { |
| to.payload = (BytesRef)payload.Clone(); |
| } |
| } |
| else |
| { |
| base.CopyTo(target); |
| ((IOffsetAttribute)target).SetOffset(startOffset, endOffset); |
| ((IPositionIncrementAttribute)target).PositionIncrement = positionIncrement; |
| ((IPayloadAttribute)target).Payload = (payload == null) ? null : (BytesRef)payload.Clone(); |
| ((IFlagsAttribute)target).Flags = flags; |
| ((ITypeAttribute)target).Type = type; |
| } |
| } |
| |
| public override void ReflectWith(IAttributeReflector reflector) |
| { |
| base.ReflectWith(reflector); |
| reflector.Reflect(typeof(IOffsetAttribute), "startOffset", startOffset); |
| reflector.Reflect(typeof(IOffsetAttribute), "endOffset", endOffset); |
| reflector.Reflect(typeof(IPositionIncrementAttribute), "positionIncrement", positionIncrement); |
| reflector.Reflect(typeof(IPayloadAttribute), "payload", payload); |
| reflector.Reflect(typeof(IFlagsAttribute), "flags", flags); |
| reflector.Reflect(typeof(ITypeAttribute), "type", type); |
| } |
| |
| private void CheckOffsets(int startOffset, int endOffset) |
| { |
| if (startOffset < 0 || endOffset < startOffset) |
| { |
| throw new ArgumentException("startOffset must be non-negative, and endOffset must be >= startOffset, " + "startOffset=" + startOffset + ",endOffset=" + endOffset); |
| } |
| } |
| |
| /// <summary> |
| /// Convenience factory that returns <see cref="Token"/> as implementation for the basic |
| /// attributes and return the default impl (with "Impl" appended) for all other |
| /// attributes. |
| /// @since 3.0 |
| /// </summary> |
| public static readonly AttributeSource.AttributeFactory TOKEN_ATTRIBUTE_FACTORY = new TokenAttributeFactory(AttributeSource.AttributeFactory.DEFAULT_ATTRIBUTE_FACTORY); |
| |
| /// <summary> |
| /// <b>Expert:</b> Creates a <see cref="TokenAttributeFactory"/> returning <see cref="Token"/> as instance for the basic attributes |
| /// and for all other attributes calls the given delegate factory. |
| /// @since 3.0 |
| /// </summary> |
| public sealed class TokenAttributeFactory : AttributeSource.AttributeFactory |
| { |
| internal readonly AttributeSource.AttributeFactory @delegate; |
| |
| /// <summary> |
| /// <b>Expert</b>: Creates an <see cref="AttributeSource.AttributeFactory"/> returning <see cref="Token"/> as instance for the basic attributes |
| /// and for all other attributes calls the given delegate factory. |
| /// </summary> |
| public TokenAttributeFactory(AttributeSource.AttributeFactory @delegate) |
| { |
| this.@delegate = @delegate; |
| } |
| |
| public override Attribute CreateAttributeInstance<T>() |
| { |
| var attClass = typeof(T); |
| return attClass.IsAssignableFrom(typeof(Token)) ? new Token() : @delegate.CreateAttributeInstance<T>(); |
| } |
| |
| public override bool Equals(object other) |
| { |
| if (this == other) |
| { |
| return true; |
| } |
| |
| if (other is TokenAttributeFactory af) |
| { |
| return this.@delegate.Equals(af.@delegate); |
| } |
| return false; |
| } |
| |
| public override int GetHashCode() |
| { |
| return @delegate.GetHashCode() ^ 0x0a45aa31; |
| } |
| } |
| } |
| } |