Skip to content

Commit 5974062

Browse files
authored
✨ Add isSorted (#325)
1 parent dfc6180 commit 5974062

File tree

3 files changed

+289
-64
lines changed

3 files changed

+289
-64
lines changed

.gas-snapshot

Lines changed: 70 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -280,69 +280,75 @@ LibRLPTest:testComputeAddressForSmallNonces() (gas: 967)
280280
LibRLPTest:testComputeAddressOriginalForLargeNonces() (gas: 1887)
281281
LibRLPTest:testComputeAddressOriginalForSmallNonces() (gas: 1477)
282282
LibRLPTest:test__codesize() (gas: 8108)
283-
LibSortTest:testInsertionSortAddressesDifferential(uint256) (runs: 256, μ: 424556, ~: 47232)
284-
LibSortTest:testInsertionSortInts() (gas: 112087)
285-
LibSortTest:testInsertionSortPsuedorandom() (gas: 62786)
286-
LibSortTest:testInsertionSortPsuedorandom(uint256) (runs: 256, μ: 62093, ~: 61687)
287-
LibSortTest:testReverse() (gas: 113774)
288-
LibSortTest:testSearchSorted() (gas: 131295)
289-
LibSortTest:testSearchSorted(uint256[],uint256) (runs: 256, μ: 11236, ~: 11759)
290-
LibSortTest:testSearchSortedAddresses() (gas: 136072)
291-
LibSortTest:testSearchSortedAddresses(address[],address) (runs: 256, μ: 20764, ~: 20682)
292-
LibSortTest:testSearchSortedBasicCases() (gas: 2379)
293-
LibSortTest:testSearchSortedEdgeCases() (gas: 1758)
294-
LibSortTest:testSearchSortedElementInArray(uint256[],uint256) (runs: 256, μ: 49709, ~: 43180)
295-
LibSortTest:testSearchSortedElementInUniquifiedArray(uint256[],uint256) (runs: 256, μ: 51558, ~: 44649)
283+
LibSortTest:testInsertionSortAddressesDifferential(uint256) (runs: 256, μ: 442644, ~: 39128)
284+
LibSortTest:testInsertionSortInts() (gas: 112043)
285+
LibSortTest:testInsertionSortPsuedorandom() (gas: 62852)
286+
LibSortTest:testInsertionSortPsuedorandom(uint256) (runs: 256, μ: 62142, ~: 61980)
287+
LibSortTest:testIsSortedAddressesDifferential(uint256) (runs: 256, μ: 61780, ~: 29956)
288+
LibSortTest:testIsSortedAndUniquifiedAddressesDifferential(uint256) (runs: 256, μ: 53901, ~: 29496)
289+
LibSortTest:testIsSortedAndUniquifiedDifferential(uint256) (runs: 256, μ: 39210, ~: 28752)
290+
LibSortTest:testIsSortedAndUniquifiedIntsDifferential(uint256) (runs: 256, μ: 53913, ~: 31850)
291+
LibSortTest:testIsSortedDifferential(uint256) (runs: 256, μ: 49645, ~: 27692)
292+
LibSortTest:testIsSortedIntsDifferential(uint256) (runs: 256, μ: 64331, ~: 31468)
293+
LibSortTest:testReverse() (gas: 113819)
294+
LibSortTest:testSearchSorted() (gas: 131337)
295+
LibSortTest:testSearchSorted(uint256[],uint256) (runs: 256, μ: 11192, ~: 11715)
296+
LibSortTest:testSearchSortedAddresses() (gas: 136117)
297+
LibSortTest:testSearchSortedAddresses(address[],address) (runs: 256, μ: 20765, ~: 20683)
298+
LibSortTest:testSearchSortedBasicCases() (gas: 2335)
299+
LibSortTest:testSearchSortedEdgeCases() (gas: 1759)
300+
LibSortTest:testSearchSortedElementInArray(uint256[],uint256) (runs: 256, μ: 49011, ~: 43577)
301+
LibSortTest:testSearchSortedElementInUniquifiedArray(uint256[],uint256) (runs: 256, μ: 51294, ~: 44436)
296302
LibSortTest:testSearchSortedElementNotInArray() (gas: 6967)
297-
LibSortTest:testSearchSortedElementNotInArray(uint256[],uint256) (runs: 256, μ: 48391, ~: 42635)
298-
LibSortTest:testSearchSortedElementNotInArrayNarrow(uint256[],uint256) (runs: 256, μ: 73163, ~: 69395)
299-
LibSortTest:testSearchSortedElementNotInUniquifiedArray(uint256[],uint256) (runs: 256, μ: 54765, ~: 44239)
300-
LibSortTest:testSearchSortedElementNotInUniquifiedArrayNarrow(uint256[],uint256) (runs: 256, μ: 72454, ~: 69629)
301-
LibSortTest:testSearchSortedInts() (gas: 133138)
302-
LibSortTest:testSearchSortedInts(int256[],int256) (runs: 256, μ: 11302, ~: 11448)
303-
LibSortTest:testSearchSortedWithEmptyArray() (gas: 745)
304-
LibSortTest:testSort(uint256[]) (runs: 256, μ: 45087, ~: 39520)
305-
LibSortTest:testSortAddressesDifferential(uint256[]) (runs: 256, μ: 76035, ~: 45681)
306-
LibSortTest:testSortAddressesPsuedorandom() (gas: 144923)
307-
LibSortTest:testSortAddressesPsuedorandom(uint256) (runs: 256, μ: 146679, ~: 146854)
308-
LibSortTest:testSortAddressesPsuedorandomBrutalizeUpperBits() (gas: 196511)
309-
LibSortTest:testSortAddressesReversed() (gas: 46044)
310-
LibSortTest:testSortAddressesSorted() (gas: 43042)
311-
LibSortTest:testSortBasicCase() (gas: 1211)
312-
LibSortTest:testSortChecksumed(uint256[]) (runs: 256, μ: 57973, ~: 42022)
313-
LibSortTest:testSortDifferential(uint256[]) (runs: 256, μ: 86623, ~: 41855)
314-
LibSortTest:testSortInts() (gas: 612215)
315-
LibSortTest:testSortMostlySame() (gas: 68029)
316-
LibSortTest:testSortOriginalMostlySame() (gas: 208629)
317-
LibSortTest:testSortOriginalPsuedorandom() (gas: 284650)
318-
LibSortTest:testSortOriginalPsuedorandom(uint256) (runs: 256, μ: 286239, ~: 286474)
319-
LibSortTest:testSortOriginalReversed() (gas: 156905)
320-
LibSortTest:testSortOriginalSorted() (gas: 142907)
321-
LibSortTest:testSortPsuedorandom() (gas: 138577)
322-
LibSortTest:testSortPsuedorandom(uint256) (runs: 256, μ: 140147, ~: 140418)
323-
LibSortTest:testSortPsuedorandomNonuniform() (gas: 145740)
324-
LibSortTest:testSortPsuedorandomNonuniform(uint256) (runs: 256, μ: 145267, ~: 145613)
303+
LibSortTest:testSearchSortedElementNotInArray(uint256[],uint256) (runs: 256, μ: 48094, ~: 43118)
304+
LibSortTest:testSearchSortedElementNotInArrayNarrow(uint256[],uint256) (runs: 256, μ: 75698, ~: 69977)
305+
LibSortTest:testSearchSortedElementNotInUniquifiedArray(uint256[],uint256) (runs: 256, μ: 54059, ~: 44303)
306+
LibSortTest:testSearchSortedElementNotInUniquifiedArrayNarrow(uint256[],uint256) (runs: 256, μ: 73975, ~: 69795)
307+
LibSortTest:testSearchSortedInts() (gas: 133094)
308+
LibSortTest:testSearchSortedInts(int256[],int256) (runs: 256, μ: 11369, ~: 11515)
309+
LibSortTest:testSearchSortedWithEmptyArray() (gas: 768)
310+
LibSortTest:testSort(uint256[]) (runs: 256, μ: 45575, ~: 39124)
311+
LibSortTest:testSortAddressesDifferential(uint256[]) (runs: 256, μ: 77259, ~: 45585)
312+
LibSortTest:testSortAddressesPsuedorandom() (gas: 144945)
313+
LibSortTest:testSortAddressesPsuedorandom(uint256) (runs: 256, μ: 146626, ~: 146782)
314+
LibSortTest:testSortAddressesPsuedorandomBrutalizeUpperBits() (gas: 196512)
315+
LibSortTest:testSortAddressesReversed() (gas: 46045)
316+
LibSortTest:testSortAddressesSorted() (gas: 42998)
317+
LibSortTest:testSortBasicCase() (gas: 1189)
318+
LibSortTest:testSortChecksumed(uint256[]) (runs: 256, μ: 56379, ~: 41929)
319+
LibSortTest:testSortDifferential(uint256[]) (runs: 256, μ: 88787, ~: 42954)
320+
LibSortTest:testSortInts() (gas: 612193)
321+
LibSortTest:testSortMostlySame() (gas: 68073)
322+
LibSortTest:testSortOriginalMostlySame() (gas: 208585)
323+
LibSortTest:testSortOriginalPsuedorandom() (gas: 284693)
324+
LibSortTest:testSortOriginalPsuedorandom(uint256) (runs: 256, μ: 286006, ~: 286558)
325+
LibSortTest:testSortOriginalReversed() (gas: 156927)
326+
LibSortTest:testSortOriginalSorted() (gas: 142885)
327+
LibSortTest:testSortPsuedorandom() (gas: 138600)
328+
LibSortTest:testSortPsuedorandom(uint256) (runs: 256, μ: 140088, ~: 140383)
329+
LibSortTest:testSortPsuedorandomNonuniform() (gas: 145762)
330+
LibSortTest:testSortPsuedorandomNonuniform(uint256) (runs: 256, μ: 145234, ~: 145511)
325331
LibSortTest:testSortReversed() (gas: 39450)
326332
LibSortTest:testSortSorted() (gas: 36386)
327-
LibSortTest:testSortTestOverhead() (gas: 102836)
328-
LibSortTest:testSortedDifferenceDifferential() (gas: 483724)
329-
LibSortTest:testSortedDifferenceDifferential(uint256[],uint256[]) (runs: 256, μ: 36105, ~: 36842)
330-
LibSortTest:testSortedDifferenceDifferentialInt(int256[],int256[]) (runs: 256, μ: 40894, ~: 41164)
331-
LibSortTest:testSortedDifferenceUnionIntersection(uint256[],uint256[]) (runs: 256, μ: 95129, ~: 96359)
332-
LibSortTest:testSortedIntersectionDifferential() (gas: 415946)
333-
LibSortTest:testSortedIntersectionDifferential(uint256[],uint256[]) (runs: 256, μ: 33160, ~: 33862)
334-
LibSortTest:testSortedIntersectionDifferentialInt(int256[],int256[]) (runs: 256, μ: 36673, ~: 36988)
335-
LibSortTest:testSortedUnionDifferential() (gas: 467791)
336-
LibSortTest:testSortedUnionDifferential(uint256[],uint256[]) (runs: 256, μ: 35706, ~: 36668)
337-
LibSortTest:testSortedUnionDifferentialInt(int256[],int256[]) (runs: 256, μ: 41438, ~: 41955)
338-
LibSortTest:testTwoComplementConversionSort(int256,int256) (runs: 256, μ: 471, ~: 471)
339-
LibSortTest:testUniquifySorted() (gas: 1688)
340-
LibSortTest:testUniquifySorted(uint256[]) (runs: 256, μ: 50395, ~: 40611)
341-
LibSortTest:testUniquifySortedAddress() (gas: 4039)
342-
LibSortTest:testUniquifySortedAddress(address[]) (runs: 256, μ: 62073, ~: 52400)
343-
LibSortTest:testUniquifySortedDifferential(uint256[]) (runs: 256, μ: 62004, ~: 44716)
333+
LibSortTest:testSortTestOverhead() (gas: 102814)
334+
LibSortTest:testSortedDifferenceDifferential() (gas: 483768)
335+
LibSortTest:testSortedDifferenceDifferential(uint256[],uint256[]) (runs: 256, μ: 36190, ~: 36909)
336+
LibSortTest:testSortedDifferenceDifferentialInt(int256[],int256[]) (runs: 256, μ: 40923, ~: 41187)
337+
LibSortTest:testSortedDifferenceUnionIntersection(uint256[],uint256[]) (runs: 256, μ: 95206, ~: 96369)
338+
LibSortTest:testSortedIntersectionDifferential() (gas: 416011)
339+
LibSortTest:testSortedIntersectionDifferential(uint256[],uint256[]) (runs: 256, μ: 33145, ~: 33840)
340+
LibSortTest:testSortedIntersectionDifferentialInt(int256[],int256[]) (runs: 256, μ: 36698, ~: 37010)
341+
LibSortTest:testSortedUnionDifferential() (gas: 467814)
342+
LibSortTest:testSortedUnionDifferential(uint256[],uint256[]) (runs: 256, μ: 35721, ~: 36668)
343+
LibSortTest:testSortedUnionDifferentialInt(int256[],int256[]) (runs: 256, μ: 41463, ~: 41977)
344+
LibSortTest:testTwoComplementConversionSort(int256,int256) (runs: 256, μ: 472, ~: 472)
345+
LibSortTest:testUniquifySorted() (gas: 1666)
346+
LibSortTest:testUniquifySorted(uint256[]) (runs: 256, μ: 50142, ~: 41134)
347+
LibSortTest:testUniquifySortedAddress() (gas: 4017)
348+
LibSortTest:testUniquifySortedAddress(address[]) (runs: 256, μ: 62379, ~: 52242)
349+
LibSortTest:testUniquifySortedDifferential(uint256[]) (runs: 256, μ: 58518, ~: 44184)
344350
LibSortTest:testUniquifySortedWithEmptyArray() (gas: 550)
345-
LibSortTest:test__codesize() (gas: 20650)
351+
LibSortTest:test__codesize() (gas: 24936)
346352
LibStringTest:testAddressToHexStringZeroRightPadded(address) (runs: 256, μ: 3464, ~: 3464)
347353
LibStringTest:testBytesToHexString() (gas: 6470)
348354
LibStringTest:testBytesToHexString(bytes) (runs: 256, μ: 660431, ~: 586251)
@@ -432,11 +438,11 @@ MerkleProofLibTest:testVerifyProofBasicCaseIsInvalid() (gas: 3029)
432438
MerkleProofLibTest:testVerifyProofBasicCaseIsValid() (gas: 2993)
433439
MerkleProofLibTest:testVerifyProofForHeightOneTree(bool,bool,bool,bool) (runs: 256, μ: 2232, ~: 2107)
434440
MerkleProofLibTest:test__codesize() (gas: 11064)
435-
MinHeapLibTest:testHeapEnqueue(uint256) (runs: 256, μ: 188331, ~: 191079)
436-
MinHeapLibTest:testHeapEnqueueGas(uint256) (runs: 256, μ: 293477, ~: 293443)
437-
MinHeapLibTest:testHeapPushAndPop(uint256) (runs: 256, μ: 103810, ~: 99702)
438-
MinHeapLibTest:testHeapPushPop(uint256) (runs: 256, μ: 251721, ~: 258454)
439-
MinHeapLibTest:testHeapReplace(uint256) (runs: 256, μ: 301589, ~: 298949)
441+
MinHeapLibTest:testHeapEnqueue(uint256) (runs: 256, μ: 185435, ~: 182909)
442+
MinHeapLibTest:testHeapEnqueueGas(uint256) (runs: 256, μ: 293441, ~: 293389)
443+
MinHeapLibTest:testHeapPushAndPop(uint256) (runs: 256, μ: 105344, ~: 99702)
444+
MinHeapLibTest:testHeapPushPop(uint256) (runs: 256, μ: 241203, ~: 240966)
445+
MinHeapLibTest:testHeapReplace(uint256) (runs: 256, μ: 305655, ~: 304724)
440446
MinHeapLibTest:testHeapRoot(uint256) (runs: 256, μ: 5232, ~: 5232)
441447
MinHeapLibTest:test__codesize() (gas: 5404)
442448
MulticallableTest:testMulticallableBenchmark() (gas: 29574)

src/utils/LibSort.sol

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,84 @@ library LibSort {
322322
reverse(_toUints(a));
323323
}
324324

325+
/// @dev Returns whether the array is sorted in ascending order.
326+
function isSorted(uint256[] memory a) internal pure returns (bool result) {
327+
/// @solidity memory-safe-assembly
328+
assembly {
329+
result := 1
330+
if iszero(lt(mload(a), 2)) {
331+
let end := add(a, shl(5, mload(a)))
332+
for { a := add(a, 0x20) } 1 {} {
333+
let p := mload(a)
334+
a := add(a, 0x20)
335+
result := iszero(gt(p, mload(a)))
336+
if iszero(mul(result, xor(a, end))) { break }
337+
}
338+
}
339+
}
340+
}
341+
342+
/// @dev Returns whether the array is sorted in ascending order.
343+
function isSorted(int256[] memory a) internal pure returns (bool result) {
344+
/// @solidity memory-safe-assembly
345+
assembly {
346+
result := 1
347+
if iszero(lt(mload(a), 2)) {
348+
let end := add(a, shl(5, mload(a)))
349+
for { a := add(a, 0x20) } 1 {} {
350+
let p := mload(a)
351+
a := add(a, 0x20)
352+
result := iszero(sgt(p, mload(a)))
353+
if iszero(mul(result, xor(a, end))) { break }
354+
}
355+
}
356+
}
357+
}
358+
359+
/// @dev Returns whether the array is sorted in ascending order.
360+
function isSorted(address[] memory a) internal pure returns (bool result) {
361+
result = isSorted(_toUints(a));
362+
}
363+
364+
/// @dev Returns whether the array is strictly ascending (sorted and uniquified).
365+
function isSortedAndUniquified(uint256[] memory a) internal pure returns (bool result) {
366+
/// @solidity memory-safe-assembly
367+
assembly {
368+
result := 1
369+
if iszero(lt(mload(a), 2)) {
370+
let end := add(a, shl(5, mload(a)))
371+
for { a := add(a, 0x20) } 1 {} {
372+
let p := mload(a)
373+
a := add(a, 0x20)
374+
result := lt(p, mload(a))
375+
if iszero(mul(result, xor(a, end))) { break }
376+
}
377+
}
378+
}
379+
}
380+
381+
/// @dev Returns whether the array is strictly ascending (sorted and uniquified).
382+
function isSortedAndUniquified(int256[] memory a) internal pure returns (bool result) {
383+
/// @solidity memory-safe-assembly
384+
assembly {
385+
result := 1
386+
if iszero(lt(mload(a), 2)) {
387+
let end := add(a, shl(5, mload(a)))
388+
for { a := add(a, 0x20) } 1 {} {
389+
let p := mload(a)
390+
a := add(a, 0x20)
391+
result := slt(p, mload(a))
392+
if iszero(mul(result, xor(a, end))) { break }
393+
}
394+
}
395+
}
396+
}
397+
398+
/// @dev Returns whether the array is strictly ascending (sorted and uniquified).
399+
function isSortedAndUniquified(address[] memory a) internal pure returns (bool result) {
400+
result = isSortedAndUniquified(_toUints(a));
401+
}
402+
325403
/// @dev Returns the sorted set difference of `a` and `b`.
326404
/// Note: Behaviour is undefined if inputs are not sorted and uniquified.
327405
function difference(uint256[] memory a, uint256[] memory b)

test/LibSort.t.sol

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -749,6 +749,132 @@ contract LibSortTest is TestPlus {
749749
}
750750
}
751751

