Skip to content

Commit 9cc4d59

Browse files
ernestognwAmxx
andauthored
Add Array.slice and Array.splice for value type arrays (#5965)
Co-authored-by: Hadrien Croubois <[email protected]>
1 parent 227c32c commit 9cc4d59

File tree

20 files changed

+566
-36
lines changed

20 files changed

+566
-36
lines changed

.changeset/swift-planets-juggle.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+
`Arrays`: Add `slice` and `splice` functions for value types (`uint256[]`, `bytes32[]`, `address[]`).

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
- `ERC6909` and the its extensions (`ERC6909ContentURI`, `ERC6909Metadata` and `ERC6909TokenSupply`) are no longer marked as draft since [EIP-6909](https://eips.ethereum.org/EIPS/eip-6909) is now final. Developers must update the import paths. Contracts behavior is not modified.
1111
- `SignerERC7702` is renamed as `SignerEIP7702`. Imports and inheritance must be updated to that new name and path. Behavior is unmodified.
1212
- `ERC721Holder`, `ERC1155Holder`, `ReentrancyGuard` and `ReentrancyGuardTransient` are flagged as stateless and are no longer transpiled. Developers using their upgradeable variants from `@openzeppelin/contracts-upgradeable` must update their imports to use the equivalent version available in `@openzeppelin/contracts`.
13-
- Update minimum pragma to 0.8.24 in `Votes`, `VotesExtended`, `ERC20Votes`, `Strings`, `ERC1155URIStorage`, `MessageHashUtils`, `ERC721URIStorage`, `ERC721Votes`, `ERC721Wrapper`, `ERC721Burnable`, `ERC721Consecutive`, `ERC721Enumerable`, `ERC721Pausable`, `ERC721Royalty`, `ERC721Wrapper`, `EIP712`, `ERC4626` and `ERC7739`. ([#5726](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5726))
13+
- Update minimum pragma to 0.8.24 in `AccessControlEnumerable`, `Arrays`, `CircularBuffer`, `EIP712`, `EnumerableMap`, `EnumerableSet`, `ERC1155`, `ERC1155Burnable`, `ERC1155Pausable`, `ERC1155Supply`, `ERC1155URIStorage`, `ERC20Votes`, `ERC4626`,`ERC721Burnable`, `ERC721Consecutive`, `ERC721Enumerable`, `ERC721Pausable`, `ERC721Royalty`, `ERC721URIStorage`, `ERC721Votes`, `ERC721Wrapper`, `ERC7739`, `Heap`, `MerkleTree`, `MessageHashUtils`, `Strings`, `Votes` and `VotesExtended`. ([#5723](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/5723), [#5726](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5726), [#5965](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5965))
1414
- `Account`: Add `signature` argument to the internal `_validateUserOp` function for custom signature handling logic. Developers overriding it must now provide the signature from the user operation (i.e. `userOp.signature`) to keep compatibility. ([#5976](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5976))
1515
- `AccountERC7579`: Installing and uninstalling fallback modules now require the corresponding `initData` and `deInitData` arguments to be at least 4 bytes long (matching the selector to which the fallback module is registered). It now reverts with `ERC7579CannotDecodeFallbackData` instead of treating the missing bytes as `0x00`. ([#5974](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/5974))
1616

contracts/access/extensions/AccessControlEnumerable.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// SPDX-License-Identifier: MIT
22
// OpenZeppelin Contracts (last updated v5.4.0) (access/extensions/AccessControlEnumerable.sol)
33

4-
pragma solidity ^0.8.20;
4+
pragma solidity ^0.8.24;
55

66
import {IAccessControlEnumerable} from "./IAccessControlEnumerable.sol";
77
import {AccessControl} from "../AccessControl.sol";

contracts/token/ERC1155/ERC1155.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// SPDX-License-Identifier: MIT
22
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC1155/ERC1155.sol)
33

4-
pragma solidity ^0.8.20;
4+
pragma solidity ^0.8.24;
55

66
import {IERC1155} from "./IERC1155.sol";
77
import {IERC1155MetadataURI} from "./extensions/IERC1155MetadataURI.sol";

contracts/token/ERC1155/extensions/ERC1155Burnable.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// SPDX-License-Identifier: MIT
22
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/extensions/ERC1155Burnable.sol)
33

4-
pragma solidity ^0.8.20;
4+
pragma solidity ^0.8.24;
55

66
import {ERC1155} from "../ERC1155.sol";
77

contracts/token/ERC1155/extensions/ERC1155Pausable.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// SPDX-License-Identifier: MIT
22
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC1155/extensions/ERC1155Pausable.sol)
33

4-
pragma solidity ^0.8.20;
4+
pragma solidity ^0.8.24;
55

66
import {ERC1155} from "../ERC1155.sol";
77
import {Pausable} from "../../../utils/Pausable.sol";

contracts/token/ERC1155/extensions/ERC1155Supply.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// SPDX-License-Identifier: MIT
22
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC1155/extensions/ERC1155Supply.sol)
33

4-
pragma solidity ^0.8.20;
4+
pragma solidity ^0.8.24;
55

66
import {ERC1155} from "../ERC1155.sol";
77
import {Arrays} from "../../../utils/Arrays.sol";

contracts/utils/Arrays.sol

Lines changed: 184 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// OpenZeppelin Contracts (last updated v5.4.0) (utils/Arrays.sol)
33
// This file was procedurally generated from scripts/generate/templates/Arrays.js.
44

5-
pragma solidity ^0.8.20;
5+
pragma solidity ^0.8.24;
66

77
import {Comparators} from "./Comparators.sol";
88
import {SlotDerivation} from "./SlotDerivation.sol";
@@ -375,6 +375,189 @@ library Arrays {
375375
return low;
376376
}
377377

378+
/**
379+
* @dev Copies the content of `array`, from `start` (included) to the end of `array` into a new address array in
380+
* memory.
381+
*
382+
* NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice[Javascript's `Array.slice`]
383+
*/
384+
function slice(address[] memory array, uint256 start) internal pure returns (address[] memory) {
385+
return slice(array, start, array.length);
386+
}
387+
388+
/**
389+
* @dev Copies the content of `array`, from `start` (included) to `end` (excluded) into a new address array in
390+
* memory. The `end` argument is truncated to the length of the `array`.
391+
*
392+
* NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice[Javascript's `Array.slice`]
393+
*/
394+
function slice(address[] memory array, uint256 start, uint256 end) internal pure returns (address[] memory) {
395+
// sanitize
396+
end = Math.min(end, array.length);
397+
start = Math.min(start, end);
398+
399+
// allocate and copy
400+
address[] memory result = new address[](end - start);
401+
assembly ("memory-safe") {
402+
mcopy(add(result, 0x20), add(add(array, 0x20), mul(start, 0x20)), mul(sub(end, start), 0x20))
403+
}
404+
405+
return result;
406+
}
407+
408+
/**
409+
* @dev Copies the content of `array`, from `start` (included) to the end of `array` into a new bytes32 array in
410+
* memory.
411+
*
412+
* NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice[Javascript's `Array.slice`]
413+
*/
414+
function slice(bytes32[] memory array, uint256 start) internal pure returns (bytes32[] memory) {
415+
return slice(array, start, array.length);
416+
}
417+
418+
/**
419+
* @dev Copies the content of `array`, from `start` (included) to `end` (excluded) into a new bytes32 array in
420+
* memory. The `end` argument is truncated to the length of the `array`.
421+
*
422+
* NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice[Javascript's `Array.slice`]
423+
*/
424+
function slice(bytes32[] memory array, uint256 start, uint256 end) internal pure returns (bytes32[] memory) {
425+
// sanitize
426+
end = Math.min(end, array.length);
427+
start = Math.min(start, end);
428+
429+
// allocate and copy
430+
bytes32[] memory result = new bytes32[](end - start);
431+
assembly ("memory-safe") {
432+
mcopy(add(result, 0x20), add(add(array, 0x20), mul(start, 0x20)), mul(sub(end, start), 0x20))
433+
}
434+
435+
return result;
436+
}
437+
438+
/**
439+
* @dev Copies the content of `array`, from `start` (included) to the end of `array` into a new uint256 array in
440+
* memory.
441+
*
442+
* NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice[Javascript's `Array.slice`]
443+
*/
444+
function slice(uint256[] memory array, uint256 start) internal pure returns (uint256[] memory) {
445+
return slice(array, start, array.length);
446+
}
447+
448+
/**
449+
* @dev Copies the content of `array`, from `start` (included) to `end` (excluded) into a new uint256 array in
450+
* memory. The `end` argument is truncated to the length of the `array`.
451+
*
452+
* NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice[Javascript's `Array.slice`]
453+
*/
454+
function slice(uint256[] memory array, uint256 start, uint256 end) internal pure returns (uint256[] memory) {
455+
// sanitize
456+
end = Math.min(end, array.length);
457+
start = Math.min(start, end);
458+
459+
// allocate and copy
460+
uint256[] memory result = new uint256[](end - start);
461+
assembly ("memory-safe") {
462+
mcopy(add(result, 0x20), add(add(array, 0x20), mul(start, 0x20)), mul(sub(end, start), 0x20))
463+
}
464+
465+
return result;
466+
}
467+
468+
/**
469+
* @dev Moves the content of `array`, from `start` (included) to the end of `array` to the start of that array.
470+
*
471+
* NOTE: This function modifies the provided array in place. If you need to preserve the original array, use {slice} instead.
472+
* NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice[Javascript's `Array.splice`]
473+
*/
474+
function splice(address[] memory array, uint256 start) internal pure returns (address[] memory) {
475+
return splice(array, start, array.length);
476+
}
477+
478+
/**
479+
* @dev Moves the content of `array`, from `start` (included) to `end` (excluded) to the start of that array. The
480+
* `end` argument is truncated to the length of the `array`.
481+
*
482+
* NOTE: This function modifies the provided array in place. If you need to preserve the original array, use {slice} instead.
483+
* NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice[Javascript's `Array.splice`]
484+
*/
485+
function splice(address[] memory array, uint256 start, uint256 end) internal pure returns (address[] memory) {
486+
// sanitize
487+
end = Math.min(end, array.length);
488+
start = Math.min(start, end);
489+
490+
// move and resize
491+
assembly ("memory-safe") {
492+
mcopy(add(array, 0x20), add(add(array, 0x20), mul(start, 0x20)), mul(sub(end, start), 0x20))
493+
mstore(array, sub(end, start))
494+
}
495+
496+
return array;
497+
}
498+
499+
/**
500+
* @dev Moves the content of `array`, from `start` (included) to the end of `array` to the start of that array.
501+
*
502+
* NOTE: This function modifies the provided array in place. If you need to preserve the original array, use {slice} instead.
503+
* NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice[Javascript's `Array.splice`]
504+
*/
505+
function splice(bytes32[] memory array, uint256 start) internal pure returns (bytes32[] memory) {
506+
return splice(array, start, array.length);
507+
}
508+
509+
/**
510+
* @dev Moves the content of `array`, from `start` (included) to `end` (excluded) to the start of that array. The
511+
* `end` argument is truncated to the length of the `array`.
512+
*
513+
* NOTE: This function modifies the provided array in place. If you need to preserve the original array, use {slice} instead.
514+
* NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice[Javascript's `Array.splice`]
515+
*/
516+
function splice(bytes32[] memory array, uint256 start, uint256 end) internal pure returns (bytes32[] memory) {
517+
// sanitize
518+
end = Math.min(end, array.length);
519+
start = Math.min(start, end);
520+
521+
// move and resize
522+
assembly ("memory-safe") {
523+
mcopy(add(array, 0x20), add(add(array, 0x20), mul(start, 0x20)), mul(sub(end, start), 0x20))
524+
mstore(array, sub(end, start))
525+
}
526+
527+
return array;
528+
}
529+
530+
/**
531+
* @dev Moves the content of `array`, from `start` (included) to the end of `array` to the start of that array.
532+
*
533+
* NOTE: This function modifies the provided array in place. If you need to preserve the original array, use {slice} instead.
534+
* NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice[Javascript's `Array.splice`]
535+
*/
536+
function splice(uint256[] memory array, uint256 start) internal pure returns (uint256[] memory) {
537+
return splice(array, start, array.length);
538+
}
539+
540+
/**
541+
* @dev Moves the content of `array`, from `start` (included) to `end` (excluded) to the start of that array. The
542+
* `end` argument is truncated to the length of the `array`.
543+
*
544+
* NOTE: This function modifies the provided array in place. If you need to preserve the original array, use {slice} instead.
545+
* NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice[Javascript's `Array.splice`]
546+
*/
547+
function splice(uint256[] memory array, uint256 start, uint256 end) internal pure returns (uint256[] memory) {
548+
// sanitize
549+
end = Math.min(end, array.length);
550+
start = Math.min(start, end);
551+
552+
// move and resize
553+
assembly ("memory-safe") {
554+
mcopy(add(array, 0x20), add(add(array, 0x20), mul(start, 0x20)), mul(sub(end, start), 0x20))
555+
mstore(array, sub(end, start))
556+
}
557+
558+
return array;
559+
}
560+
378561
/**
379562
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
380563
*

contracts/utils/Bytes.sol

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,7 @@ library Bytes {
8585
*/
8686
function slice(bytes memory buffer, uint256 start, uint256 end) internal pure returns (bytes memory) {
8787
// sanitize
88-
uint256 length = buffer.length;
89-
end = Math.min(end, length);
88+
end = Math.min(end, buffer.length);
9089
start = Math.min(start, end);
9190

9291
// allocate and copy
@@ -102,6 +101,7 @@ library Bytes {
102101
* @dev Moves the content of `buffer`, from `start` (included) to the end of `buffer` to the start of that buffer.
103102
*
104103
* NOTE: This function modifies the provided buffer in place. If you need to preserve the original buffer, use {slice} instead
104+
* NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice[Javascript's `Array.splice`]
105105
*/
106106
function splice(bytes memory buffer, uint256 start) internal pure returns (bytes memory) {
107107
return splice(buffer, start, buffer.length);
@@ -112,11 +112,11 @@ library Bytes {
112112
* `end` argument is truncated to the length of the `buffer`.
113113
*
114114
* NOTE: This function modifies the provided buffer in place. If you need to preserve the original buffer, use {slice} instead
115+
* NOTE: replicates the behavior of https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice[Javascript's `Array.splice`]
115116
*/
116117
function splice(bytes memory buffer, uint256 start, uint256 end) internal pure returns (bytes memory) {
117118
// sanitize
118-
uint256 length = buffer.length;
119-
end = Math.min(end, length);
119+
end = Math.min(end, buffer.length);
120120
start = Math.min(start, end);
121121

122122
// allocate and copy

contracts/utils/structs/CircularBuffer.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// SPDX-License-Identifier: MIT
22
// OpenZeppelin Contracts (last updated v5.3.0) (utils/structs/CircularBuffer.sol)
3-
pragma solidity ^0.8.20;
3+
pragma solidity ^0.8.24;
44

55
import {Math} from "../math/Math.sol";
66
import {Arrays} from "../Arrays.sol";

0 commit comments

Comments
 (0)