Created
February 8, 2022 15:26
-
-
Save Cr0wn-Gh0ul/13c323c879315e5fff776c436e31f550 to your computer and use it in GitHub Desktop.
Dynamic Buffer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity 0.8.4; | |
/// @title DynamicBuffer | |
/// @author David Huber (@cxkoda) and Simon Fremaux (<@!410568850283823105>) | |
/// this library is just putting together code created by David Huber | |
/// that you can find in https://github.com/cxkoda/strange-attractors/ | |
/// he gave me the authorization to put it together into a single library | |
/// @notice This library is used to allocate a big amount of memory and then always update the buffer content | |
/// without needing to reallocate memory. This allows to save a lot of gas when manipulating bytes/strings | |
/// @dev First, allocate memory. Then use DynamicBuffer.appendBytes(buffer, theBytes); | |
library DynamicBuffer { | |
function allocate(uint256 capacity) | |
internal | |
pure | |
returns (bytes memory container, bytes memory buffer) | |
{ | |
assembly { | |
// Get next-free memory address | |
container := mload(0x40) | |
// Allocate memory by setting a new next-free address | |
{ | |
// Add 2 x 32 bytes in size for the two length fields | |
let size := add(capacity, 0x40) | |
let newNextFree := add(container, size) | |
mstore(0x40, newNextFree) | |
} | |
// Set the correct container length | |
{ | |
let length := add(capacity, 0x40) | |
mstore(container, length) | |
} | |
// The buffer starts at idx 1 in the container (0 is length) | |
buffer := add(container, 0x20) | |
// Init content with length 0 | |
mstore(buffer, 0) | |
} | |
return (container, buffer); | |
} | |
/// @notice Appends data_ to buffer_, and update buffer_ length | |
/// @param buffer_ the buffer to append the data to | |
/// @param data_ the data to append | |
function appendBytes(bytes memory buffer_, bytes memory data_) | |
internal | |
pure | |
{ | |
assembly { | |
let length := mload(data_) | |
for { | |
let data := add(data_, 32) | |
let dataEnd := add(data, length) | |
let buf := add(buffer_, add(mload(buffer_), 32)) | |
} lt(data, dataEnd) { | |
data := add(data, 32) | |
buf := add(buf, 32) | |
} { | |
// Copy 32B chunks from data to buffer. | |
// This may read over data array boundaries and copy invalid | |
// bytes, which doesn't matter in the end since we will | |
// later set the correct buffer length. | |
mstore(buf, mload(data)) | |
} | |
// Update buffer length | |
mstore(buffer_, add(mload(buffer_), length)) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment