1
- pragma solidity 0.4.19 ;
1
+ pragma solidity ^ 0.4.19 ;
2
2
3
3
4
4
library BytesLib {
5
5
function concat (bytes memory _preBytes , bytes memory _postBytes ) internal pure returns (bytes ) {
6
6
bytes memory tempBytes;
7
-
7
+
8
8
assembly {
9
+ // Get a location of some free memory and store it in tempBytes as
10
+ // Solidity does for memory variables.
9
11
tempBytes := mload (0x40 )
10
12
13
+ // Store the length of the first bytes array at the beginning of
14
+ // the memory for tempBytes.
11
15
let length := mload (_preBytes)
12
16
mstore (tempBytes, length)
13
-
17
+
18
+ // Maintain a memory counter for the current write location in the
19
+ // temp bytes array by adding the 32 bytes for the array length to
20
+ // the starting location.
14
21
let mc := add (tempBytes, 0x20 )
22
+ // Stop copying when the memory counter reaches the length of the
23
+ // first bytes array.
15
24
let end := add (mc, length)
16
-
25
+
17
26
for {
27
+ // Initialize a copy counter to the start of the _preBytes data,
28
+ // 32 bytes into its memory.
18
29
let cc := add (_preBytes, 0x20 )
19
30
} lt (mc, end) {
31
+ // Increase both counters by 32 bytes each iteration.
20
32
mc := add (mc, 0x20 )
21
33
cc := add (cc, 0x20 )
22
34
} {
35
+ // Write the _preBytes data into the tempBytes memory 32 bytes
36
+ // at a time.
23
37
mstore (mc, mload (cc))
24
38
}
25
-
39
+
40
+ // Add the length of _postBytes to the current length of tempBytes
41
+ // and store it as the new length in the first 32 bytes of the
42
+ // tempBytes memory.
26
43
length := mload (_postBytes)
27
44
mstore (tempBytes, add (length, mload (tempBytes)))
28
-
45
+
46
+ // Move the memory counter back from a multiple of 0x20 to the
47
+ // actual end of the _preBytes data.
29
48
mc := end
49
+ // Stop copying when the memory counter reaches the new combined
50
+ // length of the arrays.
30
51
end := add (mc, length)
31
-
52
+
32
53
for {
33
54
let cc := add (_postBytes, 0x20 )
34
55
} lt (mc, end) {
@@ -37,21 +58,34 @@ library BytesLib {
37
58
} {
38
59
mstore (mc, mload (cc))
39
60
}
40
-
41
- //update free-memory pointer
42
- //allocating the array padded to 32 bytes like the compiler does now
43
- //make an additional check for a resulting zero-length array:
44
- // if (sub - end == 0) then end = end + 1
45
- mstore (0x40 , and (add (add (end, iszero (sub (mc, end))), 31 ), not (31 )))
61
+
62
+ // Update the free-memory pointer by padding our last write location
63
+ // to 32 bytes: add 31 bytes to the end of tempBytes to move to the
64
+ // next 32 byte block, then round down to the nearest multiple of
65
+ // 32. If the sum of the length of the two arrays is zero then add
66
+ // one before rounding down to leave a blank 32 bytes (the length block with 0).
67
+ mstore (0x40 , and (
68
+ add (add (end, iszero (add (length, mload (_preBytes)))), 31 ),
69
+ not (31 ) // Round down to the nearest 32 bytes.
70
+ ))
46
71
}
47
-
72
+
48
73
return tempBytes;
49
74
}
50
-
75
+
51
76
function concatStorage (bytes storage _preBytes , bytes memory _postBytes ) internal {
52
77
assembly {
53
- // we know _preBytes_offset is 0
78
+ // Read the first 32 bytes of _preBytes storage, which is the length
79
+ // of the array. (We don't need to use the offset into the slot
80
+ // because arrays use the entire slot.)
54
81
let fslot := sload (_preBytes_slot)
82
+ // Arrays of 31 bytes or less have an even value in their slot,
83
+ // while longer arrays have an odd value. The actual length is
84
+ // the slot divided by two for odd values, and the lowest order
85
+ // byte divided by two for even values.
86
+ // If the slot is even, bitwise and the slot with 255 and divide by
87
+ // two to get the length. If the slot is odd, bitwise and the slot
88
+ // with -1 and divide by two.
55
89
let slength := div (and (fslot, sub (mul (0x100 , iszero (and (fslot, 1 ))), 1 )), 2 )
56
90
let mlength := mload (_postBytes)
57
91
let newlength := add (slength, mlength)
@@ -60,13 +94,15 @@ library BytesLib {
60
94
// v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
61
95
switch add (lt (slength, 32 ), lt (newlength, 32 ))
62
96
case 2 {
97
+ // Since the new array still fits in the slot, we just need to
98
+ // update the contents of the slot.
63
99
// uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length
64
100
sstore (
65
101
_preBytes_slot,
66
102
// all the modifications to the slot are inside this
67
103
// next block
68
104
add (
69
- // we can just add to the slot contents because the
105
+ // we can just add to the slot contents because the
70
106
// bytes we want to change are the LSBs
71
107
fslot,
72
108
add (
@@ -89,18 +125,29 @@ library BytesLib {
89
125
)
90
126
}
91
127
case 1 {
128
+ // The stored value fits in the slot, but the combined value
129
+ // will exceed it.
92
130
// get the keccak hash to get the contents of the array
93
131
mstore (0x0 , _preBytes_slot)
94
132
let sc := add (keccak256 (0x0 , 0x20 ), div (slength, 32 ))
95
-
133
+
96
134
// save new length
97
135
sstore (_preBytes_slot, add (mul (newlength, 2 ), 1 ))
98
-
136
+
137
+ // The contents of the _postBytes array start 32 bytes into
138
+ // the structure. Our first read should obtain the `submod`
139
+ // bytes that can fit into the unused space in the last word
140
+ // of the stored array. To get this, we read 32 bytes starting
141
+ // from `submod`, so the data we read overlaps with the array
142
+ // contents by `submod` bytes. Masking the lowest-order
143
+ // `submod` bytes allows us to add that value directly to the
144
+ // stored value.
145
+
99
146
let submod := sub (32 , slength)
100
147
let mc := add (_postBytes, submod)
101
- let end := add (add ( _postBytes, 0x20 ) , mlength)
148
+ let end := add (_postBytes, mlength)
102
149
let mask := sub (exp (0x100 , submod), 1 )
103
-
150
+
104
151
sstore (
105
152
sc,
106
153
add (
@@ -111,8 +158,8 @@ library BytesLib {
111
158
and (mload (mc), mask)
112
159
)
113
160
)
114
-
115
- for {
161
+
162
+ for {
116
163
mc := add (mc, 0x20 )
117
164
sc := add (sc, 1 )
118
165
} lt (mc, end) {
@@ -121,50 +168,73 @@ library BytesLib {
121
168
} {
122
169
sstore (sc, mload (mc))
123
170
}
171
+
172
+ mask := exp (0x100 , sub (mc, end))
173
+
174
+ sstore (sc, mul (div (mload (mc), mask), mask))
124
175
}
125
176
default {
126
177
// get the keccak hash to get the contents of the array
127
178
mstore (0x0 , _preBytes_slot)
179
+ // Start copying to the last used word of the stored array.
128
180
let sc := add (keccak256 (0x0 , 0x20 ), div (slength, 32 ))
129
-
181
+
130
182
// save new length
131
183
sstore (_preBytes_slot, add (mul (newlength, 2 ), 1 ))
132
-
184
+
185
+ // Copy over the first `submod` bytes of the new data as in
186
+ // case 1 above.
133
187
let slengthmod := mod (slength, 32 )
188
+ let mlengthmod := mod (mlength, 32 )
134
189
let submod := sub (32 , slengthmod)
135
190
let mc := add (_postBytes, submod)
136
- let end := add (mc , mlength)
191
+ let end := add (_postBytes , mlength)
137
192
let mask := sub (exp (0x100 , submod), 1 )
138
-
193
+
139
194
sstore (sc, add (sload (sc), and (mload (mc), mask)))
140
195
141
196
for {
197
+ sc := add (sc, 1 )
142
198
mc := add (mc, 0x20 )
143
199
} lt (mc, end) {
144
200
sc := add (sc, 1 )
145
201
mc := add (mc, 0x20 )
146
202
} {
147
203
sstore (sc, mload (mc))
148
204
}
205
+
206
+ mask := exp (0x100 , sub (mc, end))
207
+
208
+ sstore (sc, mul (div (mload (mc), mask), mask))
149
209
}
150
210
}
151
211
}
152
-
212
+
153
213
function slice (bytes _bytes , uint _start , uint _length ) internal pure returns (bytes ) {
154
214
require (_bytes.length >= (_start + _length));
155
-
215
+
156
216
bytes memory tempBytes;
157
-
217
+
158
218
assembly {
159
219
switch iszero (_length)
160
220
case 0 {
221
+ // Get a location of some free memory and store it in tempBytes as
222
+ // Solidity does for memory variables.
161
223
tempBytes := mload (0x40 )
162
-
224
+
225
+ // The first word of the slice result is potentially a partial
226
+ // word read from the original array. To read it, we calculate
227
+ // the length of that partial word and start copying that many
228
+ // bytes into the array. The first word we copy will start with
229
+ // data we don't care about, but the last `lengthmod` bytes will
230
+ // land at the beginning of the contents of the new array. When
231
+ // we're done copying, we overwrite the full first word with
232
+ // the actual length of the slice.
163
233
let lengthmod := and (_length, 31 )
164
-
234
+
165
235
let mc := add (tempBytes, lengthmod)
166
236
let end := add (mc, _length)
167
-
237
+
168
238
for {
169
239
let cc := add (add (_bytes, lengthmod), _start)
170
240
} lt (mc, end) {
@@ -173,9 +243,9 @@ library BytesLib {
173
243
} {
174
244
mstore (mc, mload (cc))
175
245
}
176
-
246
+
177
247
mstore (tempBytes, _length)
178
-
248
+
179
249
//update free-memory pointer
180
250
//allocating the array padded to 32 bytes like the compiler does now
181
251
mstore (0x40 , and (add (mc, 31 ), not (31 )))
@@ -187,29 +257,29 @@ library BytesLib {
187
257
mstore (0x40 , add (tempBytes, 0x20 ))
188
258
}
189
259
}
190
-
260
+
191
261
return tempBytes;
192
262
}
193
-
263
+
194
264
function toAddress (bytes _bytes , uint _start ) internal pure returns (address ) {
195
265
require (_bytes.length >= (_start + 20 ));
196
266
address tempAddress;
197
-
267
+
198
268
assembly {
199
269
tempAddress := div (mload (add (add (_bytes, 0x20 ), _start)), 0x1000000000000000000000000 )
200
270
}
201
-
271
+
202
272
return tempAddress;
203
273
}
204
-
274
+
205
275
function toUint (bytes _bytes , uint _start ) internal pure returns (uint256 ) {
206
276
require (_bytes.length >= (_start + 32 ));
207
277
uint256 tempUint;
208
-
278
+
209
279
assembly {
210
280
tempUint := mload (add (add (_bytes, 0x20 ), _start))
211
281
}
212
-
282
+
213
283
return tempUint;
214
284
}
215
285
@@ -222,7 +292,7 @@ library BytesLib {
222
292
// if lengths don't match the arrays are not equal
223
293
switch eq (length, mload (_postBytes))
224
294
case 1 {
225
- // cb is a circuit breaker in the for loop since there's
295
+ // cb is a circuit breaker in the for loop since there's
226
296
// no said feature for inline assembly loops
227
297
// cb = 1 - don't breaker
228
298
// cb = 0 - break
@@ -262,6 +332,7 @@ library BytesLib {
262
332
assembly {
263
333
// we know _preBytes_offset is 0
264
334
let fslot := sload (_preBytes_slot)
335
+ // Decode the length of the stored array like in concatStorage().
265
336
let slength := div (and (fslot, sub (mul (0x100 , iszero (and (fslot, 1 ))), 1 )), 2 )
266
337
let mlength := mload (_postBytes)
267
338
@@ -283,7 +354,7 @@ library BytesLib {
283
354
}
284
355
}
285
356
default {
286
- // cb is a circuit breaker in the for loop since there's
357
+ // cb is a circuit breaker in the for loop since there's
287
358
// no said feature for inline assembly loops
288
359
// cb = 1 - don't breaker
289
360
// cb = 0 - break
@@ -292,7 +363,7 @@ library BytesLib {
292
363
// get the keccak hash to get the contents of the array
293
364
mstore (0x0 , _preBytes_slot)
294
365
let sc := keccak256 (0x0 , 0x20 )
295
-
366
+
296
367
let mc := add (_postBytes, 0x20 )
297
368
let end := add (mc, mlength)
298
369
0 commit comments