Skip to content

Instantly share code, notes, and snippets.

@Cr0wn-Gh0ul
Created February 8, 2022 15:26
Show Gist options
  • Save Cr0wn-Gh0ul/13c323c879315e5fff776c436e31f550 to your computer and use it in GitHub Desktop.
Save Cr0wn-Gh0ul/13c323c879315e5fff776c436e31f550 to your computer and use it in GitHub Desktop.
Dynamic Buffer
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