This repository was archived by the owner on Feb 23, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathIterableSet.sol
148 lines (121 loc) · 6.42 KB
/
IterableSet.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
/*//////////////////////////////////////////////////////////////
IterableSet
//////////////////////////////////////////////////////////////*/
/// @title IterableSet
/// @notice Iterable set library for address and uint256 types
library IterableSet {
/*//////////////////////////////////////////////////////////////
Address Set
//////////////////////////////////////////////////////////////*/
/// @title AddressSet
/// @notice Storage struct for iterable address set
struct AddressSet {
address[] elements; // list of elements in the set
// idxOf indexing scheme:
// idxOf[element] = index of key in self.elements + 1 OR in other words
// idxOf[element] = one-indexed location of a particular element in self.elements
// idxOf[element] = 0 denotes that an element is not present in the set
mapping(address elem => uint256 idx) idxOf;
}
/// @notice Check if the set contains a given element
function contains(AddressSet storage self, address elem) internal view returns (bool) {
return self.idxOf[elem] > 0; // idxOf[element] = 0 denotes that element is not in the set
}
/// @notice Fetch element from set by index
/// @dev Zero-indexed query to the elements array. Set does not preserve order after removals
function getByIdx(AddressSet storage self, uint256 idx) internal view returns (address) {
return self.elements[idx];
}
/// @notice Fetch all elements in the set
/// @dev Set does not preserve order after removals
function getElements(AddressSet storage self) internal view returns (address[] memory) {
return self.elements;
}
/// @notice Fetch the number of elements in the set
function length(AddressSet storage self) internal view returns (uint256) {
return self.elements.length;
}
// insertion: the element is pushed to the end of self.elements and idxOf is updated accordingly
/// @notice Insert an element into the set
/// @dev No-op if element already exists
function insert(AddressSet storage self, address elem) internal {
if (self.idxOf[elem] != 0) return; // no-op if element is already in the set
self.elements.push(elem);
self.idxOf[elem] = self.elements.length;
}
// removal: replace it with the current last element, update idxOf and call pop()
// if the element to be removed is the last element, simply update idxOf and call pop()
/// @notice Remove element from set
/// @dev No-op if element is not in the set
function remove(AddressSet storage self, address elem) internal {
if (self.idxOf[elem] == 0) return; // no-op if element is not in the set
uint256 toRemoveIdx = self.idxOf[elem] - 1; // idx of element to be removed
uint256 len = self.elements.length;
// if element to be removed is not at the end, replace it with the last element
if (toRemoveIdx != len - 1) {
address lastElem = self.elements[len - 1];
self.elements[toRemoveIdx] = lastElem;
self.idxOf[lastElem] = toRemoveIdx + 1; // idxOf mapping is 1-indexed
}
self.idxOf[elem] = 0; // idxOf[elem] = 0 denotes that it is no longer in the set
self.elements.pop(); // pop self.elements array effectively deleting elem
}
/*//////////////////////////////////////////////////////////////
Uint256 Set
//////////////////////////////////////////////////////////////*/
/// @title Uint256Set
/// @notice Storage struct for iterable uint256 set
struct Uint256Set {
uint256[] elements; // list of elements in the set
// idxOf indexing scheme:
// idxOf[element] = index of key in self.elements + 1 OR in other words
// idxOf[element] = one-indexed location of a particular element in self.elements
// idxOf[element] = 0, if element is not present in the set
mapping(uint256 elem => uint256 idx) idxOf;
}
/// @notice Check if the set contains a give element
function contains(Uint256Set storage self, uint256 elem) internal view returns (bool) {
return self.idxOf[elem] > 0; // idxOf[element] = 0 denotes that element is not in the set
}
/// @notice Fetch element from set by index
/// @dev Zero-indexed query to the elements array. Set does not preserve order after removals
function getByIdx(Uint256Set storage self, uint256 idx) internal view returns (uint256) {
return self.elements[idx];
}
/// @notice Fetch all elements in the set
/// @dev Set does not preserve order after removals
function getElements(Uint256Set storage self) internal view returns (uint256[] memory) {
return self.elements;
}
/// @notice Fetch the number of elements in the set
function length(Uint256Set storage self) internal view returns (uint256) {
return self.elements.length;
}
// insertion: the element is pushed to the end of self.elements and idxOf is updated accordingly
/// @notice Insert an element into the set
/// @dev No-op if element already exists
function insert(Uint256Set storage self, uint256 elem) internal {
if (self.idxOf[elem] != 0) return; // no-op if element is already in the set
self.elements.push(elem);
self.idxOf[elem] = self.elements.length;
}
// removal: replace it with the current last element, update idxOf and call pop()
// if the element to be removed is the last element, simply update idxOf and call pop()
/// @notice Remove element from set
/// @dev No-op if element does not exist
function remove(Uint256Set storage self, uint256 elem) internal {
if (self.idxOf[elem] == 0) return; // no-op if element is not in the set
uint256 toRemoveIdx = self.idxOf[elem] - 1; // idx of element to be removed
uint256 len = self.elements.length;
// if element to be removed is not at the end, replace it with the last element
if (toRemoveIdx != len - 1) {
uint256 lastElem = self.elements[len - 1];
self.elements[toRemoveIdx] = lastElem;
self.idxOf[lastElem] = toRemoveIdx + 1; // idxOf mapping is 1-indexed
}
self.idxOf[elem] = 0; // idxOf[elem] = 0 denotes that it is no longer in the set
self.elements.pop(); // pop self.elements array effectively deleting elem
}
}