/* * 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 System; namespace Lucene.Net.Analysis { /// A simple class that stores Strings as char[]'s in a /// hash table. Note that this is not a general purpose /// class. For example, it cannot remove items from the /// set, nor does it resize its hash table to be smaller, /// etc. It is designed to be quick to test if a char[] /// is in the set without the necessity of converting it /// to a String first. /// public class CharArraySet:System.Collections.Hashtable { public override int Count { get { return count; } } private const int INIT_SIZE = 8; private char[][] entries; private int count; private bool ignoreCase; /// Create set with enough capacity to hold startSize /// terms /// public CharArraySet(int startSize, bool ignoreCase) { this.ignoreCase = ignoreCase; int size = INIT_SIZE; while (startSize + (startSize >> 2) > size) size <<= 1; entries = new char[size][]; } /// Create set from a Collection of char[] or String public CharArraySet(System.Collections.ICollection c, bool ignoreCase):this(c.Count, ignoreCase) { System.Collections.IEnumerator e = c.GetEnumerator(); while (e.MoveNext()) { Add(e.Current); } } /// Create set from entries private CharArraySet(char[][] entries, bool ignoreCase, int count) { this.entries = entries; this.ignoreCase = ignoreCase; this.count = count; } /// true if the len chars of text starting at off /// are in the set /// public virtual bool Contains(char[] text, int off, int len) { return entries[GetSlot(text, off, len)] != null; } /// true if the System.String is in the set public virtual bool Contains(System.String cs) { return entries[GetSlot(cs)] != null; } private int GetSlot(char[] text, int off, int len) { int code = GetHashCode(text, off, len); int pos = code & (entries.Length - 1); char[] text2 = entries[pos]; if (text2 != null && !Equals(text, off, len, text2)) { int inc = ((code >> 8) + code) | 1; do { code += inc; pos = code & (entries.Length - 1); text2 = entries[pos]; } while (text2 != null && !Equals(text, off, len, text2)); } return pos; } /// Returns true if the String is in the set private int GetSlot(System.String text) { int code = GetHashCode(text); int pos = code & (entries.Length - 1); char[] text2 = entries[pos]; if (text2 != null && !Equals(text, text2)) { int inc = ((code >> 8) + code) | 1; do { code += inc; pos = code & (entries.Length - 1); text2 = entries[pos]; } while (text2 != null && !Equals(text, text2)); } return pos; } /// Add this String into the set public virtual bool Add(System.String text) { return Add(text.ToCharArray()); } /// Add this char[] directly to the set. /// If ignoreCase is true for this Set, the text array will be directly modified. /// The user should never modify this text array after calling this method. /// public virtual bool Add(char[] text) { if (ignoreCase) for (int i = 0; i < text.Length; i++) text[i] = System.Char.ToLower(text[i]); int slot = GetSlot(text, 0, text.Length); if (entries[slot] != null) return false; entries[slot] = text; count++; if (count + (count >> 2) > entries.Length) { Rehash(); } return true; } private bool Equals(char[] text1, int off, int len, char[] text2) { if (len != text2.Length) return false; if (ignoreCase) { for (int i = 0; i < len; i++) { if (System.Char.ToLower(text1[off + i]) != text2[i]) return false; } } else { for (int i = 0; i < len; i++) { if (text1[off + i] != text2[i]) return false; } } return true; } private bool Equals(System.String text1, char[] text2) { int len = text1.Length; if (len != text2.Length) return false; if (ignoreCase) { for (int i = 0; i < len; i++) { if (System.Char.ToLower(text1[i]) != text2[i]) return false; } } else { for (int i = 0; i < len; i++) { if (text1[i] != text2[i]) return false; } } return true; } private void Rehash() { int newSize = 2 * entries.Length; char[][] oldEntries = entries; entries = new char[newSize][]; for (int i = 0; i < oldEntries.Length; i++) { char[] text = oldEntries[i]; if (text != null) { // todo: could be faster... no need to compare strings on collision entries[GetSlot(text, 0, text.Length)] = text; } } } private int GetHashCode(char[] text, int offset, int len) { int code = 0; int stop = offset + len; if (ignoreCase) { for (int i = offset; i < stop; i++) { code = code * 31 + System.Char.ToLower(text[i]); } } else { for (int i = offset; i < stop; i++) { code = code * 31 + text[i]; } } return code; } private int GetHashCode(System.String text) { int code = 0; int len = text.Length; if (ignoreCase) { for (int i = 0; i < len; i++) { code = code * 31 + System.Char.ToLower(text[i]); } } else { for (int i = 0; i < len; i++) { code = code * 31 + text[i]; } } return code; } public virtual int Size() { return count; } public virtual bool IsEmpty() { return count == 0; } public override bool Contains(System.Object o) { if (o is char[]) { char[] text = (char[]) o; return Contains(text, 0, text.Length); } return Contains(o.ToString()); } public virtual bool Add(System.Object o) { if (o is char[]) { return Add((char[]) o); } if (o is System.Collections.Hashtable) { foreach (string word in ((System.Collections.Hashtable)o).Keys) { Add(word); } return true; } return Add(o.ToString()); } /// Returns an unmodifiable {@link CharArraySet}. This allows to provide /// unmodifiable views of internal sets for "read-only" use. /// /// /// a set for which the unmodifiable set is returned. /// /// an new unmodifiable {@link CharArraySet}. /// /// NullPointerException /// if the given set is null. /// public static CharArraySet UnmodifiableSet(CharArraySet set_Renamed) { if (set_Renamed == null) throw new System.NullReferenceException("Given set is null"); /* * Instead of delegating calls to the given set copy the low-level values to * the unmodifiable Subclass */ return new UnmodifiableCharArraySet(set_Renamed.entries, set_Renamed.ignoreCase, set_Renamed.count); } /// The Iterator<String> for this set. Strings are constructed on the fly, so /// use nextCharArray for more efficient access. /// public class CharArraySetIterator : System.Collections.IEnumerator { private void InitBlock(CharArraySet enclosingInstance) { this.enclosingInstance = enclosingInstance; } private CharArraySet enclosingInstance; /// Returns the next String, as a Set<String> would... /// use nextCharArray() for better efficiency. /// public virtual System.Object Current { get { return new System.String(NextCharArray()); } } public CharArraySet Enclosing_Instance { get { return enclosingInstance; } } internal int pos = - 1; internal char[] next_Renamed_Field; internal CharArraySetIterator(CharArraySet enclosingInstance) { InitBlock(enclosingInstance); GoNext(); } private void GoNext() { next_Renamed_Field = null; pos++; while (pos < Enclosing_Instance.entries.Length && (next_Renamed_Field = Enclosing_Instance.entries[pos]) == null) pos++; } public virtual bool MoveNext() { return next_Renamed_Field != null; } /// do not modify the returned char[] public virtual char[] NextCharArray() { char[] ret = next_Renamed_Field; GoNext(); return ret; } public virtual void Remove() { throw new System.NotSupportedException(); } virtual public void Reset() { System.Diagnostics.Debug.Fail("Port issue:", "Need to implement this call, CharArraySetIterator.Reset()"); // {{Aroush-2.9 } } public new System.Collections.IEnumerator GetEnumerator() { return new CharArraySetIterator(this); } /// Efficient unmodifiable {@link CharArraySet}. This implementation does not /// delegate calls to a give {@link CharArraySet} like /// {@link Collections#UnmodifiableSet(java.util.Set)} does. Instead is passes /// the internal representation of a {@link CharArraySet} to a super /// constructor and overrides all mutators. /// private sealed class UnmodifiableCharArraySet:CharArraySet { internal UnmodifiableCharArraySet(char[][] entries, bool ignoreCase, int count):base(entries, ignoreCase, count) { } public override bool Add(System.Object o) { throw new System.NotSupportedException(); } public bool AddAll(System.Collections.ICollection coll) { throw new System.NotSupportedException(); } public override bool Add(char[] text) { throw new System.NotSupportedException(); } public override bool Add(System.String text) { throw new System.NotSupportedException(); } } /// Adds all of the elements in the specified collection to this collection public virtual bool AddAll(System.Collections.ICollection items) { bool added = false; System.Collections.IEnumerator iter = items.GetEnumerator(); System.Object item; while (iter.MoveNext()) { item = iter.Current; added = Add(item); } return added; } /// Removes all elements from the set public virtual bool Clear() { throw new System.NotSupportedException(); } /// Removes from this set all of its elements that are contained in the specified collection public virtual bool RemoveAll(System.Collections.ICollection items) { throw new System.NotSupportedException(); } /// Retains only the elements in this set that are contained in the specified collection public bool RetainAll(System.Collections.ICollection coll) { throw new System.NotSupportedException(); } } }