Skip to content

Commit 07bc54f

Browse files
authored
Merge pull request #283 from solidstate-network/arrays
Array utils and pagination
2 parents 9612195 + 186bc5f commit 07bc54f

9 files changed

+939
-106
lines changed

contracts/data/DoublyLinkedList.sol

+66
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,46 @@ library DoublyLinkedList {
290290
status = _replace(self._inner, bytes32(oldValue), bytes32(newValue));
291291
}
292292

293+
function toArray(
294+
Bytes32List storage self,
295+
bytes32 prevValue,
296+
uint256 count
297+
) internal view returns (bytes32[] memory array) {
298+
array = _toArray(self._inner, prevValue, count);
299+
}
300+
301+
function toArray(
302+
AddressList storage self,
303+
address prevValue,
304+
uint256 count
305+
) internal view returns (address[] memory array) {
306+
bytes32[] memory bytes32Array = _toArray(
307+
self._inner,
308+
bytes32(uint256(uint160(prevValue))),
309+
count
310+
);
311+
312+
assembly {
313+
array := bytes32Array
314+
}
315+
}
316+
317+
function toArray(
318+
Uint256List storage self,
319+
uint256 prevValue,
320+
uint256 count
321+
) internal view returns (uint256[] memory array) {
322+
bytes32[] memory bytes32Array = _toArray(
323+
self._inner,
324+
bytes32(prevValue),
325+
count
326+
);
327+
328+
assembly {
329+
array := bytes32Array
330+
}
331+
}
332+
293333
function _contains(
294334
_DoublyLinkedList storage self,
295335
bytes32 value
@@ -425,6 +465,32 @@ library DoublyLinkedList {
425465
}
426466
}
427467

