|
| 1 | +pragma solidity ^0.5.16; |
| 2 | + |
| 3 | + |
| 4 | +// https://docs.synthetix.io/contracts/source/libraries/bytes32setlib/ |
| 5 | +library Bytes32SetLib { |
| 6 | + struct Bytes32Set { |
| 7 | + bytes32[] elements; |
| 8 | + mapping(bytes32 => uint) indices; |
| 9 | + } |
| 10 | + |
| 11 | + function contains(Bytes32Set storage set, bytes32 candidate) internal view returns (bool) { |
| 12 | + if (set.elements.length == 0) { |
| 13 | + return false; |
| 14 | + } |
| 15 | + uint index = set.indices[candidate]; |
| 16 | + return index != 0 || set.elements[0] == candidate; |
| 17 | + } |
| 18 | + |
| 19 | + function getPage( |
| 20 | + Bytes32Set storage set, |
| 21 | + uint index, |
| 22 | + uint pageSize |
| 23 | + ) internal view returns (bytes32[] memory) { |
| 24 | + // NOTE: This implementation should be converted to slice operators if the compiler is updated to v0.6.0+ |
| 25 | + uint endIndex = index + pageSize; // The check below that endIndex <= index handles overflow. |
| 26 | + |
| 27 | + // If the page extends past the end of the list, truncate it. |
| 28 | + if (endIndex > set.elements.length) { |
| 29 | + endIndex = set.elements.length; |
| 30 | + } |
| 31 | + if (endIndex <= index) { |
| 32 | + return new bytes32[](0); |
| 33 | + } |
| 34 | + |
| 35 | + uint n = endIndex - index; // We already checked for negative overflow. |
| 36 | + bytes32[] memory page = new bytes32[](n); |
| 37 | + for (uint i; i < n; i++) { |
| 38 | + page[i] = set.elements[i + index]; |
| 39 | + } |
| 40 | + return page; |
| 41 | + } |
| 42 | + |
| 43 | + function add(Bytes32Set storage set, bytes32 element) internal { |
| 44 | + // Adding to a set is an idempotent operation. |
| 45 | + if (!contains(set, element)) { |
| 46 | + set.indices[element] = set.elements.length; |
| 47 | + set.elements.push(element); |
| 48 | + } |
| 49 | + } |
| 50 | + |
| 51 | + function remove(Bytes32Set storage set, bytes32 element) internal { |
| 52 | + require(contains(set, element), "Element not in set."); |
| 53 | + // Replace the removed element with the last element of the list. |
| 54 | + uint index = set.indices[element]; |
| 55 | + uint lastIndex = set.elements.length - 1; // We required that element is in the list, so it is not empty. |
| 56 | + if (index != lastIndex) { |
| 57 | + // No need to shift the last element if it is the one we want to delete. |
| 58 | + bytes32 shiftedElement = set.elements[lastIndex]; |
| 59 | + set.elements[index] = shiftedElement; |
| 60 | + set.indices[shiftedElement] = index; |
| 61 | + } |
| 62 | + set.elements.pop(); |
| 63 | + delete set.indices[element]; |
| 64 | + } |
| 65 | +} |
0 commit comments