Skip to content

Commit 3658269

Browse files
arr00Amxx
andauthored
Add clear function to Enumerable{Set,Map} (#5486)
Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
1 parent 441dc14 commit 3658269

File tree

10 files changed

+326
-0
lines changed

10 files changed

+326
-0
lines changed

.changeset/good-cameras-rush.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'openzeppelin-solidity': minor
3+
---
4+
5+
`EnumerableMap`: Add `clear` function to EnumerableMaps which deletes all entries in the map.

.changeset/sixty-tips-wink.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'openzeppelin-solidity': minor
3+
---
4+
5+
`EnumerableSet`: Add `clear` function to EnumerableSets which deletes all values in the set.

contracts/utils/structs/EnumerableMap.sol

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {EnumerableSet} from "./EnumerableSet.sol";
1616
* - Entries are added, removed, and checked for existence in constant time
1717
* (O(1)).
1818
* - Entries are enumerated in O(n). No guarantees are made on the ordering.
19+
* - Map can be cleared (all entries removed) in O(n).
1920
*
2021
* ```solidity
2122
* contract Example {
@@ -90,6 +91,20 @@ library EnumerableMap {
9091
return map._keys.remove(key);
9192
}
9293

94+
/**
95+
* @dev Removes all the entries from a map. O(n).
96+
*
97+
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
98+
* function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block.
99+
*/
100+
function clear(Bytes32ToBytes32Map storage map) internal {
101+
uint256 len = length(map);
102+
for (uint256 i = 0; i < len; ++i) {
103+
delete map._values[map._keys.at(i)];
104+
}
105+
map._keys.clear();
106+
}
107+
93108
/**
94109
* @dev Returns true if the key is in the map. O(1).
95110
*/
@@ -185,6 +200,16 @@ library EnumerableMap {
185200
return remove(map._inner, bytes32(key));
186201
}
187202

203+
/**
204+
* @dev Removes all the entries from a map. O(n).
205+
*
206+
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
207+
* function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block.
208+
*/
209+
function clear(UintToUintMap storage map) internal {
210+
clear(map._inner);
211+
}
212+
188213
/**
189214
* @dev Returns true if the key is in the map. O(1).
190215
*/
@@ -278,6 +303,16 @@ library EnumerableMap {
278303
return remove(map._inner, bytes32(key));
279304
}
280305

306+
/**
307+
* @dev Removes all the entries from a map. O(n).
308+
*
309+
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
310+
* function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block.
311+
*/
312+
function clear(UintToAddressMap storage map) internal {
313+
clear(map._inner);
314+
}
315+
281316
/**
282317
* @dev Returns true if the key is in the map. O(1).
283318
*/
@@ -371,6 +406,16 @@ library EnumerableMap {
371406
return remove(map._inner, bytes32(key));
372407
}
373408

409+
/**
410+
* @dev Removes all the entries from a map. O(n).
411+
*
412+
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
413+
* function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block.
414+
*/
415+
function clear(UintToBytes32Map storage map) internal {
416+
clear(map._inner);
417+
}
418+
374419
/**
375420
* @dev Returns true if the key is in the map. O(1).
376421
*/
@@ -464,6 +509,16 @@ library EnumerableMap {
464509
return remove(map._inner, bytes32(uint256(uint160(key))));
465510
}
466511

512+
/**
513+
* @dev Removes all the entries from a map. O(n).
514+
*
515+
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
516+
* function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block.
517+
*/
518+
function clear(AddressToUintMap storage map) internal {
519+
clear(map._inner);
520+
}
521+
467522
/**
468523
* @dev Returns true if the key is in the map. O(1).
469524
*/
@@ -557,6 +612,16 @@ library EnumerableMap {
557612
return remove(map._inner, bytes32(uint256(uint160(key))));
558613
}
559614

615+
/**
616+
* @dev Removes all the entries from a map. O(n).
617+
*
618+
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
619+
* function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block.
620+
*/
621+
function clear(AddressToAddressMap storage map) internal {
622+
clear(map._inner);
623+
}
624+
560625
/**
561626
* @dev Returns true if the key is in the map. O(1).
562627
*/
@@ -650,6 +715,16 @@ library EnumerableMap {
650715
return remove(map._inner, bytes32(uint256(uint160(key))));
651716
}
652717

718+
/**
719+
* @dev Removes all the entries from a map. O(n).
720+
*
721+
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
722+
* function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block.
723+
*/
724+
function clear(AddressToBytes32Map storage map) internal {
725+
clear(map._inner);
726+
}
727+
653728
/**
654729
* @dev Returns true if the key is in the map. O(1).
655730
*/
@@ -743,6 +818,16 @@ library EnumerableMap {
743818
return remove(map._inner, key);
744819
}
745820

821+
/**
822+
* @dev Removes all the entries from a map. O(n).
823+
*
824+
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
825+
* function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block.
826+
*/
827+
function clear(Bytes32ToUintMap storage map) internal {
828+
clear(map._inner);
829+
}
830+
746831
/**
747832
* @dev Returns true if the key is in the map. O(1).
748833
*/
@@ -836,6 +921,16 @@ library EnumerableMap {
836921
return remove(map._inner, key);
837922
}
838923

924+
/**
925+
* @dev Removes all the entries from a map. O(n).
926+
*
927+
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
928+
* function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block.
929+
*/
930+
function clear(Bytes32ToAddressMap storage map) internal {
931+
clear(map._inner);
932+
}
933+
839934
/**
840935
* @dev Returns true if the key is in the map. O(1).
841936
*/

contracts/utils/structs/EnumerableSet.sol

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
pragma solidity ^0.8.20;
66

7+
import {Arrays} from "../Arrays.sol";
78
import {Hashes} from "../cryptography/Hashes.sol";
89

910
/**
@@ -16,6 +17,7 @@ import {Hashes} from "../cryptography/Hashes.sol";
1617
* - Elements are added, removed, and checked for existence in constant time
1718
* (O(1)).
1819
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
20+
* - Set can be cleared (all elements removed) in O(n).
1921
*
2022
* ```solidity
2123
* contract Example {
@@ -116,6 +118,20 @@ library EnumerableSet {
116118
}
117119
}
118120

121+
/**
122+
* @dev Removes all the values from a set. O(n).
123+
*
124+
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
125+
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
126+
*/
127+
function _clear(Set storage set) private {
128+
uint256 len = _length(set);
129+
for (uint256 i = 0; i < len; ++i) {
130+
delete set._positions[set._values[i]];
131+
}
132+
Arrays.unsafeSetLength(set._values, 0);
133+
}
134+
119135
/**
120136
* @dev Returns true if the value is in the set. O(1).
121137
*/
@@ -182,6 +198,16 @@ library EnumerableSet {
182198
return _remove(set._inner, value);
183199
}
184200

201+
/**
202+
* @dev Removes all the values from a set. O(n).
203+
*
204+
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
205+
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
206+
*/
207+
function clear(Bytes32Set storage set) internal {
208+
_clear(set._inner);
209+
}
210+
185211
/**
186212
* @dev Returns true if the value is in the set. O(1).
187213
*/
@@ -255,6 +281,16 @@ library EnumerableSet {
255281
return _remove(set._inner, bytes32(uint256(uint160(value))));
256282
}
257283

284+
/**
285+
* @dev Removes all the values from a set. O(n).
286+
*
287+
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
288+
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
289+
*/
290+
function clear(AddressSet storage set) internal {
291+
_clear(set._inner);
292+
}
293+
258294
/**
259295
* @dev Returns true if the value is in the set. O(1).
260296
*/
@@ -328,6 +364,16 @@ library EnumerableSet {
328364
return _remove(set._inner, bytes32(value));
329365
}
330366

367+
/**
368+
* @dev Removes all the values from a set. O(n).
369+
*
370+
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
371+
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
372+
*/
373+
function clear(UintSet storage set) internal {
374+
_clear(set._inner);
375+
}
376+
331377
/**
332378
* @dev Returns true if the value is in the set. O(1).
333379
*/
@@ -442,6 +488,24 @@ library EnumerableSet {
442488
}
443489
}
444490

