feat: keep assembly
This commit is contained in:
@@ -1,8 +1,17 @@
|
|||||||
// SPDX-License-Identifier: UNLICENSED
|
// SPDX-License-Identifier: UNLICENSED
|
||||||
pragma solidity ^0.8.0;
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
error LibPrefixLengthEncodedByteArray__InvalidEncoding();
|
/**
|
||||||
|
* @title Propellerheads PrefixLengthEncoded Byte Array Library
|
||||||
|
* @author PropellerHeads Developers
|
||||||
|
* @dev Provide a gas efficient encoding for bytes array.
|
||||||
|
*
|
||||||
|
* Array of bytes are encoded as a single bytes like this :
|
||||||
|
* 16 bits ??bits 16bits ??bits ...
|
||||||
|
* [length(elem1)] [elem1] [length(elem2)] [elem2] ...
|
||||||
|
*
|
||||||
|
* This is much more efficient and compact than default solidity encoding.
|
||||||
|
*/
|
||||||
library LibPrefixLengthEncodedByteArray {
|
library LibPrefixLengthEncodedByteArray {
|
||||||
/**
|
/**
|
||||||
* @dev Pop the first element of an array and returns it with the remaining data.
|
* @dev Pop the first element of an array and returns it with the remaining data.
|
||||||
@@ -12,45 +21,35 @@ library LibPrefixLengthEncodedByteArray {
|
|||||||
pure
|
pure
|
||||||
returns (bytes calldata elem, bytes calldata res)
|
returns (bytes calldata elem, bytes calldata res)
|
||||||
{
|
{
|
||||||
// Handle empty input
|
assembly {
|
||||||
if (encoded.length == 0) {
|
switch iszero(encoded.length)
|
||||||
return (encoded[:0], encoded[:0]);
|
case 1 {
|
||||||
|
elem.offset := 0
|
||||||
|
elem.length := 0
|
||||||
|
res.offset := 0
|
||||||
|
res.length := 0
|
||||||
|
}
|
||||||
|
default {
|
||||||
|
let l := shr(240, calldataload(encoded.offset))
|
||||||
|
elem.offset := add(encoded.offset, 2)
|
||||||
|
elem.length := l
|
||||||
|
res.offset := add(elem.offset, l)
|
||||||
|
res.length := sub(sub(encoded.length, l), 2)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure we have at least 2 bytes for length prefix
|
|
||||||
if (encoded.length < 2) revert LibPrefixLengthEncodedByteArray__InvalidEncoding();
|
|
||||||
// Extract the length prefix (first 2 bytes)
|
|
||||||
uint16 length = uint16(bytes2(encoded[:2]));
|
|
||||||
|
|
||||||
// Check if length is valid
|
|
||||||
if (2 + length > encoded.length) revert LibPrefixLengthEncodedByteArray__InvalidEncoding();
|
|
||||||
|
|
||||||
// Extract the element (after length prefix)
|
|
||||||
elem = encoded[2:2+length];
|
|
||||||
|
|
||||||
// Extract the remaining data
|
|
||||||
res = encoded[2+length:];
|
|
||||||
|
|
||||||
return (elem, res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Gets the size of the encoded array.
|
* @dev Gets the size of the encoded array.
|
||||||
*/
|
*/
|
||||||
function size(bytes calldata encoded) internal pure returns (uint256 s) {
|
function size(bytes calldata encoded) internal pure returns (uint256 s) {
|
||||||
uint256 offset = 0;
|
assembly {
|
||||||
|
let offset := encoded.offset
|
||||||
while (offset < encoded.length) {
|
let end := add(encoded.offset, encoded.length)
|
||||||
// Ensure we have at least 2 bytes for length prefix
|
for {} lt(offset, end) {} {
|
||||||
if (offset + 2 > encoded.length) revert LibPrefixLengthEncodedByteArray__InvalidEncoding();
|
offset := add(offset, add(shr(240, calldataload(offset)), 2))
|
||||||
|
s := add(s, 1)
|
||||||
uint16 length = uint16(bytes2(encoded[offset:offset + 2]));
|
}
|
||||||
|
|
||||||
// Check if length is valid
|
|
||||||
if (offset + 2 + length > encoded.length) revert LibPrefixLengthEncodedByteArray__InvalidEncoding();
|
|
||||||
|
|
||||||
offset += length + 2;
|
|
||||||
s++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user