mirror of
https://github.com/Instadapp/fluid-contracts-public.git
synced 2024-07-29 21:57:37 +00:00
68 lines
3.2 KiB
Solidity
68 lines
3.2 KiB
Solidity
|
//SPDX-License-Identifier: MIT
|
||
|
pragma solidity >=0.8.0 <0.9.0;
|
||
|
|
||
|
library BytesLib {
|
||
|
function slice(bytes memory _bytes, uint256 _start, uint256 _length) internal pure returns (bytes memory) {
|
||
|
require(_length + 31 >= _length, "slice_overflow");
|
||
|
require(_bytes.length >= _start + _length, "slice_outOfBounds");
|
||
|
|
||
|
bytes memory tempBytes;
|
||
|
|
||
|
// Check length is 0. `iszero` return 1 for `true` and 0 for `false`.
|
||
|
assembly {
|
||
|
switch iszero(_length)
|
||
|
case 0 {
|
||
|
// Get a location of some free memory and store it in tempBytes as
|
||
|
// Solidity does for memory variables.
|
||
|
tempBytes := mload(0x40)
|
||
|
|
||
|
// Calculate length mod 32 to handle slices that are not a multiple of 32 in size.
|
||
|
let lengthmod := and(_length, 31)
|
||
|
|
||
|
// tempBytes will have the following format in memory: <length><data>
|
||
|
// When copying data we will offset the start forward to avoid allocating additional memory
|
||
|
// Therefore part of the length area will be written, but this will be overwritten later anyways.
|
||
|
// In case no offset is require, the start is set to the data region (0x20 from the tempBytes)
|
||
|
// mc will be used to keep track where to copy the data to.
|
||
|
let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
|
||
|
let end := add(mc, _length)
|
||
|
|
||
|
for {
|
||
|
// Same logic as for mc is applied and additionally the start offset specified for the method is added
|
||
|
let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
|
||
|
} lt(mc, end) {
|
||
|
// increase `mc` and `cc` to read the next word from memory
|
||
|
mc := add(mc, 0x20)
|
||
|
cc := add(cc, 0x20)
|
||
|
} {
|
||
|
// Copy the data from source (cc location) to the slice data (mc location)
|
||
|
mstore(mc, mload(cc))
|
||
|
}
|
||
|
|
||
|
// Store the length of the slice. This will overwrite any partial data that
|
||
|
// was copied when having slices that are not a multiple of 32.
|
||
|
mstore(tempBytes, _length)
|
||
|
|
||
|
// update free-memory pointer
|
||
|
// allocating the array padded to 32 bytes like the compiler does now
|
||
|
// To set the used memory as a multiple of 32, add 31 to the actual memory usage (mc)
|
||
|
// and remove the modulo 32 (the `and` with `not(31)`)
|
||
|
mstore(0x40, and(add(mc, 31), not(31)))
|
||
|
}
|
||
|
// if we want a zero-length slice let's just return a zero-length array
|
||
|
default {
|
||
|
tempBytes := mload(0x40)
|
||
|
// zero out the 32 bytes slice we are about to return
|
||
|
// we need to do it because Solidity does not garbage collect
|
||
|
mstore(tempBytes, 0)
|
||
|
|
||
|
// update free-memory pointer
|
||
|
// tempBytes uses 32 bytes in memory (even when empty) for the length.
|
||
|
mstore(0x40, add(tempBytes, 0x20))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return tempBytes;
|
||
|
}
|
||
|
}
|