Commit 72c6fb0a authored by clabby's avatar clabby Committed by GitHub

Merge pull request #6081 from ethereum-optimism/clabby/dispute/libpos-updates

chore(ctb): `LibPosition` documentation, tests, perf
parents 6d07c4d6 1c8a9f59
......@@ -32,30 +32,30 @@ DisputeGameFactory_SetImplementation_Test:test_setImplementation_notOwner_revert
DisputeGameFactory_SetImplementation_Test:test_setImplementation_succeeds() (gas: 44243)
DisputeGameFactory_TransferOwnership_Test:test_transferOwnership_notOwner_reverts() (gas: 15950)
DisputeGameFactory_TransferOwnership_Test:test_transferOwnership_succeeds() (gas: 18642)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot2:test_resolvesCorrectly_succeeds() (gas: 498304)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot4:test_resolvesCorrectly_succeeds() (gas: 500038)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot:test_resolvesCorrectly_succeeds() (gas: 490057)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot2:test_resolvesCorrectly_succeeds() (gas: 495173)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot3:test_resolvesCorrectly_succeeds() (gas: 496907)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot:test_resolvesCorrectly_succeeds() (gas: 486926)
FaultDisputeGame_Test:test_clockTimeExceeded_reverts() (gas: 26444)
FaultDisputeGame_Test:test_defendRoot_reverts() (gas: 13281)
FaultDisputeGame_Test:test_duplicateClaim_reverts() (gas: 103343)
FaultDisputeGame_Test:test_extraData_succeeds() (gas: 17431)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot2:test_resolvesCorrectly_succeeds() (gas: 497198)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot4:test_resolvesCorrectly_succeeds() (gas: 499064)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot:test_resolvesCorrectly_succeeds() (gas: 489092)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot2:test_resolvesCorrectly_succeeds() (gas: 494067)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot3:test_resolvesCorrectly_succeeds() (gas: 495933)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot:test_resolvesCorrectly_succeeds() (gas: 485961)
FaultDisputeGame_Test:test_defendRoot_invalidMove_reverts() (gas: 13250)
FaultDisputeGame_Test:test_extraData_succeeds() (gas: 17409)
FaultDisputeGame_Test:test_gameData_succeeds() (gas: 17834)
FaultDisputeGame_Test:test_gameDepthExceeded_reverts() (gas: 408128)
FaultDisputeGame_Test:test_gameStart_succeeds() (gas: 10359)
FaultDisputeGame_Test:test_gameType_succeeds() (gas: 8281)
FaultDisputeGame_Test:test_initialRootClaimData_succeeds() (gas: 17669)
FaultDisputeGame_Test:test_moveAgainstNonexistentParent_reverts() (gas: 24611)
FaultDisputeGame_Test:test_move_gameNotInProgress_reverts() (gas: 10901)
FaultDisputeGame_Test:test_resolve_challengeContested() (gas: 221222)
FaultDisputeGame_Test:test_gameStart_succeeds() (gas: 10337)
FaultDisputeGame_Test:test_gameType_succeeds() (gas: 8216)
FaultDisputeGame_Test:test_initialRootClaimData_succeeds() (gas: 17691)
FaultDisputeGame_Test:test_move_clockTimeExceeded_reverts() (gas: 26410)
FaultDisputeGame_Test:test_move_duplicateClaim_reverts() (gas: 103231)
FaultDisputeGame_Test:test_move_gameDepthExceeded_reverts() (gas: 407967)
FaultDisputeGame_Test:test_move_gameNotInProgress_reverts() (gas: 10923)
FaultDisputeGame_Test:test_move_nonExistentParent_reverts() (gas: 24632)
FaultDisputeGame_Test:test_resolve_challengeContested() (gas: 221074)
FaultDisputeGame_Test:test_resolve_notInProgress_reverts() (gas: 9657)
FaultDisputeGame_Test:test_resolve_rootContested() (gas: 106144)
FaultDisputeGame_Test:test_resolve_rootUncontested() (gas: 23697)
FaultDisputeGame_Test:test_resolve_teamDeathmatch() (gas: 391960)
FaultDisputeGame_Test:test_rootClaim_succeeds() (gas: 8225)
FaultDisputeGame_Test:test_simpleAttack_succeeds() (gas: 107438)
FaultDisputeGame_Test:test_resolve_rootContested() (gas: 106120)
FaultDisputeGame_Test:test_resolve_rootUncontested() (gas: 23630)
FaultDisputeGame_Test:test_resolve_teamDeathmatch() (gas: 391731)
FaultDisputeGame_Test:test_rootClaim_succeeds() (gas: 8203)
FaultDisputeGame_Test:test_simpleAttack_succeeds() (gas: 107322)
FeeVault_Test:test_constructor_succeeds() (gas: 18185)
GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_0() (gas: 352135)
GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_1() (gas: 2950342)
......@@ -230,6 +230,7 @@ LegacyERC20ETH_Test:test_mint_doesNotExist_reverts() (gas: 10627)
LegacyERC20ETH_Test:test_transferFrom_doesNotExist_reverts() (gas: 12957)
LegacyERC20ETH_Test:test_transfer_doesNotExist_reverts() (gas: 10755)
LegacyMessagePasser_Test:test_passMessageToL1_succeeds() (gas: 34524)
LibPosition_Test:test_pos_correctness_succeeds() (gas: 38711)
MerkleTrie_get_Test:test_get_corruptedProof_reverts() (gas: 5736)
MerkleTrie_get_Test:test_get_extraProofElements_reverts() (gas: 58975)
MerkleTrie_get_Test:test_get_invalidDataRemainder_reverts() (gas: 35852)
......
......@@ -123,7 +123,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone {
// Pull the parent position out of storage.
Position parentPos = parent.position;
// Determine the position of the step.
Position stepPos = _isAttack ? parentPos.attack() : parentPos.defend();
Position stepPos = parentPos.move(_isAttack);
// Ensure that the step position is 1 deeper than the maximum game depth.
if (stepPos.depth() != MAX_GAME_DEPTH + 1) {
......@@ -214,7 +214,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone {
// Compute the position that the claim commits to. Because the parent's position is already
// known, we can compute the next position by moving left or right depending on whether
// or not the move is an attack or defense.
Position nextPosition = _isAttack ? parent.position.attack() : parent.position.defend();
Position nextPosition = parent.position.move(_isAttack);
// At the leaf nodes of the game, the only option is to run a step to prove or disprove
// the above claim. At this depth, the parent claim commits to the state after a single
......
......@@ -8,20 +8,27 @@ import "../../libraries/DisputeTypes.sol";
* @notice This library contains helper functions for working with the `Position` type.
*/
library LibPosition {
/**
* @notice Computes a generalized index (2^{depth} + indexAtDepth).
* @param _depth The depth of the position.
* @param _indexAtDepth The index at the depth of the position.
* @return position_ The computed generalized index.
*/
function wrap(uint64 _depth, uint64 _indexAtDepth) internal pure returns (Position position_) {
assembly {
// gindex = 2^{_depth} + _indexAtDepth
position_ := add(shl(_depth, 1), _indexAtDepth)
}
}
/**
* @notice Pulls the `depth` out of a packed `Position` type.
* @param _position The position to get the `depth` of.
* @return depth_ The `depth` of the `position`.
* @notice Pulls the `depth` out of a `Position` type.
* @param _position The generalized index to get the `depth` of.
* @return depth_ The `depth` of the `position` gindex.
* @custom:attribution Solady <https://github.com/Vectorized/Solady>
*/
function depth(Position _position) internal pure returns (uint64 depth_) {
// Return the most significant bit position
// Return the most significant bit offset, which signifies the depth of the gindex.
assembly {
depth_ := or(depth_, shl(6, lt(0xffffffffffffffff, shr(depth_, _position))))
depth_ := or(depth_, shl(5, lt(0xffffffff, shr(depth_, _position))))
......@@ -45,12 +52,16 @@ library LibPosition {
}
/**
* @notice Pulls the `indexAtDepth` out of a packed `Position` type.
* @param _position The position to get the `indexAtDepth` of.
* @return indexAtDepth_ The `indexAtDepth` of the `position`.
* @notice Pulls the `indexAtDepth` out of a `Position` type.
* The `indexAtDepth` is the left/right index of a position at a specific depth within
* the binary tree, starting from index 0. For example, at gindex 2, the `depth` = 1
* and the `indexAtDepth` = 0.
* @param _position The generalized index to get the `indexAtDepth` of.
* @return indexAtDepth_ The `indexAtDepth` of the `position` gindex.
*/
function indexAtDepth(Position _position) internal pure returns (uint64 indexAtDepth_) {
// Return bits p_{msb-1}...p_{0}
// Return bits p_{msb-1}...p_{0}. This effectively pulls the 2^{depth} out of the gindex,
// leaving only the `indexAtDepth`.
uint256 msb = depth(_position);
assembly {
indexAtDepth_ := sub(_position, shl(msb, 1))
......@@ -58,7 +69,7 @@ library LibPosition {
}
/**
* @notice Get the position to the left of `position`.
* @notice Get the left child of `_position`.
* @param _position The position to get the left position of.
* @return left_ The position to the left of `position`.
*/
......@@ -69,18 +80,18 @@ library LibPosition {
}
/**
* @notice Get the position to the right of `position`.
* @notice Get the right child of `_position`
* @param _position The position to get the right position of.
* @return right_ The position to the right of `position`.
*/
function right(Position _position) internal pure returns (Position right_) {
assembly {
right_ := add(1, shl(1, _position))
right_ := or(1, shl(1, _position))
}
}
/**
* @notice Get the parent position of `position`.
* @notice Get the parent position of `_position`.
* @param _position The position to get the parent position of.
* @return parent_ The parent position of `position`.
*/
......@@ -91,10 +102,11 @@ library LibPosition {
}
/**
* @notice Get the deepest, right most index relative to the `position`.
* @param _position The position to get the relative deepest, right most index of.
* @notice Get the deepest, right most gindex relative to the `position`. This is equivalent to
* calling `right` on a position until the maximum depth is reached.
* @param _position The position to get the relative deepest, right most gindex of.
* @param _maxDepth The maximum depth of the game.
* @return rightIndex_ The deepest, right most index relative to the `position`.
* @return rightIndex_ The deepest, right most gindex relative to the `position`.
*/
function rightIndex(
Position _position,
......@@ -102,34 +114,22 @@ library LibPosition {
) internal pure returns (Position rightIndex_) {
uint256 msb = depth(_position);
assembly {
switch eq(msb, _maxDepth)
case true {
rightIndex_ := _position
}
default {
let remaining := sub(_maxDepth, msb)
rightIndex_ := or(shl(remaining, _position), sub(shl(remaining, 1), 1))
}
}
}
/**
* @notice Get the attack position relative to `position`.
* @param _position The position to get the relative attack position of.
* @return attack_ The attack position relative to `position`.
*/
function attack(Position _position) internal pure returns (Position attack_) {
return left(_position);
}
/**
* @notice Get the defense position relative to `position`.
* @param _position The position to get the relative defense position of.
* @return defense_ The defense position relative to `position`.
* @notice Get the move position of `_position`, which is the left child of:
* 1. `_position + 1` if `_isAttack` is true.
* 1. `_position` if `_isAttack` is false.
* @param _position The position to get the relative attack/defense position of.
* @param _isAttack Whether or not the move is an attack move.
* @return move_ The move position relative to `position`.
*/
function defend(Position _position) internal pure returns (Position defense_) {
function move(Position _position, bool _isAttack) internal pure returns (Position move_) {
assembly {
defense_ := shl(1, add(1, shl(1, shr(1, _position))))
move_ := shl(1, or(iszero(_isAttack), _position))
}
}
}
......@@ -157,7 +157,7 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init {
/**
* @dev Tests that an attempt to defend the root claim reverts with the `CannotDefendRootClaim` error.
*/
function test_defendRoot_reverts() public {
function test_defendRoot_invalidMove_reverts() public {
vm.expectRevert(CannotDefendRootClaim.selector);
gameProxy.defend(0, Claim.wrap(bytes32(uint256(5))));
}
......@@ -166,7 +166,7 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init {
* @dev Tests that an attempt to move against a claim that does not exist reverts with the
* `ParentDoesNotExist` error.
*/
function test_moveAgainstNonexistentParent_reverts() public {
function test_move_nonExistentParent_reverts() public {
Claim claim = Claim.wrap(bytes32(uint256(5)));
// Expect an out of bounds revert for an attack
......@@ -182,7 +182,7 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init {
* @dev Tests that an attempt to move at the maximum game depth reverts with the
* `GameDepthExceeded` error.
*/
function test_gameDepthExceeded_reverts() public {
function test_move_gameDepthExceeded_reverts() public {
Claim claim = Claim.wrap(bytes32(uint256(5)));
uint256 maxDepth = gameProxy.MAX_GAME_DEPTH();
......@@ -201,7 +201,7 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init {
* @dev Tests that a move made after the clock time has exceeded reverts with the
* `ClockTimeExceeded` error.
*/
function test_clockTimeExceeded_reverts() public {
function test_move_clockTimeExceeded_reverts() public {
// Warp ahead past the clock time for the first move (3 1/2 days)
vm.warp(block.timestamp + 3 days + 12 hours + 1);
vm.expectRevert(ClockTimeExceeded.selector);
......@@ -212,7 +212,7 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init {
* @dev Tests that an identical claim cannot be made twice. The duplicate claim attempt should
* revert with the `ClaimAlreadyExists` error.
*/
function test_duplicateClaim_reverts() public {
function test_move_duplicateClaim_reverts() public {
Claim claim = Claim.wrap(bytes32(uint256(5)));
// Make the first move. This should succeed.
......@@ -250,7 +250,7 @@ contract FaultDisputeGame_Test is FaultDisputeGame_Init {
assertEq(parentIndex, 0);
assertEq(countered, false);
assertEq(Claim.unwrap(claim), Claim.unwrap(counter));
assertEq(Position.unwrap(position), Position.unwrap(Position.wrap(1).attack()));
assertEq(Position.unwrap(position), Position.unwrap(Position.wrap(1).move(true)));
assertEq(
Clock.unwrap(clock),
Clock.unwrap(LibClock.wrap(Duration.wrap(5), Timestamp.wrap(uint64(block.timestamp))))
......@@ -384,7 +384,7 @@ contract GamePlayer {
if (grandparentIndex == type(uint32).max) {
// If the parent claim is the root claim, begin by attacking.
movePos = parentPos.attack();
movePos = parentPos.move(true);
// Flag the move as an attack.
isAttack = true;
} else {
......@@ -402,10 +402,10 @@ contract GamePlayer {
if (Claim.unwrap(ourParentClaim) != Claim.unwrap(parentClaim)) {
// Attack parent.
movePos = parentPos.attack();
movePos = parentPos.move(true);
// If we also disagree with the grandparent, attack it as well.
if (Claim.unwrap(ourGrandparentClaim) != Claim.unwrap(grandparentClaim)) {
movePos2 = grandparentPos.attack();
movePos2 = grandparentPos.move(true);
}
// Flag the move as an attack.
......@@ -414,7 +414,7 @@ contract GamePlayer {
Claim.unwrap(ourParentClaim) == Claim.unwrap(parentClaim) &&
Claim.unwrap(ourGrandparentClaim) == Claim.unwrap(grandparentClaim)
) {
movePos = parentPos.defend();
movePos = parentPos.move(false);
}
}
......@@ -474,7 +474,7 @@ contract GamePlayer {
// If we have a second move position, attack the grandparent.
if (Position.unwrap(movePos2) != 0) {
(, , , Position grandparentPos, ) = gameProxy.claimData(grandparentIndex);
Claim ourGrandparentClaim = claimAt(grandparentPos.attack());
Claim ourGrandparentClaim = claimAt(grandparentPos.move(true));
gameProxy.attack(grandparentIndex, ourGrandparentClaim);
counterParty.play(claimDataLen() - 1);
......
......@@ -28,7 +28,7 @@ contract LibPosition_Test is Test {
/**
* @notice Tests that the `depth` function correctly shifts out the `depth` from a packed `Position` type.
*/
function testFuzz_depth_correctness(uint8 _depth, uint64 _indexAtDepth) public {
function testFuzz_depth_correctness_suceeds(uint8 _depth, uint64 _indexAtDepth) public {
_depth = uint8(bound(_depth, 0, MAX_DEPTH));
_indexAtDepth = boundIndexAtDepth(_depth, _indexAtDepth);
Position position = LibPosition.wrap(_depth, _indexAtDepth);
......@@ -38,7 +38,7 @@ contract LibPosition_Test is Test {
/**
* @notice Tests that the `indexAtDepth` function correctly shifts out the `indexAtDepth` from a packed `Position` type.
*/
function testFuzz_indexAtDepth_correctness(uint8 _depth, uint64 _indexAtDepth) public {
function testFuzz_indexAtDepth_correctness_suceeds(uint8 _depth, uint64 _indexAtDepth) public {
_depth = uint8(bound(_depth, 0, MAX_DEPTH));
_indexAtDepth = boundIndexAtDepth(_depth, _indexAtDepth);
Position position = LibPosition.wrap(_depth, _indexAtDepth);
......@@ -48,7 +48,7 @@ contract LibPosition_Test is Test {
/**
* @notice Tests that the `left` function correctly computes the position of the left child.
*/
function testFuzz_left_correctness(uint8 _depth, uint64 _indexAtDepth) public {
function testFuzz_left_correctness_suceeds(uint8 _depth, uint64 _indexAtDepth) public {
_depth = uint8(bound(_depth, 0, MAX_DEPTH));
_indexAtDepth = boundIndexAtDepth(_depth, _indexAtDepth);
......@@ -62,7 +62,7 @@ contract LibPosition_Test is Test {
/**
* @notice Tests that the `right` function correctly computes the position of the right child.
*/
function testFuzz_right_correctness(uint8 _depth, uint64 _indexAtDepth) public {
function testFuzz_right_correctness_suceeds(uint8 _depth, uint64 _indexAtDepth) public {
// Depth bound: [0, 63]
_depth = uint8(bound(_depth, 0, MAX_DEPTH));
_indexAtDepth = boundIndexAtDepth(_depth, _indexAtDepth);
......@@ -77,7 +77,7 @@ contract LibPosition_Test is Test {
/**
* @notice Tests that the `parent` function correctly computes the position of the parent.
*/
function testFuzz_parent_correctness(uint8 _depth, uint64 _indexAtDepth) public {
function testFuzz_parent_correctness_suceeds(uint8 _depth, uint64 _indexAtDepth) public {
_depth = uint8(bound(_depth, 1, MAX_DEPTH));
_indexAtDepth = boundIndexAtDepth(_depth, _indexAtDepth);
......@@ -92,7 +92,7 @@ contract LibPosition_Test is Test {
* @notice Tests that the `rightIndex` function correctly computes the deepest, right most index relative
* to a given position.
*/
function testFuzz_rightIndex_correctness(
function testFuzz_rightIndex_correctness_suceeds(
uint64 _maxDepth,
uint8 _depth,
uint64 _indexAtDepth
......@@ -120,13 +120,13 @@ contract LibPosition_Test is Test {
* a given position.
* @dev `attack` is an alias for `left`, but we test it separately for completeness.
*/
function testFuzz_attack_correctness(uint8 _depth, uint64 _indexAtDepth) public {
function testFuzz_attack_correctness_suceeds(uint8 _depth, uint64 _indexAtDepth) public {
// Depth bound: [0, 63]
_depth = uint8(bound(_depth, 0, MAX_DEPTH));
_indexAtDepth = boundIndexAtDepth(_depth, _indexAtDepth);
Position position = LibPosition.wrap(_depth, _indexAtDepth);
Position attack = position.attack();
Position attack = position.move(true);
assertEq(attack.depth(), _depth + 1);
assertEq(attack.indexAtDepth(), _indexAtDepth * 2);
......@@ -138,15 +138,271 @@ contract LibPosition_Test is Test {
* @dev A defense can only be given if the position does not belong to the root claim, hence the bound of [1, 127]
* on the depth.
*/
function testFuzz_defend_correctness(uint8 _depth, uint64 _indexAtDepth) public {
function testFuzz_defend_correctness_suceeds(uint8 _depth, uint64 _indexAtDepth) public {
// Depth bound: [1, 63]
_depth = uint8(bound(_depth, 1, MAX_DEPTH));
_indexAtDepth = boundIndexAtDepth(_depth, _indexAtDepth);
Position position = LibPosition.wrap(_depth, _indexAtDepth);
Position defend = position.defend();
Position defend = position.move(false);
assertEq(defend.depth(), _depth + 1);
assertEq(defend.indexAtDepth(), ((_indexAtDepth / 2) * 2 + 1) * 2);
}
/**
* @notice A static unit test for the correctness of all gindicies, (depth, index) combos,
* and the trace index in a tree of max depth = 4.
*/
function test_pos_correctness_succeeds() public {
uint256 maxDepth = 4;
Position p = LibPosition.wrap(0, 0);
assertEq(Position.unwrap(p), 1); // gindex = 1
assertEq(p.depth(), 0); // depth = 0
assertEq(p.indexAtDepth(), 0); // indexAtDepth = 0
Position r = p.rightIndex(maxDepth);
assertEq(Position.unwrap(r), 31); // right gindex = 31
assertEq(r.indexAtDepth(), 15); // trace index = 15
p = LibPosition.wrap(1, 0);
assertEq(Position.unwrap(p), 2); // gindex = 2
assertEq(p.depth(), 1); // depth = 1
assertEq(p.indexAtDepth(), 0); // indexAtDepth = 0
r = p.rightIndex(maxDepth);
assertEq(Position.unwrap(r), 23); // right gindex = 23
assertEq(r.indexAtDepth(), 7); // trace index = 7
p = LibPosition.wrap(1, 1);
assertEq(Position.unwrap(p), 3); // gindex = 3
assertEq(p.depth(), 1); // depth = 1
assertEq(p.indexAtDepth(), 1); // indexAtDepth = 1
r = p.rightIndex(maxDepth);
assertEq(Position.unwrap(r), 31); // right gindex = 31
assertEq(r.indexAtDepth(), 15); // trace index = 15
p = LibPosition.wrap(2, 0);
assertEq(Position.unwrap(p), 4); // gindex = 4
assertEq(p.depth(), 2); // depth = 2
assertEq(p.indexAtDepth(), 0); // indexAtDepth = 0
r = p.rightIndex(maxDepth);
assertEq(Position.unwrap(r), 19); // right gindex = 19
assertEq(r.indexAtDepth(), 3); // trace index = 3
p = LibPosition.wrap(2, 1);
assertEq(Position.unwrap(p), 5); // gindex = 5
assertEq(p.depth(), 2); // depth = 2
assertEq(p.indexAtDepth(), 1); // indexAtDepth = 1
r = p.rightIndex(maxDepth);
assertEq(Position.unwrap(r), 23); // right gindex = 23
assertEq(r.indexAtDepth(), 7); // trace index = 7
p = LibPosition.wrap(2, 2);
assertEq(Position.unwrap(p), 6); // gindex = 6
assertEq(p.depth(), 2); // depth = 2
assertEq(p.indexAtDepth(), 2); // indexAtDepth = 2
r = p.rightIndex(maxDepth);
assertEq(Position.unwrap(r), 27); // right gindex = 27
assertEq(r.indexAtDepth(), 11); // trace index = 11
p = LibPosition.wrap(2, 3);
assertEq(Position.unwrap(p), 7); // gindex = 7
assertEq(p.depth(), 2); // depth = 2
assertEq(p.indexAtDepth(), 3); // indexAtDepth = 3
r = p.rightIndex(maxDepth);
assertEq(Position.unwrap(r), 31); // right gindex = 31
assertEq(r.indexAtDepth(), 15); // trace index = 15
p = LibPosition.wrap(3, 0);
assertEq(Position.unwrap(p), 8); // gindex = 8
assertEq(p.depth(), 3); // depth = 3
assertEq(p.indexAtDepth(), 0); // indexAtDepth = 0
r = p.rightIndex(maxDepth);
assertEq(Position.unwrap(r), 17); // right gindex = 17
assertEq(r.indexAtDepth(), 1); // trace index = 1
p = LibPosition.wrap(3, 1);
assertEq(Position.unwrap(p), 9); // gindex = 9
assertEq(p.depth(), 3); // depth = 3
assertEq(p.indexAtDepth(), 1); // indexAtDepth = 1
r = p.rightIndex(maxDepth);
assertEq(Position.unwrap(r), 19); // right gindex = 19
assertEq(r.indexAtDepth(), 3); // trace index = 3
p = LibPosition.wrap(3, 2);
assertEq(Position.unwrap(p), 10); // gindex = 10
assertEq(p.depth(), 3); // depth = 3
assertEq(p.indexAtDepth(), 2); // indexAtDepth = 2
r = p.rightIndex(maxDepth);
assertEq(Position.unwrap(r), 21); // right gindex = 21
assertEq(r.indexAtDepth(), 5); // trace index = 5
p = LibPosition.wrap(3, 3);
assertEq(Position.unwrap(p), 11); // gindex = 11
assertEq(p.depth(), 3); // depth = 3
assertEq(p.indexAtDepth(), 3); // indexAtDepth = 3
r = p.rightIndex(maxDepth);
assertEq(Position.unwrap(r), 23); // right gindex = 23
assertEq(r.indexAtDepth(), 7); // trace index = 7
p = LibPosition.wrap(3, 4);
assertEq(Position.unwrap(p), 12); // gindex = 12
assertEq(p.depth(), 3); // depth = 3
assertEq(p.indexAtDepth(), 4); // indexAtDepth = 4
r = p.rightIndex(maxDepth);
assertEq(Position.unwrap(r), 25); // right gindex = 25
assertEq(r.indexAtDepth(), 9); // trace index = 9
p = LibPosition.wrap(3, 5);
assertEq(Position.unwrap(p), 13); // gindex = 13
assertEq(p.depth(), 3); // depth = 3
assertEq(p.indexAtDepth(), 5); // indexAtDepth = 5
r = p.rightIndex(maxDepth);
assertEq(Position.unwrap(r), 27); // right gindex = 27
assertEq(r.indexAtDepth(), 11); // trace index = 11
p = LibPosition.wrap(3, 6);
assertEq(Position.unwrap(p), 14); // gindex = 14
assertEq(p.depth(), 3); // depth = 3
assertEq(p.indexAtDepth(), 6); // indexAtDepth = 6
r = p.rightIndex(maxDepth);
assertEq(Position.unwrap(r), 29); // right gindex = 29
assertEq(r.indexAtDepth(), 13); // trace index = 13
p = LibPosition.wrap(3, 7);
assertEq(Position.unwrap(p), 15); // gindex = 15
assertEq(p.depth(), 3); // depth = 3
assertEq(p.indexAtDepth(), 7); // indexAtDepth = 7
r = p.rightIndex(maxDepth);
assertEq(Position.unwrap(r), 31); // right gindex = 31
assertEq(r.indexAtDepth(), 15); // trace index = 15
p = LibPosition.wrap(4, 0);
assertEq(Position.unwrap(p), 16); // gindex = 16
assertEq(p.depth(), 4); // depth = 4
assertEq(p.indexAtDepth(), 0); // indexAtDepth = 0
r = p.rightIndex(maxDepth);
assertEq(Position.unwrap(r), 16); // right gindex = 16
assertEq(r.indexAtDepth(), 0); // trace index = 0
p = LibPosition.wrap(4, 1);
assertEq(Position.unwrap(p), 17); // gindex = 17
assertEq(p.depth(), 4); // depth = 4
assertEq(p.indexAtDepth(), 1); // indexAtDepth = 1
r = p.rightIndex(maxDepth);
assertEq(Position.unwrap(r), 17); // right gindex = 17
assertEq(r.indexAtDepth(), 1); // trace index = 1
p = LibPosition.wrap(4, 2);
assertEq(Position.unwrap(p), 18); // gindex = 18
assertEq(p.depth(), 4); // depth = 4
assertEq(p.indexAtDepth(), 2); // indexAtDepth = 2
r = p.rightIndex(maxDepth);
assertEq(Position.unwrap(r), 18); // right gindex = 18
assertEq(r.indexAtDepth(), 2); // trace index = 2
p = LibPosition.wrap(4, 3);
assertEq(Position.unwrap(p), 19); // gindex = 19
assertEq(p.depth(), 4); // depth = 4
assertEq(p.indexAtDepth(), 3); // indexAtDepth = 3
r = p.rightIndex(maxDepth);
assertEq(Position.unwrap(r), 19); // right gindex = 19
assertEq(r.indexAtDepth(), 3); // trace index = 3
p = LibPosition.wrap(4, 4);
assertEq(Position.unwrap(p), 20); // gindex = 20
assertEq(p.depth(), 4); // depth = 4
assertEq(p.indexAtDepth(), 4); // indexAtDepth = 4
r = p.rightIndex(maxDepth);
assertEq(Position.unwrap(r), 20); // right gindex = 20
assertEq(r.indexAtDepth(), 4); // trace index = 4
p = LibPosition.wrap(4, 5);
assertEq(Position.unwrap(p), 21); // gindex = 21
assertEq(p.depth(), 4); // depth = 4
assertEq(p.indexAtDepth(), 5); // indexAtDepth = 5
r = p.rightIndex(maxDepth);
assertEq(Position.unwrap(r), 21); // right gindex = 21
assertEq(r.indexAtDepth(), 5); // trace index = 5
p = LibPosition.wrap(4, 6);
assertEq(Position.unwrap(p), 22); // gindex = 22
assertEq(p.depth(), 4); // depth = 4
assertEq(p.indexAtDepth(), 6); // indexAtDepth = 6
r = p.rightIndex(maxDepth);
assertEq(Position.unwrap(r), 22); // right gindex = 22
assertEq(r.indexAtDepth(), 6); // trace index = 6
p = LibPosition.wrap(4, 7);
assertEq(Position.unwrap(p), 23); // gindex = 23
assertEq(p.depth(), 4); // depth = 4
assertEq(p.indexAtDepth(), 7); // indexAtDepth = 7
r = p.rightIndex(maxDepth);
assertEq(Position.unwrap(r), 23); // right gindex = 23
assertEq(r.indexAtDepth(), 7); // trace index = 7
p = LibPosition.wrap(4, 8);
assertEq(Position.unwrap(p), 24); // gindex = 24
assertEq(p.depth(), 4); // depth = 4
assertEq(p.indexAtDepth(), 8); // indexAtDepth = 8
r = p.rightIndex(maxDepth);
assertEq(Position.unwrap(r), 24); // right gindex = 24
assertEq(r.indexAtDepth(), 8); // trace index = 8
p = LibPosition.wrap(4, 9);
assertEq(Position.unwrap(p), 25); // gindex = 25
assertEq(p.depth(), 4); // depth = 4
assertEq(p.indexAtDepth(), 9); // indexAtDepth = 9
r = p.rightIndex(maxDepth);
assertEq(Position.unwrap(r), 25); // right gindex = 25
assertEq(r.indexAtDepth(), 9); // trace index = 9
p = LibPosition.wrap(4, 10);
assertEq(Position.unwrap(p), 26); // gindex = 26
assertEq(p.depth(), 4); // depth = 4
assertEq(p.indexAtDepth(), 10); // indexAtDepth = 10
r = p.rightIndex(maxDepth);
assertEq(Position.unwrap(r), 26); // right gindex = 26
assertEq(r.indexAtDepth(), 10); // trace index = 10
p = LibPosition.wrap(4, 11);
assertEq(Position.unwrap(p), 27); // gindex = 27
assertEq(p.depth(), 4); // depth = 4
assertEq(p.indexAtDepth(), 11); // indexAtDepth = 11
r = p.rightIndex(maxDepth);
assertEq(Position.unwrap(r), 27); // right gindex = 27
assertEq(r.indexAtDepth(), 11); // trace index = 11
p = LibPosition.wrap(4, 12);
assertEq(Position.unwrap(p), 28); // gindex = 28
assertEq(p.depth(), 4); // depth = 4
assertEq(p.indexAtDepth(), 12); // indexAtDepth = 12
r = p.rightIndex(maxDepth);
assertEq(Position.unwrap(r), 28); // right gindex = 28
assertEq(r.indexAtDepth(), 12); // trace index = 12
p = LibPosition.wrap(4, 13);
assertEq(Position.unwrap(p), 29); // gindex = 29
assertEq(p.depth(), 4); // depth = 4
assertEq(p.indexAtDepth(), 13); // indexAtDepth = 13
r = p.rightIndex(maxDepth);
assertEq(Position.unwrap(r), 29); // right gindex = 29
assertEq(r.indexAtDepth(), 13); // trace index = 13
p = LibPosition.wrap(4, 14);
assertEq(Position.unwrap(p), 30); // gindex = 30
assertEq(p.depth(), 4); // depth = 4
assertEq(p.indexAtDepth(), 14); // indexAtDepth = 14
r = p.rightIndex(maxDepth);
assertEq(Position.unwrap(r), 30); // right gindex = 30
assertEq(r.indexAtDepth(), 14); // trace index = 14
p = LibPosition.wrap(4, 15);
assertEq(Position.unwrap(p), 31); // gindex = 31
assertEq(p.depth(), 4); // depth = 4
assertEq(p.indexAtDepth(), 15); // indexAtDepth = 15
r = p.rightIndex(maxDepth);
assertEq(Position.unwrap(r), 31); // right gindex = 31
assertEq(r.indexAtDepth(), 15); // trace index = 15
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment