pragma solidity 0.5.17; library LockUtils { struct Lock { address creator; uint96 expiresAt; } /// @notice The LockSet is like an array of unique `uint256`s, /// but additionally supports O(1) membership tests and removals. /// @dev Because the LockSet relies on a mapping, /// it can only be used in storage, not in memory. struct LockSet { // locks[positions[lock.creator] - 1] = lock Lock[] locks; mapping(address => uint256) positions; } /// @notice Check whether the LockSet `self` contains a lock by `creator` function contains(LockSet storage self, address creator) internal view returns (bool) { return (self.positions[creator] != 0); } function getLockTime(LockSet storage self, address creator) internal view returns (uint96) { uint256 positionPlusOne = self.positions[creator]; if (positionPlusOne == 0) { return 0; } return self.locks[positionPlusOne - 1].expiresAt; } /// @notice Set the lock of `creator` to `expiresAt`, /// overriding the current value if any. function setLock( LockSet storage self, address _creator, uint96 _expiresAt ) internal { uint256 positionPlusOne = self.positions[_creator]; Lock memory lock = Lock(_creator, _expiresAt); // No existing lock if (positionPlusOne == 0) { self.locks.push(lock); self.positions[_creator] = self.locks.length; // Existing lock present } else { self.locks[positionPlusOne - 1].expiresAt = _expiresAt; } } /// @notice Remove the lock of `creator`. /// If no lock present, do nothing. function releaseLock(LockSet storage self, address _creator) internal { uint256 positionPlusOne = self.positions[_creator]; if (positionPlusOne != 0) { uint256 lockCount = self.locks.length; if (positionPlusOne != lockCount) { // Not the last lock, // so we need to move the last lock into the emptied position. Lock memory lastLock = self.locks[lockCount - 1]; self.locks[positionPlusOne - 1] = lastLock; self.positions[lastLock.creator] = positionPlusOne; } self.locks.length--; self.positions[_creator] = 0; } } /// @notice Return the locks of the LockSet `self`. function enumerate(LockSet storage self) internal view returns (Lock[] memory) { return self.locks; } }