Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add clear function to Enumerable{Set,Map} #5486

Merged
merged 12 commits into from
Feb 10, 2025
5 changes: 5 additions & 0 deletions .changeset/good-cameras-rush.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'openzeppelin-solidity': minor
---

`EnumerableMap`: Add `clear` function to EnumerableMaps which deletes all entries in the map.
5 changes: 5 additions & 0 deletions .changeset/sixty-tips-wink.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'openzeppelin-solidity': minor
---

`EnumerableSet`: Add `clear` function to EnumerableSets which deletes all values in the set.
95 changes: 95 additions & 0 deletions contracts/utils/structs/EnumerableMap.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {EnumerableSet} from "./EnumerableSet.sol";
* - Entries are added, removed, and checked for existence in constant time
* (O(1)).
* - Entries are enumerated in O(n). No guarantees are made on the ordering.
* - Map can be cleared (all entries removed) in O(n).
*
* ```solidity
* contract Example {
Expand Down Expand Up @@ -90,6 +91,20 @@ library EnumerableMap {
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).
*/
Expand Down Expand Up @@ -185,6 +200,16 @@ library EnumerableMap {
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).
*/
Expand Down Expand Up @@ -278,6 +303,16 @@ library EnumerableMap {
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).
*/
Expand Down Expand Up @@ -371,6 +406,16 @@ library EnumerableMap {
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).
*/
Expand Down Expand Up @@ -464,6 +509,16 @@ library EnumerableMap {
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).
*/
Expand Down Expand Up @@ -557,6 +612,16 @@ library EnumerableMap {
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).
*/
Expand Down Expand Up @@ -650,6 +715,16 @@ library EnumerableMap {
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).
*/
Expand Down Expand Up @@ -743,6 +818,16 @@ library EnumerableMap {
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).
*/
Expand Down Expand Up @@ -836,6 +921,16 @@ library EnumerableMap {
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).
*/
Expand Down
64 changes: 64 additions & 0 deletions contracts/utils/structs/EnumerableSet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

pragma solidity ^0.8.20;

import {Arrays} from "../Arrays.sol";
import {Hashes} from "../cryptography/Hashes.sol";

/**
Expand All @@ -16,6 +17,7 @@ import {Hashes} from "../cryptography/Hashes.sol";
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
* - Set can be cleared (all elements removed) in O(n).
*
* ```solidity
* contract Example {
Expand Down Expand Up @@ -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).
*/
Expand Down Expand Up @@ -182,6 +198,16 @@ library EnumerableSet {
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).
*/
Expand Down Expand Up @@ -255,6 +281,16 @@ library EnumerableSet {
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).
*/
Expand Down Expand Up @@ -328,6 +364,16 @@ library EnumerableSet {
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).
*/
Expand Down Expand Up @@ -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)
}
Amxx marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* @dev Returns true if the value is in the self. O(1).
*/
Expand Down
25 changes: 25 additions & 0 deletions scripts/generate/templates/EnumerableMap.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {EnumerableSet} from "./EnumerableSet.sol";
* - Entries are added, removed, and checked for existence in constant time
* (O(1)).
* - Entries are enumerated in O(n). No guarantees are made on the ordering.
* - Map can be cleared (all entries removed) in O(n).
*
* \`\`\`solidity
* contract Example {
Expand Down Expand Up @@ -91,6 +92,20 @@ function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (
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).
*/
Expand Down Expand Up @@ -188,6 +203,16 @@ function remove(${name} storage map, ${keyType} key) internal returns (bool) {
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).
*/
Expand Down
Loading