Skip to content

Commit bddf4f6

Browse files
committed
Merge branch 'feature/Bytes-splice' into feature/base58
2 parents 99a1835 + 5a400eb commit bddf4f6

File tree

3 files changed

+39
-3
lines changed

3 files changed

+39
-3
lines changed

.changeset/afraid-chicken-attack.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'openzeppelin-solidity': minor
3+
---
4+
5+
`Bytes`: Add `splice(bytes,uint256)` and `splice(bytes,uint256,uint256)`, two "in place" variants of the existing slice functions

contracts/utils/Bytes.sol

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,35 @@ library Bytes {
9999
return result;
100100
}
101101

102+
/**
103+
* @dev In place slice: moves the content of `buffer`, from `start` (included) to the end of `buffer` to the start of that buffer.
104+
*
105+
* NOTE: This function modifies the provided buffer in place. If you need to preserve the original buffer, use {slice} instead
106+
*/
107+
function splice(bytes memory buffer, uint256 start) internal pure returns (bytes memory) {
108+
return splice(buffer, start, buffer.length);
109+
}
110+
111+
/**
112+
* @dev In place slice: moves the content of `buffer`, from `start` (included) to end (excluded) to the start of that buffer.
113+
*
114+
* NOTE: This function modifies the provided buffer in place. If you need to preserve the original buffer, use {slice} instead
115+
*/
116+
function splice(bytes memory buffer, uint256 start, uint256 end) internal pure returns (bytes memory) {
117+
// sanitize
118+
uint256 length = buffer.length;
119+
end = Math.min(end, length);
120+
start = Math.min(start, end);
121+
122+
// allocate and copy
123+
assembly ("memory-safe") {
124+
mcopy(add(buffer, 0x20), add(add(buffer, 0x20), start), sub(end, start))
125+
mstore(buffer, sub(end, start))
126+
}
127+
128+
return buffer;
129+
}
130+
102131
/**
103132
* @dev Reads a bytes32 from a bytes array without bounds checking.
104133
*

test/utils/Bytes.test.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ describe('Bytes', function () {
5656
});
5757
});
5858

59-
describe('slice', function () {
60-
describe('slice(bytes, uint256)', function () {
59+
describe('slice & splice', function () {
60+
describe('slice(bytes, uint256) & splice(bytes, uint256)', function () {
6161
for (const [descr, start] of Object.entries({
6262
'start = 0': 0,
6363
'start within bound': 10,
@@ -66,11 +66,12 @@ describe('Bytes', function () {
6666
it(descr, async function () {
6767
const result = ethers.hexlify(lorem.slice(start));
6868
expect(await this.mock.$slice(lorem, start)).to.equal(result);
69+
expect(await this.mock.$splice(lorem, start)).to.equal(result);
6970
});
7071
}
7172
});
7273

73-
describe('slice(bytes, uint256, uint256)', function () {
74+
describe('slice(bytes, uint256, uint256) & splice(bytes, uint256, uint256)', function () {
7475
for (const [descr, [start, end]] of Object.entries({
7576
'start = 0': [0, 42],
7677
'start and end within bound': [17, 42],
@@ -81,6 +82,7 @@ describe('Bytes', function () {
8182
it(descr, async function () {
8283
const result = ethers.hexlify(lorem.slice(start, end));
8384
expect(await this.mock.$slice(lorem, start, ethers.Typed.uint256(end))).to.equal(result);
85+
expect(await this.mock.$splice(lorem, start, ethers.Typed.uint256(end))).to.equal(result);
8486
});
8587
}
8688
});

0 commit comments

Comments
 (0)