-
Notifications
You must be signed in to change notification settings - Fork 596
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Address list renamed to address set and make adding elements idempote…
…nt. (#917)
- Loading branch information
Showing
5 changed files
with
276 additions
and
71 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
pragma solidity ^0.5.16; | ||
|
||
|
||
// https://docs.synthetix.io/contracts/source/libraries/addresssetlib/ | ||
library AddressSetLib { | ||
struct AddressSet { | ||
address[] elements; | ||
mapping(address => uint) indices; | ||
} | ||
|
||
function contains(AddressSet storage set, address candidate) internal view returns (bool) { | ||
if (set.elements.length == 0) { | ||
return false; | ||
} | ||
uint index = set.indices[candidate]; | ||
return index != 0 || set.elements[0] == candidate; | ||
} | ||
|
||
function getPage( | ||
AddressSet storage set, | ||
uint index, | ||
uint pageSize | ||
) internal view returns (address[] memory) { | ||
// NOTE: This implementation should be converted to slice operators if the compiler is updated to v0.6.0+ | ||
uint endIndex = index + pageSize; // The check below that endIndex <= index handles overflow. | ||
|
||
// If the page extends past the end of the list, truncate it. | ||
if (endIndex > set.elements.length) { | ||
endIndex = set.elements.length; | ||
} | ||
if (endIndex <= index) { | ||
return new address[](0); | ||
} | ||
|
||
uint n = endIndex - index; // We already checked for negative overflow. | ||
address[] memory page = new address[](n); | ||
for (uint i; i < n; i++) { | ||
page[i] = set.elements[i + index]; | ||
} | ||
return page; | ||
} | ||
|
||
function add(AddressSet storage set, address element) internal { | ||
// Adding to a set is an idempotent operation. | ||
if (!contains(set, element)) { | ||
set.indices[element] = set.elements.length; | ||
set.elements.push(element); | ||
} | ||
} | ||
|
||
function remove(AddressSet storage set, address element) internal { | ||
require(contains(set, element), "Element not in set."); | ||
// Replace the removed element with the last element of the list. | ||
uint index = set.indices[element]; | ||
uint lastIndex = set.elements.length - 1; // We required that element is in the list, so it is not empty. | ||
if (index != lastIndex) { | ||
// No need to shift the last element if it is the one we want to delete. | ||
address shiftedElement = set.elements[lastIndex]; | ||
set.elements[index] = shiftedElement; | ||
set.indices[shiftedElement] = index; | ||
} | ||
set.elements.pop(); | ||
delete set.indices[element]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
pragma solidity ^0.5.16; | ||
|
||
import "../AddressSetLib.sol"; | ||
|
||
|
||
contract TestableAddressSet { | ||
using AddressSetLib for AddressSetLib.AddressSet; | ||
|
||
AddressSetLib.AddressSet internal set; | ||
|
||
function contains(address candidate) public view returns (bool) { | ||
return set.contains(candidate); | ||
} | ||
|
||
function getPage(uint index, uint pageSize) public view returns (address[] memory) { | ||
return set.getPage(index, pageSize); | ||
} | ||
|
||
function add(address element) public { | ||
set.add(element); | ||
} | ||
|
||
function remove(address element) public { | ||
set.remove(element); | ||
} | ||
|
||
function size() public view returns (uint) { | ||
return set.elements.length; | ||
} | ||
|
||
function element(uint index) public view returns (address) { | ||
return set.elements[index]; | ||
} | ||
|
||
function index(address element) public view returns (uint) { | ||
return set.indices[element]; | ||
} | ||
} |
Oops, something went wrong.