Skip to content

Commit 581b9f3

Browse files
authored
⚡️ More sort optimizations (ethereum#11)
2 parents 57a20e9 + 4eb3732 commit 581b9f3

15 files changed

+143
-107
lines changed

.gas-snapshot

Lines changed: 80 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,83 @@
1-
Base64Test:testBase64EncodeEmptyString() (gas: 642)
2-
Base64Test:testBase64EncodeSentence() (gas: 4141)
3-
Base64Test:testBase64EncodeToStringWithDoublePadding() (gas: 1217)
4-
Base64Test:testBase64EncodeToStringWithNoPadding() (gas: 1151)
5-
Base64Test:testBase64EncodeToStringWithSinglePadding() (gas: 1174)
6-
Base64Test:testBase64WordBoundary() (gas: 10103)
7-
ECDSATest:testBytes32ToEthSignedMessageHash() (gas: 419)
8-
ECDSATest:testBytesToEthSignedMessageHashEmpty() (gas: 632)
9-
ECDSATest:testBytesToEthSignedMessageHashEmptyLong() (gas: 772)
10-
ECDSATest:testBytesToEthSignedMessageHashShort() (gas: 651)
11-
ECDSATest:testRecoverWithInvalidLongSignature() (gas: 5260)
12-
ECDSATest:testRecoverWithInvalidShortSignature() (gas: 5135)
13-
ECDSATest:testRecoverWithInvalidSignature() (gas: 5410)
14-
ECDSATest:testRecoverWithV0SignatureWithShortEIP2098Format() (gas: 5204)
15-
ECDSATest:testRecoverWithV0SignatureWithVersion00() (gas: 5296)
16-
ECDSATest:testRecoverWithV0SignatureWithVersion27() (gas: 5293)
17-
ECDSATest:testRecoverWithV0SignatureWithWrongVersion() (gas: 5295)
18-
ECDSATest:testRecoverWithV1SignatureWithShortEIP2098Format() (gas: 5203)
19-
ECDSATest:testRecoverWithV1SignatureWithVersion01() (gas: 5317)
20-
ECDSATest:testRecoverWithV1SignatureWithVersion28() (gas: 5273)
21-
ECDSATest:testRecoverWithV1SignatureWithWrongVersion() (gas: 5295)
22-
ECDSATest:testRecoverWithValidSignature() (gas: 5407)
23-
ECDSATest:testRecoverWithWrongSigner() (gas: 5355)
24-
LibBitmapTest:testBitmapGet() (gas: 7892)
25-
LibBitmapTest:testBitmapSet() (gas: 28709)
26-
LibBitmapTest:testBitmapSetTo() (gas: 20717)
27-
LibBitmapTest:testBitmapToggle() (gas: 41620)
28-
LibBitmapTest:testBitmapUnset() (gas: 28733)
29-
LibStringTest:testFromAddressToHexString() (gas: 3386)
30-
LibStringTest:testFromAddressToHexStringWithLeadingZeros() (gas: 3364)
31-
LibStringTest:testStringReplaceLong() (gas: 18416)
32-
LibStringTest:testStringReplaceShort() (gas: 18627)
33-
LibStringTest:testToHexStringFixedLengthInsufficientLength() (gas: 3265)
34-
LibStringTest:testToHexStringFixedLengthPositiveNumberLong() (gas: 5131)
35-
LibStringTest:testToHexStringFixedLengthPositiveNumberShort() (gas: 856)
36-
LibStringTest:testToHexStringFixedLengthUint256Max() (gas: 5089)
37-
LibStringTest:testToHexStringPositiveNumber() (gas: 735)
1+
Base64Test:testBase64EncodeEmptyString() (gas: 575)
2+
Base64Test:testBase64EncodeSentence() (gas: 4098)
3+
Base64Test:testBase64EncodeToStringWithDoublePadding() (gas: 1174)
4+
Base64Test:testBase64EncodeToStringWithNoPadding() (gas: 1152)
5+
Base64Test:testBase64EncodeToStringWithSinglePadding() (gas: 1153)
6+
Base64Test:testBase64WordBoundary() (gas: 10085)
7+
ECDSATest:testBytes32ToEthSignedMessageHash() (gas: 375)
8+
ECDSATest:testBytesToEthSignedMessageHashEmpty() (gas: 610)
9+
ECDSATest:testBytesToEthSignedMessageHashEmptyLong() (gas: 771)
10+
ECDSATest:testBytesToEthSignedMessageHashShort() (gas: 629)
11+
ECDSATest:testRecoverWithInvalidLongSignature() (gas: 5083)
12+
ECDSATest:testRecoverWithInvalidShortSignature() (gas: 4957)
13+
ECDSATest:testRecoverWithInvalidSignature() (gas: 5211)
14+
ECDSATest:testRecoverWithV0SignatureWithShortEIP2098Format() (gas: 5004)
15+
ECDSATest:testRecoverWithV0SignatureWithVersion00() (gas: 5119)
16+
ECDSATest:testRecoverWithV0SignatureWithVersion27() (gas: 5094)
17+
ECDSATest:testRecoverWithV0SignatureWithWrongVersion() (gas: 5118)
18+
ECDSATest:testRecoverWithV1SignatureWithShortEIP2098Format() (gas: 5026)
19+
ECDSATest:testRecoverWithV1SignatureWithVersion01() (gas: 5117)
20+
ECDSATest:testRecoverWithV1SignatureWithVersion28() (gas: 5096)
21+
ECDSATest:testRecoverWithV1SignatureWithWrongVersion() (gas: 5095)
22+
ECDSATest:testRecoverWithValidSignature() (gas: 5186)
23+
ECDSATest:testRecoverWithWrongSigner() (gas: 5178)
24+
LibBitmapTest:testBitmapGet() (gas: 7825)
25+
LibBitmapTest:testBitmapSet() (gas: 28687)
26+
LibBitmapTest:testBitmapSetTo() (gas: 20735)
27+
LibBitmapTest:testBitmapToggle() (gas: 41566)
28+
LibBitmapTest:testBitmapUnset() (gas: 28688)
29+
LibStringTest:testFromAddressToHexString() (gas: 3342)
30+
LibStringTest:testFromAddressToHexStringWithLeadingZeros() (gas: 3341)
31+
LibStringTest:testStringReplaceLong() (gas: 18394)
32+
LibStringTest:testStringReplaceShort() (gas: 18605)
33+
LibStringTest:testToHexStringFixedLengthInsufficientLength() (gas: 3242)
34+
LibStringTest:testToHexStringFixedLengthPositiveNumberLong() (gas: 5087)
35+
LibStringTest:testToHexStringFixedLengthPositiveNumberShort() (gas: 811)
36+
LibStringTest:testToHexStringFixedLengthUint256Max() (gas: 5111)
37+
LibStringTest:testToHexStringPositiveNumber() (gas: 779)
3838
LibStringTest:testToHexStringUint256Max() (gas: 4467)
3939
LibStringTest:testToHexStringZero() (gas: 635)
40-
LibStringTest:testToStringPositiveNumber() (gas: 780)
41-
LibStringTest:testToStringUint256Max() (gas: 6773)
42-
LibStringTest:testToStringZero() (gas: 565)
43-
MerkleProofTest:testVerifyMultiProofIsInvalid() (gas: 4589)
44-
MerkleProofTest:testVerifyMultiProofIsValid() (gas: 5597)
45-
MerkleProofTest:testVerifyProofIsInvalid() (gas: 2405)
46-
MerkleProofTest:testVerifyProofIsValid() (gas: 2459)
47-
SafeTransferLibTest:testApproveWithMissingReturn() (gas: 30776)
48-
SafeTransferLibTest:testApproveWithNonContract() (gas: 2948)
49-
SafeTransferLibTest:testApproveWithReturnsTooMuch() (gas: 31179)
50-
SafeTransferLibTest:testApproveWithStandardERC20() (gas: 30908)
51-
SafeTransferLibTest:testFailApproveWithReturnsFalse() (gas: 5518)
52-
SafeTransferLibTest:testFailApproveWithReturnsTooLittle() (gas: 5460)
53-
SafeTransferLibTest:testFailApproveWithReverting() (gas: 5416)
54-
SafeTransferLibTest:testFailTransferETHToContractWithoutFallback() (gas: 7181)
55-
SafeTransferLibTest:testFailTransferFromWithReturnsFalse() (gas: 13684)
56-
SafeTransferLibTest:testFailTransferFromWithReturnsTooLittle() (gas: 13545)
57-
SafeTransferLibTest:testFailTransferFromWithReverting() (gas: 9868)
58-
SafeTransferLibTest:testFailTransferWithReturnsFalse() (gas: 8481)
59-
SafeTransferLibTest:testFailTransferWithReturnsTooLittle() (gas: 8421)
40+
LibStringTest:testToStringPositiveNumber() (gas: 757)
41+
LibStringTest:testToStringUint256Max() (gas: 6706)
42+
LibStringTest:testToStringZero() (gas: 542)
43+
MerkleProofTest:testVerifyMultiProofIsInvalid() (gas: 4588)
44+
MerkleProofTest:testVerifyMultiProofIsValid() (gas: 5618)
45+
MerkleProofTest:testVerifyProofIsInvalid() (gas: 2427)
46+
MerkleProofTest:testVerifyProofIsValid() (gas: 2414)
47+
SafeTransferLibTest:testApproveWithMissingReturn() (gas: 30799)
48+
SafeTransferLibTest:testApproveWithNonContract() (gas: 2991)
49+
SafeTransferLibTest:testApproveWithReturnsTooMuch() (gas: 31157)
50+
SafeTransferLibTest:testApproveWithStandardERC20() (gas: 30885)
51+
SafeTransferLibTest:testFailApproveWithReturnsFalse() (gas: 5473)
52+
SafeTransferLibTest:testFailApproveWithReturnsTooLittle() (gas: 5438)
53+
SafeTransferLibTest:testFailApproveWithReverting() (gas: 5460)
54+
SafeTransferLibTest:testFailTransferETHToContractWithoutFallback() (gas: 7137)
55+
SafeTransferLibTest:testFailTransferFromWithReturnsFalse() (gas: 13625)
56+
SafeTransferLibTest:testFailTransferFromWithReturnsTooLittle() (gas: 13530)
57+
SafeTransferLibTest:testFailTransferFromWithReverting() (gas: 9875)
58+
SafeTransferLibTest:testFailTransferWithReturnsFalse() (gas: 8458)
59+
SafeTransferLibTest:testFailTransferWithReturnsTooLittle() (gas: 8377)
6060
SafeTransferLibTest:testFailTransferWithReverting() (gas: 8398)
61-
SafeTransferLibTest:testTransferETH() (gas: 34623)
62-
SafeTransferLibTest:testTransferFromWithMissingReturn() (gas: 49412)
63-
SafeTransferLibTest:testTransferFromWithNonContract() (gas: 2995)
64-
SafeTransferLibTest:testTransferFromWithReturnsTooMuch() (gas: 50036)
65-
SafeTransferLibTest:testTransferFromWithStandardERC20() (gas: 47864)
66-
SafeTransferLibTest:testTransferWithMissingReturn() (gas: 36761)
67-
SafeTransferLibTest:testTransferWithNonContract() (gas: 3012)
68-
SafeTransferLibTest:testTransferWithReturnsTooMuch() (gas: 37164)
69-
SafeTransferLibTest:testTransferWithStandardERC20() (gas: 36770)
70-
SortTest:testSortAddressesPsuedorandom() (gas: 91269)
71-
SortTest:testSortAddressesPsuedorandomBrutalizeUpperBits() (gas: 108051)
72-
SortTest:testSortAddressesReversed() (gas: 49771)
73-
SortTest:testSortAddressesSorted() (gas: 44963)
74-
SortTest:testSortBasicCase() (gas: 1088)
75-
SortTest:testSortOriginalPsuedorandom() (gas: 222863)
76-
SortTest:testSortOriginalReversed() (gas: 162509)
77-
SortTest:testSortOriginalSorted() (gas: 148467)
78-
SortTest:testSortPsuedorandom() (gas: 84693)
79-
SortTest:testSortReversed() (gas: 43150)
80-
SortTest:testSortSorted() (gas: 38344)
81-
SortTest:testSortTestOverhead() (gas: 37516)
61+
SafeTransferLibTest:testTransferETH() (gas: 34601)
62+
SafeTransferLibTest:testTransferFromWithMissingReturn() (gas: 49417)
63+
SafeTransferLibTest:testTransferFromWithNonContract() (gas: 2973)
64+
SafeTransferLibTest:testTransferFromWithReturnsTooMuch() (gas: 50042)
65+
SafeTransferLibTest:testTransferFromWithStandardERC20() (gas: 47835)
66+
SafeTransferLibTest:testTransferWithMissingReturn() (gas: 36805)
67+
SafeTransferLibTest:testTransferWithNonContract() (gas: 2990)
68+
SafeTransferLibTest:testTransferWithReturnsTooMuch() (gas: 37186)
69+
SafeTransferLibTest:testTransferWithStandardERC20() (gas: 36812)
70+
SortTest:testSortAddressesPsuedorandom() (gas: 91222)
71+
SortTest:testSortAddressesPsuedorandomBrutalizeUpperBits() (gas: 103840)
72+
SortTest:testSortAddressesReversed() (gas: 49716)
73+
SortTest:testSortAddressesSorted() (gas: 44922)
74+
SortTest:testSortBasicCase() (gas: 1055)
75+
SortTest:testSortMostlySame() (gas: 78584)
76+
SortTest:testSortOriginalMostlySame() (gas: 214536)
77+
SortTest:testSortOriginalPsuedorandom() (gas: 222956)
78+
SortTest:testSortOriginalReversed() (gas: 162580)
79+
SortTest:testSortOriginalSorted() (gas: 148494)
80+
SortTest:testSortPsuedorandom() (gas: 84670)
81+
SortTest:testSortReversed() (gas: 43094)
82+
SortTest:testSortSorted() (gas: 38304)
83+
SortTest:testSortTestOverhead() (gas: 37472)

.gitmodules

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
url = https://github.com/foundry-rs/forge-std
44
[submodule "lib/solmate"]
55
path = lib/solmate
6-
url = https://github.com/rari-capital/solmate
6+
url = https://github.com/transmissions11/solmate

foundry.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# See more config options at: https://github.com/gakonst/foundry/tree/master/config
44

55
# The Default Profile
6-
[default]
6+
[profile.default]
77
solc_version = '0.8.15'
88
auto_detect_solc = false
99
optimizer = true

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "solady",
33
"license": "MIT",
4-
"version": "0.0.4",
4+
"version": "0.0.5",
55
"description": "Optimized Solidity snippets.",
66
"files": [
77
"src/**/*.sol"

scripts/replace-solidity-versions.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ async function main() {
1919
return source
2020
.replace(/pragma solidity ([>=^0-9\.]+);/g, 'pragma solidity ^0.8.4;')
2121
.replace('// SPDX-License-Identifier: AGPL-3.0-only', '// SPDX-License-Identifier: MIT')
22-
.replace('/// @author Solmate', '/// @author Modified from Solmate');
22+
.replace('/// @author Solmate', '/// @author Modified from Solmate')
23+
.replace(/\/rari-capital\//i, '/transmissions11/');
2324
};
2425

2526
const walkAndReplace = dirPath => {

src/utils/Base64.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ pragma solidity ^0.8.4;
33

44
/// @notice Library to encode strings in Base64.
55
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Base64.sol)
6-
/// @author Modified from Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/Base64.sol)
6+
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/Base64.sol)
77
/// @author Modified from (https://github.com/Brechtpd/base64/blob/main/base64.sol) by Brecht Devos - <[email protected]>.
88
library Base64 {
99
function encode(bytes memory data) internal pure returns (string memory result) {

src/utils/ECDSA.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ pragma solidity ^0.8.4;
33

44
/// @notice Gas optimized ECDSA wrapper.
55
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ECDSA.sol)
6-
/// @author Modified from Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/ECDSA.sol)
6+
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ECDSA.sol)
77
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/ECDSA.sol)
88
library ECDSA {
99
function recover(bytes32 hash, bytes calldata signature) internal view returns (address result) {

src/utils/LibBitmap.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ pragma solidity ^0.8.4;
33

44
/// @notice Efficient bitmap library for mapping integers to single bit booleans.
55
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBitmap.sol)
6-
/// @author Modified from Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/LibBitmap.sol)
6+
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibBitmap.sol)
77
library LibBitmap {
88
struct Bitmap {
99
mapping(uint256 => uint256) map;

src/utils/LibString.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ pragma solidity ^0.8.4;
33

44
/// @notice Library for converting numbers into strings and other string operations.
55
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol)
6-
/// @author Modified from Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/LibString.sol)
6+
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol)
77
library LibString {
88
/*//////////////////////////////////////////////////////////////
99
CUSTOM ERRORS

src/utils/MerkleProof.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ pragma solidity ^0.8.4;
33

44
/// @notice Gas optimized verification of proof of inclusion for a leaf in a Merkle tree.
55
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/MerkleProof.sol)
6-
/// @author Modified from Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/MerkleProof.sol)
6+
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/MerkleProof.sol)
77
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/MerkleProof.sol)
88
library MerkleProof {
99
function verify(

src/utils/SafeTransferLib.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ pragma solidity ^0.8.4;
33

44
/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
55
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)
6-
/// @author Modified from Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/SafeTransferLib.sol)
6+
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
77
/// @dev Caution! This library won't check that a token has code, responsibility is delegated to the caller.
88
library SafeTransferLib {
99
/*//////////////////////////////////////////////////////////////

src/utils/Sort.sol

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ library Sort {
1414
// For the linear congruential generator.
1515
uint256 private constant _LCG_MODULO = 0x7fffffff;
1616

17-
// This must be co-prime to `_LCG_MODULO`.
17+
// Any integer from `[1 .. _LCG_MODULO - 1]` will do, since `_LCG_MODULO` is prime.
1818
uint256 private constant _LCG_SEED = 0xbeef;
1919

2020
function sort(uint256[] memory a) internal pure {
@@ -26,7 +26,8 @@ library Sort {
2626
let stack := mload(0x40)
2727
let stackBottom := stack
2828

29-
if iszero(lt(n, 2)) {
29+
// prettier-ignore
30+
for {} iszero(lt(n, 2)) {} {
3031
// Push `l` and `h` to the stack.
3132
// The `shl` by 5 is equivalent to multiplying by `0x20`.
3233
let l := add(a, 0x20)
@@ -46,17 +47,12 @@ library Sort {
4647
if iszero(lt(j, h)) { break }
4748
}
4849

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)
55-
}
50+
// If the array is already sorted.
51+
// prettier-ignore
52+
if iszero(s) { break }
5653

57-
// If 50% or more of the elements are out of order,
58-
// reverse the array.
59-
if iszero(lt(shl(1, s), n)) {
54+
// If the array is reversed sorted.
55+
if eq(add(s, 1), n) {
6056
h := sub(h, 0x20)
6157
// prettier-ignore
6258
for {} 1 {} {
@@ -68,7 +64,14 @@ library Sort {
6864
// prettier-ignore
6965
if iszero(lt(l, h)) { break }
7066
}
67+
break
7168
}
69+
70+
// Push `l` and `h` onto the stack.
71+
mstore(stack, l)
72+
mstore(add(stack, 0x20), sub(h, 0x20))
73+
stack := add(stack, 0x40)
74+
break
7275
}
7376

7477
// Linear congruential generator (LCG) for psuedo-random partitioning
@@ -128,14 +131,14 @@ library Sort {
128131
for {} 1 {} {
129132
i := add(i, 0x20)
130133
// prettier-ignore
131-
if iszero(lt(mload(i), x)) { break }
134+
if iszero(gt(x, mload(i))) { break }
132135
}
133136
let j := p
134137
// prettier-ignore
135138
for {} 1 {} {
136139
j := sub(j, 0x20)
137140
// prettier-ignore
138-
if iszero(gt(mload(j), x)) { break }
141+
if iszero(lt(x, mload(j))) { break }
139142
}
140143
p := j
141144
// prettier-ignore

test/Sort.t.sol

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,19 @@ contract SortTest is Test {
116116
}
117117
}
118118

119+
function testSortMostlySame() public {
120+
unchecked {
121+
uint256[] memory a = new uint256[](100);
122+
for (uint256 i; i < a.length; ++i) {
123+
a[i] = i % 8 == 0 ? i : 0;
124+
}
125+
Sort.sort(a);
126+
for (uint256 i = 1; i < a.length; ++i) {
127+
assertTrue(a[i - 1] <= a[i]);
128+
}
129+
}
130+
}
131+
119132
function testSortTestOverhead() public {
120133
unchecked {
121134
uint256[] memory a = new uint256[](100);
@@ -203,7 +216,7 @@ contract SortTest is Test {
203216
lcg = (lcg * 1664525 + 1013904223) & 0xFFFFFFFF;
204217
a[i] = lcg;
205218
}
206-
sortOriginal(a, 0, int256(a.length - 1));
219+
sortOriginal(a);
207220
for (uint256 i = 1; i < a.length; ++i) {
208221
assertTrue(a[i - 1] <= a[i]);
209222
}
@@ -220,7 +233,7 @@ contract SortTest is Test {
220233
for (uint256 i; i < a.length; ++i) {
221234
a[i] = i;
222235
}
223-
sortOriginal(a, 0, int256(a.length - 1));
236+
sortOriginal(a);
224237
for (uint256 i = 1; i < a.length; ++i) {
225238
assertTrue(a[i - 1] <= a[i]);
226239
}
@@ -233,13 +246,30 @@ contract SortTest is Test {
233246
for (uint256 i; i < a.length; ++i) {
234247
a[i] = 999 - i;
235248
}
236-
sortOriginal(a, 0, int256(a.length - 1));
249+
sortOriginal(a);
237250
for (uint256 i = 1; i < a.length; ++i) {
238251
assertTrue(a[i - 1] <= a[i]);
239252
}
240253
}
241254
}
242255

256+
function testSortOriginalMostlySame() public {
257+
unchecked {
258+
uint256[] memory a = new uint256[](100);
259+
for (uint256 i; i < a.length; ++i) {
260+
a[i] = i % 8 == 0 ? i : 0;
261+
}
262+
sortOriginal(a);
263+
for (uint256 i = 1; i < a.length; ++i) {
264+
assertTrue(a[i - 1] <= a[i]);
265+
}
266+
}
267+
}
268+
269+
function sortOriginal(uint256[] memory a) internal pure {
270+
sortOriginal(a, 0, int256(a.length - 1));
271+
}
272+
243273
function sortOriginal(
244274
uint256[] memory arr,
245275
int256 left,

0 commit comments

Comments
 (0)