Skip to content

Commit

Permalink
T
Browse files Browse the repository at this point in the history
  • Loading branch information
Vectorized committed Sep 18, 2024
1 parent f6cc896 commit 156bf1f
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 8 deletions.
17 changes: 9 additions & 8 deletions src/utils/DynamicArrayLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,20 @@ library DynamicArrayLib {
/// @dev Clears the array without deallocating the memory.
function clear(DynamicArray memory array) internal pure returns (DynamicArray memory result) {
_deallocate(result);
result = array;
/// @solidity memory-safe-assembly
assembly {
mstore(mload(array), 0)
mstore(mload(result), 0)
}
result = array;
}

/// @dev Clears the array and attempts to free the memory if possible.
function free(DynamicArray memory array) internal pure returns (DynamicArray memory result) {
_deallocate(result);
result = array;
/// @solidity memory-safe-assembly
assembly {
let arrData := mload(array)
let arrData := mload(result)
if iszero(eq(arrData, 0x60)) {
let prime := 8188386068317523
let cap := mload(sub(arrData, 0x20))
Expand All @@ -52,10 +53,9 @@ library DynamicArrayLib {
if eq(mload(0x40), add(arrData, add(0x20, cap))) {
mstore(0x40, sub(arrData, 0x20))
}
mstore(array, 0x60)
mstore(result, 0x60)
}
}
result = array;
}

/// @dev Resizes the array to contain `n` elements. New elements will be zeroized.
Expand All @@ -65,7 +65,8 @@ library DynamicArrayLib {
returns (DynamicArray memory result)
{
_deallocate(result);
result = reserve(array, n);
result = array;
reserve(result, n);
/// @solidity memory-safe-assembly
assembly {
let arrData := mload(result)
Expand All @@ -88,7 +89,7 @@ library DynamicArrayLib {
/// @solidity memory-safe-assembly
assembly {
if iszero(lt(minimum, 0xffffffff)) { invalid() } // For extra safety.
for { let arrData := mload(array) } gt(minimum, mload(arrData)) {} {
for { let arrData := mload(array) } 1 {} {
// Some random prime number to multiply `cap`, so that
// we know that the `cap` is for a dynamic array.
// Selected to be larger than any memory pointer realistically.
Expand All @@ -110,7 +111,7 @@ library DynamicArrayLib {
cap := mul(div(cap, prime), iszero(mod(cap, prime)))
let newCap := shl(5, minimum)
// If we don't need to grow the memory.
if iszero(gt(newCap, cap)) { break }
if iszero(and(gt(minimum, mload(arrData)), gt(newCap, cap))) { break }
// If the memory is contiguous, we can simply expand it.
if eq(mload(0x40), add(arrData, add(0x20, cap))) {
mstore(add(arrData, w), mul(prime, newCap)) // Store the capacity.
Expand Down
22 changes: 22 additions & 0 deletions test/DynamicArrayLib.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,28 @@ contract DynamicArrayLibTest is SoladyTest {
}
}

function testDynamicArrayGas() public {
uint256 n = 100;
DynamicArrayLib.DynamicArray memory a;
a.reserve(n);
unchecked {
for (uint256 i; i != n; ++i) {
a.set(i, i);
}
}
a.resize(n);
}

function testStaticArrayGas() public {
uint256 n = 100;
uint256[] memory a = new uint256[](n);
unchecked {
for (uint256 i; i != n; ++i) {
a[i] = i;
}
}
}

function testDynamicArrayPushPop(uint256 n, uint256 r) public {
n = _bound(n, 0, 50);
if (_randomChance(2)) _misalignFreeMemoryPointer();
Expand Down

0 comments on commit 156bf1f

Please sign in to comment.