491+
/**
492+
* @dev Removes all the values from a set. O(n).
493+
*
494+
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
495+
* function uncallable if the set grows to the point where clearing it consumes too much gas to fit in a block.
496+
*/
497+
function clear(Bytes32x2Set storage self) internal {
498+
bytes32[2][] storage v = self._values;
499+
500+
uint256 len = length(self);
501+
for (uint256 i = 0; i < len; ++i) {
502+
delete self._positions[_hash(v[i])];
503+
}
504+
assembly ("memory-safe") {
505+
sstore(v.slot, 0)
506+
}
507+
}
508+
445509
/**
446510
* @dev Returns true if the value is in the self. O(1).
447511
*/

scripts/generate/templates/EnumerableMap.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {EnumerableSet} from "./EnumerableSet.sol";
1717
* - Entries are added, removed, and checked for existence in constant time
1818
* (O(1)).
1919
* - Entries are enumerated in O(n). No guarantees are made on the ordering.
20+
* - Map can be cleared (all entries removed) in O(n).
2021
*
2122
* \`\`\`solidity
2223
* contract Example {
@@ -91,6 +92,20 @@ function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (
9192
return map._keys.remove(key);
9293
}
9394
95+
/**
96+
* @dev Removes all the entries from a map. O(n).
97+
*
98+
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
99+
* function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block.
100+
*/
101+
function clear(Bytes32ToBytes32Map storage map) internal {
102+
uint256 len = length(map);
103+
for (uint256 i = 0; i < len; ++i) {
104+
delete map._values[map._keys.at(i)];
105+
}
106+
map._keys.clear();
107+
}
108+
94109
/**
95110
* @dev Returns true if the key is in the map. O(1).
96111
*/
@@ -188,6 +203,16 @@ function remove(${name} storage map, ${keyType} key) internal returns (bool) {
188203
return remove(map._inner, ${toBytes32(keyType, 'key')});
189204
}
190205
206+
/**
207+
* @dev Removes all the entries from a map. O(n).
208+
*
209+
* WARNING: Developers should keep in mind that this function has an unbounded cost and using it may render the
210+
* function uncallable if the map grows to the point where clearing it consumes too much gas to fit in a block.
211+
*/
212+
function clear(${name} storage map) internal {
213+
clear(map._inner);
214+
}
215+
191216
/**
192217
* @dev Returns true if the key is in the map. O(1).
193218
*/

0 commit comments

Comments
 (0)