752+
function testIsSortedDifferential(uint256) public {
753+
unchecked {
754+
uint256 n = _random() % 2 == 0 ? _random() % 4 : _randomArrayLength();
755+
uint256[] memory a = new uint256[](n);
756+
for (uint256 i; i != n; ++i) {
757+
a[i] = _random() % 4;
758+
}
759+
assertEq(LibSort.isSorted(a), _isSorted(a));
760+
LibSort.sort(a);
761+
assertEq(LibSort.isSorted(a), _isSorted(a));
762+
if (n != 0) {
763+
a[_random() % n] = 0;
764+
if (_random() % 2 == 0) {
765+
a[_random() % n] = a[_random() % n];
766+
}
767+
}
768+
assertEq(LibSort.isSorted(a), _isSorted(a));
769+
}
770+
}
771+
772+
function testIsSortedIntsDifferential(uint256) public {
773+
unchecked {
774+
uint256 n = _random() % 2 == 0 ? _random() % 4 : _randomArrayLength();
775+
int256[] memory a = new int256[](n);
776+
for (uint256 i; i != n; ++i) {
777+
a[i] = int256(_random() % 4);
778+
if (_random() % 2 == 0) {
779+
a[i] = -a[i];
780+
}
781+
}
782+
assertEq(LibSort.isSorted(a), _isSorted(a));
783+
LibSort.sort(a);
784+
assertEq(LibSort.isSorted(a), _isSorted(a));
785+
if (n != 0) {
786+
a[_random() % n] = 0;
787+
if (_random() % 2 == 0) {
788+
a[_random() % n] = a[_random() % n];
789+
}
790+
}
791+
assertEq(LibSort.isSorted(a), _isSorted(a));
792+
}
793+
}
794+
795+
function testIsSortedAddressesDifferential(uint256) public {
796+
unchecked {
797+
uint256 n = _random() % 2 == 0 ? _random() % 4 : _randomArrayLength();
798+
address[] memory a = new address[](n);
799+
for (uint256 i; i != n; ++i) {
800+
a[i] = address(uint160(_random() % 4));
801+
}
802+
assertEq(LibSort.isSorted(a), _isSorted(a));
803+
LibSort.sort(a);
804+
assertEq(LibSort.isSorted(a), _isSorted(a));
805+
if (n != 0) {
806+
a[_random() % n] = address(0);
807+
if (_random() % 2 == 0) {
808+
a[_random() % n] = a[_random() % n];
809+
}
810+
}
811+
assertEq(LibSort.isSorted(a), _isSorted(a));
812+
}
813+
}
814+
815+
function testIsSortedAndUniquifiedDifferential(uint256) public {
816+
unchecked {
817+
uint256 n = _random() % 2 == 0 ? _random() % 4 : _randomArrayLength();
818+
uint256[] memory a = new uint256[](n);
819+
for (uint256 i; i != n; ++i) {
820+
a[i] = _random() % 4;
821+
}
822+
assertEq(LibSort.isSortedAndUniquified(a), _isSortedAndUniquified(a));
823+
LibSort.sort(a);
824+
assertEq(LibSort.isSortedAndUniquified(a), _isSortedAndUniquified(a));
825+
if (n != 0) {
826+
a[_random() % n] = 0;
827+
if (_random() % 2 == 0) {
828+
a[_random() % n] = a[_random() % n];
829+
}
830+
}
831+
assertEq(LibSort.isSortedAndUniquified(a), _isSortedAndUniquified(a));
832+
}
833+
}
834+
835+
function testIsSortedAndUniquifiedIntsDifferential(uint256) public {
836+
unchecked {
837+
uint256 n = _random() % 2 == 0 ? _random() % 4 : _randomArrayLength();
838+
int256[] memory a = new int256[](n);
839+
for (uint256 i; i != n; ++i) {
840+
a[i] = int256(_random() % 4);
841+
if (_random() % 2 == 0) {
842+
a[i] = -a[i];
843+
}
844+
}
845+
assertEq(LibSort.isSortedAndUniquified(a), _isSortedAndUniquified(a));
846+
LibSort.sort(a);
847+
assertEq(LibSort.isSortedAndUniquified(a), _isSortedAndUniquified(a));
848+
if (n != 0) {
849+
a[_random() % n] = 0;
850+
if (_random() % 2 == 0) {
851+
a[_random() % n] = a[_random() % n];
852+
}
853+
}
854+
assertEq(LibSort.isSortedAndUniquified(a), _isSortedAndUniquified(a));
855+
}
856+
}
857+
858+
function testIsSortedAndUniquifiedAddressesDifferential(uint256) public {
859+
unchecked {
860+
uint256 n = _random() % 2 == 0 ? _random() % 4 : _randomArrayLength();
861+
address[] memory a = new address[](n);
862+
for (uint256 i; i != n; ++i) {
863+
a[i] = address(uint160(_random() % 4));
864+
}
865+
assertEq(LibSort.isSortedAndUniquified(a), _isSortedAndUniquified(a));
866+
LibSort.sort(a);
867+
assertEq(LibSort.isSortedAndUniquified(a), _isSortedAndUniquified(a));
868+
if (n != 0) {
869+
a[_random() % n] = address(0);
870+
if (_random() % 2 == 0) {
871+
a[_random() % n] = a[_random() % n];
872+
}
873+
}
874+
assertEq(LibSort.isSortedAndUniquified(a), _isSortedAndUniquified(a));
875+
}
876+
}
877+
752878
function _unionOriginal(uint256[] memory a, uint256[] memory b)
753879
private
754880
pure
@@ -917,6 +1043,21 @@ contract LibSortTest is TestPlus {
9171043
}
9181044
}
9191045

1046+
function _isSortedAndUniquified(int256[] memory a) private pure returns (bool) {
1047+
if (a.length == 0) {
1048+
return true;
1049+
}
1050+
unchecked {
1051+
uint256 end = a.length - 1;
1052+
for (uint256 i = 0; i != end; ++i) {
1053+
if (a[i] >= a[i + 1]) {
1054+
return false;
1055+
}
1056+
}
1057+
return true;
1058+
}
1059+
}
1060+
9201061
function _isSortedAndUniquified(address[] memory a) private pure returns (bool) {
9211062
if (a.length == 0) {
9221063
return true;

0 commit comments

Comments
 (0)