Skip to content

Commit 95907aa

Browse files
committed
Update docs
1 parent ecdb768 commit 95907aa

File tree

1 file changed

+32
-17
lines changed

1 file changed

+32
-17
lines changed

docs/modules/ROOT/pages/utilities.adoc

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -463,37 +463,52 @@ await instance.multicall([
463463

464464
=== Memory
465465

466-
The `Memory` library provides functions for advanced use cases that require granular memory management. A common use case is to avoid unnecessary memory expansion costs when iterating over a section of the code that allocates new memory. Consider the following example:
466+
The `Memory` library provides functions for advanced use cases that require granular memory management. A common use case is to avoid unnecessary memory expansion costs when performing repeated operations that allocate memory in a loop. Consider the following example:
467467

468468
[source,solidity]
469469
----
470-
function callFoo(address target) internal {
471-
bytes memory callData = abi.encodeWithSelector(
472-
bytes4(keccak256("foo()"))
473-
)
474-
(bool success, /* bytes memory returndata */) = target.call(callData);
475-
require(success);
470+
function processMultipleItems(uint256[] memory items) internal {
471+
for (uint256 i = 0; i < items.length; i++) {
472+
bytes memory tempData = abi.encode(items[i], block.timestamp);
473+
// Process tempData...
474+
}
476475
}
477476
----
478477

479-
Note the function allocates memory for both the `callData` argument and for the returndata even if it's ignored. As such, it may be desirable to reset the free memory pointer after the end of the function.
478+
Note that each iteration allocates new memory for `tempData`, causing the memory to expand continuously. This can be optimized by resetting the memory pointer between iterations:
480479

481480
[source,solidity]
482481
----
483-
function callFoo(address target) internal {
482+
function processMultipleItems(uint256[] memory items) internal {
484483
Memory.Pointer ptr = Memory.getFreePointer(); // Cache pointer
485-
bytes memory callData = abi.encodeWithSelector(
486-
bytes4(keccak256("foo()"))
487-
)
488-
(bool success, /* bytes memory returndata */) = target.call(callData);
489-
require(success);
490-
Memory.setFreePointer(ptr); // Reset pointer
484+
for (uint256 i = 0; i < items.length; i++) {
485+
bytes memory tempData = abi.encode(items[i], block.timestamp);
486+
// Process tempData...
487+
Memory.setFreePointer(ptr); // Reset pointer for reuse
488+
}
491489
}
492490
----
493491

494-
This way, memory is allocated to accommodate the `callData`, and the `returndata` is freed. This allows other memory operations to reuse that space, thus reducing the memory expansion costs of these operations. In particular, this allows many `callFoo` to be performed in a loop with limited memory expansion costs.
492+
This way, memory allocated for `tempData` in each iteration is reused, significantly reducing memory expansion costs when processing many items.
495493

496-
IMPORTANT: By default, Solidity handles memory safely. Using this library without understanding how memory works may be dangerous. Consider thoroughly reading the Solidity documentation about the https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_memory.html[memory layout] and how the language defines https://docs.soliditylang.org/en/v0.8.20/assembly.html#memory-safety[memory safety].
494+
==== Copying memory buffers
495+
496+
The `Memory` library provides a `copy` function that allows copying data between memory locations. This is useful when you need to extract a segment of data from a larger buffer or when you want to avoid unnecessary memory allocations. The following example demonstrates how to copy a segment of data from a source buffer:
497+
498+
[source,solidity]
499+
----
500+
function copyDataSegment(bytes memory source, uint256 offset, uint256 length)
501+
internal pure returns (bytes memory result) {
502+
503+
result = new bytes(length);
504+
Memory.Pointer srcPtr = Memory.addOffset(Memory.contentPointer(source), offset);
505+
Memory.Pointer destPtr = Memory.contentPointer(result);
506+
507+
Memory.copy(destPtr, srcPtr, length);
508+
}
509+
----
510+
511+
IMPORTANT: Manual memory management increases gas costs and prevents compiler optimizations. Only use these functions after profiling confirms they're necessary. By default, Solidity handles memory safely - using this library without understanding memory layout and safety may be dangerous. See the https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_memory.html[memory layout] and https://docs.soliditylang.org/en/v0.8.20/assembly.html#memory-safety[memory safety] documentation for details.
497512

498513
=== Historical Block Hashes
499514

0 commit comments

Comments
 (0)