Add clear function to Enumerable{Set,Map} (#5486)
Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
This commit is contained in:
5
.changeset/good-cameras-rush.md
Normal file
5
.changeset/good-cameras-rush.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'openzeppelin-solidity': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
`EnumerableMap`: Add `clear` function to EnumerableMaps which deletes all entries in the map.
|
||||||
5
.changeset/sixty-tips-wink.md
Normal file
5
.changeset/sixty-tips-wink.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'openzeppelin-solidity': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
`EnumerableSet`: Add `clear` function to EnumerableSets which deletes all values in the set.
|
||||||
@ -16,6 +16,7 @@ import {EnumerableSet} from "./EnumerableSet.sol";
|
|||||||
* - Entries are added, removed, and checked for existence in constant time
|
* - Entries are added, removed, and checked for existence in constant time
|
||||||
* (O(1)).
|
* (O(1)).
|
||||||
* - Entries are enumerated in O(n). No guarantees are made on the ordering.
|
* - Entries are enumerated in O(n). No guarantees are made on the ordering.
|
||||||
|
* - Map can be cleared (all entries removed) in O(n).
|
||||||
*
|
*
|
||||||
* ```solidity
|
* ```solidity
|
||||||
* contract Example {
|
* contract Example {
|
||||||
@ -90,6 +91,20 @@ library EnumerableMap {
|
|||||||
return map._keys.remove(key);
|
return map._keys.remove(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Removes all the entries from a map. O(n).
|
||||||
|
*
|
||||||
|
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
|
||||||
|
* function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block.
|
||||||
|
*/
|
||||||
|
function clear(Bytes32ToBytes32Map storage map) internal {
|
||||||
|
uint256 len = length(map);
|
||||||
|
for (uint256 i = 0; i < len; ++i) {
|
||||||
|
delete map._values[map._keys.at(i)];
|
||||||
|
}
|
||||||
|
map._keys.clear();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Returns true if the key is in the map. O(1).
|
* @dev Returns true if the key is in the map. O(1).
|
||||||
*/
|
*/
|
||||||
@ -185,6 +200,16 @@ library EnumerableMap {
|
|||||||
return remove(map._inner, bytes32(key));
|
return remove(map._inner, bytes32(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Removes all the entries from a map. O(n).
|
||||||
|
*
|
||||||
|
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
|
||||||
|
* function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block.
|
||||||
|
*/
|
||||||
|
function clear(UintToUintMap storage map) internal {
|
||||||
|
clear(map._inner);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Returns true if the key is in the map. O(1).
|
* @dev Returns true if the key is in the map. O(1).
|
||||||
*/
|
*/
|
||||||
@ -278,6 +303,16 @@ library EnumerableMap {
|
|||||||
return remove(map._inner, bytes32(key));
|
return remove(map._inner, bytes32(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Removes all the entries from a map. O(n).
|
||||||
|
*
|
||||||
|
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
|
||||||
|
* function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block.
|
||||||
|
*/
|
||||||
|
function clear(UintToAddressMap storage map) internal {
|
||||||
|
clear(map._inner);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Returns true if the key is in the map. O(1).
|
* @dev Returns true if the key is in the map. O(1).
|
||||||
*/
|
*/
|
||||||
@ -371,6 +406,16 @@ library EnumerableMap {
|
|||||||
return remove(map._inner, bytes32(key));
|
return remove(map._inner, bytes32(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Removes all the entries from a map. O(n).
|
||||||
|
*
|
||||||
|
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
|
||||||
|
* function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block.
|
||||||
|
*/
|
||||||
|
function clear(UintToBytes32Map storage map) internal {
|
||||||
|
clear(map._inner);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Returns true if the key is in the map. O(1).
|
* @dev Returns true if the key is in the map. O(1).
|
||||||
*/
|
*/
|
||||||
@ -464,6 +509,16 @@ library EnumerableMap {
|
|||||||
return remove(map._inner, bytes32(uint256(uint160(key))));
|
return remove(map._inner, bytes32(uint256(uint160(key))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Removes all the entries from a map. O(n).
|
||||||
|
*
|
||||||
|
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
|
||||||
|
* function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block.
|
||||||
|
*/
|
||||||
|
function clear(AddressToUintMap storage map) internal {
|
||||||
|
clear(map._inner);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Returns true if the key is in the map. O(1).
|
* @dev Returns true if the key is in the map. O(1).
|
||||||
*/
|
*/
|
||||||
@ -557,6 +612,16 @@ library EnumerableMap {
|
|||||||
return remove(map._inner, bytes32(uint256(uint160(key))));
|
return remove(map._inner, bytes32(uint256(uint160(key))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Removes all the entries from a map. O(n).
|
||||||
|
*
|
||||||
|
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
|
||||||
|
* function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block.
|
||||||
|
*/
|
||||||
|
function clear(AddressToAddressMap storage map) internal {
|
||||||
|
clear(map._inner);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Returns true if the key is in the map. O(1).
|
* @dev Returns true if the key is in the map. O(1).
|
||||||
*/
|
*/
|
||||||
@ -650,6 +715,16 @@ library EnumerableMap {
|
|||||||
return remove(map._inner, bytes32(uint256(uint160(key))));
|
return remove(map._inner, bytes32(uint256(uint160(key))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Removes all the entries from a map. O(n).
|
||||||
|
*
|
||||||
|
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
|
||||||
|
* function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block.
|
||||||
|
*/
|
||||||
|
function clear(AddressToBytes32Map storage map) internal {
|
||||||
|
clear(map._inner);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Returns true if the key is in the map. O(1).
|
* @dev Returns true if the key is in the map. O(1).
|
||||||
*/
|
*/
|
||||||
@ -743,6 +818,16 @@ library EnumerableMap {
|
|||||||
return remove(map._inner, key);
|
return remove(map._inner, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Removes all the entries from a map. O(n).
|
||||||
|
*
|
||||||
|
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
|
||||||
|
* function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block.
|
||||||
|
*/
|
||||||
|
function clear(Bytes32ToUintMap storage map) internal {
|
||||||
|
clear(map._inner);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Returns true if the key is in the map. O(1).
|
* @dev Returns true if the key is in the map. O(1).
|
||||||
*/
|
*/
|
||||||
@ -836,6 +921,16 @@ library EnumerableMap {
|
|||||||
return remove(map._inner, key);
|
return remove(map._inner, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Removes all the entries from a map. O(n).
|
||||||
|
*
|
||||||
|
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
|
||||||
|
* function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block.
|
||||||
|
*/
|
||||||
|
function clear(Bytes32ToAddressMap storage map) internal {
|
||||||
|
clear(map._inner);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Returns true if the key is in the map. O(1).
|
* @dev Returns true if the key is in the map. O(1).
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
pragma solidity ^0.8.20;
|
pragma solidity ^0.8.20;
|
||||||
|
|
||||||
|
import {Arrays} from "../Arrays.sol";
|
||||||
import {Hashes} from "../cryptography/Hashes.sol";
|
import {Hashes} from "../cryptography/Hashes.sol";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -16,6 +17,7 @@ import {Hashes} from "../cryptography/Hashes.sol";
|
|||||||
* - Elements are added, removed, and checked for existence in constant time
|
* - Elements are added, removed, and checked for existence in constant time
|
||||||
* (O(1)).
|
* (O(1)).
|
||||||
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
|
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
|
||||||
|
* - Set can be cleared (all elements removed) in O(n).
|
||||||
*
|
*
|
||||||
* ```solidity
|
* ```solidity
|
||||||
* contract Example {
|
* contract Example {
|
||||||
@ -116,6 +118,20 @@ library EnumerableSet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Removes all the values from a set. O(n).
|
||||||
|
*
|
||||||
|
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
|
||||||
|
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
|
||||||
|
*/
|
||||||
|
function _clear(Set storage set) private {
|
||||||
|
uint256 len = _length(set);
|
||||||
|
for (uint256 i = 0; i < len; ++i) {
|
||||||
|
delete set._positions[set._values[i]];
|
||||||
|
}
|
||||||
|
Arrays.unsafeSetLength(set._values, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Returns true if the value is in the set. O(1).
|
* @dev Returns true if the value is in the set. O(1).
|
||||||
*/
|
*/
|
||||||
@ -182,6 +198,16 @@ library EnumerableSet {
|
|||||||
return _remove(set._inner, value);
|
return _remove(set._inner, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Removes all the values from a set. O(n).
|
||||||
|
*
|
||||||
|
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
|
||||||
|
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
|
||||||
|
*/
|
||||||
|
function clear(Bytes32Set storage set) internal {
|
||||||
|
_clear(set._inner);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Returns true if the value is in the set. O(1).
|
* @dev Returns true if the value is in the set. O(1).
|
||||||
*/
|
*/
|
||||||
@ -255,6 +281,16 @@ library EnumerableSet {
|
|||||||
return _remove(set._inner, bytes32(uint256(uint160(value))));
|
return _remove(set._inner, bytes32(uint256(uint160(value))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Removes all the values from a set. O(n).
|
||||||
|
*
|
||||||
|
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
|
||||||
|
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
|
||||||
|
*/
|
||||||
|
function clear(AddressSet storage set) internal {
|
||||||
|
_clear(set._inner);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Returns true if the value is in the set. O(1).
|
* @dev Returns true if the value is in the set. O(1).
|
||||||
*/
|
*/
|
||||||
@ -328,6 +364,16 @@ library EnumerableSet {
|
|||||||
return _remove(set._inner, bytes32(value));
|
return _remove(set._inner, bytes32(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Removes all the values from a set. O(n).
|
||||||
|
*
|
||||||
|
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
|
||||||
|
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
|
||||||
|
*/
|
||||||
|
function clear(UintSet storage set) internal {
|
||||||
|
_clear(set._inner);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Returns true if the value is in the set. O(1).
|
* @dev Returns true if the value is in the set. O(1).
|
||||||
*/
|
*/
|
||||||
@ -442,6 +488,24 @@ library EnumerableSet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Removes all the values from a set. O(n).
|
||||||
|
*
|
||||||
|
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
|
||||||
|
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
|
||||||
|
*/
|
||||||
|
function clear(Bytes32x2Set storage self) internal {
|
||||||
|
bytes32[2][] storage v = self._values;
|
||||||
|
|
||||||
|
uint256 len = length(self);
|
||||||
|
for (uint256 i = 0; i < len; ++i) {
|
||||||
|
delete self._positions[_hash(v[i])];
|
||||||
|
}
|
||||||
|
assembly ("memory-safe") {
|
||||||
|
sstore(v.slot, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Returns true if the value is in the self. O(1).
|
* @dev Returns true if the value is in the self. O(1).
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import {EnumerableSet} from "./EnumerableSet.sol";
|
|||||||
* - Entries are added, removed, and checked for existence in constant time
|
* - Entries are added, removed, and checked for existence in constant time
|
||||||
* (O(1)).
|
* (O(1)).
|
||||||
* - Entries are enumerated in O(n). No guarantees are made on the ordering.
|
* - Entries are enumerated in O(n). No guarantees are made on the ordering.
|
||||||
|
* - Map can be cleared (all entries removed) in O(n).
|
||||||
*
|
*
|
||||||
* \`\`\`solidity
|
* \`\`\`solidity
|
||||||
* contract Example {
|
* contract Example {
|
||||||
@ -91,6 +92,20 @@ function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (
|
|||||||
return map._keys.remove(key);
|
return map._keys.remove(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Removes all the entries from a map. O(n).
|
||||||
|
*
|
||||||
|
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
|
||||||
|
* function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block.
|
||||||
|
*/
|
||||||
|
function clear(Bytes32ToBytes32Map storage map) internal {
|
||||||
|
uint256 len = length(map);
|
||||||
|
for (uint256 i = 0; i < len; ++i) {
|
||||||
|
delete map._values[map._keys.at(i)];
|
||||||
|
}
|
||||||
|
map._keys.clear();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Returns true if the key is in the map. O(1).
|
* @dev Returns true if the key is in the map. O(1).
|
||||||
*/
|
*/
|
||||||
@ -188,6 +203,16 @@ function remove(${name} storage map, ${keyType} key) internal returns (bool) {
|
|||||||
return remove(map._inner, ${toBytes32(keyType, 'key')});
|
return remove(map._inner, ${toBytes32(keyType, 'key')});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Removes all the entries from a map. O(n).
|
||||||
|
*
|
||||||
|
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
|
||||||
|
* function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block.
|
||||||
|
*/
|
||||||
|
function clear(${name} storage map) internal {
|
||||||
|
clear(map._inner);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Returns true if the key is in the map. O(1).
|
* @dev Returns true if the key is in the map. O(1).
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -5,6 +5,7 @@ const { TYPES } = require('./EnumerableSet.opts');
|
|||||||
const header = `\
|
const header = `\
|
||||||
pragma solidity ^0.8.20;
|
pragma solidity ^0.8.20;
|
||||||
|
|
||||||
|
import {Arrays} from "../Arrays.sol";
|
||||||
import {Hashes} from "../cryptography/Hashes.sol";
|
import {Hashes} from "../cryptography/Hashes.sol";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -17,6 +18,7 @@ import {Hashes} from "../cryptography/Hashes.sol";
|
|||||||
* - Elements are added, removed, and checked for existence in constant time
|
* - Elements are added, removed, and checked for existence in constant time
|
||||||
* (O(1)).
|
* (O(1)).
|
||||||
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
|
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
|
||||||
|
* - Set can be cleared (all elements removed) in O(n).
|
||||||
*
|
*
|
||||||
* \`\`\`solidity
|
* \`\`\`solidity
|
||||||
* contract Example {
|
* contract Example {
|
||||||
@ -119,6 +121,20 @@ function _remove(Set storage set, bytes32 value) private returns (bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Removes all the values from a set. O(n).
|
||||||
|
*
|
||||||
|
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
|
||||||
|
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
|
||||||
|
*/
|
||||||
|
function _clear(Set storage set) private {
|
||||||
|
uint256 len = _length(set);
|
||||||
|
for (uint256 i = 0; i < len; ++i) {
|
||||||
|
delete set._positions[set._values[i]];
|
||||||
|
}
|
||||||
|
Arrays.unsafeSetLength(set._values, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Returns true if the value is in the set. O(1).
|
* @dev Returns true if the value is in the set. O(1).
|
||||||
*/
|
*/
|
||||||
@ -187,6 +203,16 @@ function remove(${name} storage set, ${type} value) internal returns (bool) {
|
|||||||
return _remove(set._inner, ${toBytes32(type, 'value')});
|
return _remove(set._inner, ${toBytes32(type, 'value')});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Removes all the values from a set. O(n).
|
||||||
|
*
|
||||||
|
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
|
||||||
|
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
|
||||||
|
*/
|
||||||
|
function clear(${name} storage set) internal {
|
||||||
|
_clear(set._inner);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Returns true if the value is in the set. O(1).
|
* @dev Returns true if the value is in the set. O(1).
|
||||||
*/
|
*/
|
||||||
@ -303,6 +329,24 @@ function remove(${name} storage self, ${type} memory value) internal returns (bo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dev Removes all the values from a set. O(n).
|
||||||
|
*
|
||||||
|
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
|
||||||
|
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
|
||||||
|
*/
|
||||||
|
function clear(${name} storage self) internal {
|
||||||
|
${type}[] storage v = self._values;
|
||||||
|
|
||||||
|
uint256 len = length(self);
|
||||||
|
for (uint256 i = 0; i < len; ++i) {
|
||||||
|
delete self._positions[_hash(v[i])];
|
||||||
|
}
|
||||||
|
assembly ("memory-safe") {
|
||||||
|
sstore(v.slot, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dev Returns true if the value is in the self. O(1).
|
* @dev Returns true if the value is in the self. O(1).
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -117,6 +117,49 @@ function shouldBehaveLikeMap() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('clear', function () {
|
||||||
|
it('clears a single entry', async function () {
|
||||||
|
await this.methods.set(this.keyA, this.valueA);
|
||||||
|
|
||||||
|
await this.methods.clear();
|
||||||
|
|
||||||
|
expect(await this.methods.contains(this.keyA)).to.be.false;
|
||||||
|
await expectMembersMatch(this.methods, [], []);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('clears multiple entries', async function () {
|
||||||
|
await this.methods.set(this.keyA, this.valueA);
|
||||||
|
await this.methods.set(this.keyB, this.valueB);
|
||||||
|
await this.methods.set(this.keyC, this.valueC);
|
||||||
|
|
||||||
|
await this.methods.clear();
|
||||||
|
|
||||||
|
expect(await this.methods.contains(this.keyA)).to.be.false;
|
||||||
|
expect(await this.methods.contains(this.keyB)).to.be.false;
|
||||||
|
expect(await this.methods.contains(this.keyC)).to.be.false;
|
||||||
|
await expectMembersMatch(this.methods, [], []);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not revert on empty map', async function () {
|
||||||
|
await this.methods.clear();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('clear then add entry', async function () {
|
||||||
|
await this.methods.set(this.keyA, this.valueA);
|
||||||
|
await this.methods.set(this.keyB, this.valueB);
|
||||||
|
await this.methods.set(this.keyC, this.valueC);
|
||||||
|
|
||||||
|
await this.methods.clear();
|
||||||
|
|
||||||
|
await this.methods.set(this.keyA, this.valueA);
|
||||||
|
|
||||||
|
expect(await this.methods.contains(this.keyA)).to.be.true;
|
||||||
|
expect(await this.methods.contains(this.keyB)).to.be.false;
|
||||||
|
expect(await this.methods.contains(this.keyC)).to.be.false;
|
||||||
|
await expectMembersMatch(this.methods, [this.keyA], [this.valueA]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('read', function () {
|
describe('read', function () {
|
||||||
beforeEach(async function () {
|
beforeEach(async function () {
|
||||||
await this.methods.set(this.keyA, this.valueA);
|
await this.methods.set(this.keyA, this.valueA);
|
||||||
|
|||||||
@ -26,6 +26,7 @@ async function fixture() {
|
|||||||
get: `$get_EnumerableMap_${name}(uint256,${keyType})`,
|
get: `$get_EnumerableMap_${name}(uint256,${keyType})`,
|
||||||
tryGet: `$tryGet_EnumerableMap_${name}(uint256,${keyType})`,
|
tryGet: `$tryGet_EnumerableMap_${name}(uint256,${keyType})`,
|
||||||
remove: `$remove_EnumerableMap_${name}(uint256,${keyType})`,
|
remove: `$remove_EnumerableMap_${name}(uint256,${keyType})`,
|
||||||
|
clear: `$clear_EnumerableMap_${name}(uint256)`,
|
||||||
length: `$length_EnumerableMap_${name}(uint256)`,
|
length: `$length_EnumerableMap_${name}(uint256)`,
|
||||||
at: `$at_EnumerableMap_${name}(uint256,uint256)`,
|
at: `$at_EnumerableMap_${name}(uint256,uint256)`,
|
||||||
contains: `$contains_EnumerableMap_${name}(uint256,${keyType})`,
|
contains: `$contains_EnumerableMap_${name}(uint256,${keyType})`,
|
||||||
|
|||||||
@ -109,6 +109,49 @@ function shouldBehaveLikeSet() {
|
|||||||
expect(await this.methods.contains(this.valueB)).to.be.false;
|
expect(await this.methods.contains(this.valueB)).to.be.false;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('clear', function () {
|
||||||
|
it('clears a single value', async function () {
|
||||||
|
await this.methods.add(this.valueA);
|
||||||
|
|
||||||
|
await this.methods.clear();
|
||||||
|
|
||||||
|
expect(await this.methods.contains(this.valueA)).to.be.false;
|
||||||
|
await expectMembersMatch(this.methods, []);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('clears multiple values', async function () {
|
||||||
|
await this.methods.add(this.valueA);
|
||||||
|
await this.methods.add(this.valueB);
|
||||||
|
await this.methods.add(this.valueC);
|
||||||
|
|
||||||
|
await this.methods.clear();
|
||||||
|
|
||||||
|
expect(await this.methods.contains(this.valueA)).to.be.false;
|
||||||
|
expect(await this.methods.contains(this.valueB)).to.be.false;
|
||||||
|
expect(await this.methods.contains(this.valueC)).to.be.false;
|
||||||
|
await expectMembersMatch(this.methods, []);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not revert on empty set', async function () {
|
||||||
|
await this.methods.clear();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('clear then add value', async function () {
|
||||||
|
await this.methods.add(this.valueA);
|
||||||
|
await this.methods.add(this.valueB);
|
||||||
|
await this.methods.add(this.valueC);
|
||||||
|
|
||||||
|
await this.methods.clear();
|
||||||
|
|
||||||
|
await this.methods.add(this.valueA);
|
||||||
|
|
||||||
|
expect(await this.methods.contains(this.valueA)).to.be.true;
|
||||||
|
expect(await this.methods.contains(this.valueB)).to.be.false;
|
||||||
|
expect(await this.methods.contains(this.valueC)).to.be.false;
|
||||||
|
await expectMembersMatch(this.methods, [this.valueA]);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|||||||
@ -30,6 +30,7 @@ async function fixture() {
|
|||||||
methods: getMethods(mock, {
|
methods: getMethods(mock, {
|
||||||
add: `$add(uint256,${type})`,
|
add: `$add(uint256,${type})`,
|
||||||
remove: `$remove(uint256,${type})`,
|
remove: `$remove(uint256,${type})`,
|
||||||
|
clear: `$clear_EnumerableSet_${name}(uint256)`,
|
||||||
contains: `$contains(uint256,${type})`,
|
contains: `$contains(uint256,${type})`,
|
||||||
length: `$length_EnumerableSet_${name}(uint256)`,
|
length: `$length_EnumerableSet_${name}(uint256)`,
|
||||||
at: `$at_EnumerableSet_${name}(uint256,uint256)`,
|
at: `$at_EnumerableSet_${name}(uint256,uint256)`,
|
||||||
|
|||||||
Reference in New Issue
Block a user