// ----------------------------------------------------------------------- // // // 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.Util { using System; using System.Collections.Generic; using System.Linq; using System.Text; using Lucene.Net.Support; /// /// This class represents a slice of a an existing char[]. /// The property should never be null, default to if necessary. /// /// /// /// This class might be transformed into a immutable value type depending on its use /// in the Lucene code base. /// /// public class CharsRef : IComparable, ICharSequence, ICloneable, IEnumerable, IEquatable { private static readonly char[] emptyArray = new char[0]; private static readonly UTF8Comparer comparer = new UTF8Comparer(); /// /// Initializes a new instance of the class. /// public CharsRef() { this.Chars = emptyArray; } /// /// Initializes a new instance of the class. /// /// The capacity. public CharsRef(int capacity) { if (capacity < 0) throw new ArgumentException("capacity can not be less than 0", "capacity"); this.Chars = new char[capacity]; } /// /// Initializes a new instance of the class. /// /// The source. /// The offset. /// The length. /// Thrown when is null. /// /// Thrown when the length of is less than and /// combined. /// public CharsRef(char[] source, int offset = 0, int length = 0) { if (source == null) throw new ArgumentNullException("source"); if (source.Length < (offset + length)) throw new ArgumentException( "The length of source, source.Length, must be equal to or greater than the offset & length combined."); if (length == 0) length = source.Length; this.Chars = source; this.Offset = offset; this.Length = length; } /// /// Initializes a new instance of the class. /// /// The source. /// Thrown when is null. public CharsRef(string source) { if (source == null) throw new ArgumentNullException("source"); this.Chars = source.ToCharArray(); this.Length = this.Chars.Length; } /// /// Initializes a new instance of the class. /// /// The source. /// Thrown when is null. public CharsRef(CharsRef source) { if (source == null) throw new ArgumentNullException("source"); this.Chars = emptyArray; this.Copy(source); } /// /// Gets the UT F16 sorted as UT f8 comparer. /// /// The UT F16 sorted as UT f8 comparer. public static IComparer UTF16SortedAsUTF8Comparer { get { return comparer; } } /// /// Gets or sets the chars. /// /// The chars. public char[] Chars { get; protected set; } /// /// Gets or sets the length. /// /// The length. public int Length { get; protected set; } /// /// Gets or sets the offset. /// /// The offset. public int Offset { get; protected set; } /// /// Implements the operator ==. /// /// The left. /// The right. /// The result of the operator. public static bool operator ==(CharsRef left, CharsRef right) { if (left == null) return right == null; return left.Equals(right); } /// /// Implements the operator !=. /// /// The left. /// The right. /// The result of the operator. public static bool operator !=(CharsRef left, CharsRef right) { if (left == null) return right != null; return !left.Equals(right); } /// /// Implements the operator >. /// /// The left. /// The right. /// The result of the operator. public static bool operator >(CharsRef left, CharsRef right) { return left.CompareTo(right) > 0; } /// /// Implements the operator <. /// /// The left. /// The right. /// The result of the operator. public static bool operator <(CharsRef left, CharsRef right) { return left.CompareTo(right) < 0; } /// /// Appends the specified value. /// /// The value. /// The offset. /// The length. public void Append(char[] value, int offset = 0, int length = 0) { if (length == 0) length = value.Length; this.Grow(this.Offset + length); Array.Copy(value, offset, this.Chars, this.Offset, length); this.Length = length; } /// /// Finds the at the specified index. /// /// The index. /// An instance of . public char CharAt(int index) { return this.Chars[index]; } /// /// Clones this instance. /// /// an cloned instance of public CharsRef Clone() { return new CharsRef(this); } /// /// Compares to. /// /// The other. /// An instance of . public int CompareTo(CharsRef other) { if (this.Equals(other)) return 0; char[] leftChars = this.Chars, rightChars = other.Chars; int leftOffset = this.Offset, rightOffset = other.Offset, end = leftOffset + Math.Min(this.Length, other.Length); while (leftOffset < end) { int leftChar = leftChars[leftOffset++]; int rightChar = rightChars[rightOffset++]; if (leftChar > rightChar) return 1; if (leftChar < rightChar) return -1; } return this.Length - other.Length; } /// /// Copies the specified and resets the current instance's to 0. /// /// The source. public void Copy(CharsRef source) { this.Chars = ArrayUtil.Grow(this.Chars, source.Length); Array.Copy(source.Chars, source.Offset, this.Chars, 0, source.Length); this.Length = source.Length; this.Offset = 0; } /// /// Copies the char[] into this instance and sets this instance's to 0. /// /// The source. /// The offset. /// The length. public void Copy(char[] source, int offset = 0, int length = 0) { if (length == 0) length = source.Length; this.Offset = 0; this.Append(source, offset, length); } /// /// Determines whether the specified is equal to this instance. /// /// The right. /// true if is equal to this instance, otherwise false. public bool Equals(CharsRef right) { if (this.Length != right.Length) return false; int rightOffset = right.Offset, end = this.Offset + this.Length; char[] rightChars = right.Chars, leftChars = this.Chars; for (int leftOffset = this.Offset; leftOffset < end; leftOffset++, rightOffset++) { if (leftChars[leftOffset] != rightChars[rightOffset]) return false; } return true; } /// /// 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) { CharsRef otherCharRef = obj as CharsRef; if (otherCharRef != null) return this.Equals(otherCharRef); if (!obj.IsCharSequence()) return false; ICharSequence sequence = null; if (obj is string) { sequence = obj.ToString().ToCharSequence(); } else if (obj is ICharSequence) { sequence = (ICharSequence)obj; } else { sequence = ((IEnumerable)obj).ToCharSequence(); } if (this.Length != sequence.Length) return false; int end = this.Length, i = this.Offset, j = 0; while (end-- != 0) { if (this.Chars[i++] != sequence.CharAt(j++)) return false; } return true; } /// /// Gets the enumerator. /// /// /// An instance of of char. /// public IEnumerator GetEnumerator() { // there might be a better way to do this. return this.Chars.ToList().GetEnumerator(); } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return this.GetEnumerator(); } /// /// 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 result = 0, end = this.Offset + this.Length; for (int i = this.Offset; i < end; i++) result = (31 * result) + this.Chars[i]; return result; } /// /// Grows the specified length. /// /// The length. public void Grow(int length) { if (this.Chars.Length < length) this.Chars = ArrayUtil.Grow(this.Chars, length); } /// /// Gets the subset sequence of characters from the current sequence. /// /// The start. /// The end. /// /// An instance of . /// public ICharSequence SubSequence(int start, int end) { return new CharsRef(this.Chars, this.Offset + start, this.Offset + end - 1); } /// /// Returns a representation of this instance. This override /// creates a new string passing in the char array, offset, and length. /// /// /// A that represents this instance. /// public override string ToString() { return new string(this.Chars, this.Offset, this.Length); } object ICloneable.Clone() { return this.Clone(); } private sealed class UTF8Comparer : IComparer { /// /// Compares the specified left. /// /// /// /// http://icu-project.org/docs/papers/utf16_code_point_order.html /// /// /// A good deal of the code was pulled from the icu-project. /// /// /// The left. /// The right. /// /// 0 if and are equal. Returns an int less than 0 /// if the is less than the , otherwise an int greater than 0. /// public int Compare(CharsRef left, CharsRef right) { if (left == right) return 0; char[] leftChars = left.Chars, rightChars = right.Chars; int leftOffset = left.Offset, rightOffset = right.Offset, end = leftOffset + Math.Min(left.Length, right.Length); Func normalize = (value) => { if (value >= 0xe000) value -= 0x800; else value += 0x2000; return value; }; while (leftOffset < end) { int leftChar = leftChars[leftOffset++]; int rightChar = rightChars[rightOffset++]; if (leftChar != rightChar) { //// http://icu-project.org/docs/papers/utf16_code_point_order.html //// fix up each value if both values are inside of or above the surrogate range. then compare. if (leftChar >= 0xd800 && rightChar >= 0xd800) { leftChar = normalize(leftChar); rightChar = normalize(rightChar); } return leftChar - rightChar; } } return left.Length - right.Length; } } } }