diff --git a/docs/utils/fixedpointmathlib.md b/docs/utils/fixedpointmathlib.md index b9aaeb31d..848c95757 100644 --- a/docs/utils/fixedpointmathlib.md +++ b/docs/utils/fixedpointmathlib.md @@ -462,6 +462,30 @@ function ternary(bool condition, address x, address y) Returns `condition ? x : y`, without branching. +### coalesce(uint256,uint256) + +```solidity +function coalesce(uint256 x, uint256 y) internal pure returns (uint256 z) +``` + +Returns `x != 0 ? x : y`, without branching. + +### coalesce(bytes32,bytes32) + +```solidity +function coalesce(bytes32 x, bytes32 y) internal pure returns (bytes32 z) +``` + +Returns `x != bytes32(0) ? x : y`, without branching. + +### coalesce(address,address) + +```solidity +function coalesce(address x, address y) internal pure returns (address z) +``` + +Returns `x != address(0) ? x : y`, without branching. + ### rpow(uint256,uint256,uint256) ```solidity diff --git a/src/utils/FixedPointMathLib.sol b/src/utils/FixedPointMathLib.sol index d44c6e777..fdae47f2d 100644 --- a/src/utils/FixedPointMathLib.sol +++ b/src/utils/FixedPointMathLib.sol @@ -709,6 +709,30 @@ library FixedPointMathLib { } } + /// @dev Returns `x != 0 ? x : y`, without branching. + function coalesce(uint256 x, uint256 y) internal pure returns (uint256 z) { + /// @solidity memory-safe-assembly + assembly { + z := or(x, mul(y, iszero(x))) + } + } + + /// @dev Returns `x != bytes32(0) ? x : y`, without branching. + function coalesce(bytes32 x, bytes32 y) internal pure returns (bytes32 z) { + /// @solidity memory-safe-assembly + assembly { + z := or(x, mul(y, iszero(x))) + } + } + + /// @dev Returns `x != address(0) ? x : y`, without branching. + function coalesce(address x, address y) internal pure returns (address z) { + /// @solidity memory-safe-assembly + assembly { + z := or(x, mul(y, iszero(shl(96, x)))) + } + } + /// @dev Exponentiate `x` to `y` by squaring, denominated in base `b`. /// Reverts if the computation overflows. function rpow(uint256 x, uint256 y, uint256 b) internal pure returns (uint256 z) { diff --git a/test/FixedPointMathLib.t.sol b/test/FixedPointMathLib.t.sol index f1846eb49..48ab79c89 100644 --- a/test/FixedPointMathLib.t.sol +++ b/test/FixedPointMathLib.t.sol @@ -2195,10 +2195,30 @@ contract FixedPointMathLibTest is SoladyTest { return a; } + function testCoalesce(uint256 x, uint256 y) public { + assertEq(x == 0 ? y : x, FixedPointMathLib.coalesce(x, y)); + } + + function testCoalesce(address x, address y) public { + assertEq(x == address(0) ? y : x, FixedPointMathLib.coalesce(x, y)); + } + + function testCoalesce(bytes32 x, bytes32 y) public { + assertEq(x == bytes32(0) ? y : x, FixedPointMathLib.coalesce(x, y)); + } + function testTernary(bool condition, uint256 x, uint256 y) public { assertEq(condition ? x : y, FixedPointMathLib.ternary(condition, x, y)); } + function testTernary(bool condition, bytes32 x, bytes32 y) public { + assertEq(condition ? x : y, FixedPointMathLib.ternary(condition, x, y)); + } + + function testTernary(bool condition, address x, address y) public { + assertEq(condition ? x : y, FixedPointMathLib.ternary(condition, x, y)); + } + function testIsEven(uint256 x) public { assertEq(FixedPointMathLib.isEven(x), x % 2 == 0); }