Skip to content

Commit 79e4988

Browse files
ernestognwarr00Amxx
authored
Add replace functions to Arrays.sol and Bytes.sol (#5995)
Co-authored-by: Arr00 <13561405+arr00@users.noreply.github.com> Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
1 parent 53c2c64 commit 79e4988

File tree

7 files changed

+481
-0
lines changed

7 files changed

+481
-0
lines changed

.changeset/fluffy-facts-brake.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 `replace` functions enabling in-place array modification of `address[]`, `bytes32[]` and `uint256[]` arrays, with new content from another array.

.changeset/forty-ads-design.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 `replace` functions that replaces a portion of a bytes buffer with content from another buffer.

contracts/utils/Arrays.sol

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,57 @@ library Arrays {
496496
return array;
497497
}
498498

499+
/**
500+
* @dev Replaces elements in `array` starting at `pos` with all elements from `replacement`.
501+
*
502+
* Parameters are clamped to valid ranges (i.e. `pos` is clamped to `[0, array.length]`).
503+
* If `pos >= array.length`, no replacement occurs and the array is returned unchanged.
504+
*
505+
* NOTE: This function modifies the provided array in place.
506+
*/
507+
function replace(
508+
address[] memory array,
509+
uint256 pos,
510+
address[] memory replacement
511+
) internal pure returns (address[] memory) {
512+
return replace(array, pos, replacement, 0, replacement.length);
513+
}
514+
515+
/**
516+
* @dev Replaces elements in `array` starting at `pos` with elements from `replacement` starting at `offset`.
517+
* Copies at most `length` elements from `replacement` to `array`.
518+
*
519+
* Parameters are clamped to valid ranges (i.e. `pos` is clamped to `[0, array.length]`, `offset` is
520+
* clamped to `[0, replacement.length]`, and `length` is clamped to `min(length, replacement.length - offset,
521+
* array.length - pos)`). If `pos >= array.length` or `offset >= replacement.length`, no replacement occurs
522+
* and the array is returned unchanged.
523+
*
524+
* NOTE: This function modifies the provided array in place.
525+
*/
526+
function replace(
527+
address[] memory array,
528+
uint256 pos,
529+
address[] memory replacement,
530+
uint256 offset,
531+
uint256 length
532+
) internal pure returns (address[] memory) {
533+
// sanitize
534+
pos = Math.min(pos, array.length);
535+
offset = Math.min(offset, replacement.length);
536+
length = Math.min(length, Math.min(replacement.length - offset, array.length - pos));
537+
538+
// allocate and copy
539+
assembly ("memory-safe") {
540+
mcopy(
541+
add(add(array, 0x20), mul(pos, 0x20)),
542+
add(add(replacement, 0x20), mul(offset, 0x20)),
543+
mul(length, 0x20)
544+
)
545+
}
546+
547+
return array;
548+
}
549+
499550
/**
500551
* @dev Moves the content of `array`, from `start` (included) to the end of `array` to the start of that array.
501552
*
@@ -527,6 +578,57 @@ library Arrays {
527578
return array;
528579
}
529580

581+
/**
582+
* @dev Replaces elements in `array` starting at `pos` with all elements from `replacement`.
583+
*
584+
* Parameters are clamped to valid ranges (i.e. `pos` is clamped to `[0, array.length]`).
585+
* If `pos >= array.length`, no replacement occurs and the array is returned unchanged.
586+
*
587+
* NOTE: This function modifies the provided array in place.
588+
*/
589+
function replace(
590+
bytes32[] memory array,
591+
uint256 pos,
592+
bytes32[] memory replacement
593+
) internal pure returns (bytes32[] memory) {
594+
return replace(array, pos, replacement, 0, replacement.length);
595+
}
596+
597+
/**
598+
* @dev Replaces elements in `array` starting at `pos` with elements from `replacement` starting at `offset`.
599+
* Copies at most `length` elements from `replacement` to `array`.
600+
*
601+
* Parameters are clamped to valid ranges (i.e. `pos` is clamped to `[0, array.length]`, `offset` is
602+
* clamped to `[0, replacement.length]`, and `length` is clamped to `min(length, replacement.length - offset,
603+
* array.length - pos)`). If `pos >= array.length` or `offset >= replacement.length`, no replacement occurs
604+
* and the array is returned unchanged.
605+
*
606+
* NOTE: This function modifies the provided array in place.
607+
*/
608+
function replace(
609+
bytes32[] memory array,
610+
uint256 pos,
611+
bytes32[] memory replacement,
612+
uint256 offset,
613+
uint256 length
614+
) internal pure returns (bytes32[] memory) {
615+
// sanitize
616+
pos = Math.min(pos, array.length);
617+
offset = Math.min(offset, replacement.length);
618+
length = Math.min(length, Math.min(replacement.length - offset, array.length - pos));
619+
620+
// allocate and copy
621+
assembly ("memory-safe") {
622+
mcopy(
623+
add(add(array, 0x20), mul(pos, 0x20)),
624+
add(add(replacement, 0x20), mul(offset, 0x20)),
625+
mul(length, 0x20)
626+
)
627+
}
628+
629+
return array;
630+
}
631+
530632
/**
531633
* @dev Moves the content of `array`, from `start` (included) to the end of `array` to the start of that array.
532634
*
@@ -558,6 +660,57 @@ library Arrays {
558660
return array;
559661
}
560662

663+
/**
664+
* @dev Replaces elements in `array` starting at `pos` with all elements from `replacement`.
665+
*
666+
* Parameters are clamped to valid ranges (i.e. `pos` is clamped to `[0, array.length]`).
667+
* If `pos >= array.length`, no replacement occurs and the array is returned unchanged.
668+
*
669+
* NOTE: This function modifies the provided array in place.
670+
*/
671+
function replace(
672+
uint256[] memory array,
673+
uint256 pos,
674+
uint256[] memory replacement
675+
) internal pure returns (uint256[] memory) {
676+
return replace(array, pos, replacement, 0, replacement.length);
677+
}
678+
679+
/**
680+
* @dev Replaces elements in `array` starting at `pos` with elements from `replacement` starting at `offset`.
681+
* Copies at most `length` elements from `replacement` to `array`.
682+
*
683+
* Parameters are clamped to valid ranges (i.e. `pos` is clamped to `[0, array.length]`, `offset` is
684+
* clamped to `[0, replacement.length]`, and `length` is clamped to `min(length, replacement.length - offset,
685+
* array.length - pos)`). If `pos >= array.length` or `offset >= replacement.length`, no replacement occurs
686+
* and the array is returned unchanged.
687+
*
688+
* NOTE: This function modifies the provided array in place.
689+
*/
690+
function replace(
691+
uint256[] memory array,
692+
uint256 pos,
693+
uint256[] memory replacement,
694+
uint256 offset,
695+
uint256 length
696+
) internal pure returns (uint256[] memory) {
697+
// sanitize
698+
pos = Math.min(pos, array.length);
699+
offset = Math.min(offset, replacement.length);
700+
length = Math.min(length, Math.min(replacement.length - offset, array.length - pos));
701+
702+
// allocate and copy
703+
assembly ("memory-safe") {
704+
mcopy(
705+
add(add(array, 0x20), mul(pos, 0x20)),
706+
add(add(replacement, 0x20), mul(offset, 0x20)),
707+
mul(length, 0x20)
708+
)
709+
}
710+
711+
return array;
712+
}
713+
561714
/**
562715
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check.
563716
*

contracts/utils/Bytes.sol

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,49 @@ library Bytes {
128128
return buffer;
129129
}
130130

131+
/**
132+
* @dev Replaces bytes in `buffer` starting at `pos` with all bytes from `replacement`.
133+
*
134+
* Parameters are clamped to valid ranges (i.e. `pos` is clamped to `[0, buffer.length]`).
135+
* If `pos >= buffer.length`, no replacement occurs and the buffer is returned unchanged.
136+
*
137+
* NOTE: This function modifies the provided buffer in place.
138+
*/
139+
function replace(bytes memory buffer, uint256 pos, bytes memory replacement) internal pure returns (bytes memory) {
140+
return replace(buffer, pos, replacement, 0, replacement.length);
141+
}
142+
143+
/**
144+
* @dev Replaces bytes in `buffer` starting at `pos` with bytes from `replacement` starting at `offset`.
145+
* Copies at most `length` bytes from `replacement` to `buffer`.
146+
*
147+
* Parameters are clamped to valid ranges (i.e. `pos` is clamped to `[0, buffer.length]`, `offset` is
148+
* clamped to `[0, replacement.length]`, and `length` is clamped to `min(length, replacement.length - offset,
149+
* buffer.length - pos))`. If `pos >= buffer.length` or `offset >= replacement.length`, no replacement occurs
150+
* and the buffer is returned unchanged.
151+
*
152+
* NOTE: This function modifies the provided buffer in place.
153+
*/
154+
function replace(
155+
bytes memory buffer,
156+
uint256 pos,
157+
bytes memory replacement,
158+
uint256 offset,
159+
uint256 length
160+
) internal pure returns (bytes memory) {
161+
// sanitize
162+
pos = Math.min(pos, buffer.length);
163+
offset = Math.min(offset, replacement.length);
164+
length = Math.min(length, Math.min(replacement.length - offset, buffer.length - pos));
165+
166+
// allocate and copy
167+
assembly ("memory-safe") {
168+
mcopy(add(add(buffer, 0x20), pos), add(add(replacement, 0x20), offset), length)
169+
}
170+
171+
return buffer;
172+
}
173+
131174
/**
132175
* @dev Concatenate an array of bytes into a single bytes object.
133176
*

scripts/generate/templates/Arrays.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,57 @@ function splice(${type.name}[] memory array, uint256 start, uint256 end) interna
422422
423423
return array;
424424
}
425+
426+
/**
427+
* @dev Replaces elements in \`array\` starting at \`pos\` with all elements from \`replacement\`.
428+
*
429+
* Parameters are clamped to valid ranges (i.e. \`pos\` is clamped to \`[0, array.length]\`).
430+
* If \`pos >= array.length\`, no replacement occurs and the array is returned unchanged.
431+
*
432+
* NOTE: This function modifies the provided array in place.
433+
*/
434+
function replace(
435+
${type.name}[] memory array,
436+
uint256 pos,
437+
${type.name}[] memory replacement
438+
) internal pure returns (${type.name}[] memory) {
439+
return replace(array, pos, replacement, 0, replacement.length);
440+
}
441+
442+
/**
443+
* @dev Replaces elements in \`array\` starting at \`pos\` with elements from \`replacement\` starting at \`offset\`.
444+
* Copies at most \`length\` elements from \`replacement\` to \`array\`.
445+
*
446+
* Parameters are clamped to valid ranges (i.e. \`pos\` is clamped to \`[0, array.length]\`, \`offset\` is
447+
* clamped to \`[0, replacement.length]\`, and \`length\` is clamped to \`min(length, replacement.length - offset,
448+
* array.length - pos)\`). If \`pos >= array.length\` or \`offset >= replacement.length\`, no replacement occurs
449+
* and the array is returned unchanged.
450+
*
451+
* NOTE: This function modifies the provided array in place.
452+
*/
453+
function replace(
454+
${type.name}[] memory array,
455+
uint256 pos,
456+
${type.name}[] memory replacement,
457+
uint256 offset,
458+
uint256 length
459+
) internal pure returns (${type.name}[] memory) {
460+
// sanitize
461+
pos = Math.min(pos, array.length);
462+
offset = Math.min(offset, replacement.length);
463+
length = Math.min(length, Math.min(replacement.length - offset, array.length - pos));
464+
465+
// allocate and copy
466+
assembly ("memory-safe") {
467+
mcopy(
468+
add(add(array, 0x20), mul(pos, 0x20)),
469+
add(add(replacement, 0x20), mul(offset, 0x20)),
470+
mul(length, 0x20)
471+
)
472+
}
473+
474+
return array;
475+
}
425476
`;
426477

427478
// GENERATE

0 commit comments

Comments
 (0)