diff --git a/solidity/contracts/TypedMemView.sol b/solidity/contracts/TypedMemView.sol index dca6dc55..2e9488bb 100644 --- a/solidity/contracts/TypedMemView.sol +++ b/solidity/contracts/TypedMemView.sol @@ -42,6 +42,29 @@ library TypedMemView { uint256 constant TWO_BYTE_MASK = 0xffff; // mask out top 28 bytes uint256 constant FIFTEEN_BYTE_MASK = 0xffffffffffffffffffffffffffffff; // mask out top 17 bytes + /// @notice Changes the endianness of a uint256 + /// @dev https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel + /// @param _b The unsigned integer to reverse + /// @return The reversed value + function reverseUint256(uint256 _b) private pure returns (uint256 v) { + v = _b; + + // swap bytes + v = ((v >> 8) & 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) | + ((v & 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) << 8); + // swap 2-byte long pairs + v = ((v >> 16) & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) | + ((v & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) << 16); + // swap 4-byte long pairs + v = ((v >> 32) & 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) | + ((v & 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) << 32); + // swap 8-byte long pairs + v = ((v >> 64) & 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) | + ((v & 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) << 64); + // swap 16-byte long pairs + v = (v >> 128) | (v << 128); + } + /// Create a mask with the lowest `_len` bits set function rightMask(uint8 _len) private pure returns (uint256 mask) { mask = (1 << uint256(_len)) - 1; @@ -220,6 +243,11 @@ library TypedMemView { return uint256(index(memView, _index, _bytes)) >> ((32 - _bytes) * 8); } + /// Parse an unsigned integer from LE bytes. + function indexLEUint(bytes32 memView, uint256 _index, uint8 _bytes) internal pure returns (uint256 result) { + return reverseUint256(uint256(index(memView, _index, _bytes))) & rightMask(_bytes * 8); + } + /// Parse a signed integer from the view at `_index`. Requires that the /// view have >= `_bytes` bytes following that index. function indexInt(bytes32 memView, uint256 _index, uint8 _bytes) internal pure returns (int256 result) { diff --git a/solidity/contracts/test/TestMemView.sol b/solidity/contracts/test/TestMemView.sol index ec01a804..35c56c2b 100644 --- a/solidity/contracts/test/TestMemView.sol +++ b/solidity/contracts/test/TestMemView.sol @@ -98,7 +98,7 @@ contract TestMemView { ); } - function slicing() public pure { + function slicing() public { // 76 bytes - 3 words // solium-disable-next-line max-len @@ -152,6 +152,11 @@ contract TestMemView { "index mismatch 14 byte uint" ); + require( + v1.indexLEUint(0, 14) == 0x0d0c0b0a09080706050403020100, + "index mismatch 14 byte uint le" + ); + require( v1.indexInt(0, 14) == 0x000102030405060708090a0b0c0d, "index mismatch 14 byte int"