@@ -4,31 +4,52 @@ pragma solidity ^0.4.19;
44library BytesLib {
55 function concat (bytes memory _preBytes , bytes memory _postBytes ) internal pure returns (bytes ) {
66 bytes memory tempBytes;
7-
7+
88 assembly {
9+ // Get a location of some free memory and store it in tempBytes as
10+ // Solidity does for memory variables.
911 tempBytes := mload (0x40 )
1012
13+ // Store the length of the first bytes array at the beginning of
14+ // the memory for tempBytes.
1115 let length := mload (_preBytes)
1216 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.
1421 let mc := add (tempBytes, 0x20 )
22+ // Stop copying when the memory counter reaches the length of the
23+ // first bytes array.
1524 let end := add (mc, length)
16-
25+
1726 for {
27+ // Initialize a copy counter to the start of the _preBytes data,
28+ // 32 bytes into its memory.
1829 let cc := add (_preBytes, 0x20 )
1930 } lt (mc, end) {
31+ // Increase both counters by 32 bytes each iteration.
2032 mc := add (mc, 0x20 )
2133 cc := add (cc, 0x20 )
2234 } {
35+ // Write the _preBytes data into the tempBytes memory 32 bytes
36+ // at a time.
2337 mstore (mc, mload (cc))
2438 }
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.
2643 length := mload (_postBytes)
2744 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.
2948 mc := end
49+ // Stop copying when the memory counter reaches the new combined
50+ // length of the arrays.
3051 end := add (mc, length)
31-
52+
3253 for {
3354 let cc := add (_postBytes, 0x20 )
3455 } lt (mc, end) {
@@ -37,21 +58,34 @@ library BytesLib {
3758 } {
3859 mstore (mc, mload (cc))
3960 }
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 (add (length, mload (_preBytes)))), 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+ ))
4671 }
47-
72+
4873 return tempBytes;
4974 }
50-
75+
5176 function concatStorage (bytes storage _preBytes , bytes memory _postBytes ) internal {
5277 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.)
5481 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.
5589 let slength := div (and (fslot, sub (mul (0x100 , iszero (and (fslot, 1 ))), 1 )), 2 )
5690 let mlength := mload (_postBytes)
5791 let newlength := add (slength, mlength)
@@ -60,13 +94,15 @@ library BytesLib {
6094 // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
6195 switch add (lt (slength, 32 ), lt (newlength, 32 ))
6296 case 2 {
97+ // Since the new array still fits in the slot, we just need to
98+ // update the contents of the slot.
6399 // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length
64100 sstore (
65101 _preBytes_slot,
66102 // all the modifications to the slot are inside this
67103 // next block
68104 add (
69- // we can just add to the slot contents because the
105+ // we can just add to the slot contents because the
70106 // bytes we want to change are the LSBs
71107 fslot,
72108 add (
@@ -89,18 +125,29 @@ library BytesLib {
89125 )
90126 }
91127 case 1 {
128+ // The stored value fits in the slot, but the combined value
129+ // will exceed it.
92130 // get the keccak hash to get the contents of the array
93131 mstore (0x0 , _preBytes_slot)
94132 let sc := add (keccak256 (0x0 , 0x20 ), div (slength, 32 ))
95-
133+
96134 // save new length
97135 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+
99146 let submod := sub (32 , slength)
100147 let mc := add (_postBytes, submod)
101148 let end := add (_postBytes, mlength)
102149 let mask := sub (exp (0x100 , submod), 1 )
103-
150+
104151 sstore (
105152 sc,
106153 add (
@@ -111,8 +158,8 @@ library BytesLib {
111158 and (mload (mc), mask)
112159 )
113160 )
114-
115- for {
161+
162+ for {
116163 mc := add (mc, 0x20 )
117164 sc := add (sc, 1 )
118165 } lt (mc, end) {
@@ -129,18 +176,21 @@ library BytesLib {
129176 default {
130177 // get the keccak hash to get the contents of the array
131178 mstore (0x0 , _preBytes_slot)
179+ // Start copying to the last used word of the stored array.
132180 let sc := add (keccak256 (0x0 , 0x20 ), div (slength, 32 ))
133-
181+
134182 // save new length
135183 sstore (_preBytes_slot, add (mul (newlength, 2 ), 1 ))
136-
184+
185+ // Copy over the first `submod` bytes of the new data as in
186+ // case 1 above.
137187 let slengthmod := mod (slength, 32 )
138188 let mlengthmod := mod (mlength, 32 )
139189 let submod := sub (32 , slengthmod)
140190 let mc := add (_postBytes, submod)
141191 let end := add (_postBytes, mlength)
142192 let mask := sub (exp (0x100 , submod), 1 )
143-
193+
144194 sstore (sc, add (sload (sc), and (mload (mc), mask)))
145195
146196 for {
@@ -159,22 +209,32 @@ library BytesLib {
159209 }
160210 }
161211 }
162-
212+
163213 function slice (bytes _bytes , uint _start , uint _length ) internal pure returns (bytes ) {
164214 require (_bytes.length >= (_start + _length));
165-
215+
166216 bytes memory tempBytes;
167-
217+
168218 assembly {
169219 switch iszero (_length)
170220 case 0 {
221+ // Get a location of some free memory and store it in tempBytes as
222+ // Solidity does for memory variables.
171223 tempBytes := mload (0x40 )
172-
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.
173233 let lengthmod := and (_length, 31 )
174-
234+
175235 let mc := add (tempBytes, lengthmod)
176236 let end := add (mc, _length)
177-
237+
178238 for {
179239 let cc := add (add (_bytes, lengthmod), _start)
180240 } lt (mc, end) {
@@ -183,9 +243,9 @@ library BytesLib {
183243 } {
184244 mstore (mc, mload (cc))
185245 }
186-
246+
187247 mstore (tempBytes, _length)
188-
248+
189249 //update free-memory pointer
190250 //allocating the array padded to 32 bytes like the compiler does now
191251 mstore (0x40 , and (add (mc, 31 ), not (31 )))
@@ -197,29 +257,29 @@ library BytesLib {
197257 mstore (0x40 , add (tempBytes, 0x20 ))
198258 }
199259 }
200-
260+
201261 return tempBytes;
202262 }
203-
263+
204264 function toAddress (bytes _bytes , uint _start ) internal pure returns (address ) {
205265 require (_bytes.length >= (_start + 20 ));
206266 address tempAddress;
207-
267+
208268 assembly {
209269 tempAddress := div (mload (add (add (_bytes, 0x20 ), _start)), 0x1000000000000000000000000 )
210270 }
211-
271+
212272 return tempAddress;
213273 }
214-
274+
215275 function toUint (bytes _bytes , uint _start ) internal pure returns (uint256 ) {
216276 require (_bytes.length >= (_start + 32 ));
217277 uint256 tempUint;
218-
278+
219279 assembly {
220280 tempUint := mload (add (add (_bytes, 0x20 ), _start))
221281 }
222-
282+
223283 return tempUint;
224284 }
225285
@@ -232,7 +292,7 @@ library BytesLib {
232292 // if lengths don't match the arrays are not equal
233293 switch eq (length, mload (_postBytes))
234294 case 1 {
235- // 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
236296 // no said feature for inline assembly loops
237297 // cb = 1 - don't breaker
238298 // cb = 0 - break
@@ -272,6 +332,7 @@ library BytesLib {
272332 assembly {
273333 // we know _preBytes_offset is 0
274334 let fslot := sload (_preBytes_slot)
335+ // Decode the length of the stored array like in concatStorage().
275336 let slength := div (and (fslot, sub (mul (0x100 , iszero (and (fslot, 1 ))), 1 )), 2 )
276337 let mlength := mload (_postBytes)
277338
@@ -293,7 +354,7 @@ library BytesLib {
293354 }
294355 }
295356 default {
296- // 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
297358 // no said feature for inline assembly loops
298359 // cb = 1 - don't breaker
299360 // cb = 0 - break
@@ -302,7 +363,7 @@ library BytesLib {
302363 // get the keccak hash to get the contents of the array
303364 mstore (0x0 , _preBytes_slot)
304365 let sc := keccak256 (0x0 , 0x20 )
305-
366+
306367 let mc := add (_postBytes, 0x20 )
307368 let end := add (mc, mlength)
308369
0 commit comments