BUG: LUCENENET-602. Added Lucene.Net.Support.EqualityComparer<T> implementation to fix incomplete support for value types with generics on MONO AOT platforms. Added missing constructor overload to Lucene.Net.Facet.Taxonomy.LRUHashMap so the issue can be worked around using a custom IEqualityComparer<T> implementation if desired. Fixed inconsistencies with optimized C5 EqualityComparer, which was not being used in all of the C5-derived classes.
Project: http://git-wip-us.apache.org/repos/asf/lucenenet/repo Commit: http://git-wip-us.apache.org/repos/asf/lucenenet/commit/199fab06 Tree: http://git-wip-us.apache.org/repos/asf/lucenenet/tree/199fab06 Diff: http://git-wip-us.apache.org/repos/asf/lucenenet/diff/199fab06 Branch: refs/heads/master Commit: 199fab0660b9a20508e6f1b86882441f0ec654e8 Parents: a66190d Author: Shad Storhaug <[email protected]> Authored: Fri Jun 15 06:43:37 2018 +0700 Committer: Shad Storhaug <[email protected]> Committed: Fri Jun 15 06:43:37 2018 +0700 ---------------------------------------------------------------------- .../Analysis/Util/CharArrayMap.cs | 2 +- .../Directory/DirectoryTaxonomyReader.cs | 8 +- src/Lucene.Net.Facet/Taxonomy/LRUHashMap.cs | 32 ++++- src/Lucene.Net.Tests/Support/C5/Events.cs | 2 +- src/Lucene.Net.Tests/Support/C5/HashBag.cs | 2 +- src/Lucene.Net.Tests/Support/TestLurchTable.cs | 18 +-- src/Lucene.Net.Tests/Support/TestTreeSet.cs | 14 +-- src/Lucene.Net/Search/LiveFieldValues.cs | 9 +- src/Lucene.Net/Support/C5.Support.cs | 4 +- .../Compatibility/ConcurrentDictionary.cs | 2 +- src/Lucene.Net/Support/EqualityComparer.cs | 124 +++++++++++++++++++ src/Lucene.Net/Support/HashMap.cs | 7 +- src/Lucene.Net/Support/LinkedHashMap.cs | 2 +- src/Lucene.Net/Support/LurchTable.cs | 43 ++++--- src/Lucene.Net/Support/TreeDictionary.cs | 2 +- src/Lucene.Net/Support/TreeSet.cs | 2 +- src/Lucene.Net/Util/Fst/FST.cs | 8 +- src/Lucene.Net/Util/PriorityQueue.cs | 2 +- 18 files changed, 225 insertions(+), 58 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/lucenenet/blob/199fab06/src/Lucene.Net.Analysis.Common/Analysis/Util/CharArrayMap.cs ---------------------------------------------------------------------- diff --git a/src/Lucene.Net.Analysis.Common/Analysis/Util/CharArrayMap.cs b/src/Lucene.Net.Analysis.Common/Analysis/Util/CharArrayMap.cs index cfe5625..c642bc8 100644 --- a/src/Lucene.Net.Analysis.Common/Analysis/Util/CharArrayMap.cs +++ b/src/Lucene.Net.Analysis.Common/Analysis/Util/CharArrayMap.cs @@ -764,7 +764,7 @@ namespace Lucene.Net.Analysis.Util if (!this.ContainsKey(iter.Current.Key)) return false; - if (!EqualityComparer<TValue>.Default.Equals(this[iter.Current.Key], iter.Current.Value)) + if (!Support.EqualityComparer<TValue>.Default.Equals(this[iter.Current.Key], iter.Current.Value)) return false; } http://git-wip-us.apache.org/repos/asf/lucenenet/blob/199fab06/src/Lucene.Net.Facet/Taxonomy/Directory/DirectoryTaxonomyReader.cs ---------------------------------------------------------------------- diff --git a/src/Lucene.Net.Facet/Taxonomy/Directory/DirectoryTaxonomyReader.cs b/src/Lucene.Net.Facet/Taxonomy/Directory/DirectoryTaxonomyReader.cs index 994b644..13a5feb 100644 --- a/src/Lucene.Net.Facet/Taxonomy/Directory/DirectoryTaxonomyReader.cs +++ b/src/Lucene.Net.Facet/Taxonomy/Directory/DirectoryTaxonomyReader.cs @@ -1,4 +1,5 @@ -using System; +using Lucene.Net.Support; +using System; using System.Collections.Generic; using System.IO; using System.Text; @@ -22,7 +23,6 @@ namespace Lucene.Net.Facet.Taxonomy.Directory * limitations under the License. */ - using Lucene.Net.Facet.Taxonomy; using BytesRef = Lucene.Net.Util.BytesRef; using Directory = Lucene.Net.Store.Directory; using DirectoryReader = Lucene.Net.Index.DirectoryReader; @@ -83,8 +83,8 @@ namespace Lucene.Net.Facet.Taxonomy.Directory this.taxoEpoch = taxoWriter == null ? -1 : taxoWriter.TaxonomyEpoch; // use the same instance of the cache, note the protective code in getOrdinal and getPath - this.ordinalCache = ordinalCache == null ? new LRUHashMap<FacetLabel, Int32Class>(DEFAULT_CACHE_VALUE) : ordinalCache; - this.categoryCache = categoryCache == null ? new LRUHashMap<int, FacetLabel>(DEFAULT_CACHE_VALUE) : categoryCache; + this.ordinalCache = ordinalCache ?? new LRUHashMap<FacetLabel, Int32Class>(DEFAULT_CACHE_VALUE); + this.categoryCache = categoryCache ?? new LRUHashMap<int, FacetLabel>(DEFAULT_CACHE_VALUE); this.taxoArrays = taxoArrays != null ? new TaxonomyIndexArrays(indexReader, taxoArrays) : null; } http://git-wip-us.apache.org/repos/asf/lucenenet/blob/199fab06/src/Lucene.Net.Facet/Taxonomy/LRUHashMap.cs ---------------------------------------------------------------------- diff --git a/src/Lucene.Net.Facet/Taxonomy/LRUHashMap.cs b/src/Lucene.Net.Facet/Taxonomy/LRUHashMap.cs index f38c8d2..bd449b9 100644 --- a/src/Lucene.Net.Facet/Taxonomy/LRUHashMap.cs +++ b/src/Lucene.Net.Facet/Taxonomy/LRUHashMap.cs @@ -50,7 +50,7 @@ namespace Lucene.Net.Facet.Taxonomy /// The maximum size (in number of entries) to which the map can grow /// before the least recently used entries start being removed. /// <para/> - /// Setting maxSize to a very large value, like <see cref="int.MaxValue"/> + /// Setting <paramref name="limit"/> to a very large value, like <see cref="int.MaxValue"/> /// is allowed, but is less efficient than /// using <see cref="Support.HashMap{TKey, TValue}"/> or /// <see cref="Dictionary{TKey, TValue}"/> because our class needs @@ -59,8 +59,36 @@ namespace Lucene.Net.Facet.Taxonomy /// maximum size. /// </param> public LRUHashMap(int limit) + : this(limit, null) { - cache = new LurchTable<TKey, TValue>(LurchTableOrder.Access, limit); + } + + /// <summary> + /// Create a new hash map with a bounded size and with least recently + /// used entries removed. + /// <para/> + /// LUCENENET specific overload to allow passing in custom <see cref="IEqualityComparer{T}"/>. + /// See LUCENENET-602. + /// </summary> + /// <param name="limit"> + /// The maximum size (in number of entries) to which the map can grow + /// before the least recently used entries start being removed. + /// <para/> + /// Setting <paramref name="limit"/> to a very large value, like <see cref="int.MaxValue"/> + /// is allowed, but is less efficient than + /// using <see cref="Support.HashMap{TKey, TValue}"/> or + /// <see cref="Dictionary{TKey, TValue}"/> because our class needs + /// to keep track of the use order (via an additional doubly-linked + /// list) which is not used when the map's size is always below the + /// maximum size. + /// </param> + /// <param name="comparer"> + /// The <see cref="IEqualityComparer{TKey}"/> implementation to use when comparing keys, + /// or <c>null</c> to use the default <see cref="IEqualityComparer{TKey}"/> for the type of the key. + /// </param> + public LRUHashMap(int limit, IEqualityComparer<TKey> comparer) + { + cache = new LurchTable<TKey, TValue>(LurchTableOrder.Access, limit, comparer); } /// <summary> http://git-wip-us.apache.org/repos/asf/lucenenet/blob/199fab06/src/Lucene.Net.Tests/Support/C5/Events.cs ---------------------------------------------------------------------- diff --git a/src/Lucene.Net.Tests/Support/C5/Events.cs b/src/Lucene.Net.Tests/Support/C5/Events.cs index f0f5082..c3e982d 100644 --- a/src/Lucene.Net.Tests/Support/C5/Events.cs +++ b/src/Lucene.Net.Tests/Support/C5/Events.cs @@ -38,7 +38,7 @@ namespace Lucene.Net.Support.Templates.Events { this.collection = list; listenTo = testSpec; - seen = new CollectionEventList<TItem>(EqualityComparer<TItem>.Default, memoryType); + seen = new CollectionEventList<TItem>(C5.EqualityComparer<TItem>.Default, memoryType); } public SCG.IEnumerable<EventTypeEnum> SpecsBasic http://git-wip-us.apache.org/repos/asf/lucenenet/blob/199fab06/src/Lucene.Net.Tests/Support/C5/HashBag.cs ---------------------------------------------------------------------- diff --git a/src/Lucene.Net.Tests/Support/C5/HashBag.cs b/src/Lucene.Net.Tests/Support/C5/HashBag.cs index 288198a..9b46e63 100644 --- a/src/Lucene.Net.Tests/Support/C5/HashBag.cs +++ b/src/Lucene.Net.Tests/Support/C5/HashBag.cs @@ -50,7 +50,7 @@ namespace Lucene.Net.Support.C5 /// <summary> /// Create a hash bag with the default item equalityComparer. /// </summary> - public HashBag(MemoryType memoryType = MemoryType.Normal) : this(EqualityComparer<T>.Default, memoryType) { } + public HashBag(MemoryType memoryType = MemoryType.Normal) : this(C5.EqualityComparer<T>.Default, memoryType) { } /// <summary> /// Create a hash bag with an external item equalityComparer. http://git-wip-us.apache.org/repos/asf/lucenenet/blob/199fab06/src/Lucene.Net.Tests/Support/TestLurchTable.cs ---------------------------------------------------------------------- diff --git a/src/Lucene.Net.Tests/Support/TestLurchTable.cs b/src/Lucene.Net.Tests/Support/TestLurchTable.cs index 47c22a7..af38e5c 100644 --- a/src/Lucene.Net.Tests/Support/TestLurchTable.cs +++ b/src/Lucene.Net.Tests/Support/TestLurchTable.cs @@ -180,7 +180,7 @@ namespace Lucene.Net.Support { //multiple of prime will produce hash collision, thus testing removal of non-first elements const int prime = 1103; - var test = new LurchTable<int, string>(LurchTableOrder.Access, 3, prime, 10, 10, EqualityComparer<int>.Default); + var test = new LurchTable<int, string>(LurchTableOrder.Access, 3, prime, 10, 10, Support.EqualityComparer<int>.Default); test[1 * prime] = "a"; test[2 * prime] = "b"; test[3 * prime] = "c"; @@ -207,7 +207,7 @@ namespace Lucene.Net.Support public void TestCrudEvents() { var recorder = new RecordEvents<int, string>(); - var test = new LurchTable<int, string>(LurchTableOrder.Access, 3, 1103, 10, 10, EqualityComparer<int>.Default); + var test = new LurchTable<int, string>(LurchTableOrder.Access, 3, 1103, 10, 10, Support.EqualityComparer<int>.Default); test.ItemAdded += recorder.ItemAdded; test.ItemUpdated += recorder.ItemUpdated; test.ItemRemoved += recorder.ItemRemoved; @@ -247,7 +247,7 @@ namespace Lucene.Net.Support { //multiple of prime will produce hash collision, thus testing removal of non-first elements const int prime = 1103; - var test = new LurchTable<int, string>(LurchTableOrder.Access, 10, prime, 10, 10, EqualityComparer<int>.Default); + var test = new LurchTable<int, string>(LurchTableOrder.Access, 10, prime, 10, 10, Support.EqualityComparer<int>.Default); test[1 * prime] = "a"; test[2 * prime] = "b"; test[3 * prime] = "c"; @@ -487,8 +487,8 @@ namespace Lucene.Net.Support var keys = new List<int>(); foreach (var kv in sample) keys.Add(kv.Key); - VerifyCollection(EqualityComparer<int>.Default, keys.AsReadOnly(), items.Keys); - VerifyCollection(EqualityComparer<int>.Default, keys.AsReadOnly(), dict.Keys); + VerifyCollection(Support.EqualityComparer<int>.Default, keys.AsReadOnly(), items.Keys); + VerifyCollection(Support.EqualityComparer<int>.Default, keys.AsReadOnly(), dict.Keys); } [Test, LuceneNetSpecific] @@ -500,8 +500,8 @@ namespace Lucene.Net.Support var values = new List<string>(); foreach (var kv in sample) values.Add(kv.Value); - VerifyCollection(EqualityComparer<string>.Default, values.AsReadOnly(), items.Values); - VerifyCollection(EqualityComparer<string>.Default, values.AsReadOnly(), dict.Values); + VerifyCollection(Support.EqualityComparer<string>.Default, values.AsReadOnly(), items.Values); + VerifyCollection(Support.EqualityComparer<string>.Default, values.AsReadOnly(), dict.Values); } [Test] @@ -518,8 +518,8 @@ namespace Lucene.Net.Support class KeyValueEquality<TKey, TValue> : IEqualityComparer<KeyValuePair<TKey, TValue>> { - IEqualityComparer<TKey> KeyComparer = EqualityComparer<TKey>.Default; - IEqualityComparer<TValue> ValueComparer = EqualityComparer<TValue>.Default; + IEqualityComparer<TKey> KeyComparer = Support.EqualityComparer<TKey>.Default; + IEqualityComparer<TValue> ValueComparer = Support.EqualityComparer<TValue>.Default; public bool Equals(KeyValuePair<TKey, TValue> x, KeyValuePair<TKey, TValue> y) { return KeyComparer.Equals(x.Key, y.Key) && ValueComparer.Equals(x.Value, y.Value); http://git-wip-us.apache.org/repos/asf/lucenenet/blob/199fab06/src/Lucene.Net.Tests/Support/TestTreeSet.cs ---------------------------------------------------------------------- diff --git a/src/Lucene.Net.Tests/Support/TestTreeSet.cs b/src/Lucene.Net.Tests/Support/TestTreeSet.cs index 448e27c..56f88cf 100644 --- a/src/Lucene.Net.Tests/Support/TestTreeSet.cs +++ b/src/Lucene.Net.Tests/Support/TestTreeSet.cs @@ -416,7 +416,7 @@ namespace Lucene.Net.Support.RBTreeSet [Test, LuceneNetSpecific] public void NullEqualityComparerinConstructor3() { - Assert.Throws<NullReferenceException>(() => new TreeSet<int>(null, EqualityComparer<int>.Default)); + Assert.Throws<NullReferenceException>(() => new TreeSet<int>(null, Support.EqualityComparer<int>.Default)); } [Test, LuceneNetSpecific] @@ -2784,9 +2784,9 @@ namespace Lucene.Net.Support.RBTreeSet [SetUp] public void Init() { - dit = new TreeSet<int>(SCG.Comparer<int>.Default, EqualityComparer<int>.Default); - dat = new TreeSet<int>(SCG.Comparer<int>.Default, EqualityComparer<int>.Default); - dut = new TreeSet<int>(new RevIC(), EqualityComparer<int>.Default); + dit = new TreeSet<int>(SCG.Comparer<int>.Default, Support.EqualityComparer<int>.Default); + dat = new TreeSet<int>(SCG.Comparer<int>.Default, Support.EqualityComparer<int>.Default); + dut = new TreeSet<int>(new RevIC(), Support.EqualityComparer<int>.Default); } @@ -2880,9 +2880,9 @@ namespace Lucene.Net.Support.RBTreeSet [SetUp] public void Init() { - dit = new TreeSet<int>(SCG.Comparer<int>.Default, EqualityComparer<int>.Default); - dat = new TreeSet<int>(SCG.Comparer<int>.Default, EqualityComparer<int>.Default); - dut = new TreeSet<int>(new RevIC(), EqualityComparer<int>.Default); + dit = new TreeSet<int>(SCG.Comparer<int>.Default, Support.EqualityComparer<int>.Default); + dat = new TreeSet<int>(SCG.Comparer<int>.Default, Support.EqualityComparer<int>.Default); + dut = new TreeSet<int>(new RevIC(), Support.EqualityComparer<int>.Default); } http://git-wip-us.apache.org/repos/asf/lucenenet/blob/199fab06/src/Lucene.Net/Search/LiveFieldValues.cs ---------------------------------------------------------------------- diff --git a/src/Lucene.Net/Search/LiveFieldValues.cs b/src/Lucene.Net/Search/LiveFieldValues.cs index 6f2ab6f..43603a3 100644 --- a/src/Lucene.Net/Search/LiveFieldValues.cs +++ b/src/Lucene.Net/Search/LiveFieldValues.cs @@ -114,26 +114,27 @@ namespace Lucene.Net.Search // First try to get the "live" value: T value; current.TryGetValue(id, out value); - if (EqualityComparer<T>.Default.Equals(value, missingValue)) + var comparer = Support.EqualityComparer<T>.Default; + if (comparer.Equals(value, missingValue)) { // Deleted but the deletion is not yet reflected in // the reader: return default(T); } - else if (!EqualityComparer<T>.Default.Equals(value, default(T))) + else if (!comparer.Equals(value, default(T))) { return value; } else { old.TryGetValue(id, out value); - if (EqualityComparer<T>.Default.Equals(value, missingValue)) + if (comparer.Equals(value, missingValue)) { // Deleted but the deletion is not yet reflected in // the reader: return default(T); } - else if (!EqualityComparer<T>.Default.Equals(value, default(T))) + else if (!comparer.Equals(value, default(T))) { return value; } http://git-wip-us.apache.org/repos/asf/lucenenet/blob/199fab06/src/Lucene.Net/Support/C5.Support.cs ---------------------------------------------------------------------- diff --git a/src/Lucene.Net/Support/C5.Support.cs b/src/Lucene.Net/Support/C5.Support.cs index fc80bbc..9789d88 100644 --- a/src/Lucene.Net/Support/C5.Support.cs +++ b/src/Lucene.Net/Support/C5.Support.cs @@ -3967,7 +3967,7 @@ namespace Lucene.Net.Support.C5 /// <item><description>If the actual generic argument T implements /// <see cref="T:C5.ICollection`1"/> for some value W of its generic parameter T, /// the equalityComparer will be <see cref="T:C5.UnsequencedCollectionEqualityComparer`2"/></description></item> - /// <item><description>Otherwise the SCG.EqualityComparer<T>.Default is returned</description></item> + /// <item><description>Otherwise the Support.EqualityComparer<T>.Default is returned</description></item> /// </list> /// </summary> /// <value>The comparer</value> @@ -4005,7 +4005,7 @@ namespace Lucene.Net.Support.C5 return CreateAndCache(UnsequencedCollectionEqualityComparer.MakeGenericType(new[] { type, icollection.GetGenericArguments()[0] })); } - return _default = SCG.EqualityComparer<T>.Default; + return _default = Support.EqualityComparer<T>.Default; } } http://git-wip-us.apache.org/repos/asf/lucenenet/blob/199fab06/src/Lucene.Net/Support/Compatibility/ConcurrentDictionary.cs ---------------------------------------------------------------------- diff --git a/src/Lucene.Net/Support/Compatibility/ConcurrentDictionary.cs b/src/Lucene.Net/Support/Compatibility/ConcurrentDictionary.cs index 58f6dd8..22f1531 100644 --- a/src/Lucene.Net/Support/Compatibility/ConcurrentDictionary.cs +++ b/src/Lucene.Net/Support/Compatibility/ConcurrentDictionary.cs @@ -45,7 +45,7 @@ namespace System.Collections.Concurrent { } public ConcurrentDictionary(int capacity) - : this(capacity, EqualityComparer<TKey>.Default) + : this(capacity, Support.EqualityComparer<TKey>.Default) { } public ConcurrentDictionary(int capacity, IEqualityComparer<TKey> comparer) http://git-wip-us.apache.org/repos/asf/lucenenet/blob/199fab06/src/Lucene.Net/Support/EqualityComparer.cs ---------------------------------------------------------------------- diff --git a/src/Lucene.Net/Support/EqualityComparer.cs b/src/Lucene.Net/Support/EqualityComparer.cs new file mode 100644 index 0000000..6ea40cb --- /dev/null +++ b/src/Lucene.Net/Support/EqualityComparer.cs @@ -0,0 +1,124 @@ +using System.Collections.Generic; +using System.Reflection; + +namespace Lucene.Net.Support +{ + /* + * 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. + */ + + /// <summary> + /// <see cref="IEqualityComparer{T}"/> to patch value type support for generics in MONO AOT. + /// Value types for generics in this environment at the time of this writing is + /// not supported, but is currently under development and eventually should be. + /// <para/> + /// This class can be used to patch the behavior when using MONO AOT, at the cost + /// of throwing an exception to reliably detect when generic types are not supported. + /// See <a href=""></a> + /// <para/> + /// See LUCENENET-602. + /// </summary> + /// <typeparam name="T">The type of objects to compare.</typeparam> + public sealed class EqualityComparer<T> + { + private static readonly bool IsValueType = typeof(T).GetTypeInfo().IsValueType; + + /// <summary> + /// Returns a default equality comparer for the type specified by the generic argument. + /// <para/> + /// LUCENENET specific constant that is used for the comparer + /// rather than creating a custom <see cref="IEqualityComparer{T}"/> for value types. + /// See LUCENENET-602. + /// </summary> + public static System.Collections.Generic.EqualityComparer<T> Default { get; } = CreateComparer(); + + private static System.Collections.Generic.EqualityComparer<T> CreateComparer() + { + if (!EqualityComparerConstants.ValueTypesSupported.HasValue) + { + if (EqualityComparerConstants.ValueTypesSupported == true) + { + return System.Collections.Generic.EqualityComparer<T>.Default; + } + else + { + return IsValueType ? + new ValueTypeEqualityComparer() : + System.Collections.Generic.EqualityComparer<T>.Default; + } + } + + // We test for an exception the first time this is called on this runtime instance, + // and store it in the ValueTypesSupported property (called once for any value type). + // This is not currently supported under MONO AOT compilation, but is under development, + // so eventually the catch path will be unreachable. + try + { + var result = System.Collections.Generic.EqualityComparer<T>.Default; + EqualityComparerConstants.ValueTypesSupported = true; + return result; + } + catch when (IsValueType) + { + EqualityComparerConstants.ValueTypesSupported = false; + return new ValueTypeEqualityComparer(); + } + } + + /// <summary> + /// Comparer for any .NET value type. + /// <para/> + /// In some platforms, such as Xamarin iOS, the implementation of <see cref="System.Collections.Generic.EqualityComparer{T}.Default"/> doesn't + /// work for value types. This class is used to provide equality comparers in cases where value types are required. + /// </summary> + internal class ValueTypeEqualityComparer : System.Collections.Generic.EqualityComparer<T> // where T : struct + { + /// <summary> + /// Determines whether two objects of type T are equal. + /// </summary> + /// <param name="x">The first value type to compare.</param> + /// <param name="y">The second value type to compare.</param> + /// <returns><c>true</c> if the specified objects are equal; otherwise, <c>false</c>.</returns> + public override bool Equals(T x, T y) + { + if (x != null) + { + if (y != null) return x.Equals(y); + return false; + } + if (y != null) return false; + return true; + } + + /// <summary> + /// Serves as the default hash function. + /// <para/> + /// This is the same as calling obj.GetHashCode(). + /// </summary> + /// <param name="obj">The object for which to get a hash code.</param> + /// <returns>A hash code for the specified object.</returns> + public override int GetHashCode(T obj) + { + return obj == null ? 0 : obj.GetHashCode(); + } + } + } + + internal class EqualityComparerConstants + { + public static bool? ValueTypesSupported { get; set; } = null; + } +} http://git-wip-us.apache.org/repos/asf/lucenenet/blob/199fab06/src/Lucene.Net/Support/HashMap.cs ---------------------------------------------------------------------- diff --git a/src/Lucene.Net/Support/HashMap.cs b/src/Lucene.Net/Support/HashMap.cs index 6a293c3..65ba883 100644 --- a/src/Lucene.Net/Support/HashMap.cs +++ b/src/Lucene.Net/Support/HashMap.cs @@ -95,7 +95,7 @@ namespace Lucene.Net.Support } public HashMap(int initialCapacity) - : this(initialCapacity, EqualityComparer<TKey>.Default) + : this(initialCapacity, Support.EqualityComparer<TKey>.Default) { } @@ -115,7 +115,8 @@ namespace Lucene.Net.Support internal HashMap(IDictionary<TKey, TValue> wrappedDict, IEqualityComparer<TKey> comparer) { - _comparer = EqualityComparer<TKey>.Default; + // LUCENENET TODO: Is this a bug? Shouldn't we be using the passed in comparer if non-null? + _comparer = /* comparer ?? */ Support.EqualityComparer<TKey>.Default; _dict = wrappedDict; _hasNullValue = false; @@ -260,7 +261,7 @@ namespace Lucene.Net.Support { if (!_isValueType && _comparer.Equals(item.Key, default(TKey))) { - return _hasNullValue && EqualityComparer<TValue>.Default.Equals(item.Value, _nullValue); + return _hasNullValue && Support.EqualityComparer<TValue>.Default.Equals(item.Value, _nullValue); } return _dict.Contains(item); http://git-wip-us.apache.org/repos/asf/lucenenet/blob/199fab06/src/Lucene.Net/Support/LinkedHashMap.cs ---------------------------------------------------------------------- diff --git a/src/Lucene.Net/Support/LinkedHashMap.cs b/src/Lucene.Net/Support/LinkedHashMap.cs index e3d9c94..dbc5d3b 100644 --- a/src/Lucene.Net/Support/LinkedHashMap.cs +++ b/src/Lucene.Net/Support/LinkedHashMap.cs @@ -199,7 +199,7 @@ namespace Lucene.Net.Support private bool TryGetNode(TKey key, TValue value, out LinkedListNode<KeyValuePair<TKey, TValue>> node) { LinkedListNode<KeyValuePair<TKey, TValue>> n; - if (dict.TryGetValue(key, out n) && EqualityComparer<TValue>.Default.Equals(value, n.Value.Value)) + if (dict.TryGetValue(key, out n) && Support.EqualityComparer<TValue>.Default.Equals(value, n.Value.Value)) { node = n; return true; http://git-wip-us.apache.org/repos/asf/lucenenet/blob/199fab06/src/Lucene.Net/Support/LurchTable.cs ---------------------------------------------------------------------- diff --git a/src/Lucene.Net/Support/LurchTable.cs b/src/Lucene.Net/Support/LurchTable.cs index 71379c8..47d251f 100644 --- a/src/Lucene.Net/Support/LurchTable.cs +++ b/src/Lucene.Net/Support/LurchTable.cs @@ -75,35 +75,48 @@ namespace Lucene.Net.Support private int _used, _count; private int _allocNext, _freeVersion; - /// <summary>Creates a LurchTable that can store up to (capacity) items efficiently.</summary> + + + /// <summary>Creates a LurchTable that can store up to <paramref name="capacity"/> items efficiently.</summary> + /// <param name="capacity">The initial allowable number of items before allocation of more memory</param> public LurchTable(int capacity) - : this(LurchTableOrder.None, int.MaxValue, capacity >> 1, capacity >> 4, capacity >> 8, EqualityComparer<TKey>.Default) { } + : this(LurchTableOrder.None, int.MaxValue, capacity >> 1, capacity >> 4, capacity >> 8, null) { } - /// <summary>Creates a LurchTable that can store up to (capacity) items efficiently.</summary> + /// <summary>Creates a LurchTable that can store up to <paramref name="capacity"/> items efficiently.</summary> + /// <param name="capacity">The initial allowable number of items before allocation of more memory</param> + /// <param name="ordering">The type of linking for the items</param> public LurchTable(int capacity, LurchTableOrder ordering) - : this(ordering, int.MaxValue, capacity >> 1, capacity >> 4, capacity >> 8, EqualityComparer<TKey>.Default) { } + : this(ordering, int.MaxValue, capacity >> 1, capacity >> 4, capacity >> 8, null) { } - /// <summary>Creates a LurchTable that can store up to (capacity) items efficiently.</summary> + /// <summary>Creates a LurchTable that can store up to <paramref name="capacity"/> items efficiently.</summary> + /// <param name="capacity">The initial allowable number of items before allocation of more memory</param> + /// <param name="ordering">The type of linking for the items</param> + /// <param name="comparer">The element hash generator for keys, or <c>null</c> to use <see cref="Support.EqualityComparer{TKey}.Default"/></param> public LurchTable(int capacity, LurchTableOrder ordering, IEqualityComparer<TKey> comparer) : this(ordering, int.MaxValue, capacity >> 1, capacity >> 4, capacity >> 8, comparer) { } - /// <summary>Creates a LurchTable that orders items by (ordering) and removes items once the specified (limit) is reached.</summary> + /// <summary>Creates a LurchTable that orders items by <paramref name="ordering"/> and removes items once the specified <paramref name="limit"/> is reached.</summary> + /// <param name="ordering">The type of linking for the items</param> + /// <param name="limit">The maximum allowable number of items, or int.MaxValue for unlimited</param> public LurchTable(LurchTableOrder ordering, int limit) - : this(ordering, limit, limit >> 1, limit >> 4, limit >> 8, EqualityComparer<TKey>.Default) { } + : this(ordering, limit, limit >> 1, limit >> 4, limit >> 8, null) { } - /// <summary>Creates a LurchTable that orders items by (ordering) and removes items once the specified (limit) is reached.</summary> + /// <summary>Creates a LurchTable that orders items by <paramref name="ordering"/> and removes items once the specified <paramref name="limit"/> is reached.</summary> + /// <param name="ordering">The type of linking for the items</param> + /// <param name="limit">The maximum allowable number of items, or int.MaxValue for unlimited</param> + /// <param name="comparer">The element hash generator for keys, or <c>null</c> to use <see cref="Support.EqualityComparer{TKey}.Default"/></param> public LurchTable(LurchTableOrder ordering, int limit, IEqualityComparer<TKey> comparer) : this(ordering, limit, limit >> 1, limit >> 4, limit >> 8, comparer) { } /// <summary> - /// Creates a LurchTable that orders items by (ordering) and removes items once the specified (limit) is reached. + /// Creates a LurchTable that orders items by <paramref name="ordering"/> and removes items once the specified <paramref name="limit"/> is reached. /// </summary> /// <param name="ordering">The type of linking for the items</param> /// <param name="limit">The maximum allowable number of items, or int.MaxValue for unlimited</param> /// <param name="hashSize">The number of hash buckets to use for the collection, usually 1/2 estimated capacity</param> /// <param name="allocSize">The number of entries to allocate at a time, usually 1/16 estimated capacity</param> /// <param name="lockSize">The number of concurrency locks to preallocate, usually 1/256 estimated capacity</param> - /// <param name="comparer">The element hash generator for keys</param> + /// <param name="comparer">The element hash generator for keys, or <c>null</c> to use <see cref="Support.EqualityComparer{TKey}.Default"/></param> public LurchTable(LurchTableOrder ordering, int limit, int hashSize, int allocSize, int lockSize, IEqualityComparer<TKey> comparer) { if (limit <= 0) @@ -112,7 +125,7 @@ namespace Lucene.Net.Support throw new ArgumentOutOfRangeException("ordering"); _limit = limit <= 0 ? int.MaxValue : limit; - _comparer = comparer; + _comparer = comparer ?? Support.EqualityComparer<TKey>.Default; _ordering = ordering; allocSize = (int)Math.Min((long)allocSize + OverAlloc, 0x3fffffff); @@ -457,7 +470,7 @@ namespace Lucene.Net.Support { TValue test; if (TryGetValue(item.Key, out test)) - return EqualityComparer<TValue>.Default.Equals(item.Value, test); + return Support.EqualityComparer<TValue>.Default.Equals(item.Value, test); return false; } @@ -754,7 +767,7 @@ namespace Lucene.Net.Support /// </summary> public bool Contains(TValue value) { - var comparer = EqualityComparer<TValue>.Default; + var comparer = Support.EqualityComparer<TValue>.Default; foreach (var item in _owner) { if (comparer.Equals(item.Value, value)) @@ -1413,7 +1426,7 @@ namespace Lucene.Net.Support { Value = value; - if (_hasTestValue && !EqualityComparer<TValue>.Default.Equals(_testValue, value)) + if (_hasTestValue && !Support.EqualityComparer<TValue>.Default.Equals(_testValue, value)) return false; if (Condition != null && !Condition(key, value)) return false; @@ -1508,7 +1521,7 @@ namespace Lucene.Net.Support } public bool UpdateValue(TKey key, ref TValue value) { - if (_hasTestValue && !EqualityComparer<TValue>.Default.Equals(_testValue, value)) + if (_hasTestValue && !Support.EqualityComparer<TValue>.Default.Equals(_testValue, value)) return false; value = Value; http://git-wip-us.apache.org/repos/asf/lucenenet/blob/199fab06/src/Lucene.Net/Support/TreeDictionary.cs ---------------------------------------------------------------------- diff --git a/src/Lucene.Net/Support/TreeDictionary.cs b/src/Lucene.Net/Support/TreeDictionary.cs index f1b50f1..fe43a57 100644 --- a/src/Lucene.Net/Support/TreeDictionary.cs +++ b/src/Lucene.Net/Support/TreeDictionary.cs @@ -40,7 +40,7 @@ namespace Lucene.Net.Support /// Create a red-black tree dictionary using the natural comparer for keys. /// <exception cref="ArgumentException"/> if the key type K is not comparable. /// </summary> - public TreeDictionary(MemoryType memoryType = MemoryType.Normal) : this(SCG.Comparer<K>.Default, EqualityComparer<K>.Default, memoryType) { } + public TreeDictionary(MemoryType memoryType = MemoryType.Normal) : this(SCG.Comparer<K>.Default, C5.EqualityComparer<K>.Default, memoryType) { } /// <summary> /// Create a red-black tree dictionary using an external comparer for keys. http://git-wip-us.apache.org/repos/asf/lucenenet/blob/199fab06/src/Lucene.Net/Support/TreeSet.cs ---------------------------------------------------------------------- diff --git a/src/Lucene.Net/Support/TreeSet.cs b/src/Lucene.Net/Support/TreeSet.cs index 559477f..f0d78c7 100644 --- a/src/Lucene.Net/Support/TreeSet.cs +++ b/src/Lucene.Net/Support/TreeSet.cs @@ -228,7 +228,7 @@ namespace Lucene.Net.Support /// </summary> /// <exception cref="NotComparableException">If <code>T</code> is not comparable. /// </exception> - public TreeSet(MemoryType memoryType = MemoryType.Normal) : this(SCG.Comparer<T>.Default, EqualityComparer<T>.Default, memoryType) { } + public TreeSet(MemoryType memoryType = MemoryType.Normal) : this(SCG.Comparer<T>.Default, C5.EqualityComparer<T>.Default, memoryType) { } /// <summary> http://git-wip-us.apache.org/repos/asf/lucenenet/blob/199fab06/src/Lucene.Net/Util/Fst/FST.cs ---------------------------------------------------------------------- diff --git a/src/Lucene.Net/Util/Fst/FST.cs b/src/Lucene.Net/Util/Fst/FST.cs index 8982395..c4053fd 100644 --- a/src/Lucene.Net/Util/Fst/FST.cs +++ b/src/Lucene.Net/Util/Fst/FST.cs @@ -362,7 +362,7 @@ namespace Lucene.Net.Util.Fst { throw new InvalidOperationException("already finished"); } - if (newStartNode == FST.FINAL_END_NODE && !EqualityComparer<T>.Default.Equals(emptyOutput, default(T))) + if (newStartNode == FST.FINAL_END_NODE && !Support.EqualityComparer<T>.Default.Equals(emptyOutput, default(T))) { newStartNode = 0; } @@ -514,7 +514,7 @@ namespace Lucene.Net.Util.Fst } // TODO: really we should encode this as an arc, arriving // to the root node, instead of special casing here: - if (!EqualityComparer<T>.Default.Equals(emptyOutput, default(T))) + if (!Support.EqualityComparer<T>.Default.Equals(emptyOutput, default(T))) { // Accepts empty string @out.WriteByte(1); @@ -875,7 +875,7 @@ namespace Lucene.Net.Util.Fst /// </summary> public FST.Arc<T> GetFirstArc(FST.Arc<T> arc) { - if (!EqualityComparer<T>.Default.Equals(emptyOutput, default(T))) + if (!Support.EqualityComparer<T>.Default.Equals(emptyOutput, default(T))) { arc.Flags = FST.BIT_FINAL_ARC | FST.BIT_LAST_ARC; arc.NextFinalOutput = emptyOutput; @@ -2053,7 +2053,7 @@ namespace Lucene.Net.Util.Fst fst.startNode = newNodeAddress.Get((int)startNode); //System.out.println("new startNode=" + fst.startNode + " old startNode=" + startNode); - if (!EqualityComparer<T>.Default.Equals(emptyOutput, default(T))) + if (!Support.EqualityComparer<T>.Default.Equals(emptyOutput, default(T))) { fst.EmptyOutput = emptyOutput; } http://git-wip-us.apache.org/repos/asf/lucenenet/blob/199fab06/src/Lucene.Net/Util/PriorityQueue.cs ---------------------------------------------------------------------- diff --git a/src/Lucene.Net/Util/PriorityQueue.cs b/src/Lucene.Net/Util/PriorityQueue.cs index 36d5be5..391dd4f 100644 --- a/src/Lucene.Net/Util/PriorityQueue.cs +++ b/src/Lucene.Net/Util/PriorityQueue.cs @@ -88,7 +88,7 @@ namespace Lucene.Net.Util { // If sentinel objects are supported, populate the queue with them T sentinel = GetSentinelObject(); - if (!EqualityComparer<T>.Default.Equals(sentinel, default(T))) + if (!Support.EqualityComparer<T>.Default.Equals(sentinel, default(T))) { heap[1] = sentinel; for (int i = 2; i < heap.Length; i++)
