|
|
|
@ -15,7 +15,7 @@ import {Math} from "./math/Math.sol"; |
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const sort = type => `\
|
|
|
|
|
/** |
|
|
|
|
/** |
|
|
|
|
* @dev Sort an array of ${type} (in memory) following the provided comparator function. |
|
|
|
|
* |
|
|
|
|
* This function does the sorting "in place", meaning that it overrides the input. The object is returned for |
|
|
|
@ -26,28 +26,28 @@ const sort = type => `\ |
|
|
|
|
* when executing this as part of a transaction. If the array being sorted is too large, the sort operation may |
|
|
|
|
* consume more gas than is available in a block, leading to potential DoS. |
|
|
|
|
*/ |
|
|
|
|
function sort( |
|
|
|
|
function sort( |
|
|
|
|
${type}[] memory array, |
|
|
|
|
function(${type}, ${type}) pure returns (bool) comp |
|
|
|
|
) internal pure returns (${type}[] memory) { |
|
|
|
|
) internal pure returns (${type}[] memory) { |
|
|
|
|
${ |
|
|
|
|
type === 'bytes32' |
|
|
|
|
? '_quickSort(_begin(array), _end(array), comp);' |
|
|
|
|
: 'sort(_castToBytes32Array(array), _castToBytes32Comp(comp));' |
|
|
|
|
} |
|
|
|
|
return array; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
/** |
|
|
|
|
* @dev Variant of {sort} that sorts an array of ${type} in increasing order. |
|
|
|
|
*/ |
|
|
|
|
function sort(${type}[] memory array) internal pure returns (${type}[] memory) { |
|
|
|
|
function sort(${type}[] memory array) internal pure returns (${type}[] memory) { |
|
|
|
|
${type === 'bytes32' ? 'sort(array, _defaultComp);' : 'sort(_castToBytes32Array(array), _defaultComp);'} |
|
|
|
|
return array; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const quickSort = ` |
|
|
|
|
const quickSort = `\
|
|
|
|
|
/** |
|
|
|
|
* @dev Performs a quick sort of a segment of memory. The segment sorted starts at \`begin\` (inclusive), and stops
|
|
|
|
|
* at end (exclusive). Sorting follows the \`comp\` comparator.
|
|
|
|
@ -123,34 +123,34 @@ function _swap(uint256 ptr1, uint256 ptr2) private pure { |
|
|
|
|
} |
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const defaultComparator = ` |
|
|
|
|
/// @dev Comparator for sorting arrays in increasing order.
|
|
|
|
|
function _defaultComp(bytes32 a, bytes32 b) private pure returns (bool) { |
|
|
|
|
const defaultComparator = `\
|
|
|
|
|
/// @dev Comparator for sorting arrays in increasing order.
|
|
|
|
|
function _defaultComp(bytes32 a, bytes32 b) private pure returns (bool) { |
|
|
|
|
return a < b; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const castArray = type => `\
|
|
|
|
|
/// @dev Helper: low level cast ${type} memory array to uint256 memory array
|
|
|
|
|
function _castToBytes32Array(${type}[] memory input) private pure returns (bytes32[] memory output) { |
|
|
|
|
/// @dev Helper: low level cast ${type} memory array to uint256 memory array
|
|
|
|
|
function _castToBytes32Array(${type}[] memory input) private pure returns (bytes32[] memory output) { |
|
|
|
|
assembly { |
|
|
|
|
output := input |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const castComparator = type => `\
|
|
|
|
|
/// @dev Helper: low level cast ${type} comp function to bytes32 comp function
|
|
|
|
|
function _castToBytes32Comp( |
|
|
|
|
/// @dev Helper: low level cast ${type} comp function to bytes32 comp function
|
|
|
|
|
function _castToBytes32Comp( |
|
|
|
|
function(${type}, ${type}) pure returns (bool) input |
|
|
|
|
) private pure returns (function(bytes32, bytes32) pure returns (bool) output) { |
|
|
|
|
) private pure returns (function(bytes32, bytes32) pure returns (bool) output) { |
|
|
|
|
assembly { |
|
|
|
|
output := input |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const search = ` |
|
|
|
|
const search = `\
|
|
|
|
|
/** |
|
|
|
|
* @dev Searches a sorted \`array\` and returns the first index that contains
|
|
|
|
|
* a value greater or equal to \`element\`. If no such index exists (i.e. all
|
|
|
|
@ -319,12 +319,12 @@ function upperBoundMemory(uint256[] memory array, uint256 element) internal pure |
|
|
|
|
} |
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const unsafeAccessStorage = type => ` |
|
|
|
|
const unsafeAccessStorage = type => `\
|
|
|
|
|
/** |
|
|
|
|
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. |
|
|
|
|
* |
|
|
|
|
* WARNING: Only use if you are certain \`pos\` is lower than the array length.
|
|
|
|
|
*/ |
|
|
|
|
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. |
|
|
|
|
* |
|
|
|
|
* WARNING: Only use if you are certain \`pos\` is lower than the array length.
|
|
|
|
|
*/ |
|
|
|
|
function unsafeAccess(${type}[] storage arr, uint256 pos) internal pure returns (StorageSlot.${capitalize( |
|
|
|
|
type, |
|
|
|
|
)}Slot storage) { |
|
|
|
@ -334,9 +334,10 @@ function unsafeAccess(${type}[] storage arr, uint256 pos) internal pure returns |
|
|
|
|
slot := arr.slot |
|
|
|
|
} |
|
|
|
|
return slot.deriveArray().offset(pos).get${capitalize(type)}Slot(); |
|
|
|
|
}`;
|
|
|
|
|
} |
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const unsafeAccessMemory = type => ` |
|
|
|
|
const unsafeAccessMemory = type => `\
|
|
|
|
|
/** |
|
|
|
|
* @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. |
|
|
|
|
* |
|
|
|
@ -349,7 +350,7 @@ function unsafeMemoryAccess(${type}[] memory arr, uint256 pos) internal pure ret |
|
|
|
|
} |
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
const unsafeSetLength = type => ` |
|
|
|
|
const unsafeSetLength = type => `\
|
|
|
|
|
/** |
|
|
|
|
* @dev Helper to set the length of an dynamic array. Directly writing to \`.length\` is forbidden.
|
|
|
|
|
* |
|
|
|
@ -360,14 +361,18 @@ function unsafeSetLength(${type}[] storage array, uint256 len) internal { |
|
|
|
|
assembly { |
|
|
|
|
sstore(array.slot, len) |
|
|
|
|
} |
|
|
|
|
}`;
|
|
|
|
|
} |
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
// GENERATE
|
|
|
|
|
module.exports = format( |
|
|
|
|
header.trimEnd(), |
|
|
|
|
'library Arrays {', |
|
|
|
|
format( |
|
|
|
|
[].concat( |
|
|
|
|
'using SlotDerivation for bytes32;', |
|
|
|
|
'using StorageSlot for bytes32;', |
|
|
|
|
'', |
|
|
|
|
// sorting, comparator, helpers and internal
|
|
|
|
|
sort('bytes32'), |
|
|
|
|
TYPES.filter(type => type !== 'bytes32').map(sort), |
|
|
|
@ -381,5 +386,7 @@ module.exports = format( |
|
|
|
|
TYPES.map(unsafeAccessStorage), |
|
|
|
|
TYPES.map(unsafeAccessMemory), |
|
|
|
|
TYPES.map(unsafeSetLength), |
|
|
|
|
), |
|
|
|
|
).trimEnd(), |
|
|
|
|
'}', |
|
|
|
|
); |
|
|
|
|