@@ -23,41 +23,50 @@ library Sort {
23
23
mstore (a, 0 ) // For insertion sort's inner loop to terminate.
24
24
25
25
// Let the stack be the start of the free memory.
26
- let stackBottom := mload (0x40 )
27
- let stack := add (stackBottom, 0x40 )
26
+ let stack := mload (0x40 )
27
+ let stackBottom := stack
28
28
29
- {
29
+ if iszero ( lt (n, 2 )) {
30
30
// Push `l` and `h` to the stack.
31
31
// The `shl` by 5 is equivalent to multiplying by `0x20`.
32
32
let l := add (a, 0x20 )
33
- let h := add (a, shl (5 , n))
34
- mstore (stackBottom, l)
35
- mstore (add (stackBottom, 0x20 ), h)
33
+ let h := add (l, shl (5 , n))
36
34
37
- let s := 0 // Number of out of order elements.
38
35
let u := mload (l) // Previous slot value, `u`.
36
+ let j := add (l, 0x20 )
37
+ let s := 0 // Number of out of order elements.
38
+
39
39
// prettier-ignore
40
- for { let j := add (l, 0x20 ) } iszero ( gt (j, h)) { j := add (j, 0x20 ) } {
40
+ for {} 1 { } {
41
41
let v := mload (j) // Current slot value, `v`.
42
42
s := add (s, gt (u, v)) // Increment `s` by 1 if out of order.
43
43
u := v // Set previous slot value to current slot value.
44
+ j := add (j, 0x20 )
45
+ // prettier-ignore
46
+ if iszero (lt (j, h)) { break }
47
+ }
48
+
49
+ // If the array is not sorted or reverse sorted,
50
+ // push `l` and `h` onto the `stack`.
51
+ if iszero (or (iszero (s), eq (add (s, 1 ), n))) {
52
+ mstore (stack, l)
53
+ mstore (add (stack, 0x20 ), sub (h, 0x20 ))
54
+ stack := add (stack, 0x40 )
44
55
}
45
- // If the array is sorted, or reverse sorted,
46
- // subtract `0x40` from `stack` to make it equal to `stackBottom`,
47
- // which skips the sort.
48
- // `shl` 6 is equivalent to multiplying by `0x40`.
49
- stack := sub (stack, shl (6 , or (iszero (s), eq (add (s, 1 ), n))))
50
56
51
57
// If 50% or more of the elements are out of order,
52
58
// reverse the array.
53
59
if iszero (lt (shl (1 , s), n)) {
60
+ h := sub (h, 0x20 )
54
61
// prettier-ignore
55
- for {} lt (l, h) {} {
62
+ for {} 1 {} {
56
63
let t := mload (l)
57
64
mstore (l, mload (h))
58
65
mstore (h, t)
59
66
h := sub (h, 0x20 )
60
67
l := add (l, 0x20 )
68
+ // prettier-ignore
69
+ if iszero (lt (l, h)) { break }
61
70
}
62
71
}
63
72
}
@@ -72,10 +81,17 @@ library Sort {
72
81
let l := mload (stack)
73
82
let h := mload (add (stack, 0x20 ))
74
83
75
- // Do insertion sort if `h - l < 0x20 * 16`.
76
- if iszero (shr (9 , sub (h, l))) {
84
+ // Do insertion sort if `h - l <= 0x20 * 12`.
85
+ // Threshold is fine-tuned via trial and error.
86
+ if iszero (gt (sub (h, l), 0x180 )) {
87
+ // Hardcode sort the first 2 elements.
88
+ let t := mload (add (l, 0x20 ))
89
+ if iszero (lt (mload (l), t)) {
90
+ mstore (add (l, 0x20 ), mload (l))
91
+ mstore (l, t)
92
+ }
77
93
// prettier-ignore
78
- for { let i := add (l, 0x20 ) } iszero (gt (i, h)) { i := add (i, 0x20 ) } {
94
+ for { let i := add (l, 0x40 ) } iszero (gt (i, h)) { i := add (i, 0x20 ) } {
79
95
let k := mload (i) // Key.
80
96
let j := sub (i, 0x20 ) // The slot before the current slot.
81
97
let v := mload (j) // The value of `j`.
@@ -134,15 +150,13 @@ library Sort {
134
150
{
135
151
// We can skip `mstore(stack, l)`.
136
152
mstore (add (stack, 0x20 ), p)
137
- // `shl` 6 is equivalent to multiplying by `0x40`.
138
- stack := add (stack, shl (6 , gt (p, l)))
153
+ stack := add (stack, mul (0x40 , gt (p, l)))
139
154
}
140
155
// If slice on right of pivot is non-empty, push onto stack.
141
156
{
142
157
mstore (stack, add (p, 0x20 ))
143
158
mstore (add (stack, 0x20 ), h)
144
- // `shl` 6 is equivalent to multiplying by `0x40`.
145
- stack := add (stack, shl (6 , lt (add (p, 0x20 ), h)))
159
+ stack := add (stack, mul (0x40 , lt (add (p, 0x20 ), h)))
146
160
}
147
161
}
148
162
mstore (a, n) // Restore the length of `a`.
0 commit comments