| ... | @@ -47,10 +47,10 @@ pub fn pdqContext(a: usize, b: usize, context: anytype) void { | ... | @@ -47,10 +47,10 @@ pub fn pdqContext(a: usize, b: usize, context: anytype) void { |
| 47 | const max_limit = std.math.floorPowerOfTwo(usize, b - a) + 1; | 47 | const max_limit = std.math.floorPowerOfTwo(usize, b - a) + 1; |
| 48 | | 48 | |
| 49 | // set upper bound on stack memory usage. | 49 | // set upper bound on stack memory usage. |
| 50 | const Range = struct { a: usize, b: usize, limit: usize }; | 50 | const Range = struct { a: usize, b: usize, limit: usize, leftmost: bool }; |
| 51 | const stack_size = math.log2(math.maxInt(usize) + 1); | 51 | const stack_size = math.log2(math.maxInt(usize) + 1); |
| 52 | var stack: [stack_size]Range = undefined; | 52 | var stack: [stack_size]Range = undefined; |
| 53 | var range = Range{ .a = a, .b = b, .limit = max_limit }; | 53 | var range = Range{ .a = a, .b = b, .limit = max_limit, .leftmost = true }; |
| 54 | var top: usize = 0; | 54 | var top: usize = 0; |
| 55 | | 55 | |
| 56 | while (true) { | 56 | while (true) { |
| ... | @@ -62,7 +62,11 @@ pub fn pdqContext(a: usize, b: usize, context: anytype) void { | ... | @@ -62,7 +62,11 @@ pub fn pdqContext(a: usize, b: usize, context: anytype) void { |
| 62 | | 62 | |
| 63 | // very short slices get sorted using insertion sort. | 63 | // very short slices get sorted using insertion sort. |
| 64 | if (len <= max_insertion) { | 64 | if (len <= max_insertion) { |
| 65 | break sort.insertionContext(range.a, range.b, context); | 65 | if (range.leftmost) { |
| | 66 | break sort.insertionContext(range.a, range.b, context); |
| | 67 | } else { |
| | 68 | break unguardedInsertionContext(range.a, range.b, context); |
| | 69 | } |
| 66 | } | 70 | } |
| 67 | | 71 | |
| 68 | // if too many bad pivot choices were made, simply fall back to heapsort in order to | 72 | // if too many bad pivot choices were made, simply fall back to heapsort in order to |
| ... | @@ -115,12 +119,13 @@ pub fn pdqContext(a: usize, b: usize, context: anytype) void { | ... | @@ -115,12 +119,13 @@ pub fn pdqContext(a: usize, b: usize, context: anytype) void { |
| 115 | const balanced_threshold = len / 8; | 119 | const balanced_threshold = len / 8; |
| 116 | if (left_len < right_len) { | 120 | if (left_len < right_len) { |
| 117 | was_balanced = left_len >= balanced_threshold; | 121 | was_balanced = left_len >= balanced_threshold; |
| 118 | stack[top] = .{ .a = range.a, .b = mid, .limit = range.limit }; | 122 | stack[top] = .{ .a = range.a, .b = mid, .limit = range.limit, .leftmost = range.leftmost }; |
| 119 | top += 1; | 123 | top += 1; |
| 120 | range.a = mid + 1; | 124 | range.a = mid + 1; |
| | 125 | range.leftmost = false; |
| 121 | } else { | 126 | } else { |
| 122 | was_balanced = right_len >= balanced_threshold; | 127 | was_balanced = right_len >= balanced_threshold; |
| 123 | stack[top] = .{ .a = mid + 1, .b = range.b, .limit = range.limit }; | 128 | stack[top] = .{ .a = mid + 1, .b = range.b, .limit = range.limit, .leftmost = false }; |
| 124 | top += 1; | 129 | top += 1; |
| 125 | range.b = mid; | 130 | range.b = mid; |
| 126 | } | 131 | } |
| ... | @@ -131,6 +136,18 @@ pub fn pdqContext(a: usize, b: usize, context: anytype) void { | ... | @@ -131,6 +136,18 @@ pub fn pdqContext(a: usize, b: usize, context: anytype) void { |
| 131 | } | 136 | } |
| 132 | } | 137 | } |
| 133 | | 138 | |
| | 139 | /// Insertion sort that assumes `items[a-1]` exists and is <= all elements in `[a, b)`, |
| | 140 | /// allowing the inner loop to skip the bounds check. |
| | 141 | fn unguardedInsertionContext(a: usize, b: usize, context: anytype) void { |
| | 142 | var i = a + 1; |
| | 143 | while (i < b) : (i += 1) { |
| | 144 | var j = i; |
| | 145 | while (context.lessThan(j, j - 1)) : (j -= 1) { |
| | 146 | context.swap(j, j - 1); |
| | 147 | } |
| | 148 | } |
| | 149 | } |
| | 150 | |
| 134 | /// partitions `items[a..b]` into elements smaller than `items[pivot]`, | 151 | /// partitions `items[a..b]` into elements smaller than `items[pivot]`, |
| 135 | /// followed by elements greater than or equal to `items[pivot]`. | 152 | /// followed by elements greater than or equal to `items[pivot]`. |
| 136 | /// | 153 | /// |