-
Notifications
You must be signed in to change notification settings - Fork 47
/
Copy pathEnumerableBytes32Set.sol
202 lines (184 loc) · 5.98 KB
/
EnumerableBytes32Set.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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
/**
* Copyright 2017-2021, bZeroX, LLC. All Rights Reserved.
* Licensed under the Apache License, Version 2.0.
*/
pragma solidity 0.5.17;
/**
* @title Library for managing loan sets.
*
* @notice Sets have the following properties:
*
* - 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.
*
* Include with `using EnumerableBytes32Set for EnumerableBytes32Set.Bytes32Set;`.
* */
library EnumerableBytes32Set {
struct Bytes32Set {
/// Position of the value in the `values` array, plus 1 because index 0
/// means a value is not in the set.
mapping(bytes32 => uint256) index;
bytes32[] values;
}
/**
* @notice Add an address value to a set. O(1).
*
* @param set The set of values.
* @param addrvalue The address to add.
*
* @return False if the value was already in the set.
*/
function addAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {
bytes32 value;
assembly {
value := addrvalue
}
return addBytes32(set, value);
}
/**
* @notice Add a value to a set. O(1).
*
* @param set The set of values.
* @param value The new value to add.
*
* @return False if the value was already in the set.
*/
function addBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {
if (!contains(set, value)) {
set.index[value] = set.values.push(value);
return true;
} else {
return false;
}
}
/**
* @notice Remove an address value from a set. O(1).
*
* @param set The set of values.
* @param addrvalue The address to remove.
*
* @return False if the address was not present in the set.
*/
function removeAddress(Bytes32Set storage set, address addrvalue) internal returns (bool) {
bytes32 value;
assembly {
value := addrvalue
}
return removeBytes32(set, value);
}
/**
* @notice Remove a value from a set. O(1).
*
* @param set The set of values.
* @param value The value to remove.
*
* @return False if the value was not present in the set.
*/
function removeBytes32(Bytes32Set storage set, bytes32 value) internal returns (bool) {
if (contains(set, value)) {
uint256 toDeleteIndex = set.index[value] - 1;
uint256 lastIndex = set.values.length - 1;
/// If the element we're deleting is the last one,
/// we can just remove it without doing a swap.
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set.values[lastIndex];
/// Move the last value to the index where the deleted value is.
set.values[toDeleteIndex] = lastValue;
/// Update the index for the moved value.
set.index[lastValue] = toDeleteIndex + 1; // All indexes are 1-based
}
/// Delete the index entry for the deleted value.
delete set.index[value];
/// Delete the old entry for the moved value.
set.values.pop();
return true;
} else {
return false;
}
}
/**
* @notice Find out whether a value exists in the set.
*
* @param set The set of values.
* @param value The value to find.
*
* @return True if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return set.index[value] != 0;
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function containsAddress(
Bytes32Set storage set,
address addrvalue
) internal view returns (bool) {
bytes32 value;
assembly {
value := addrvalue
}
return set.index[value] != 0;
}
/**
* @notice Get all set values.
*
* @param set The set of values.
* @param start The offset of the returning set.
* @param count The limit of number of values to return.
*
* @return An array with all values in the set. O(N).
*
* @dev Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* WARNING: This function may run out of gas on large sets: use {length} and
* {get} instead in these cases.
*/
function enumerate(
Bytes32Set storage set,
uint256 start,
uint256 count
) internal view returns (bytes32[] memory output) {
uint256 end = start + count;
require(end >= start, "addition overflow");
end = set.values.length < end ? set.values.length : end;
if (end == 0 || start >= end) {
return output;
}
output = new bytes32[](end - start);
for (uint256 i; i < end - start; i++) {
output[i] = set.values[i + start];
}
return output;
}
/**
* @notice Get the legth of the set.
*
* @param set The set of values.
*
* @return the number of elements on the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return set.values.length;
}
/**
* @notice Get an item from the set by its index.
*
* @dev Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*
* @param set The set of values.
* @param index The index of the value to return.
*
* @return the element stored at position `index` in the set. O(1).
*/
function get(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return set.values[index];
}
}