Add deepCopyBytes method to LibBytes
This commit is contained in:
@@ -25,6 +25,23 @@ contract TestLibBytes is
|
||||
LibBytes
|
||||
{
|
||||
|
||||
/// @dev Performs a deep copy of a section of a byte array.
|
||||
/// @param b Byte array that will be sliced.
|
||||
/// @param startIndex Index of first byte to copy.
|
||||
/// @param endIndex Index of last byte to copy + 1.
|
||||
/// @return A deep copy of b from startIndex to endIndex.
|
||||
function publicDeepCopyBytes(
|
||||
bytes memory b,
|
||||
uint256 startIndex,
|
||||
uint256 endIndex)
|
||||
public
|
||||
pure
|
||||
returns (bytes memory copy)
|
||||
{
|
||||
copy = deepCopyBytes(b, startIndex, endIndex);
|
||||
return copy;
|
||||
}
|
||||
|
||||
/// @dev Tests equality of two byte arrays.
|
||||
/// @param lhs First byte array to compare.
|
||||
/// @param rhs Second byte array to compare.
|
||||
|
@@ -21,9 +21,50 @@ pragma solidity ^0.4.24;
|
||||
contract LibBytes {
|
||||
|
||||
// Revert reasons
|
||||
string constant GT_ZERO_LENGTH_REQUIRED = "Length must be greater than 0.";
|
||||
string constant GTE_4_LENGTH_REQUIRED = "Length must be greater than or equal to 4.";
|
||||
string constant GTE_20_LENGTH_REQUIRED = "Length must be greater than or equal to 20.";
|
||||
string constant GTE_32_LENGTH_REQUIRED = "Length must be greater than or equal to 32.";
|
||||
string constant INDEX_OUT_OF_BOUNDS = "Specified array index is out of bounds.";
|
||||
|
||||
/// @dev Performs a deep copy of a section of a byte array.
|
||||
/// @param b Byte array that will be copied.
|
||||
/// @param index Index of first byte to copy.
|
||||
/// @param len Number of bytes to copy starting from index.
|
||||
/// @return A deep copy `len` bytes of b starting from index.
|
||||
function deepCopyBytes(
|
||||
bytes memory b,
|
||||
uint256 index,
|
||||
uint256 len)
|
||||
internal
|
||||
pure
|
||||
returns (bytes memory)
|
||||
{
|
||||
require(
|
||||
len > 0,
|
||||
GT_ZERO_LENGTH_REQUIRED
|
||||
);
|
||||
require(
|
||||
b.length >= index + len,
|
||||
INDEX_OUT_OF_BOUNDS
|
||||
);
|
||||
|
||||
bytes memory copy = new bytes(len);
|
||||
|
||||
// Arrays are prefixed by a 256 bit length parameter
|
||||
index += 32;
|
||||
|
||||
assembly {
|
||||
// Start storing onto copy after length field
|
||||
let storeStartIndex := add(copy, 32)
|
||||
// Start loading from b at index
|
||||
let startLoadIndex := add(b, index)
|
||||
for {let i := 0} lt(i, len) {i := add(i, 32)} {
|
||||
mstore(add(storeStartIndex, i), mload(add(startLoadIndex, i)))
|
||||
}
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
/// @dev Tests equality of two byte arrays.
|
||||
/// @param lhs First byte array to compare.
|
||||
|
@@ -60,6 +60,40 @@ describe('LibBytes', () => {
|
||||
await blockchainLifecycle.revertAsync();
|
||||
});
|
||||
|
||||
describe.only('deepCopyBytes', () => {
|
||||
const byteArrayLongerThan32BytesLen = (byteArrayLongerThan32Bytes.length - 2) / 2;
|
||||
it('should throw if length of copy is 0', async () => {
|
||||
const index = new BigNumber(0);
|
||||
const len = new BigNumber(0);
|
||||
return expect(
|
||||
libBytes.publicDeepCopyBytes.callAsync(byteArrayLongerThan32Bytes, index, len),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
});
|
||||
|
||||
it('should throw if start index + length to copy is greater than length of byte array', async () => {
|
||||
const index = new BigNumber(0);
|
||||
const len = new BigNumber(byteArrayLongerThan32BytesLen + 1);
|
||||
return expect(
|
||||
libBytes.publicDeepCopyBytes.callAsync(byteArrayLongerThan32Bytes, index, len),
|
||||
).to.be.rejectedWith(constants.REVERT);
|
||||
});
|
||||
|
||||
it('should copy the entire byte array if index = 0 and len = b.length', async () => {
|
||||
const index = new BigNumber(0);
|
||||
const len = new BigNumber(byteArrayLongerThan32BytesLen);
|
||||
const copy = await libBytes.publicDeepCopyBytes.callAsync(byteArrayLongerThan32Bytes, index, len);
|
||||
expect(copy).to.equal(byteArrayLongerThan32Bytes);
|
||||
});
|
||||
|
||||
it('should copy part of the byte array if area to copy is less than b.length', async () => {
|
||||
const index = new BigNumber(10);
|
||||
const len = new BigNumber(4);
|
||||
const copy = await libBytes.publicDeepCopyBytes.callAsync(byteArrayLongerThan32Bytes, index, len);
|
||||
const expectedCopy = `0x${byteArrayLongerThan32Bytes.slice(22, 30)}`;
|
||||
expect(copy).to.equal(expectedCopy);
|
||||
});
|
||||
});
|
||||
|
||||
describe('areBytesEqual', () => {
|
||||
it('should return true if byte arrays are equal (both arrays < 32 bytes)', async () => {
|
||||
const areBytesEqual = await libBytes.publicAreBytesEqual.callAsync(
|
||||
|
Reference in New Issue
Block a user