Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 50b4122

Browse files
authoredFeb 6, 2023
add library TWStringSet (#331)
1 parent c220bc0 commit 50b4122

File tree

2 files changed

+184
-0
lines changed

2 files changed

+184
-0
lines changed
 

‎contracts/lib/TWStringSet.sol‎

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
// SPDX-License-Identifier: Apache 2.0
2+
// OpenZeppelin Contracts (last updated v4.7.0) (utils/structs/EnumerableSet.sol)
3+
4+
pragma solidity ^0.8.0;
5+
6+
library TWStringSet {
7+
struct Set {
8+
// Storage of set values
9+
string[] _values;
10+
// Position of the value in the `values` array, plus 1 because index 0
11+
// means a value is not in the set.
12+
mapping(string => uint256) _indexes;
13+
}
14+
15+
/**
16+
* @dev Add a value to a set. O(1).
17+
*
18+
* Returns true if the value was added to the set, that is if it was not
19+
* already present.
20+
*/
21+
function _add(Set storage set, string memory value) private returns (bool) {
22+
if (!_contains(set, value)) {
23+
set._values.push(value);
24+
// The value is stored at length-1, but we add 1 to all indexes
25+
// and use 0 as a sentinel value
26+
set._indexes[value] = set._values.length;
27+
return true;
28+
} else {
29+
return false;
30+
}
31+
}
32+
33+
/**
34+
* @dev Removes a value from a set. O(1).
35+
*
36+
* Returns true if the value was removed from the set, that is if it was
37+
* present.
38+
*/
39+
function _remove(Set storage set, string memory value) private returns (bool) {
40+
// We read and store the value's index to prevent multiple reads from the same storage slot
41+
uint256 valueIndex = set._indexes[value];
42+
43+
if (valueIndex != 0) {
44+
// Equivalent to contains(set, value)
45+
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
46+
// the array, and then remove the last element (sometimes called as 'swap and pop').
47+
// This modifies the order of the array, as noted in {at}.
48+
49+
uint256 toDeleteIndex = valueIndex - 1;
50+
uint256 lastIndex = set._values.length - 1;
51+
52+
if (lastIndex != toDeleteIndex) {
53+
string memory lastValue = set._values[lastIndex];
54+
55+
// Move the last value to the index where the value to delete is
56+
set._values[toDeleteIndex] = lastValue;
57+
// Update the index for the moved value
58+
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
59+
}
60+
61+
// Delete the slot where the moved value was stored
62+
set._values.pop();
63+
64+
// Delete the index for the deleted slot
65+
delete set._indexes[value];
66+
67+
return true;
68+
} else {
69+
return false;
70+
}
71+
}
72+
73+
/**
74+
* @dev Returns true if the value is in the set. O(1).
75+
*/
76+
function _contains(Set storage set, string memory value) private view returns (bool) {
77+
return set._indexes[value] != 0;
78+
}
79+
80+
/**
81+
* @dev Returns the number of values on the set. O(1).
82+
*/
83+
function _length(Set storage set) private view returns (uint256) {
84+
return set._values.length;
85+
}
86+
87+
/**
88+
* @dev Returns the value stored at position `index` in the set. O(1).
89+
*
90+
* Note that there are no guarantees on the ordering of values inside the
91+
* array, and it may change when more values are added or removed.
92+
*
93+
* Requirements:
94+
*
95+
* - `index` must be strictly less than {length}.
96+
*/
97+
function _at(Set storage set, uint256 index) private view returns (string memory) {
98+
return set._values[index];
99+
}
100+
101+
/**
102+
* @dev Return the entire set in an array
103+
*
104+
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
105+
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
106+
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
107+
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
108+
*/
109+
function _values(Set storage set) private view returns (string[] memory) {
110+
return set._values;
111+
}
112+
113+
/**
114+
* @dev Add a value to a set. O(1).
115+
*
116+
* Returns true if the value was added to the set, that is if it was not
117+
* already present.
118+
*/
119+
function add(Set storage set, string memory value) internal returns (bool) {
120+
return _add(set, value);
121+
}
122+
123+
/**
124+
* @dev Removes a value from a set. O(1).
125+
*
126+
* Returns true if the value was removed from the set, that is if it was
127+
* present.
128+
*/
129+
function remove(Set storage set, string memory value) internal returns (bool) {
130+
return _remove(set, value);
131+
}
132+
133+
/**
134+
* @dev Returns true if the value is in the set. O(1).
135+
*/
136+
function contains(Set storage set, string memory value) internal view returns (bool) {
137+
return _contains(set, value);
138+
}
139+
140+
/**
141+
* @dev Returns the number of values in the set. O(1).
142+
*/
143+
function length(Set storage set) internal view returns (uint256) {
144+
return _length(set);
145+
}
146+
147+
/**
148+
* @dev Returns the value stored at position `index` in the set. O(1).
149+
*
150+
* Note that there are no guarantees on the ordering of values inside the
151+
* array, and it may change when more values are added or removed.
152+
*
153+
* Requirements:
154+
*
155+
* - `index` must be strictly less than {length}.
156+
*/
157+
function at(Set storage set, uint256 index) internal view returns (string memory) {
158+
return _at(set, index);
159+
}
160+
161+
/**
162+
* @dev Return the entire set in an array
163+
*
164+
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
165+
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
166+
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
167+
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
168+
*/
169+
function values(Set storage set) internal view returns (string[] memory) {
170+
return _values(set);
171+
}
172+
}

‎docs/TWStringSet.md‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# TWStringSet
2+
3+
4+
5+
6+
7+
8+
9+
10+
11+
12+

0 commit comments

Comments
 (0)
Please sign in to comment.