From 3e55bba14a09c3a8f14a32bbaddddc9c19f287e4 Mon Sep 17 00:00:00 2001 From: Paul Irwin Date: Tue, 3 Dec 2024 22:01:07 -0700 Subject: [PATCH 1/3] Add operator overrides for IComparable types, #683 --- .../Quality/QualityQuery.cs | 27 +++++++++- .../VectorHighlight/FieldPhraseList.cs | 51 ++++++++++++++++++- .../VectorHighlight/FieldTermStack.cs | 25 ++++++++- .../Surround/Query/SimpleTerm.cs | 31 ++++++++++- src/Lucene.Net.Spatial/Prefix/Tree/Cell.cs | 36 ++++++++++--- .../Suggest/Fst/FSTCompletion.cs | 23 +++++++++ src/Lucene.Net.Suggest/Suggest/Lookup.cs | 31 +++++++++-- src/Lucene.Net/Index/IndexCommit.cs | 29 +++++++++-- src/Lucene.Net/Index/Term.cs | 25 ++++++++- src/Lucene.Net/Util/Automaton/State.cs | 27 +++++++++- src/Lucene.Net/Util/BytesRef.cs | 23 +++++++++ src/Lucene.Net/Util/CharsRef.cs | 23 +++++++++ src/Lucene.Net/Util/IntsRef.cs | 23 +++++++++ src/Lucene.Net/Util/LongsRef.cs | 23 +++++++++ src/Lucene.Net/Util/Mutable/MutableValue.cs | 29 +++++++++-- 15 files changed, 400 insertions(+), 26 deletions(-) diff --git a/src/Lucene.Net.Benchmark/Quality/QualityQuery.cs b/src/Lucene.Net.Benchmark/Quality/QualityQuery.cs index cc45910d14..5791fd3b74 100644 --- a/src/Lucene.Net.Benchmark/Quality/QualityQuery.cs +++ b/src/Lucene.Net.Benchmark/Quality/QualityQuery.cs @@ -28,13 +28,13 @@ namespace Lucene.Net.Benchmarks.Quality /// /// The ID allows to map the quality query with its judgements. /// - /// The name-value pairs are used by a + /// The name-value pairs are used by a /// /// to create a Lucene . /// /// It is very likely that name-value-pairs would be mapped into fields in a Lucene query, /// but it is up to the QualityQueryParser how to map - e.g. all values in a single field, - /// or each pair as its own field, etc., - and this of course must match the way the + /// or each pair as its own field, etc., - and this of course must match the way the /// searched index was constructed. /// public class QualityQuery : IComparable @@ -99,5 +99,28 @@ public virtual int CompareTo(QualityQuery other) return queryID.CompareToOrdinal(other.queryID); } } + + #region Operator overrides + // LUCENENET specific - per csharpsquid:S1210, IComparable should override comparison operators + + public static bool operator <(QualityQuery left, QualityQuery right) + => left is null ? right is not null : left.CompareTo(right) < 0; + + public static bool operator <=(QualityQuery left, QualityQuery right) + => left is null || left.CompareTo(right) <= 0; + + public static bool operator >(QualityQuery left, QualityQuery right) + => left is not null && left.CompareTo(right) > 0; + + public static bool operator >=(QualityQuery left, QualityQuery right) + => left is null ? right is null : left.CompareTo(right) >= 0; + + public static bool operator ==(QualityQuery left, QualityQuery right) + => left?.Equals(right) ?? right is null; + + public static bool operator !=(QualityQuery left, QualityQuery right) + => !(left == right); + + #endregion } } diff --git a/src/Lucene.Net.Highlighter/VectorHighlight/FieldPhraseList.cs b/src/Lucene.Net.Highlighter/VectorHighlight/FieldPhraseList.cs index f2f8996add..5badc34b34 100644 --- a/src/Lucene.Net.Highlighter/VectorHighlight/FieldPhraseList.cs +++ b/src/Lucene.Net.Highlighter/VectorHighlight/FieldPhraseList.cs @@ -442,7 +442,7 @@ public override int GetHashCode() public override bool Equals(object obj) { - if (this == obj) + if (ReferenceEquals(this, obj)) { return true; } @@ -470,6 +470,29 @@ public override bool Equals(object obj) return true; } + #region Operator overrides + // LUCENENET specific - per csharpsquid:S1210, IComparable should override comparison operators + + public static bool operator <(WeightedPhraseInfo left, WeightedPhraseInfo right) + => left is null ? right is not null : left.CompareTo(right) < 0; + + public static bool operator <=(WeightedPhraseInfo left, WeightedPhraseInfo right) + => left is null || left.CompareTo(right) <= 0; + + public static bool operator >(WeightedPhraseInfo left, WeightedPhraseInfo right) + => left is not null && left.CompareTo(right) > 0; + + public static bool operator >=(WeightedPhraseInfo left, WeightedPhraseInfo right) + => left is null ? right is null : left.CompareTo(right) >= 0; + + public static bool operator ==(WeightedPhraseInfo left, WeightedPhraseInfo right) + => left?.Equals(right) ?? right is null; + + public static bool operator !=(WeightedPhraseInfo left, WeightedPhraseInfo right) + => !(left == right); + + #endregion + /// /// Term offsets (start + end) /// @@ -512,7 +535,7 @@ public override int GetHashCode() public override bool Equals(object obj) { - if (this == obj) + if (ReferenceEquals(this, obj)) { return true; } @@ -535,12 +558,36 @@ public override bool Equals(object obj) } return true; } + public override string ToString() { StringBuilder sb = new StringBuilder(); sb.Append('(').Append(startOffset).Append(',').Append(endOffset).Append(')'); return sb.ToString(); } + + #region Operator overrides + // LUCENENET specific - per csharpsquid:S1210, IComparable should override comparison operators + + public static bool operator <(Toffs left, Toffs right) + => left is null ? right is not null : left.CompareTo(right) < 0; + + public static bool operator <=(Toffs left, Toffs right) + => left is null || left.CompareTo(right) <= 0; + + public static bool operator >(Toffs left, Toffs right) + => left is not null && left.CompareTo(right) > 0; + + public static bool operator >=(Toffs left, Toffs right) + => left is null ? right is null : left.CompareTo(right) >= 0; + + public static bool operator ==(Toffs left, Toffs right) + => left?.Equals(right) ?? right is null; + + public static bool operator !=(Toffs left, Toffs right) + => !(left == right); + + #endregion } } } diff --git a/src/Lucene.Net.Highlighter/VectorHighlight/FieldTermStack.cs b/src/Lucene.Net.Highlighter/VectorHighlight/FieldTermStack.cs index 5c909b1094..4393af3931 100644 --- a/src/Lucene.Net.Highlighter/VectorHighlight/FieldTermStack.cs +++ b/src/Lucene.Net.Highlighter/VectorHighlight/FieldTermStack.cs @@ -265,7 +265,7 @@ public override int GetHashCode() public override bool Equals(object obj) { - if (this == obj) + if (ReferenceEquals(this, obj)) { return true; } @@ -284,6 +284,29 @@ public override bool Equals(object obj) } return true; } + + #region Operator overrides + // LUCENENET specific - per csharpsquid:S1210, IComparable should override comparison operators + + public static bool operator <(TermInfo left, TermInfo right) + => left is null ? right is not null : left.CompareTo(right) < 0; + + public static bool operator <=(TermInfo left, TermInfo right) + => left is null || left.CompareTo(right) <= 0; + + public static bool operator >(TermInfo left, TermInfo right) + => left is not null && left.CompareTo(right) > 0; + + public static bool operator >=(TermInfo left, TermInfo right) + => left is null ? right is null : left.CompareTo(right) >= 0; + + public static bool operator ==(TermInfo left, TermInfo right) + => left?.Equals(right) ?? right is null; + + public static bool operator !=(TermInfo left, TermInfo right) + => !(left == right); + + #endregion } } } diff --git a/src/Lucene.Net.QueryParser/Surround/Query/SimpleTerm.cs b/src/Lucene.Net.QueryParser/Surround/Query/SimpleTerm.cs index ad9c6dcadd..69641bd73f 100644 --- a/src/Lucene.Net.QueryParser/Surround/Query/SimpleTerm.cs +++ b/src/Lucene.Net.QueryParser/Surround/Query/SimpleTerm.cs @@ -28,8 +28,8 @@ namespace Lucene.Net.QueryParsers.Surround.Query public abstract class SimpleTerm : SrndQuery, IDistanceSubQuery, IComparable { protected SimpleTerm(bool quoted) // LUCENENET: CA1012: Abstract types should not have constructors (marked protected) - { - this.quoted = quoted; + { + this.quoted = quoted; } private readonly bool quoted; // LUCENENET: marked readonly @@ -115,5 +115,32 @@ public override Search.Query MakeLuceneQueryFieldNoBoost(string fieldName, Basic { return new SimpleTermRewriteQuery(this, fieldName, qf); } + + #region Operator overrides + // LUCENENET specific - per csharpsquid:S1210, IComparable should override comparison operators + // NOTE: The CompareTo method is marked as obsolete, but we still need to implement the comparison operators + // since this is public in 4.8. Suppressing the obsolete warning here. + +#pragma warning disable CS0618 // Type or member is obsolete + public static bool operator <(SimpleTerm left, SimpleTerm right) + => left is null ? right is not null : left.CompareTo(right) < 0; + + public static bool operator <=(SimpleTerm left, SimpleTerm right) + => left is null || left.CompareTo(right) <= 0; + + public static bool operator >(SimpleTerm left, SimpleTerm right) + => left is not null && left.CompareTo(right) > 0; + + public static bool operator >=(SimpleTerm left, SimpleTerm right) + => left is null ? right is null : left.CompareTo(right) >= 0; +#pragma warning restore CS0618 // Type or member is obsolete + + public static bool operator ==(SimpleTerm left, SimpleTerm right) + => left?.Equals(right) ?? right is null; + + public static bool operator !=(SimpleTerm left, SimpleTerm right) + => !(left == right); + + #endregion } } diff --git a/src/Lucene.Net.Spatial/Prefix/Tree/Cell.cs b/src/Lucene.Net.Spatial/Prefix/Tree/Cell.cs index d342144387..9d48a8b57c 100644 --- a/src/Lucene.Net.Spatial/Prefix/Tree/Cell.cs +++ b/src/Lucene.Net.Spatial/Prefix/Tree/Cell.cs @@ -28,13 +28,13 @@ namespace Lucene.Net.Spatial.Prefix.Tree /// /// Represents a grid cell. These are not necessarily thread-safe, although new /// Cell("") (world cell) must be. - /// + /// /// @lucene.experimental /// public abstract class Cell : IComparable { /// - /// LUCENENET specific - we need to set the SpatialPrefixTree before calling overridden + /// LUCENENET specific - we need to set the SpatialPrefixTree before calling overridden /// members of this class, just in case those overridden members require it. This is /// not possible from the subclass because the constructor of the base class runs first. /// So we need to move the reference here and also set it before running the normal constructor @@ -90,7 +90,7 @@ protected Cell(SpatialPrefixTree spatialPrefixTree, string token) { this.token = token.Substring(0, (token.Length - 1) - 0); // LUCENENET specific - calling private instead of virtual to avoid initialization issues - SetLeafInternal(); + SetLeafInternal(); } if (Level == 0) { @@ -178,8 +178,8 @@ private void B_fixLeaf() public virtual bool IsLeaf => m_leaf; /// Note: not supported at level 0. - /// - /// NOTE: When overriding this method, be aware that the constructor of this class calls + /// + /// NOTE: When overriding this method, be aware that the constructor of this class calls /// a private method and not this virtual method. So if you need to override /// the behavior during the initialization, call your own private method from the constructor /// with whatever custom behavior you need. @@ -232,7 +232,7 @@ public virtual byte[] GetTokenBytes() //public Cell getParent(); /// /// Like GetSubCells() but with the results filtered by a shape. If - /// that shape is a then it must call + /// that shape is a then it must call /// . The returned cells /// should have ShapeRel set to their relation with /// . In addition, @@ -337,5 +337,27 @@ public override string ToString() #endregion + #region Operator overrides + // LUCENENET specific - per csharpsquid:S1210, IComparable should override comparison operators + + public static bool operator <(Cell? left, Cell? right) + => left is null ? right is not null : left.CompareTo(right) < 0; + + public static bool operator <=(Cell? left, Cell? right) + => left is null || left.CompareTo(right) <= 0; + + public static bool operator >(Cell? left, Cell? right) + => left is not null && left.CompareTo(right) > 0; + + public static bool operator >=(Cell? left, Cell? right) + => left is null ? right is null : left.CompareTo(right) >= 0; + + public static bool operator ==(Cell? left, Cell? right) + => left?.Equals(right) ?? right is null; + + public static bool operator !=(Cell? left, Cell? right) + => !(left == right); + + #endregion } -} \ No newline at end of file +} diff --git a/src/Lucene.Net.Suggest/Suggest/Fst/FSTCompletion.cs b/src/Lucene.Net.Suggest/Suggest/Fst/FSTCompletion.cs index a2a4f90387..a18ffe7aa3 100644 --- a/src/Lucene.Net.Suggest/Suggest/Fst/FSTCompletion.cs +++ b/src/Lucene.Net.Suggest/Suggest/Fst/FSTCompletion.cs @@ -67,6 +67,29 @@ public int CompareTo(Completion o) { return this.Utf8.CompareTo(o.Utf8); } + + #region Operator overrides + // LUCENENET specific - per csharpsquid:S1210, IComparable should override comparison operators + + public static bool operator <(Completion left, Completion right) + => left is null ? right is not null : left.CompareTo(right) < 0; + + public static bool operator <=(Completion left, Completion right) + => left is null || left.CompareTo(right) <= 0; + + public static bool operator >(Completion left, Completion right) + => left is not null && left.CompareTo(right) > 0; + + public static bool operator >=(Completion left, Completion right) + => left is null ? right is null : left.CompareTo(right) >= 0; + + public static bool operator ==(Completion left, Completion right) + => left?.Equals(right) ?? right is null; + + public static bool operator !=(Completion left, Completion right) + => !(left == right); + + #endregion } /// diff --git a/src/Lucene.Net.Suggest/Suggest/Lookup.cs b/src/Lucene.Net.Suggest/Suggest/Lookup.cs index a04cb73daa..2920ca3c05 100644 --- a/src/Lucene.Net.Suggest/Suggest/Lookup.cs +++ b/src/Lucene.Net.Suggest/Suggest/Lookup.cs @@ -43,7 +43,7 @@ public sealed class LookupResult : IComparable /// /// Expert: custom Object to hold the result of a - /// highlighted suggestion. + /// highlighted suggestion. /// public object HighlightKey { get; private set; } @@ -122,6 +122,29 @@ public int CompareTo(LookupResult o) { return CHARSEQUENCE_COMPARER.Compare(Key, o.Key); } + + #region Operator overrides + // LUCENENET specific - per csharpsquid:S1210, IComparable should override comparison operators + + public static bool operator <(LookupResult left, LookupResult right) + => left is null ? right is not null : left.CompareTo(right) < 0; + + public static bool operator <=(LookupResult left, LookupResult right) + => left is null || left.CompareTo(right) <= 0; + + public static bool operator >(LookupResult left, LookupResult right) + => left is not null && left.CompareTo(right) > 0; + + public static bool operator >=(LookupResult left, LookupResult right) + => left is null ? right is null : left.CompareTo(right) >= 0; + + public static bool operator ==(LookupResult left, LookupResult right) + => left?.Equals(right) ?? right is null; + + public static bool operator !=(LookupResult left, LookupResult right) + => !(left == right); + + #endregion } /// @@ -129,7 +152,7 @@ public int CompareTo(LookupResult o) /// public static readonly IComparer CHARSEQUENCE_COMPARER = new CharSequenceComparer(); - // LUCENENET: It is no longer good practice to use binary serialization. + // LUCENENET: It is no longer good practice to use binary serialization. // See: https://github.com/dotnet/corefx/issues/23584#issuecomment-325724568 #if FEATURE_SERIALIZABLE [Serializable] @@ -201,7 +224,7 @@ public LookupResult[] GetResults() } /// - /// Sole constructor. (For invocation by subclass + /// Sole constructor. (For invocation by subclass /// constructors, typically implicit.) /// protected Lookup() // LUCENENET: CA1012: Abstract types should not have constructors (marked protected) @@ -306,4 +329,4 @@ public virtual IList DoLookup(string key, bool onlyMorePopular, in /// ram size of the lookup implementation in bytes public abstract long GetSizeInBytes(); } -} \ No newline at end of file +} diff --git a/src/Lucene.Net/Index/IndexCommit.cs b/src/Lucene.Net/Index/IndexCommit.cs index 3caabec528..8d85907696 100644 --- a/src/Lucene.Net/Index/IndexCommit.cs +++ b/src/Lucene.Net/Index/IndexCommit.cs @@ -117,8 +117,8 @@ public override int GetHashCode() public abstract long Generation { get; } /// - /// Returns userData, previously passed to - /// } for this commit. + /// Returns userData, previously passed to + /// } for this commit. /// The dictionary is -> . /// public abstract IDictionary UserData { get; } @@ -145,5 +145,28 @@ public virtual int CompareTo(IndexCommit commit) return 0; } } + + #region Operator overrides + // LUCENENET specific - per csharpsquid:S1210, IComparable should override comparison operators + + public static bool operator <(IndexCommit left, IndexCommit right) + => left is null ? right is not null : left.CompareTo(right) < 0; + + public static bool operator <=(IndexCommit left, IndexCommit right) + => left is null || left.CompareTo(right) <= 0; + + public static bool operator >(IndexCommit left, IndexCommit right) + => left is not null && left.CompareTo(right) > 0; + + public static bool operator >=(IndexCommit left, IndexCommit right) + => left is null ? right is null : left.CompareTo(right) >= 0; + + public static bool operator ==(IndexCommit left, IndexCommit right) + => left?.Equals(right) ?? right is null; + + public static bool operator !=(IndexCommit left, IndexCommit right) + => !(left == right); + + #endregion } -} \ No newline at end of file +} diff --git a/src/Lucene.Net/Index/Term.cs b/src/Lucene.Net/Index/Term.cs index e7841ca78c..dc21ea40d6 100644 --- a/src/Lucene.Net/Index/Term.cs +++ b/src/Lucene.Net/Index/Term.cs @@ -189,5 +189,28 @@ public override string ToString() { return Field + ":" + Text; } + + #region Operator overrides + // LUCENENET specific - per csharpsquid:S1210, IComparable should override comparison operators + + public static bool operator <(Term left, Term right) + => left is null ? right is not null : left.CompareTo(right) < 0; + + public static bool operator <=(Term left, Term right) + => left is null || left.CompareTo(right) <= 0; + + public static bool operator >(Term left, Term right) + => left is not null && left.CompareTo(right) > 0; + + public static bool operator >=(Term left, Term right) + => left is null ? right is null : left.CompareTo(right) >= 0; + + public static bool operator ==(Term left, Term right) + => left?.Equals(right) ?? right is null; + + public static bool operator !=(Term left, Term right) + => !(left == right); + + #endregion } -} \ No newline at end of file +} diff --git a/src/Lucene.Net/Util/Automaton/State.cs b/src/Lucene.Net/Util/Automaton/State.cs index 898bdff630..83aab6c0d5 100644 --- a/src/Lucene.Net/Util/Automaton/State.cs +++ b/src/Lucene.Net/Util/Automaton/State.cs @@ -360,17 +360,42 @@ public virtual int CompareTo(State s) return s.id - id; } - // LUCENENET NOTE: DO NOT IMPLEMENT Equals()!!! + // LUCENENET NOTE: DO NOT IMPLEMENT Equals() with structural equality!!! // Although it doesn't match GetHashCode(), checking for // reference equality is by design. // Implementing Equals() causes difficult to diagnose // IndexOutOfRangeExceptions when using FuzzyTermsEnum. // See GH-296. + // Overriding here to prevent CS0660 warning due to defining the == operator. + public override bool Equals(object obj) => ReferenceEquals(this, obj); [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() { return id; } + + #region Operator overrides + // LUCENENET specific - per csharpsquid:S1210, IComparable should override comparison operators + + public static bool operator <(State left, State right) + => left is null ? right is not null : left.CompareTo(right) < 0; + + public static bool operator <=(State left, State right) + => left is null || left.CompareTo(right) <= 0; + + public static bool operator >(State left, State right) + => left is not null && left.CompareTo(right) > 0; + + public static bool operator >=(State left, State right) + => left is null ? right is null : left.CompareTo(right) >= 0; + + public static bool operator ==(State left, State right) + => left is null ? right is null : ReferenceEquals(left, right); + + public static bool operator !=(State left, State right) + => !(left == right); + + #endregion } } diff --git a/src/Lucene.Net/Util/BytesRef.cs b/src/Lucene.Net/Util/BytesRef.cs index b381f31eb8..78be76cb65 100644 --- a/src/Lucene.Net/Util/BytesRef.cs +++ b/src/Lucene.Net/Util/BytesRef.cs @@ -400,6 +400,29 @@ public bool IsValid() } return true; } + + #region Operator overrides + // LUCENENET specific - per csharpsquid:S1210, IComparable should override comparison operators + + public static bool operator <(BytesRef left, BytesRef right) + => left is null ? right is not null : left.CompareTo(right) < 0; + + public static bool operator <=(BytesRef left, BytesRef right) + => left is null || left.CompareTo(right) <= 0; + + public static bool operator >(BytesRef left, BytesRef right) + => left is not null && left.CompareTo(right) > 0; + + public static bool operator >=(BytesRef left, BytesRef right) + => left is null ? right is null : left.CompareTo(right) >= 0; + + public static bool operator ==(BytesRef left, BytesRef right) + => left?.Equals(right) ?? right is null; + + public static bool operator !=(BytesRef left, BytesRef right) + => !(left == right); + + #endregion } // LUCENENET: It is no longer good practice to use binary serialization. diff --git a/src/Lucene.Net/Util/CharsRef.cs b/src/Lucene.Net/Util/CharsRef.cs index 14cc2b1de8..835a342557 100644 --- a/src/Lucene.Net/Util/CharsRef.cs +++ b/src/Lucene.Net/Util/CharsRef.cs @@ -443,5 +443,28 @@ public bool IsValid() } return true; } + + #region Operator overrides + // LUCENENET specific - per csharpsquid:S1210, IComparable should override comparison operators + + public static bool operator <(CharsRef left, CharsRef right) + => left is null ? right is not null : left.CompareTo(right) < 0; + + public static bool operator <=(CharsRef left, CharsRef right) + => left is null || left.CompareTo(right) <= 0; + + public static bool operator >(CharsRef left, CharsRef right) + => left is not null && left.CompareTo(right) > 0; + + public static bool operator >=(CharsRef left, CharsRef right) + => left is null ? right is null : left.CompareTo(right) >= 0; + + public static bool operator ==(CharsRef left, CharsRef right) + => left?.Equals(right) ?? right is null; + + public static bool operator !=(CharsRef left, CharsRef right) + => !(left == right); + + #endregion } } diff --git a/src/Lucene.Net/Util/IntsRef.cs b/src/Lucene.Net/Util/IntsRef.cs index ef90b03e47..803aa04873 100644 --- a/src/Lucene.Net/Util/IntsRef.cs +++ b/src/Lucene.Net/Util/IntsRef.cs @@ -293,5 +293,28 @@ public bool IsValid() } return true; } + + #region Operator overrides + // LUCENENET specific - per csharpsquid:S1210, IComparable should override comparison operators + + public static bool operator <(Int32sRef left, Int32sRef right) + => left is null ? right is not null : left.CompareTo(right) < 0; + + public static bool operator <=(Int32sRef left, Int32sRef right) + => left is null || left.CompareTo(right) <= 0; + + public static bool operator >(Int32sRef left, Int32sRef right) + => left is not null && left.CompareTo(right) > 0; + + public static bool operator >=(Int32sRef left, Int32sRef right) + => left is null ? right is null : left.CompareTo(right) >= 0; + + public static bool operator ==(Int32sRef left, Int32sRef right) + => left?.Equals(right) ?? right is null; + + public static bool operator !=(Int32sRef left, Int32sRef right) + => !(left == right); + + #endregion } } diff --git a/src/Lucene.Net/Util/LongsRef.cs b/src/Lucene.Net/Util/LongsRef.cs index 94cf2f873a..a90914fbe1 100644 --- a/src/Lucene.Net/Util/LongsRef.cs +++ b/src/Lucene.Net/Util/LongsRef.cs @@ -292,5 +292,28 @@ public bool IsValid() } return true; } + + #region Operator overrides + // LUCENENET specific - per csharpsquid:S1210, IComparable should override comparison operators + + public static bool operator <(Int64sRef left, Int64sRef right) + => left is null ? right is not null : left.CompareTo(right) < 0; + + public static bool operator <=(Int64sRef left, Int64sRef right) + => left is null || left.CompareTo(right) <= 0; + + public static bool operator >(Int64sRef left, Int64sRef right) + => left is not null && left.CompareTo(right) > 0; + + public static bool operator >=(Int64sRef left, Int64sRef right) + => left is null ? right is null : left.CompareTo(right) >= 0; + + public static bool operator ==(Int64sRef left, Int64sRef right) + => left?.Equals(right) ?? right is null; + + public static bool operator !=(Int64sRef left, Int64sRef right) + => !(left == right); + + #endregion } } diff --git a/src/Lucene.Net/Util/Mutable/MutableValue.cs b/src/Lucene.Net/Util/Mutable/MutableValue.cs index 183f30e9e5..45c77f6bab 100644 --- a/src/Lucene.Net/Util/Mutable/MutableValue.cs +++ b/src/Lucene.Net/Util/Mutable/MutableValue.cs @@ -61,8 +61,8 @@ public virtual int CompareTo(MutableValue other) } - // LUCENENET specific implementation, for use with FunctionFirstPassGroupingCollector - // (note that IComparable does not inherit IComparable, so we need to explicitly + // LUCENENET specific implementation, for use with FunctionFirstPassGroupingCollector + // (note that IComparable does not inherit IComparable, so we need to explicitly // implement here in order to support IComparable) public virtual int CompareTo(object other) { @@ -91,5 +91,28 @@ public override string ToString() { return Exists ? ToObject().ToString() : "(null)"; } + + #region Operator overrides + // LUCENENET specific - per csharpsquid:S1210, IComparable should override comparison operators + + public static bool operator <(MutableValue left, MutableValue right) + => left is null ? right is not null : left.CompareTo(right) < 0; + + public static bool operator <=(MutableValue left, MutableValue right) + => left is null || left.CompareTo(right) <= 0; + + public static bool operator >(MutableValue left, MutableValue right) + => left is not null && left.CompareTo(right) > 0; + + public static bool operator >=(MutableValue left, MutableValue right) + => left is null ? right is null : left.CompareTo(right) >= 0; + + public static bool operator ==(MutableValue left, MutableValue right) + => left?.Equals(right) ?? right is null; + + public static bool operator !=(MutableValue left, MutableValue right) + => !(left == right); + + #endregion } -} \ No newline at end of file +} From 95399b41f258f1305d9d3458a18ca6b398275856 Mon Sep 17 00:00:00 2001 From: Paul Irwin Date: Wed, 4 Dec 2024 08:21:33 -0700 Subject: [PATCH 2/3] Fix null reference exception in MutableValue.Equals --- src/Lucene.Net/Util/Mutable/MutableValue.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Lucene.Net/Util/Mutable/MutableValue.cs b/src/Lucene.Net/Util/Mutable/MutableValue.cs index 45c77f6bab..3701c36628 100644 --- a/src/Lucene.Net/Util/Mutable/MutableValue.cs +++ b/src/Lucene.Net/Util/Mutable/MutableValue.cs @@ -82,7 +82,7 @@ public virtual int CompareTo(object other) public override bool Equals(object other) { - return (this.GetType() == other.GetType()) && this.EqualsSameType(other); + return this.GetType() == other?.GetType() && this.EqualsSameType(other); } public override abstract int GetHashCode(); From 53527b536efc1905ba68f585648a5fe6dd993a9b Mon Sep 17 00:00:00 2001 From: Paul Irwin Date: Wed, 4 Dec 2024 12:55:25 -0700 Subject: [PATCH 3/3] Add Equals and GetHashCode to QualityQuery, enavle nullable, clean up CompareTo implementation --- Lucene.Net.sln.DotSettings | 1 + .../Quality/QualityQuery.cs | 58 ++++++++++++------- 2 files changed, 37 insertions(+), 22 deletions(-) diff --git a/Lucene.Net.sln.DotSettings b/Lucene.Net.sln.DotSettings index 6fd109800d..dae1019ebe 100644 --- a/Lucene.Net.sln.DotSettings +++ b/Lucene.Net.sln.DotSettings @@ -1,4 +1,5 @@  True + True True True \ No newline at end of file diff --git a/src/Lucene.Net.Benchmark/Quality/QualityQuery.cs b/src/Lucene.Net.Benchmark/Quality/QualityQuery.cs index 5791fd3b74..b15aac7223 100644 --- a/src/Lucene.Net.Benchmark/Quality/QualityQuery.cs +++ b/src/Lucene.Net.Benchmark/Quality/QualityQuery.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Globalization; +#nullable enable namespace Lucene.Net.Benchmarks.Quality { @@ -49,8 +50,8 @@ public class QualityQuery : IComparable /// The contents of this quality query. public QualityQuery(string queryID, IDictionary nameValPairs) { - this.queryID = queryID; - this.nameValPairs = nameValPairs; + this.queryID = queryID ?? throw new ArgumentNullException(nameof(queryID)); + this.nameValPairs = nameValPairs ?? throw new ArgumentNullException(nameof(nameValPairs)); } /// @@ -66,10 +67,9 @@ public virtual string[] GetNames() /// /// The name whose value should be returned. /// - public virtual string GetValue(string name) + public virtual string? GetValue(string name) { - nameValPairs.TryGetValue(name, out string result); - return result; + return nameValPairs.TryGetValue(name, out string? result) ? result : null; } /// @@ -82,43 +82,57 @@ public virtual string GetValue(string name) /// For a nicer sort of input queries before running them. /// Try first as ints, fall back to string if not int. /// - /// - /// - public virtual int CompareTo(QualityQuery other) + /// The other to compare to. + /// 0 if equal, a negative value if smaller, a positive value if larger. + public virtual int CompareTo(QualityQuery? other) { - try + if (other is null) { - // compare as ints when ids ints - int n = int.Parse(queryID, CultureInfo.InvariantCulture); - int nOther = int.Parse(other.queryID, CultureInfo.InvariantCulture); - return n - nOther; + return 1; } - catch (Exception e) when (e.IsNumberFormatException()) + + if (int.TryParse(queryID, NumberStyles.Integer, CultureInfo.InvariantCulture, out int n) + && int.TryParse(other.queryID, NumberStyles.Integer, CultureInfo.InvariantCulture, out int nOther)) { - // fall back to string comparison - return queryID.CompareToOrdinal(other.queryID); + return n - nOther; } + + // fall back to string comparison + return queryID.CompareToOrdinal(other.queryID); } + // LUCENENET specific - provide Equals and GetHashCode due to providing operator overrides + protected bool Equals(QualityQuery? other) => queryID == other?.queryID; + + public override bool Equals(object? obj) + { + if (obj is null) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != GetType()) return false; + return Equals((QualityQuery)obj); + } + + public override int GetHashCode() => queryID.GetHashCode(); + #region Operator overrides // LUCENENET specific - per csharpsquid:S1210, IComparable should override comparison operators - public static bool operator <(QualityQuery left, QualityQuery right) + public static bool operator <(QualityQuery? left, QualityQuery? right) => left is null ? right is not null : left.CompareTo(right) < 0; - public static bool operator <=(QualityQuery left, QualityQuery right) + public static bool operator <=(QualityQuery? left, QualityQuery? right) => left is null || left.CompareTo(right) <= 0; - public static bool operator >(QualityQuery left, QualityQuery right) + public static bool operator >(QualityQuery? left, QualityQuery? right) => left is not null && left.CompareTo(right) > 0; - public static bool operator >=(QualityQuery left, QualityQuery right) + public static bool operator >=(QualityQuery? left, QualityQuery? right) => left is null ? right is null : left.CompareTo(right) >= 0; - public static bool operator ==(QualityQuery left, QualityQuery right) + public static bool operator ==(QualityQuery? left, QualityQuery? right) => left?.Equals(right) ?? right is null; - public static bool operator !=(QualityQuery left, QualityQuery right) + public static bool operator !=(QualityQuery? left, QualityQuery? right) => !(left == right); #endregion