Skip to content

Commit

Permalink
Add clear function to Enumerable{Set,Map} (#5486)
Browse files Browse the repository at this point in the history
Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
  • Loading branch information
arr00 and Amxx authored Feb 10, 2025
1 parent 441dc14 commit 3658269
Show file tree
Hide file tree
Showing 10 changed files with 326 additions and 0 deletions.
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)
}
}

/**
* @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

0 comments on commit 3658269

Please sign in to comment.