Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
4fec530
implement binary heap
Amxx Jun 16, 2024
8fa2eeb
codespell & lib naming
Amxx Jun 16, 2024
792fcba
tests
Amxx Jun 16, 2024
0c86005
fix fuzzing tests
Amxx Jun 16, 2024
248baf6
codespell
Amxx Jun 16, 2024
53db2ab
update
Amxx Jun 17, 2024
945e0f4
procedural generation
Amxx Jun 17, 2024
df82b15
testing
Amxx Jun 17, 2024
8b965fc
overflow handling
Amxx Jun 21, 2024
e952cf6
add replace and changeset
Amxx Jun 21, 2024
f5fa274
rename top -> peek
Amxx Jun 21, 2024
1f0fef0
internal renaming
Amxx Jun 21, 2024
d0972a3
codespell
Amxx Jun 21, 2024
8e3dda6
regenerate
Amxx Jun 21, 2024
38e1813
auto regenerate
Amxx Jun 21, 2024
02f224d
Update .githooks/pre-push
Amxx Jun 21, 2024
7e88481
up
Amxx Jun 21, 2024
a46cc63
Merge branch 'master' into struct/heap
Amxx Jun 21, 2024
b2fda31
up
Amxx Jun 21, 2024
516f1ca
tests
Amxx Jun 21, 2024
cf1278e
Update test/utils/structs/Heap.test.js
Amxx Jun 21, 2024
5f15d1c
Update test/utils/structs/Heap.test.js
Amxx Jun 21, 2024
32e9b49
Apply suggestions from code review
Amxx Jun 27, 2024
c083d79
regenrate
Amxx Jun 27, 2024
0e6ada0
Merge branch 'master' into struct/heap
Amxx Jul 3, 2024
7c98102
update inline comments
Amxx Jul 15, 2024
a1767d4
update
Amxx Jul 15, 2024
1c1e84b
Address comment for the PR
Amxx Jul 16, 2024
0e7fe7a
rewrite Arrays.sol to use uint256[] as the default, and use Comparato…
Amxx Jul 17, 2024
d495859
Update scripts/generate/templates/Heap.js
Amxx Jul 18, 2024
fe8e902
regenerate
Amxx Jul 18, 2024
3abeb84
Add docs
ernestognw Jul 23, 2024
8801d98
Update scripts/generate/templates/Heap.js
Amxx Jul 23, 2024
f78df0c
Apply suggestions from code review
Amxx Jul 23, 2024
bb37dfb
fix generation + change key type
Amxx Jul 23, 2024
1fb4b81
more invariant check
Amxx Jul 23, 2024
d3308c4
Update scripts/generate/templates/Heap.js
ernestognw Jul 23, 2024
5b07512
Generate
ernestognw Jul 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
rename top -> peek
  • Loading branch information
