-
Notifications
You must be signed in to change notification settings - Fork 28
/
Array.sol
155 lines (124 loc) · 5.99 KB
/
Array.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
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
contract Array {
// Declare array variables.
uint256[3] fixedArray; // Elements stored @ slots 0, 1, 2.
uint256[] dynamicArray; // Length stored @ slot 3, elements in slots keccak256(3) to (keccak256(3) + (length - 1)).
uint8[] smallArray; // Slot keccak256(4).
constructor() {
// Initialize array variables.
fixedArray = [10, 20, 30];
dynamicArray = [100, 200, 300];
smallArray = [1, 2, 3];
}
function readFixedArray(uint256 _index) public view returns (uint256 ret) {
assembly {
// Get slot of fixed array.
let slot := fixedArray.slot
// Fixed arrays are not stored at the locations of the hash of their slots.
// This is because, the length of the array has already been defined and its slots can be
// mapped to it with no effects.
// In this case, fixedArray elements are stored at indexes 0, 1 and 2.
// The value at index 0 takes the first storage slot, followed by the subsequent indexes.
// Info: https://rb.gy/yvbfwf.
// Increment slot by the index we want to read.
ret := sload(add(slot, _index))
}
}
function readDynamicArray(uint256 _index) public view returns (uint256 ret) {
assembly {
// Get slot of the dynamic array.
let slot := dynamicArray.slot
// Store the value of the slot in memory at location 0x00.
mstore(0x00, slot)
// Hash the first 20 bytes of memory location 0x00 and assign it to the `location` variable.
// We do this to get the sha256 hash of the slot which is the location for the dynamic array.
let location := keccak256(0x00, 0x20)
// Increment the location of the dynamic array by the _index we want to read.
ret := sload(add(location, _index))
}
}
function readDynamicArrayLength() public view returns (uint256 length) {
assembly {
length := sload(dynamicArray.slot)
}
}
function readSmallArray() public view returns (bytes32 ret) {
assembly {
// Get slot of small array.
let slot := smallArray.slot
// Store the value of the slot in memory at location 0x00.
mstore(0x00, slot)
// Hash the first 20 bytes of memory location 0x00 and assign it to the `location` variable.
let location := keccak256(0x00, 0x20)
// Since small array is an array of uint8 we won't be able to read each index because they'll be packed into a 32 bytes word.
ret := sload(location)
// Returns 0x0...030201.
}
}
function readSmallArrayIndex(uint256 _index) public view returns (uint256 value) {
assembly {
// Get slot of small array.
let slot := smallArray.slot
// Store the value of the slot in memory at location 0x00.
mstore(0x00, slot)
// Hash the first 20 bytes of memory location 0x00 and assign it to the `location` variable.
let location := keccak256(0x00, 0x20)
// Load the value of location on storage.
// 0x0000000000000000000000000000000000000000000000000000000000030201
let bytesValue := sload(location)
let shifted
switch _index
case 0 {
// Use bit masking to clear all indexes in bytes except the last byte.
// 0x0000000000000000000000000000000000000000000000000000000000000001
value := and(bytesValue, 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0f0ff)
} case 1 {
// Shift bytes to the right by 8 bits, or 1 byte,
// this will push the second index to the end.
// 0x0000000000000000000000000000000000000000000000000000000000000302
shifted := shr(8, bytesValue)
// Use bit masking to clear all indexes in bytes except the last byte.
// 0x0000000000000000000000000000000000000000000000000000000000000002
value := and(shifted, 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0ff)
} case 2 {
// Shift bytes by 16 bits, or 2 bytes, this will push the third index to the end.
// 0x0000000000000000000000000000000000000000000000000000000000000003
shifted := shr(16, bytesValue)
// No point in bit masking, the bytes are already clear.
value := shifted
} default {
value := 0x00
}
}
}
function pushToArray(uint256 num) public {
assembly {
// Store the value of the slot in memory at location 0x00.
mstore(0x00, 0x03)
// Hash the first 20 bytes of memory location 0x00 and assign it to the `location` variable.
let location := keccak256(0x00, 0x20)
// Load the value of location on storage.
let count := sload(0x03)
// Increment the count by 1.
sstore(0x03, add(count, 1))
// Store the value of num at the location of the dynamic array.
sstore(add(location, count), num)
}
}
function popArray() public {
assembly {
// Store the value of the slot in memory at location 0x00.
mstore(0x00, 0x03)
// Hash the first 20 bytes of memory location 0x00 and assign it to the `location` variable.
let location := keccak256(0x00, 0x20)
// Load the value of location on storage.
let count := sload(0x03)
// Revert if count is 0.
if eq(count, 0) { revert(0x00, 0x00) }
// Decrement the count by 1 and set the value at the location of the dynamic array to 0.
sstore(0x03, sub(count, 1))
sstore(add(location, sub(count, 1)), 0x00)
}
}
}