Skip to content

Commit 231fae3

Browse files
Amxxernestognwcairoeth
authored
Add Binary heap structure (#5084)
Co-authored-by: Ernesto García <ernestognw@gmail.com> Co-authored-by: cairo <cairoeth@protonmail.com>
1 parent 9e73c4b commit 231fae3

File tree

16 files changed

+1406
-65
lines changed

16 files changed

+1406
-65
lines changed

.changeset/fluffy-buses-jump.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'openzeppelin-solidity': minor
3+
---
4+
5+
`Comparator`: A library of comparator functions, useful for customizing the behavior of the Heap structure.

.changeset/great-pianos-work.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'openzeppelin-solidity': minor
3+
---
4+
5+
`Heap`: A data structure that implements a heap-based priority queue.

.githooks/pre-push

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@
33
set -euo pipefail
44

55
if [ "${CI:-"false"}" != "true" ]; then
6+
npm run test:generation
67
npm run lint
78
fi

contracts/mocks/Stateless.sol

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {ERC165} from "../utils/introspection/ERC165.sol";
2222
import {ERC165Checker} from "../utils/introspection/ERC165Checker.sol";
2323
import {ERC1967Utils} from "../proxy/ERC1967/ERC1967Utils.sol";
2424
import {ERC721Holder} from "../token/ERC721/utils/ERC721Holder.sol";
25+
import {Heap} from "../utils/structs/Heap.sol";
2526
import {Math} from "../utils/math/Math.sol";
2627
import {MerkleProof} from "../utils/cryptography/MerkleProof.sol";
2728
import {MessageHashUtils} from "../utils/cryptography/MessageHashUtils.sol";

contracts/utils/Arrays.sol

Lines changed: 34 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
pragma solidity ^0.8.20;
66

7+
import {Comparators} from "./Comparators.sol";
78
import {SlotDerivation} from "./SlotDerivation.sol";
89
import {StorageSlot} from "./StorageSlot.sol";
910
import {Math} from "./math/Math.sol";
@@ -16,7 +17,7 @@ library Arrays {
1617
using StorageSlot for bytes32;
1718

1819
/**
19-
* @dev Sort an array of bytes32 (in memory) following the provided comparator function.
20+
* @dev Sort an array of uint256 (in memory) following the provided comparator function.
2021
*
2122
* This function does the sorting "in place", meaning that it overrides the input. The object is returned for
2223
* convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.
@@ -27,18 +28,18 @@ library Arrays {
2728
* consume more gas than is available in a block, leading to potential DoS.
2829
*/
2930
function sort(
30-
bytes32[] memory array,
31-
function(bytes32, bytes32) pure returns (bool) comp
32-
) internal pure returns (bytes32[] memory) {
31+
uint256[] memory array,
32+
function(uint256, uint256) pure returns (bool) comp
33+
) internal pure returns (uint256[] memory) {
3334
_quickSort(_begin(array), _end(array), comp);
3435
return array;
3536
}
3637

3738
/**
38-
* @dev Variant of {sort} that sorts an array of bytes32 in increasing order.
39+
* @dev Variant of {sort} that sorts an array of uint256 in increasing order.
3940
*/
40-
function sort(bytes32[] memory array) internal pure returns (bytes32[] memory) {
41-
sort(array, _defaultComp);
41+
function sort(uint256[] memory array) internal pure returns (uint256[] memory) {
42+
sort(array, Comparators.lt);
4243
return array;
4344
}
4445

@@ -57,20 +58,20 @@ library Arrays {
5758
address[] memory array,
5859
function(address, address) pure returns (bool) comp
5960
) internal pure returns (address[] memory) {
60-
sort(_castToBytes32Array(array), _castToBytes32Comp(comp));
61+
sort(_castToUint256Array(array), _castToUint256Comp(comp));
6162
return array;
6263
}
6364

6465
/**
6566
* @dev Variant of {sort} that sorts an array of address in increasing order.
6667
*/
6768
function sort(address[] memory array) internal pure returns (address[] memory) {
68-
sort(_castToBytes32Array(array), _defaultComp);
69+
sort(_castToUint256Array(array), Comparators.lt);
6970
return array;
7071
}
7172

7273
/**
73-
* @dev Sort an array of uint256 (in memory) following the provided comparator function.
74+
* @dev Sort an array of bytes32 (in memory) following the provided comparator function.
7475
*
7576
* This function does the sorting "in place", meaning that it overrides the input. The object is returned for
7677
* convenience, but that returned value can be discarded safely if the caller has a memory pointer to the array.
@@ -81,18 +82,18 @@ library Arrays {
8182
* consume more gas than is available in a block, leading to potential DoS.
8283
*/
8384
function sort(
84-
uint256[] memory array,
85-
function(uint256, uint256) pure returns (bool) comp
86-
) internal pure returns (uint256[] memory) {
87-
sort(_castToBytes32Array(array), _castToBytes32Comp(comp));
85+
bytes32[] memory array,
86+
function(bytes32, bytes32) pure returns (bool) comp
87+
) internal pure returns (bytes32[] memory) {
88+
sort(_castToUint256Array(array), _castToUint256Comp(comp));
8889
return array;
8990
}
9091

9192
/**
92-
* @dev Variant of {sort} that sorts an array of uint256 in increasing order.
93+
* @dev Variant of {sort} that sorts an array of bytes32 in increasing order.
9394
*/
94-
function sort(uint256[] memory array) internal pure returns (uint256[] memory) {
95-
sort(_castToBytes32Array(array), _defaultComp);
95+
function sort(bytes32[] memory array) internal pure returns (bytes32[] memory) {
96+
sort(_castToUint256Array(array), Comparators.lt);
9697
return array;
9798
}
9899

@@ -105,12 +106,12 @@ library Arrays {
105106
* IMPORTANT: Memory locations between `begin` and `end` are not validated/zeroed. This function should
106107
* be used only if the limits are within a memory array.
107108
*/
108-
function _quickSort(uint256 begin, uint256 end, function(bytes32, bytes32) pure returns (bool) comp) private pure {
109+
function _quickSort(uint256 begin, uint256 end, function(uint256, uint256) pure returns (bool) comp) private pure {
109110
unchecked {
110111
if (end - begin < 0x40) return;
111112

112113
// Use first element as pivot
113-
bytes32 pivot = _mload(begin);
114+
uint256 pivot = _mload(begin);
114115
// Position where the pivot should be at the end of the loop
115116
uint256 pos = begin;
116117

@@ -132,7 +133,7 @@ library Arrays {
132133
/**
133134
* @dev Pointer to the memory location of the first element of `array`.
134135
*/
135-
function _begin(bytes32[] memory array) private pure returns (uint256 ptr) {
136+
function _begin(uint256[] memory array) private pure returns (uint256 ptr) {
136137
/// @solidity memory-safe-assembly
137138
assembly {
138139
ptr := add(array, 0x20)
@@ -143,16 +144,16 @@ library Arrays {
143144
* @dev Pointer to the memory location of the first memory word (32bytes) after `array`. This is the memory word
144145
* that comes just after the last element of the array.
145146
*/
146-
function _end(bytes32[] memory array) private pure returns (uint256 ptr) {
147+
function _end(uint256[] memory array) private pure returns (uint256 ptr) {
147148
unchecked {
148149
return _begin(array) + array.length * 0x20;
149150
}
150151
}
151152

152153
/**
153-
* @dev Load memory word (as a bytes32) at location `ptr`.
154+
* @dev Load memory word (as a uint256) at location `ptr`.
154155
*/
155-
function _mload(uint256 ptr) private pure returns (bytes32 value) {
156+
function _mload(uint256 ptr) private pure returns (uint256 value) {
156157
assembly {
157158
value := mload(ptr)
158159
}
@@ -170,38 +171,33 @@ library Arrays {
170171
}
171172
}
172173

173-
/// @dev Comparator for sorting arrays in increasing order.
174-
function _defaultComp(bytes32 a, bytes32 b) private pure returns (bool) {
175-
return a < b;
176-
}
177-
178174
/// @dev Helper: low level cast address memory array to uint256 memory array
179-
function _castToBytes32Array(address[] memory input) private pure returns (bytes32[] memory output) {
175+
function _castToUint256Array(address[] memory input) private pure returns (uint256[] memory output) {
180176
assembly {
181177
output := input
182178
}
183179
}
184180

185-
/// @dev Helper: low level cast uint256 memory array to uint256 memory array
186-
function _castToBytes32Array(uint256[] memory input) private pure returns (bytes32[] memory output) {
181+
/// @dev Helper: low level cast bytes32 memory array to uint256 memory array
182+
function _castToUint256Array(bytes32[] memory input) private pure returns (uint256[] memory output) {
187183
assembly {
188184
output := input
189185
}
190186
}
191187

192-
/// @dev Helper: low level cast address comp function to bytes32 comp function
193-
function _castToBytes32Comp(
188+
/// @dev Helper: low level cast address comp function to uint256 comp function
189+
function _castToUint256Comp(
194190
function(address, address) pure returns (bool) input
195-
) private pure returns (function(bytes32, bytes32) pure returns (bool) output) {
191+
) private pure returns (function(uint256, uint256) pure returns (bool) output) {
196192
assembly {
197193
output := input
198194
}
199195
}
200196

201-
/// @dev Helper: low level cast uint256 comp function to bytes32 comp function
202-
function _castToBytes32Comp(
203-
function(uint256, uint256) pure returns (bool) input
204-
) private pure returns (function(bytes32, bytes32) pure returns (bool) output) {
197+
/// @dev Helper: low level cast bytes32 comp function to uint256 comp function
198+
function _castToUint256Comp(
199+
function(bytes32, bytes32) pure returns (bool) input
200+
) private pure returns (function(uint256, uint256) pure returns (bool) output) {
205201
assembly {
206202
output := input
207203
}

contracts/utils/Comparators.sol

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.8.20;
4+
5+
library Comparators {
6+
function lt(uint256 a, uint256 b) internal pure returns (bool) {
7+
return a < b;
8+
}
9+
10+
function gt(uint256 a, uint256 b) internal pure returns (bool) {
11+
return a > b;
12+
}
13+
}

contracts/utils/README.adoc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Miscellaneous contracts and libraries containing utility functions you can use t
2525
* {DoubleEndedQueue}: An implementation of a https://en.wikipedia.org/wiki/Double-ended_queue[double ended queue] whose values can be removed added or remove from both sides. Useful for FIFO and LIFO structures.
2626
* {CircularBuffer}: A data structure to store the last N values pushed to it.
2727
* {Checkpoints}: A data structure to store values mapped to an strictly increasing key. Can be used for storing and accessing values over time.
28+
* {Heap}: A library that implements a https://en.wikipedia.org/wiki/Binary_heap[binary heap] in storage.
2829
* {MerkleTree}: A library with https://wikipedia.org/wiki/Merkle_Tree[Merkle Tree] data structures and helper functions.
2930
* {Create2}: Wrapper around the https://blog.openzeppelin.com/getting-the-most-out-of-create2/[`CREATE2` EVM opcode] for safe use without having to deal with low-level assembly.
3031
* {Address}: Collection of functions for overloading Solidity's https://docs.soliditylang.org/en/latest/types.html#address[`address`] type.
@@ -38,6 +39,7 @@ Miscellaneous contracts and libraries containing utility functions you can use t
3839
* {Context}: An utility for abstracting the sender and calldata in the current execution context.
3940
* {Packing}: A library for packing and unpacking multiple values into bytes32
4041
* {Panic}: A library to revert with https://docs.soliditylang.org/en/v0.8.20/control-structures.html#panic-via-assert-and-error-via-require[Solidity panic codes].
42+
* {Comparators}: A library that contains comparator functions to use with with the {Heap} library.
4143

4244
[NOTE]
4345
====
@@ -102,6 +104,8 @@ Ethereum contracts have no native concept of an interface, so applications must
102104

103105
{{Checkpoints}}
104106

107+
{{Heap}}
108+
105109
{{MerkleTree}}
106110

107111
== Libraries
@@ -129,3 +133,5 @@ Ethereum contracts have no native concept of an interface, so applications must
129133
{{Packing}}
130134

131135
{{Panic}}
136+
137+
{{Comparators}}

0 commit comments

Comments
 (0)