From 149465f0d8fed5e81ee9d17ad6f2f60c291f541c Mon Sep 17 00:00:00 2001 From: "Akshat(DeterminedSage)" Date: Thu, 24 Apr 2025 22:00:21 +0530 Subject: [PATCH 01/10] Implement opCmp for Nullable objects Fixes : #10743 --- code.patch | 146 +++++++++++++++++++++++++++++++++++++++++++++++++ std/typecons.d | 106 +++++++++++++++++++++++++++++++++++ 2 files changed, 252 insertions(+) create mode 100644 code.patch diff --git a/code.patch b/code.patch new file mode 100644 index 00000000000..1468982b35d --- /dev/null +++ b/code.patch @@ -0,0 +1,146 @@ +diff --git a/std/typecons.d b/std/typecons.d +index d7f86d17a..846b68f2b 100644 +--- a/std/typecons.d ++++ b/std/typecons.d +@@ -3675,6 +3675,141 @@ struct Nullable(T) + + private bool _isNull = true; + ++ /** ++ * Compares two Nullable values. ++ * - If one is null and the other is not, the null one is considered smaller. ++ * - If both are null, they are equal. ++ * - If both are non-null, compares the payloads. ++ * ++ * Returns: ++ * Negative if `this < rhs`, zero if equal, positive if `this > rhs`. ++ */ ++ int opCmp(this This, Rhs)(auto ref Rhs rhs) const ++ if (is(typeof(_value.payload < rhs.get)) && is(typeof(_value.payload > rhs.get))) ++ { ++ static if (is(Rhs == This)) ++ { ++ if (_isNull) ++ return rhs._isNull ? 0 : -1; ++ else if (rhs._isNull) ++ return 1; ++ else ++ return _value.payload < rhs._value.payload ? -1 : ++ _value.payload > rhs._value.payload ? 1 : 0; ++ } ++ else ++ { ++ static if (is(typeof(rhs.isNull))) ++ { ++ if (_isNull) ++ return rhs.isNull ? 0 : -1; ++ else if (rhs.isNull) ++ return 1; ++ else ++ return _value.payload < rhs.get ? -1 : ++ _value.payload > rhs.get ? 1 : 0; ++ } ++ else ++ { ++ return _isNull ? -1 : (_value.payload < rhs ? -1 : (_value.payload > rhs ? 1 : 0)); ++ } ++ } ++ } ++ ++ /// Nullable comparison tests ++ // Test 1: Basic Comparison ++ @safe unittest { ++ Nullable!int a = 5; ++ Nullable!int b = Nullable!int.init; // null ++ ++ assert(a > b); ++ assert(b < a); ++ assert(a == a); ++ assert(b == b); ++ } ++ ++ // Test 2: Sorting an array of Nullable ++ @safe unittest { ++ import std.algorithm : sort; ++ ++ auto arr = [Nullable!int(10), Nullable!int(), Nullable!int(5), Nullable!int()]; ++ sort(arr); ++ ++ assert(arr[0].isNull); ++ assert(arr[1].isNull); ++ assert(arr[2].get == 5); ++ assert(arr[3].get == 10); ++ } ++ ++ // Test 3: Uniqueness with Nullable values ++ @safe unittest { ++ import std.algorithm : sort, uniq; ++ import std.array : array; ++ ++ auto arr = [Nullable!int(10), Nullable!int(), Nullable!int(5), Nullable!int(10), Nullable!int()]; ++ sort(arr); ++ auto uniqueVals = arr.uniq.array; ++ ++ assert(uniqueVals.length == 3); ++ assert(uniqueVals[0].isNull); ++ assert(uniqueVals[1].get == 5); ++ assert(uniqueVals[2].get == 10); ++ } ++ ++ // Test 4: Nullable inside a struct with sorting ++ @safe unittest { ++ import std.algorithm : sort; ++ ++ struct Person { ++ string name; ++ Nullable!int age; ++ ++ int opCmp(const Person other) const { ++ return age.opCmp(other.age); ++ } ++ } ++ ++ Person[] people = [ ++ Person("Alice", Nullable!int(30)), ++ Person("Bob", Nullable!int()), ++ Person("Charlie", Nullable!int(25)), ++ ]; ++ ++ sort(people); ++ assert(people[0].name == "Bob"); ++ assert(people[1].name == "Charlie"); ++ assert(people[2].name == "Alice"); ++ } ++ ++ // Test 5: Nullable with custom type ++ @safe unittest { ++ import std.algorithm : sort; ++ import std.format : format; ++ ++ struct Point { ++ int x, y; ++ ++ int opCmp(const Point other) const { ++ return (x * x + y * y) - (other.x * other.x + other.y * other.y); ++ } ++ ++ string toString() const { ++ return format("(%s,%s)", x, y); ++ } ++ } ++ ++ auto arr = [ ++ Nullable!Point(Point(3, 4)), // distance = 25 ++ Nullable!Point(), // null ++ Nullable!Point(Point(1, 1)) // distance = 2 ++ ]; ++ ++ sort(arr); ++ assert(arr[0].isNull); ++ assert(arr[1].get == Point(1, 1)); ++ assert(arr[2].get == Point(3, 4)); ++ } ++ + /** + * Constructor initializing `this` with `value`. + * diff --git a/std/typecons.d b/std/typecons.d index d7f86d17aed..5ce04269e52 100644 --- a/std/typecons.d +++ b/std/typecons.d @@ -3675,6 +3675,112 @@ struct Nullable(T) private bool _isNull = true; + /** + * Compares two Nullable values. + * - If one is null and the other is not, the null one is considered smaller. + * - If both are null, they are equal. + * - If both are non-null, compares the payloads. + * + * Returns: + * Negative if `this < rhs`, zero if equal, positive if `this > rhs`. + */ + int opCmp(this This, Rhs)(auto ref Rhs rhs) const + if (is(typeof(_value.payload < rhs.get)) && is(typeof(_value.payload > rhs.get))) + { + static if (is(Rhs == This)) + { + if (_isNull) + return rhs._isNull ? 0 : -1; + else if (rhs._isNull) + return 1; + else + return _value.payload < rhs._value.payload ? -1 : + _value.payload > rhs._value.payload ? 1 : 0; + } + else + { + static if (is(typeof(rhs.isNull))) + { + if (_isNull) + return rhs.isNull ? 0 : -1; + else if (rhs.isNull) + return 1; + else + return _value.payload < rhs.get ? -1 : + _value.payload > rhs.get ? 1 : 0; + } + else + { + return _isNull ? -1 : (_value.payload < rhs ? -1 : (_value.payload > rhs ? 1 : 0)); + } + } + } + + /// Nullable comparison tests + // Test 1: Basic Comparison + @safe unittest { + Nullable!int a = 5; + Nullable!int b = Nullable!int.init; // null + + assert(a > b); + assert(b < a); + assert(a == a); + assert(b == b); + } + + // Test 2: Sorting an array of Nullable + @safe unittest { + import std.algorithm : sort; + + auto arr = [Nullable!int(10), Nullable!int(), Nullable!int(5), Nullable!int()]; + sort(arr); + + assert(arr[0].isNull); + assert(arr[1].isNull); + assert(arr[2].get == 5); + assert(arr[3].get == 10); + } + + // Test 3: Uniqueness with Nullable values + @safe unittest { + import std.algorithm : sort, uniq; + import std.array : array; + + auto arr = [Nullable!int(10), Nullable!int(), Nullable!int(5), Nullable!int(10), Nullable!int()]; + sort(arr); + auto uniqueVals = arr.uniq.array; + + assert(uniqueVals.length == 3); + assert(uniqueVals[0].isNull); + assert(uniqueVals[1].get == 5); + assert(uniqueVals[2].get == 10); + } + + // Test 4: Nullable inside a struct with sorting + @safe unittest { + import std.algorithm : sort; + + struct Person { + string name; + Nullable!int age; + + int opCmp(const Person other) const { + return age.opCmp(other.age); + } + } + + Person[] people = [ + Person("Alice", Nullable!int(30)), + Person("Bob", Nullable!int()), + Person("Charlie", Nullable!int(25)), + ]; + + sort(people); + assert(people[0].name == "Bob"); + assert(people[1].name == "Charlie"); + assert(people[2].name == "Alice"); + } + /** * Constructor initializing `this` with `value`. * From 643a1b2c3067585d8754050595a26e804867fdb9 Mon Sep 17 00:00:00 2001 From: Akshat Sharma Date: Thu, 24 Apr 2025 23:51:03 +0530 Subject: [PATCH 02/10] Delete code.patch --- code.patch | 146 ----------------------------------------------------- 1 file changed, 146 deletions(-) delete mode 100644 code.patch diff --git a/code.patch b/code.patch deleted file mode 100644 index 1468982b35d..00000000000 --- a/code.patch +++ /dev/null @@ -1,146 +0,0 @@ -diff --git a/std/typecons.d b/std/typecons.d -index d7f86d17a..846b68f2b 100644 ---- a/std/typecons.d -+++ b/std/typecons.d -@@ -3675,6 +3675,141 @@ struct Nullable(T) - - private bool _isNull = true; - -+ /** -+ * Compares two Nullable values. -+ * - If one is null and the other is not, the null one is considered smaller. -+ * - If both are null, they are equal. -+ * - If both are non-null, compares the payloads. -+ * -+ * Returns: -+ * Negative if `this < rhs`, zero if equal, positive if `this > rhs`. -+ */ -+ int opCmp(this This, Rhs)(auto ref Rhs rhs) const -+ if (is(typeof(_value.payload < rhs.get)) && is(typeof(_value.payload > rhs.get))) -+ { -+ static if (is(Rhs == This)) -+ { -+ if (_isNull) -+ return rhs._isNull ? 0 : -1; -+ else if (rhs._isNull) -+ return 1; -+ else -+ return _value.payload < rhs._value.payload ? -1 : -+ _value.payload > rhs._value.payload ? 1 : 0; -+ } -+ else -+ { -+ static if (is(typeof(rhs.isNull))) -+ { -+ if (_isNull) -+ return rhs.isNull ? 0 : -1; -+ else if (rhs.isNull) -+ return 1; -+ else -+ return _value.payload < rhs.get ? -1 : -+ _value.payload > rhs.get ? 1 : 0; -+ } -+ else -+ { -+ return _isNull ? -1 : (_value.payload < rhs ? -1 : (_value.payload > rhs ? 1 : 0)); -+ } -+ } -+ } -+ -+ /// Nullable comparison tests -+ // Test 1: Basic Comparison -+ @safe unittest { -+ Nullable!int a = 5; -+ Nullable!int b = Nullable!int.init; // null -+ -+ assert(a > b); -+ assert(b < a); -+ assert(a == a); -+ assert(b == b); -+ } -+ -+ // Test 2: Sorting an array of Nullable -+ @safe unittest { -+ import std.algorithm : sort; -+ -+ auto arr = [Nullable!int(10), Nullable!int(), Nullable!int(5), Nullable!int()]; -+ sort(arr); -+ -+ assert(arr[0].isNull); -+ assert(arr[1].isNull); -+ assert(arr[2].get == 5); -+ assert(arr[3].get == 10); -+ } -+ -+ // Test 3: Uniqueness with Nullable values -+ @safe unittest { -+ import std.algorithm : sort, uniq; -+ import std.array : array; -+ -+ auto arr = [Nullable!int(10), Nullable!int(), Nullable!int(5), Nullable!int(10), Nullable!int()]; -+ sort(arr); -+ auto uniqueVals = arr.uniq.array; -+ -+ assert(uniqueVals.length == 3); -+ assert(uniqueVals[0].isNull); -+ assert(uniqueVals[1].get == 5); -+ assert(uniqueVals[2].get == 10); -+ } -+ -+ // Test 4: Nullable inside a struct with sorting -+ @safe unittest { -+ import std.algorithm : sort; -+ -+ struct Person { -+ string name; -+ Nullable!int age; -+ -+ int opCmp(const Person other) const { -+ return age.opCmp(other.age); -+ } -+ } -+ -+ Person[] people = [ -+ Person("Alice", Nullable!int(30)), -+ Person("Bob", Nullable!int()), -+ Person("Charlie", Nullable!int(25)), -+ ]; -+ -+ sort(people); -+ assert(people[0].name == "Bob"); -+ assert(people[1].name == "Charlie"); -+ assert(people[2].name == "Alice"); -+ } -+ -+ // Test 5: Nullable with custom type -+ @safe unittest { -+ import std.algorithm : sort; -+ import std.format : format; -+ -+ struct Point { -+ int x, y; -+ -+ int opCmp(const Point other) const { -+ return (x * x + y * y) - (other.x * other.x + other.y * other.y); -+ } -+ -+ string toString() const { -+ return format("(%s,%s)", x, y); -+ } -+ } -+ -+ auto arr = [ -+ Nullable!Point(Point(3, 4)), // distance = 25 -+ Nullable!Point(), // null -+ Nullable!Point(Point(1, 1)) // distance = 2 -+ ]; -+ -+ sort(arr); -+ assert(arr[0].isNull); -+ assert(arr[1].get == Point(1, 1)); -+ assert(arr[2].get == Point(3, 4)); -+ } -+ - /** - * Constructor initializing `this` with `value`. - * From fb2102aa07aa2300913797f30980dfdfcedfa5f0 Mon Sep 17 00:00:00 2001 From: Akshat Sharma Date: Thu, 24 Apr 2025 23:58:56 +0530 Subject: [PATCH 03/10] format as per D style --- std/typecons.d | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/std/typecons.d b/std/typecons.d index 5ce04269e52..152443c674f 100644 --- a/std/typecons.d +++ b/std/typecons.d @@ -3718,7 +3718,8 @@ struct Nullable(T) /// Nullable comparison tests // Test 1: Basic Comparison - @safe unittest { + @safe unittest + { Nullable!int a = 5; Nullable!int b = Nullable!int.init; // null @@ -3729,9 +3730,10 @@ struct Nullable(T) } // Test 2: Sorting an array of Nullable - @safe unittest { + @safe unittest + { import std.algorithm : sort; - + auto arr = [Nullable!int(10), Nullable!int(), Nullable!int(5), Nullable!int()]; sort(arr); @@ -3742,7 +3744,8 @@ struct Nullable(T) } // Test 3: Uniqueness with Nullable values - @safe unittest { + @safe unittest + { import std.algorithm : sort, uniq; import std.array : array; @@ -3757,7 +3760,8 @@ struct Nullable(T) } // Test 4: Nullable inside a struct with sorting - @safe unittest { + @safe unittest + { import std.algorithm : sort; struct Person { From 0ff000895c2611eef90e5449a6449c5a79501837 Mon Sep 17 00:00:00 2001 From: Akshat Sharma Date: Fri, 25 Apr 2025 00:13:36 +0530 Subject: [PATCH 04/10] Update typecons.d format as per D style --- std/typecons.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/typecons.d b/std/typecons.d index 152443c674f..05902402568 100644 --- a/std/typecons.d +++ b/std/typecons.d @@ -3733,7 +3733,7 @@ struct Nullable(T) @safe unittest { import std.algorithm : sort; - + auto arr = [Nullable!int(10), Nullable!int(), Nullable!int(5), Nullable!int()]; sort(arr); From cb391a8eb0e265362737d877c3787992c7c31ca3 Mon Sep 17 00:00:00 2001 From: Akshat Sharma Date: Fri, 25 Apr 2025 00:25:33 +0530 Subject: [PATCH 05/10] Update typecons.d Format as per D style --- std/typecons.d | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/std/typecons.d b/std/typecons.d index 05902402568..5b645eec8f4 100644 --- a/std/typecons.d +++ b/std/typecons.d @@ -3675,6 +3675,9 @@ struct Nullable(T) private bool _isNull = true; + import std.algorithm : sort, uniq; + import std.array : array; + /** * Compares two Nullable values. * - If one is null and the other is not, the null one is considered smaller. @@ -3732,7 +3735,6 @@ struct Nullable(T) // Test 2: Sorting an array of Nullable @safe unittest { - import std.algorithm : sort; auto arr = [Nullable!int(10), Nullable!int(), Nullable!int(5), Nullable!int()]; sort(arr); @@ -3746,8 +3748,6 @@ struct Nullable(T) // Test 3: Uniqueness with Nullable values @safe unittest { - import std.algorithm : sort, uniq; - import std.array : array; auto arr = [Nullable!int(10), Nullable!int(), Nullable!int(5), Nullable!int(10), Nullable!int()]; sort(arr); @@ -3762,7 +3762,6 @@ struct Nullable(T) // Test 4: Nullable inside a struct with sorting @safe unittest { - import std.algorithm : sort; struct Person { string name; From fe82e26fec0c3f8a26bf3c3154c2aea22377b254 Mon Sep 17 00:00:00 2001 From: Akshat Sharma Date: Fri, 25 Apr 2025 00:36:57 +0530 Subject: [PATCH 06/10] Update typecons.d Format as per D style --- std/typecons.d | 2 ++ 1 file changed, 2 insertions(+) diff --git a/std/typecons.d b/std/typecons.d index 5b645eec8f4..3a457ff6cda 100644 --- a/std/typecons.d +++ b/std/typecons.d @@ -75,6 +75,8 @@ import std.meta : AliasSeq, allSatisfy; import std.range.primitives : isOutputRange; import std.traits; import std.internal.attributes : betterC; +import std.algorithm : sort, uniq; +import std.array : array; /// Value tuples @safe unittest From fb07e990bab0b432be0dc54ad948f3c0030c876d Mon Sep 17 00:00:00 2001 From: Akshat Sharma Date: Fri, 25 Apr 2025 00:46:49 +0530 Subject: [PATCH 07/10] Update typecons.d Format as per D style --- std/typecons.d | 60 +------------------------------------------------- 1 file changed, 1 insertion(+), 59 deletions(-) diff --git a/std/typecons.d b/std/typecons.d index 3a457ff6cda..b5deaa5afc9 100644 --- a/std/typecons.d +++ b/std/typecons.d @@ -75,8 +75,6 @@ import std.meta : AliasSeq, allSatisfy; import std.range.primitives : isOutputRange; import std.traits; import std.internal.attributes : betterC; -import std.algorithm : sort, uniq; -import std.array : array; /// Value tuples @safe unittest @@ -3677,9 +3675,6 @@ struct Nullable(T) private bool _isNull = true; - import std.algorithm : sort, uniq; - import std.array : array; - /** * Compares two Nullable values. * - If one is null and the other is not, the null one is considered smaller. @@ -3721,8 +3716,7 @@ struct Nullable(T) } } - /// Nullable comparison tests - // Test 1: Basic Comparison + // Basic Null Comparison @safe unittest { Nullable!int a = 5; @@ -3734,58 +3728,6 @@ struct Nullable(T) assert(b == b); } - // Test 2: Sorting an array of Nullable - @safe unittest - { - - auto arr = [Nullable!int(10), Nullable!int(), Nullable!int(5), Nullable!int()]; - sort(arr); - - assert(arr[0].isNull); - assert(arr[1].isNull); - assert(arr[2].get == 5); - assert(arr[3].get == 10); - } - - // Test 3: Uniqueness with Nullable values - @safe unittest - { - - auto arr = [Nullable!int(10), Nullable!int(), Nullable!int(5), Nullable!int(10), Nullable!int()]; - sort(arr); - auto uniqueVals = arr.uniq.array; - - assert(uniqueVals.length == 3); - assert(uniqueVals[0].isNull); - assert(uniqueVals[1].get == 5); - assert(uniqueVals[2].get == 10); - } - - // Test 4: Nullable inside a struct with sorting - @safe unittest - { - - struct Person { - string name; - Nullable!int age; - - int opCmp(const Person other) const { - return age.opCmp(other.age); - } - } - - Person[] people = [ - Person("Alice", Nullable!int(30)), - Person("Bob", Nullable!int()), - Person("Charlie", Nullable!int(25)), - ]; - - sort(people); - assert(people[0].name == "Bob"); - assert(people[1].name == "Charlie"); - assert(people[2].name == "Alice"); - } - /** * Constructor initializing `this` with `value`. * From 95a092bf14624e2176c7a6e5ab23078375a3d739 Mon Sep 17 00:00:00 2001 From: Akshat Sharma Date: Fri, 25 Apr 2025 09:13:19 +0530 Subject: [PATCH 08/10] Update typecons.d Format as per D style --- std/typecons.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/typecons.d b/std/typecons.d index b5deaa5afc9..2b96db0d938 100644 --- a/std/typecons.d +++ b/std/typecons.d @@ -3720,7 +3720,7 @@ struct Nullable(T) @safe unittest { Nullable!int a = 5; - Nullable!int b = Nullable!int.init; // null + Nullable!int b = Nullable!int.init; assert(a > b); assert(b < a); From 6719043308e88116c9cbe87463922035ed0d3512 Mon Sep 17 00:00:00 2001 From: Akshat Sharma Date: Sat, 26 Apr 2025 19:35:21 +0530 Subject: [PATCH 09/10] Update std/typecons.d Co-authored-by: Richard (Rikki) Andrew Cattermole --- std/typecons.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/typecons.d b/std/typecons.d index 2b96db0d938..bd72cc0ac04 100644 --- a/std/typecons.d +++ b/std/typecons.d @@ -3687,7 +3687,7 @@ struct Nullable(T) int opCmp(this This, Rhs)(auto ref Rhs rhs) const if (is(typeof(_value.payload < rhs.get)) && is(typeof(_value.payload > rhs.get))) { - static if (is(Rhs == This)) + static if (is(Rhs == Nullable)) { if (_isNull) return rhs._isNull ? 0 : -1; From cb8d3ec8f3a3edfff9235a20fb1c06a91865ebda Mon Sep 17 00:00:00 2001 From: Akshat Sharma Date: Sat, 26 Apr 2025 19:53:45 +0530 Subject: [PATCH 10/10] Update typecons.d Remove extra parameter --- std/typecons.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/typecons.d b/std/typecons.d index bd72cc0ac04..da812015e65 100644 --- a/std/typecons.d +++ b/std/typecons.d @@ -3684,7 +3684,7 @@ struct Nullable(T) * Returns: * Negative if `this < rhs`, zero if equal, positive if `this > rhs`. */ - int opCmp(this This, Rhs)(auto ref Rhs rhs) const + int opCmp(Rhs)(auto ref Rhs rhs) const if (is(typeof(_value.payload < rhs.get)) && is(typeof(_value.payload > rhs.get))) { static if (is(Rhs == Nullable))