I'm trying to test the gas costs for storing and retrieving strings on-chain, and I've found the most gas efficient way to put them there is with the following function (Its gas cost is a linear function of the value being stored)
mapping(string => bytes[]) private text_parts;
// ...
function append_to_text_part(string memory key, string memory value) public {
text_parts[key].push(bytes(value));
}
To retrieve one of these stored strings I use
function retrieve_stored_byte_arrays_as_string(string memory text_part_label) private view returns(string memory) {
string memory joined_string = "";
bytes[] memory selected_text_parts = text_parts[text_part_label];
uint selected_text_part_length = text_parts[text_part_label].length;
for (uint i = 0; i < selected_text_part_length; i++) {
joined_string = string(abi.encodePacked(joined_string, selected_text_parts[i]));
}
return joined_string;
}
My function seems to have linear memory cost relative to the total size of stored string. However, it's continually creating new strings and holding two in memory at once while using abi.encodePacked
, which seems wasteful.
An efficient way to do this in another language would be the check the size of the stored bytes, create a byte[]
with the total length, and memcpy
the stored bytes into the appropriate positions in the returned array.
Is this possible to do in Solidity?