@@ -35,22 +35,25 @@ const Allocator = std.mem.Allocator;
3535const testing = std .testing ;
3636const assert = std .debug .assert ;
3737
38- /// Creates a Red-black tree type for the given data type and comparison context.
38+ /// Creates a Red-black tree type for the given data type and key-comparison function.
39+ ///
40+ /// The `compare` function is the same three-way comparator used by every other
41+ /// generic-key container in the library (`BTreeMap`, `SkipListMap`, `SortedSet`,
42+ /// and `CartesianTreeMap`), so tree types compose uniformly.
3943///
4044/// ## Parameters
4145/// - `T`: The data type to store in the tree
42- /// - `Context `: A type providing a `lessThan(ctx, a, b) bool` method for comparison
46+ /// - `compare `: Three-way comparison function returning `std.math.Order`
4347///
4448/// ## Example
4549/// ```zig
46- /// const Context = struct {
47- /// pub fn lessThan(_: @This(), a: i32, b: i32) bool {
48- /// return a < b;
49- /// }
50- /// };
51- /// var tree = RedBlackTreeSet(i32, Context).init(allocator, .{});
50+ /// fn i32Order(a: i32, b: i32) std.math.Order { return std.math.order(a, b); }
51+ /// var tree = RedBlackTreeSet(i32, i32Order).init(allocator);
5252/// ```
53- pub fn RedBlackTreeSet (comptime T : type , comptime Context : type ) type {
53+ pub fn RedBlackTreeSet (
54+ comptime T : type ,
55+ comptime compare : fn (lhs : T , rhs : T ) std.math.Order ,
56+ ) type {
5457 return struct {
5558 const Self = @This ();
5659
@@ -74,19 +77,16 @@ pub fn RedBlackTreeSet(comptime T: type, comptime Context: type) type {
7477
7578 root : ? * Node ,
7679 allocator : Allocator ,
77- context : Context ,
7880 size : usize ,
7981
8082 /// Creates a new empty Red-black tree.
8183 ///
8284 /// ## Parameters
8385 /// - `allocator`: Memory allocator for node allocation
84- /// - `context`: Comparison context instance
85- pub fn init (allocator : Allocator , context : Context ) Self {
86+ pub fn init (allocator : Allocator ) Self {
8687 return Self {
8788 .root = null ,
8889 .allocator = allocator ,
89- .context = context ,
9090 .size = 0 ,
9191 };
9292 }
@@ -124,7 +124,7 @@ pub fn RedBlackTreeSet(comptime T: type, comptime Context: type) type {
124124
125125 /// Inserts or updates a value in the tree.
126126 ///
127- /// If the value already exists (as determined by the context's lessThan method ),
127+ /// If the value already exists (as determined by the `compare` function ),
128128 /// it will be updated. Otherwise, a new node is created.
129129 ///
130130 /// Time complexity: O(log n)
@@ -160,15 +160,15 @@ pub fn RedBlackTreeSet(comptime T: type, comptime Context: type) type {
160160
161161 while (current != null ) {
162162 parent = current ;
163- if (self . context . lessThan (data , current .? .data )) {
163+ if (compare (data , current .? .data ) == .lt ) {
164164 current = current .? .left ;
165165 } else {
166166 current = current .? .right ;
167167 }
168168 }
169169
170170 new_node .parent = parent ;
171- if (self . context . lessThan (data , parent .? .data )) {
171+ if (compare (data , parent .? .data ) == .lt ) {
172172 parent .? .left = new_node ;
173173 } else {
174174 parent .? .right = new_node ;
@@ -442,12 +442,10 @@ pub fn RedBlackTreeSet(comptime T: type, comptime Context: type) type {
442442 var current = self .root ;
443443
444444 while (current ) | node | {
445- if (self .context .lessThan (data , node .data )) {
446- current = node .left ;
447- } else if (self .context .lessThan (node .data , data )) {
448- current = node .right ;
449- } else {
450- return node ;
445+ switch (compare (data , node .data )) {
446+ .lt = > current = node .left ,
447+ .gt = > current = node .right ,
448+ .eq = > return node ,
451449 }
452450 }
453451
@@ -536,24 +534,13 @@ pub fn RedBlackTreeSet(comptime T: type, comptime Context: type) type {
536534 };
537535}
538536
539- /// Default context for comparable types
540- pub fn DefaultContext (comptime T : type ) type {
541- return struct {
542- pub fn lessThan (self : @This (), a : T , b : T ) bool {
543- _ = self ;
544- return a < b ;
545- }
546- };
547- }
548-
549- // Convenience type aliases
550- pub fn RedBlackTreeSetManaged (comptime T : type ) type {
551- return RedBlackTreeSet (T , DefaultContext (T ));
537+ fn i32Compare (lhs : i32 , rhs : i32 ) std.math.Order {
538+ return std .math .order (lhs , rhs );
552539}
553540
554541test "RedBlackTreeSet: basic operations" {
555542 const allocator = std .testing .allocator ;
556- var tree = RedBlackTreeSet (i32 , DefaultContext ( i32 )) .init (allocator , .{} );
543+ var tree = RedBlackTreeSet (i32 , i32Compare ) .init (allocator );
557544 defer tree .deinit ();
558545
559546 try tree .put (10 );
@@ -568,7 +555,7 @@ test "RedBlackTreeSet: basic operations" {
568555
569556test "RedBlackTreeSet: empty tree operations" {
570557 const allocator = std .testing .allocator ;
571- var tree = RedBlackTreeSet (i32 , DefaultContext ( i32 )) .init (allocator , .{} );
558+ var tree = RedBlackTreeSet (i32 , i32Compare ) .init (allocator );
572559 defer tree .deinit ();
573560
574561 try std .testing .expect (! tree .contains (42 ));
@@ -578,7 +565,7 @@ test "RedBlackTreeSet: empty tree operations" {
578565
579566test "RedBlackTreeSet: single element" {
580567 const allocator = std .testing .allocator ;
581- var tree = RedBlackTreeSet (i32 , DefaultContext ( i32 )) .init (allocator , .{} );
568+ var tree = RedBlackTreeSet (i32 , i32Compare ) .init (allocator );
582569 defer tree .deinit ();
583570
584571 try tree .put (42 );
@@ -594,7 +581,7 @@ test "RedBlackTreeSet: single element" {
594581
595582test "RedBlackTreeSet: duplicate insertions" {
596583 const allocator = std .testing .allocator ;
597- var tree = RedBlackTreeSet (i32 , DefaultContext ( i32 )) .init (allocator , .{} );
584+ var tree = RedBlackTreeSet (i32 , i32Compare ) .init (allocator );
598585 defer tree .deinit ();
599586
600587 try tree .put (10 );
@@ -607,7 +594,7 @@ test "RedBlackTreeSet: duplicate insertions" {
607594
608595test "RedBlackTreeSet: sequential insertion" {
609596 const allocator = std .testing .allocator ;
610- var tree = RedBlackTreeSet (i32 , DefaultContext ( i32 )) .init (allocator , .{} );
597+ var tree = RedBlackTreeSet (i32 , i32Compare ) .init (allocator );
611598 defer tree .deinit ();
612599
613600 var i : i32 = 0 ;
@@ -626,7 +613,7 @@ test "RedBlackTreeSet: sequential insertion" {
626613
627614test "RedBlackTreeSet: reverse insertion" {
628615 const allocator = std .testing .allocator ;
629- var tree = RedBlackTreeSet (i32 , DefaultContext ( i32 )) .init (allocator , .{} );
616+ var tree = RedBlackTreeSet (i32 , i32Compare ) .init (allocator );
630617 defer tree .deinit ();
631618
632619 var i : i32 = 50 ;
@@ -640,7 +627,7 @@ test "RedBlackTreeSet: reverse insertion" {
640627
641628test "RedBlackTreeSet: remove from middle" {
642629 const allocator = std .testing .allocator ;
643- var tree = RedBlackTreeSet (i32 , DefaultContext ( i32 )) .init (allocator , .{} );
630+ var tree = RedBlackTreeSet (i32 , i32Compare ) .init (allocator );
644631 defer tree .deinit ();
645632
646633 try tree .put (10 );
@@ -659,7 +646,7 @@ test "RedBlackTreeSet: remove from middle" {
659646
660647test "RedBlackTreeSet: remove root" {
661648 const allocator = std .testing .allocator ;
662- var tree = RedBlackTreeSet (i32 , DefaultContext ( i32 )) .init (allocator , .{} );
649+ var tree = RedBlackTreeSet (i32 , i32Compare ) .init (allocator );
663650 defer tree .deinit ();
664651
665652 try tree .put (10 );
@@ -674,7 +661,7 @@ test "RedBlackTreeSet: remove root" {
674661
675662test "RedBlackTreeSet: minimum and maximum" {
676663 const allocator = std .testing .allocator ;
677- var tree = RedBlackTreeSet (i32 , DefaultContext ( i32 )) .init (allocator , .{} );
664+ var tree = RedBlackTreeSet (i32 , i32Compare ) .init (allocator );
678665 defer tree .deinit ();
679666
680667 try tree .put (10 );
@@ -694,7 +681,7 @@ test "RedBlackTreeSet: minimum and maximum" {
694681
695682test "RedBlackTreeSet: iterator empty tree" {
696683 const allocator = std .testing .allocator ;
697- var tree = RedBlackTreeSet (i32 , DefaultContext ( i32 )) .init (allocator , .{} );
684+ var tree = RedBlackTreeSet (i32 , i32Compare ) .init (allocator );
698685 defer tree .deinit ();
699686
700687 var iter = try tree .iterator ();
@@ -706,7 +693,7 @@ test "RedBlackTreeSet: iterator empty tree" {
706693
707694test "RedBlackTreeSet: clear" {
708695 const allocator = std .testing .allocator ;
709- var tree = RedBlackTreeSet (i32 , DefaultContext ( i32 )) .init (allocator , .{} );
696+ var tree = RedBlackTreeSet (i32 , i32Compare ) .init (allocator );
710697 defer tree .deinit ();
711698
712699 try tree .put (1 );
@@ -720,7 +707,7 @@ test "RedBlackTreeSet: clear" {
720707
721708test "RedBlackTreeSet: negative numbers" {
722709 const allocator = std .testing .allocator ;
723- var tree = RedBlackTreeSet (i32 , DefaultContext ( i32 )) .init (allocator , .{} );
710+ var tree = RedBlackTreeSet (i32 , i32Compare ) .init (allocator );
724711 defer tree .deinit ();
725712
726713 try tree .put (-10 );
@@ -735,7 +722,7 @@ test "RedBlackTreeSet: negative numbers" {
735722
736723test "RedBlackTreeSet: get returns correct node" {
737724 const allocator = std .testing .allocator ;
738- var tree = RedBlackTreeSet (i32 , DefaultContext ( i32 )) .init (allocator , .{} );
725+ var tree = RedBlackTreeSet (i32 , i32Compare ) .init (allocator );
739726 defer tree .deinit ();
740727
741728 try tree .put (10 );
0 commit comments