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]; } }