-
Notifications
You must be signed in to change notification settings - Fork 49
/
Copy pathEnumerableBytes4Set.sol
156 lines (141 loc) · 4.75 KB
/
EnumerableBytes4Set.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
/**
* 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 EnumerableBytes4Set for EnumerableBytes4Set.Bytes4Set;`.
* */
library EnumerableBytes4Set {
struct Bytes4Set {
/// Position of the value in the `values` array, plus 1 because index 0
/// means a value is not in the set.
mapping(bytes4 => uint256) index;
bytes4[] values;
}
/**
* @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 addBytes4(Bytes4Set storage set, bytes4 value) internal returns (bool) {
if (!contains(set, value)) {
set.index[value] = set.values.push(value);
return true;
} else {
return false;
}
}
/**
* @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 removeBytes4(Bytes4Set storage set, bytes4 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) {
bytes4 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(Bytes4Set storage set, bytes4 value) internal view returns (bool) {
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(
Bytes4Set storage set,
uint256 start,
uint256 count
) internal view returns (bytes4[] 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 bytes4[](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(Bytes4Set 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(Bytes4Set storage set, uint256 index) internal view returns (bytes4) {
return set.values[index];
}
}