Skip to content

Commit

Permalink
feat(stamps): improve sorting
Browse files Browse the repository at this point in the history
  • Loading branch information
NicoAcosta committed Nov 1, 2024
1 parent af1f217 commit 7a03070
Showing 1 changed file with 52 additions and 16 deletions.
68 changes: 52 additions & 16 deletions src/points/MultipleFollowerSincePoints.sol
Original file line number Diff line number Diff line change
Expand Up @@ -155,10 +155,16 @@ contract MultipleFollowerSincePoints is Points, IMultipleFollowerSincePoints {
}
}

// Validate indices
if (end > totalHolders) {
end = totalHolders;
// If no holders, return empty arrays
if (totalHolders == 0) {
return (new address[](0), new uint256[](0));
}

// Validate start index
if (start >= totalHolders) revert IndexOutOfBounds();

// Adjust end if it exceeds total holders
end = Math.min(end, totalHolders);
uint256 length = end - start;

// Create return arrays
Expand All @@ -178,21 +184,24 @@ contract MultipleFollowerSincePoints is Points, IMultipleFollowerSincePoints {
}
}

// Sort using insertion sort (efficient for smaller arrays)
for (uint256 i = 1; i < totalHolders; ) {
uint256 j = i;
while (j > 0 && sortedBalances[j - 1] < sortedBalances[j]) {
// Swap balances
(sortedBalances[j], sortedBalances[j - 1]) = (sortedBalances[j - 1], sortedBalances[j]);
// Swap addresses
(sortedAddresses[j], sortedAddresses[j - 1]) = (sortedAddresses[j - 1], sortedAddresses[j]);
// Replace insertion sort with optimized quicksort for larger datasets
if (totalHolders > 10) {
_quickSort(sortedAddresses, sortedBalances, 0, int256(totalHolders - 1));
} else {
// Keep insertion sort for small arrays
for (uint256 i = 1; i < totalHolders; ) {
uint256 j = i;
while (j > 0 && sortedBalances[j - 1] < sortedBalances[j]) {
(sortedBalances[j], sortedBalances[j - 1]) = (sortedBalances[j - 1], sortedBalances[j]);
(sortedAddresses[j], sortedAddresses[j - 1]) = (sortedAddresses[j - 1], sortedAddresses[j]);
unchecked {
--j;
}
}
unchecked {
--j;
++i;
}
}
unchecked {
++i;
}
}

// Copy requested range to return arrays
Expand All @@ -217,12 +226,39 @@ contract MultipleFollowerSincePoints is Points, IMultipleFollowerSincePoints {
}

/// @dev Helper function to get total unique holders across all stamps
/// @return maxHolders A conservative estimate of maximum possible unique holders
function _getTotalUniqueHolders() private view returns (uint256 maxHolders) {
// Find the stamp with maximum supply as a better estimate
for (uint256 i; i < _stampCount; ) {
maxHolders += _stamps[i].stamp.totalSupply();
uint256 supply = _stamps[i].stamp.totalSupply();
maxHolders = Math.max(maxHolders, supply);
unchecked {
++i;
}
}
}

/// @dev Quicksort implementation for more efficient sorting of larger arrays
function _quickSort(address[] memory addresses, uint256[] memory balances, int256 left, int256 right) private pure {
if (left >= right) return;

int256 i = left;
int256 j = right;
uint256 pivot = balances[uint256(left + (right - left) / 2)];

while (i <= j) {
while (balances[uint256(i)] > pivot) i++;
while (balances[uint256(j)] < pivot) j--;

if (i <= j) {
(balances[uint256(i)], balances[uint256(j)]) = (balances[uint256(j)], balances[uint256(i)]);
(addresses[uint256(i)], addresses[uint256(j)]) = (addresses[uint256(j)], addresses[uint256(i)]);
i++;
j--;
}
}

if (left < j) _quickSort(addresses, balances, left, j);
if (i < right) _quickSort(addresses, balances, i, right);
}
}

0 comments on commit 7a03070

Please sign in to comment.