Amxx committed Jun 21, 2024
commit f5fa2743ef7081898a4f99df6e71eb9cccd19f49
22 changes: 14 additions & 8 deletions contracts/utils/structs/Heap.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@ library Heap {
* smallest value is the one at the root. It can be retrieved in O(1) at `heap.data[heap.data[0].index].value`
*
* This structure is designed for the following complexities:
* - insert: 0(log(n))
* - pop (remove smallest value in set): O(log(n))
* - top (get smallest value in set): O(1)
* - peek (get the smallest value in set): O(1)
* - insert (insert a value in the set): 0(log(n))
* - pop (remove the smallest value in set): O(log(n))
* - replace (replace the smallest value in set with a new value): O(log(n))
*/
struct Uint256Heap {
Uint256HeapNode[] data;
Expand All @@ -44,7 +45,7 @@ library Heap {
/**
* @dev Lookup the root element of the heap.
*/
function top(Uint256Heap storage self) internal view returns (uint256) {
function peek(Uint256Heap storage self) internal view returns (uint256) {
return _unsafeNodeAccess(self, self.data[0].index).value;
}

Expand Down Expand Up @@ -140,6 +141,7 @@ library Heap {

/**
* @dev Return the root element for the heap, and replace it with a new value, using the default comparator.
* This is equivalent to using {pop} and {insert}, but requires only one rebalancing operation.
*
* Note: All inserting and removal from a heap should always be done using the same comparator. Mixing comparator
* during the lifecycle of a heap will result in undefined behavior.
Expand All @@ -150,6 +152,7 @@ library Heap {

/**
* @dev Return the root element for the heap, and replace it with a new value, using the provided comparator.
* This is equivalent to using {pop} and {insert}, but requires only one rebalancing operation.
*
* Note: All inserting and removal from a heap should always be done using the same comparator. Mixing comparator
* during the lifecycle of a heap will result in undefined behavior.
Expand Down Expand Up @@ -305,9 +308,10 @@ library Heap {
* smallest value is the one at the root. It can be retrieved in O(1) at `heap.data[heap.data[0].index].value`
*
* This structure is designed for the following complexities:
* - insert: 0(log(n))
* - pop (remove smallest value in set): O(log(n))
* - top (get smallest value in set): O(1)
* - peek (get the smallest value in set): O(1)
* - insert (insert a value in the set): 0(log(n))
* - pop (remove the smallest value in set): O(log(n))
* - replace (replace the smallest value in set with a new value): O(log(n))
*/
struct Uint208Heap {
Uint208HeapNode[] data;
Expand All @@ -322,7 +326,7 @@ library Heap {
/**
* @dev Lookup the root element of the heap.
*/
function top(Uint208Heap storage self) internal view returns (uint208) {
function peek(Uint208Heap storage self) internal view returns (uint208) {
return _unsafeNodeAccess(self, self.data[0].index).value;
}

Expand Down Expand Up @@ -418,6 +422,7 @@ library Heap {

/**
* @dev Return the root element for the heap, and replace it with a new value, using the default comparator.
* This is equivalent to using {pop} and {insert}, but requires only one rebalancing operation.
*
* Note: All inserting and removal from a heap should always be done using the same comparator. Mixing comparator
* during the lifecycle of a heap will result in undefined behavior.
Expand All @@ -428,6 +433,7 @@ library Heap {

/**
* @dev Return the root element for the heap, and replace it with a new value, using the provided comparator.
* This is equivalent to using {pop} and {insert}, but requires only one rebalancing operation.
*
* Note: All inserting and removal from a heap should always be done using the same comparator. Mixing comparator
* during the lifecycle of a heap will result in undefined behavior.
Expand Down
11 changes: 7 additions & 4 deletions scripts/generate/templates/Heap.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ const generate = ({ struct, node, valueType, indexType, blockSize }) => `\
* smallest value is the one at the root. It can be retrieved in O(1) at \`heap.data[heap.data[0].index].value\`
*
* This structure is designed for the following complexities:
* - insert: 0(log(n))
* - pop (remove smallest value in set): O(log(n))
* - top (get smallest value in set): O(1)
* - peek (get the smallest value in set): O(1)
* - insert (insert a value in the set): 0(log(n))
* - pop (remove the smallest value in set): O(log(n))
* - replace (replace the smallest value in set with a new value): O(log(n))
*/
struct ${struct} {
${node}[] data;
Expand All @@ -46,7 +47,7 @@ struct ${node} {
/**
* @dev Lookup the root element of the heap.
*/
function top(${struct} storage self) internal view returns (${valueType}) {
function peek(${struct} storage self) internal view returns (${valueType}) {
return _unsafeNodeAccess(self, self.data[0].index).value;
}

Expand Down Expand Up @@ -142,6 +143,7 @@ function insert(

/**
* @dev Return the root element for the heap, and replace it with a new value, using the default comparator.
* This is equivalent to using {pop} and {insert}, but requires only one rebalancing operation.
*
* Note: All inserting and removal from a heap should always be done using the same comparator. Mixing comparator
* during the lifecycle of a heap will result in undefined behavior.
Expand All @@ -152,6 +154,7 @@ function replace(${struct} storage self, ${valueType} newValue) internal returns

/**
* @dev Return the root element for the heap, and replace it with a new value, using the provided comparator.
* This is equivalent to using {pop} and {insert}, but requires only one rebalancing operation.
*
* Note: All inserting and removal from a heap should always be done using the same comparator. Mixing comparator
* during the lifecycle of a heap will result in undefined behavior.
Expand Down
16 changes: 8 additions & 8 deletions test/utils/structs/Heap.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ contract Uint256HeapTest is Test {
_validateHeap(Comparators.lt);

min = Math.min(min, input[i]);
assertEq(heap.top(), min);
assertEq(heap.peek(), min);
}

uint256 max = 0;
for (uint256 i = 0; i < input.length; ++i) {
uint256 top = heap.top();
uint256 top = heap.peek();
uint256 pop = heap.pop();
assertEq(heap.length(), input.length - i - 1);
_validateHeap(Comparators.lt);
Expand All @@ -62,12 +62,12 @@ contract Uint256HeapTest is Test {
_validateHeap(Comparators.gt);

max = Math.max(max, input[i]);
assertEq(heap.top(), max);
assertEq(heap.peek(), max);
}

uint256 min = type(uint256).max;
for (uint256 i = 0; i < input.length; ++i) {
uint256 top = heap.top();
uint256 top = heap.peek();
uint256 pop = heap.pop(Comparators.gt);
assertEq(heap.length(), input.length - i - 1);
_validateHeap(Comparators.gt);
Expand Down Expand Up @@ -106,12 +106,12 @@ contract Uint208HeapTest is Test {
_validateHeap(Comparators.lt);

min = Math.min(min, input[i]);
assertEq(heap.top(), min);
assertEq(heap.peek(), min);
}

uint256 max = 0;
for (uint256 i = 0; i < input.length; ++i) {
uint208 top = heap.top();
uint208 top = heap.peek();
uint208 pop = heap.pop();
assertEq(heap.length(), input.length - i - 1);
_validateHeap(Comparators.lt);
Expand All @@ -133,12 +133,12 @@ contract Uint208HeapTest is Test {
_validateHeap(Comparators.gt);

max = Math.max(max, input[i]);
assertEq(heap.top(), max);
assertEq(heap.peek(), max);
}

uint256 min = type(uint256).max;
for (uint256 i = 0; i < input.length; ++i) {
uint208 top = heap.top();
uint208 top = heap.peek();
uint208 pop = heap.pop(Comparators.gt);
assertEq(heap.length(), input.length - i - 1);
_validateHeap(Comparators.gt);
Expand Down
12 changes: 6 additions & 6 deletions test/utils/structs/Heap.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@ describe('Heap', function () {
replace: (...args) => this.mock[`$replace(uint256,${valueType})`](0, ...args),
length: (...args) => this.mock[`$length_Heap_${struct}`](0, ...args),
pop: (...args) => this.mock[`$pop_Heap_${struct}`](0, ...args),
top: (...args) => this.mock[`$top_Heap_${struct}`](0, ...args),
peek: (...args) => this.mock[`$peek_Heap_${struct}`](0, ...args),
};
});

it('starts empty', async function () {
await expect(this.helper.top()).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS);
await expect(this.helper.peek()).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS);
expect(await this.helper.length()).to.equal(0n);
});

Expand All @@ -44,12 +44,12 @@ describe('Heap', function () {
await this.helper.insert(42n);

expect(await this.helper.length()).to.equal(1n);
expect(await this.helper.top()).to.equal(42n);
expect(await this.helper.peek()).to.equal(42n);

await this.helper.clear();

expect(await this.helper.length()).to.equal(0n);
await expect(this.helper.top()).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS);
await expect(this.helper.peek()).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS);
});

it('support duplicated items', async function () {
Expand Down Expand Up @@ -119,9 +119,9 @@ describe('Heap', function () {
}
expect(await this.helper.length()).to.equal(heap.length);
if (heap.length == 0) {
await expect(this.helper.top()).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS);
await expect(this.helper.peek()).to.be.revertedWithPanic(PANIC_CODES.ARRAY_ACCESS_OUT_OF_BOUNDS);
} else {
expect(await this.helper.top()).to.equal(heap[0]);
expect(await this.helper.peek()).to.equal(heap[0]);
}
}
});
Expand Down