468+
function _toArray(
469+
_DoublyLinkedList storage self,
470+
bytes32 prevValue,
471+
uint256 count
472+
) private view returns (bytes32[] memory array) {
473+
array = new bytes32[](count);
474+
475+
for (uint i; i < count; i++) {
476+
bytes32 nextValue = self._nextValues[prevValue];
477+
478+
if (nextValue == 0) {
479+
if (i == 0 && _prev(self, 0) != prevValue)
480+
revert DoublyLinkedList__NonExistentEntry();
481+
482+
// truncate the array if end of list is reached
483+
assembly {
484+
mstore(array, i)
485+
}
486+
487+
break;
488+
}
489+
490+
array[i] = prevValue = nextValue;
491+
}
492+
}
493+
428494
function _link(
429495
_DoublyLinkedList storage self,
430496
bytes32 prevValue,

contracts/data/EnumerableMap.sol

+54
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
pragma solidity ^0.8.20;
44

5+
import { Math } from '../utils/Math.sol';
6+
57
/**
68
* @title Map implementation with enumeration functions
79
* @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts (MIT license)
@@ -153,6 +155,33 @@ library EnumerableMap {
153155
}
154156
}
155157

158+
function toArray(
159+
AddressToAddressMap storage map,
160+
uint256 startIndex,
161+
uint256 count
162+
)
163+
internal
164+
view
165+
returns (address[] memory keysOut, address[] memory valuesOut)
166+
{
167+
uint256 size = length(map);
168+
169+
if (startIndex >= size) revert EnumerableMap__IndexOutOfBounds();
170+
171+
uint256 outputSize = Math.min(count, size - startIndex);
172+
keysOut = new address[](outputSize);
173+
valuesOut = new address[](outputSize);
174+
175+
for (uint256 i; i < count; i++) {
176+
keysOut[i] = address(
177+
uint160(uint256(map._inner._entries[startIndex + i]._key))
178+
);
179+
valuesOut[i] = address(
180+
uint160(uint256(map._inner._entries[startIndex + i]._value))
181+
);
182+
}
183+
}
184+
156185
function toArray(
157186
UintToAddressMap storage map
158187
)
@@ -175,6 +204,31 @@ library EnumerableMap {
175204
}
176205
}
177206

207+
function toArray(
208+
UintToAddressMap storage map,
209+
uint256 startIndex,
210+
uint256 count
211+
)
212+
internal
213+
view
214+
returns (uint256[] memory keysOut, address[] memory valuesOut)
215+
{
216+
uint256 size = length(map);
217+
218+
if (startIndex >= size) revert EnumerableMap__IndexOutOfBounds();
219+
220+
uint256 outputSize = Math.min(count, size - startIndex);
221+
keysOut = new uint256[](outputSize);
222+
valuesOut = new address[](outputSize);
223+
224+
for (uint256 i; i < count; i++) {
225+
keysOut[i] = uint256(map._inner._entries[startIndex + i]._key);
226+
valuesOut[i] = address(
227+
uint160(uint256(map._inner._entries[startIndex + i]._value))
228+
);
229+
}
230+
}
231+
178232
function keys(
179233
AddressToAddressMap storage map
180234
) internal view returns (address[] memory keysOut) {

contracts/data/EnumerableSet.sol

+60-13
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,16 @@
22

33
pragma solidity ^0.8.20;
44

5+
import { ArrayUtils } from '../utils/ArrayUtils.sol';
6+
import { Math } from '../utils/Math.sol';
7+
58
/**
69
* @title Set implementation with enumeration functions
710
* @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts (MIT license)
811
*/
912
library EnumerableSet {
13+
using ArrayUtils for bytes32[];
14+
1015
error EnumerableSet__IndexOutOfBounds();
1116

1217
struct Set {
@@ -144,33 +149,51 @@ library EnumerableSet {
144149
function toArray(
145150
Bytes32Set storage set
146151
) internal view returns (bytes32[] memory) {
147-
return set._inner._values;
152+
return _toArray(set._inner);
148153
}
149154

150155
function toArray(
151156
AddressSet storage set
152157
) internal view returns (address[] memory) {
153-
bytes32[] storage values = set._inner._values;
154-
address[] storage array;
155-
156-
assembly {
157-
array.slot := values.slot
158-
}
159-
160-
return array;
158+
return _toArray(set._inner).toAddressArray();
161159
}
162160

163161
function toArray(
164162
UintSet storage set
165163
) internal view returns (uint256[] memory) {
166-
bytes32[] storage values = set._inner._values;
167-
uint256[] storage array;
164+
return _toArray(set._inner).toUint256Array();
165+
}
166+
167+
function toArray(
168+
Bytes32Set storage set,
169+
uint256 startIndex,
170+
uint256 count
171+
) internal view returns (bytes32[] memory array) {
172+
array = _toArray(set._inner, startIndex, count);
173+
}
174+
175+
function toArray(
176+
AddressSet storage set,
177+
uint256 startIndex,
178+
uint256 count
179+
) internal view returns (address[] memory array) {
180+
bytes32[] memory bytes32Array = _toArray(set._inner, startIndex, count);
168181

169182
assembly {
170-
array.slot := values.slot
183+
array := bytes32Array
171184
}
185+
}
172186

173-
return array;
187+
function toArray(
188+
UintSet storage set,
189+
uint256 startIndex,
190+
uint256 count
191+
) internal view returns (uint256[] memory array) {
192+
bytes32[] memory bytes32Array = _toArray(set._inner, startIndex, count);
193+
194+
assembly {
195+
array := bytes32Array
196+
}
174197
}
175198

176199
function _at(
@@ -236,4 +259,28 @@ library EnumerableSet {
236259
status = true;
237260
}
238261
}
262+
263+
function _toArray(
264+
Set storage set
265+
) private view returns (bytes32[] storage array) {
266+
array = set._values;
267+
}
268+
269+
function _toArray(
270+
Set storage set,
271+
uint256 startIndex,
272+
uint256 count
273+
) private view returns (bytes32[] memory array) {
274+
unchecked {
275+
uint256 size = _length(set);
276+
277+
if (startIndex >= size) revert EnumerableSet__IndexOutOfBounds();
278+
279+
array = new bytes32[](Math.min(count, size - startIndex));
280+
281+
for (uint256 i; i < count; i++) {
282+
array[i] = set._values[startIndex + i];
283+
}
284+
}
285+
}
239286
}

contracts/data/PackedDoublyLinkedList.sol

+70
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,22 @@ library PackedDoublyLinkedList {
188188
status = _replace(self._inner, bytes16(oldValue), bytes16(newValue));
189189
}
190190

191+
function toArray(
192+
Bytes16List storage self,
193+
bytes16 prevValue,
194+
uint256 count
195+
) internal view returns (bytes16[] memory array) {
196+
array = _toArray(self._inner, prevValue, count);
197+
}
198+
199+
function toArray(
200+
Uint128List storage self,
201+
uint128 prevValue,
202+
uint256 count
203+
) internal view returns (uint128[] memory array) {
204+
array = _toArray(self._inner, prevValue, count);
205+
}
206+
191207
function _contains(
192208
_PackedDoublyLinkedList storage self,
193209
bytes16 value
@@ -347,6 +363,60 @@ library PackedDoublyLinkedList {
347363
}
348364
}
349365

366+
function _toArray(
367+
_PackedDoublyLinkedList storage self,
368+
bytes16 prevValue,
369+
uint256 count
370+
) internal view returns (bytes16[] memory array) {
371+
array = new bytes16[](count);
372+
373+
for (uint i; i < count; i++) {
374+
(, bytes16 nextValue) = _parseLinks(self._links[prevValue]);
375+
376+
if (nextValue == 0) {
377+
if (i == 0 && _prev(self, 0) != prevValue)
378+
revert PackedDoublyLinkedList__NonExistentEntry();
379+
380+
// truncate the array if end of list is reached
381+
assembly {
382+
mstore(array, i)
383+
}
384+
385+
break;
386+
}
387+
388+
array[i] = prevValue = nextValue;
389+
}
390+
}
391+
392+
function _toArray(
393+
_PackedDoublyLinkedList storage self,
394+
uint128 prevValue,
395+
uint256 count
396+
) internal view returns (uint128[] memory array) {
397+
array = new uint128[](count);
398+
399+
for (uint i; i < count; i++) {
400+
(, bytes16 nextValue) = _parseLinks(
401+
self._links[bytes16(prevValue)]
402+
);
403+
404+
if (nextValue == 0) {
405+
if (i == 0 && _prev(self, 0) != bytes16(prevValue))
406+
revert PackedDoublyLinkedList__NonExistentEntry();
407+
408+
// truncate the array if end of list is reached
409+
assembly {
410+
mstore(array, i)
411+
}
412+
413+
break;
414+
}
415+
416+
array[i] = prevValue = uint128(nextValue);
417+
}
418+
}
419+
350420
function _formatLinks(
351421
bytes16 prevValue,
352422
bytes16 nextValue

contracts/utils/ArrayUtils.sol

+26
Original file line numberDiff line numberDiff line change
@@ -116,4 +116,30 @@ library ArrayUtils {
116116

117117
return maxValue;
118118
}
119+
120+
/**
121+
* @notice cast bytes32[] storage pointer to address[] storage pointer
122+
* @param array bytes32 array to cast
123+
* @return addressArray address array
124+
*/
125+
function toAddressArray(
126+
bytes32[] storage array
127+
) internal pure returns (address[] storage addressArray) {
128+
assembly {
129+
addressArray.slot := array.slot
130+
}
131+
}
132+
133+
/**
134+
* @notice cast bytes32[] storage pointer to uint256[] storage pointer
135+
* @param array bytes32 array to cast
136+
* @return uint256Array uint256 array
137+
*/
138+
function toUint256Array(
139+
bytes32[] storage array
140+
) internal pure returns (uint256[] storage uint256Array) {
141+
assembly {
142+
uint256Array.slot := array.slot
143+
}
144+
}
119145
}

0 commit comments

Comments
 (0)