Skip to content

Commit 0b48e71

Browse files
committed
Optimized SqlValue.cs's CompareTo method by changing the ternary chain into switches.
1 parent 73c953a commit 0b48e71

1 file changed

Lines changed: 37 additions & 23 deletions

File tree

SqlServerSimulator/Storage/SqlValue.cs

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -746,32 +746,46 @@ public bool Equals(SqlValue other) =>
746746
/// responsibility (SQL's NULL-comparison semantics differ from .NET's
747747
/// IComparable convention, so we throw here rather than pick a side).
748748
/// </summary>
749+
/// <remarks>
750+
/// Dispatches on <see cref="SqlType.Category"/> so the hot path is a
751+
/// jump-table-friendly switch rather than the linear type-test chain it
752+
/// replaced. The single-arm collapse for Integer / DateTime / Money relies
753+
/// on the invariant that each type in those categories stores its ordered
754+
/// value directly in <see cref="primitive"/> — Bit's 0/1 sorts as long the
755+
/// same way <see cref="bool.CompareTo(bool)"/> does, all DateTime variants
756+
/// already used <see cref="primitive"/>, and Money/SmallMoney hold scaled
757+
/// integers there. Approximate is the only category that can't unify
758+
/// (the IEEE 754 bit pattern in <see cref="primitive"/> isn't monotonic
759+
/// across the sign bit and mishandles NaN), so it splits Float vs Real.
760+
/// </remarks>
749761
/// <exception cref="InvalidOperationException">Either operand is NULL.</exception>
750762
/// <exception cref="NotSupportedException">The operands' types differ, or comparison for that type isn't implemented yet.</exception>
751763
public int CompareTo(SqlValue other) =>
752-
this.IsNull || other.IsNull ? throw new InvalidOperationException("CompareTo on NULL is undefined; check IsNull before calling.")
753-
: this.Type != other.Type ? throw new NotSupportedException($"Cross-type comparison isn't implemented: {this.Type} vs {other.Type}.")
754-
: this.Type == SqlType.Int32 ? this.AsInt32.CompareTo(other.AsInt32)
755-
: this.Type == SqlType.BigInt ? this.AsInt64.CompareTo(other.AsInt64)
756-
: this.Type == SqlType.SmallInt ? this.AsInt16.CompareTo(other.AsInt16)
757-
: this.Type == SqlType.TinyInt ? this.AsByte.CompareTo(other.AsByte)
758-
: this.Type == SqlType.Bit ? this.AsBoolean.CompareTo(other.AsBoolean)
759-
: IsStringTypeRef(this.Type) ? this.Type.Collation!.Compare(TrimTrailing((string)this.reference!), TrimTrailing((string)other.reference!))
760-
: this.Type is RowVersionSqlType ? this.primitive.CompareTo(other.primitive)
761-
: this.Type is VarbinarySqlType or BinarySqlType or ImageSqlType ? this.AsBytes.AsSpan().SequenceCompareTo(other.AsBytes)
762-
: this.Type == SqlType.Date ? this.primitive.CompareTo(other.primitive)
763-
: this.Type == SqlType.DateTime ? this.primitive.CompareTo(other.primitive)
764-
: this.Type == SqlType.SmallDateTime ? this.primitive.CompareTo(other.primitive)
765-
: this.Type is DateTime2SqlType ? this.primitive.CompareTo(other.primitive)
766-
: this.Type is TimeSqlType ? this.primitive.CompareTo(other.primitive)
767-
: this.Type is DateTimeOffsetSqlType ? this.primitive.CompareTo(other.primitive)
768-
: this.Type == SqlType.UniqueIdentifier ? new SqlGuid(this.AsGuid).CompareTo(new SqlGuid(other.AsGuid))
769-
: this.Type == SqlType.HierarchyId ? HierarchyIdSqlType.ComparePaths(this.AsHierarchyId, other.AsHierarchyId)
770-
: this.Type is DecimalSqlType ? this.AsDecimal.CompareTo(other.AsDecimal)
771-
: this.Type == SqlType.Float ? this.AsDouble.CompareTo(other.AsDouble)
772-
: this.Type == SqlType.Real ? this.AsSingle.CompareTo(other.AsSingle)
773-
: this.Type == SqlType.Money || this.Type == SqlType.SmallMoney ? this.primitive.CompareTo(other.primitive)
774-
: throw new NotSupportedException($"Comparison for {this.Type} isn't implemented yet.");
764+
this.IsNull || other.IsNull
765+
? throw new InvalidOperationException("CompareTo on NULL is undefined; check IsNull before calling.")
766+
: this.Type != other.Type
767+
? throw new NotSupportedException($"Cross-type comparison isn't implemented: {this.Type} vs {other.Type}.")
768+
: this.Type.Category switch
769+
{
770+
SqlTypeCategory.Integer or SqlTypeCategory.DateTime or SqlTypeCategory.Money
771+
=> this.primitive.CompareTo(other.primitive),
772+
SqlTypeCategory.Decimal => this.AsDecimal.CompareTo(other.AsDecimal),
773+
SqlTypeCategory.Approximate => this.Type == SqlType.Float
774+
? this.AsDouble.CompareTo(other.AsDouble)
775+
: this.AsSingle.CompareTo(other.AsSingle),
776+
SqlTypeCategory.String => this.Type.Collation!.Compare(
777+
TrimTrailing((string)this.reference!),
778+
TrimTrailing((string)other.reference!)),
779+
SqlTypeCategory.UniqueIdentifier => new SqlGuid(this.AsGuid).CompareTo(new SqlGuid(other.AsGuid)),
780+
SqlTypeCategory.Other => this.Type switch
781+
{
782+
VarbinarySqlType or BinarySqlType or ImageSqlType => this.AsBytes.AsSpan().SequenceCompareTo(other.AsBytes),
783+
RowVersionSqlType => this.primitive.CompareTo(other.primitive),
784+
HierarchyIdSqlType => HierarchyIdSqlType.ComparePaths(this.AsHierarchyId, other.AsHierarchyId),
785+
_ => throw new NotSupportedException($"Comparison for {this.Type} isn't implemented yet."),
786+
},
787+
_ => throw new NotSupportedException($"Comparison for {this.Type} isn't implemented yet."),
788+
};
775789

776790
public override bool Equals(object? obj) => obj is SqlValue other && this.Equals(other);
777791

0 commit comments

Comments
 (0)