1- pragma solidity 0.4.19 ;
1+ pragma solidity ^ 0.4.19 ;
22
33
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 (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+ ))
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)
101- let end := add (add ( _postBytes, 0x20 ) , mlength)
148+ 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) {
@@ -121,50 +168,73 @@ library BytesLib {
121168 } {
122169 sstore (sc, mload (mc))
123170 }
171+
172+ mask := exp (0x100 , sub (mc, end))
173+
174+ sstore (sc, mul (div (mload (mc), mask), mask))
124175 }
125176 default {
126177 // get the keccak hash to get the contents of the array
127178 mstore (0x0 , _preBytes_slot)
179+ // Start copying to the last used word of the stored array.
128180 let sc := add (keccak256 (0x0 , 0x20 ), div (slength, 32 ))
129-
181+
130182 // save new length
131183 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.
133187 let slengthmod := mod (slength, 32 )
188+ let mlengthmod := mod (mlength, 32 )
134189 let submod := sub (32 , slengthmod)
135190 let mc := add (_postBytes, submod)
136- let end := add (mc , mlength)
191+ let end := add (_postBytes , mlength)
137192 let mask := sub (exp (0x100 , submod), 1 )
138-
193+
139194 sstore (sc, add (sload (sc), and (mload (mc), mask)))
140195
141196 for {
197+ sc := add (sc, 1 )
142198 mc := add (mc, 0x20 )
143199 } lt (mc, end) {
144200 sc := add (sc, 1 )
145201 mc := add (mc, 0x20 )
146202 } {
147203 sstore (sc, mload (mc))
148204 }
205+
206+ mask := exp (0x100 , sub (mc, end))
207+
208+ sstore (sc, mul (div (mload (mc), mask), mask))
149209 }
150210 }
151211 }
152-
212+
153213 function slice (bytes _bytes , uint _start , uint _length ) internal pure returns (bytes ) {
154214 require (_bytes.length >= (_start + _length));
155-
215+
156216 bytes memory tempBytes;
157-
217+
158218 assembly {
159219 switch iszero (_length)
160220 case 0 {
221+ // Get a location of some free memory and store it in tempBytes as
222+ // Solidity does for memory variables.
161223 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.
163233 let lengthmod := and (_length, 31 )
164-
234+
165235 let mc := add (tempBytes, lengthmod)
166236 let end := add (mc, _length)
167-
237+
168238 for {
169239 let cc := add (add (_bytes, lengthmod), _start)
170240 } lt (mc, end) {
@@ -173,9 +243,9 @@ library BytesLib {
173243 } {
174244 mstore (mc, mload (cc))
175245 }
176-
246+
177247 mstore (tempBytes, _length)
178-
248+
179249 //update free-memory pointer
180250 //allocating the array padded to 32 bytes like the compiler does now
181251 mstore (0x40 , and (add (mc, 31 ), not (31 )))
@@ -187,29 +257,29 @@ library BytesLib {
187257 mstore (0x40 , add (tempBytes, 0x20 ))
188258 }
189259 }
190-
260+
191261 return tempBytes;
192262 }
193-
263+
194264 function toAddress (bytes _bytes , uint _start ) internal pure returns (address ) {
195265 require (_bytes.length >= (_start + 20 ));
196266 address tempAddress;
197-
267+
198268 assembly {
199269 tempAddress := div (mload (add (add (_bytes, 0x20 ), _start)), 0x1000000000000000000000000 )
200270 }
201-
271+
202272 return tempAddress;
203273 }
204-
274+
205275 function toUint (bytes _bytes , uint _start ) internal pure returns (uint256 ) {
206276 require (_bytes.length >= (_start + 32 ));
207277 uint256 tempUint;
208-
278+
209279 assembly {
210280 tempUint := mload (add (add (_bytes, 0x20 ), _start))
211281 }
212-
282+
213283 return tempUint;
214284 }
215285
@@ -222,7 +292,7 @@ library BytesLib {
222292 // if lengths don't match the arrays are not equal
223293 switch eq (length, mload (_postBytes))
224294 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
226296 // no said feature for inline assembly loops
227297 // cb = 1 - don't breaker
228298 // cb = 0 - break
@@ -262,6 +332,7 @@ library BytesLib {
262332 assembly {
263333 // we know _preBytes_offset is 0
264334 let fslot := sload (_preBytes_slot)
335+ // Decode the length of the stored array like in concatStorage().
265336 let slength := div (and (fslot, sub (mul (0x100 , iszero (and (fslot, 1 ))), 1 )), 2 )
266337 let mlength := mload (_postBytes)
267338
@@ -283,7 +354,7 @@ library BytesLib {
283354 }
284355 }
285356 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
287358 // no said feature for inline assembly loops
288359 // cb = 1 - don't breaker
289360 // cb = 0 - break
@@ -292,7 +363,7 @@ library BytesLib {
292363 // get the keccak hash to get the contents of the array
293364 mstore (0x0 , _preBytes_slot)
294365 let sc := keccak256 (0x0 , 0x20 )
295-
366+
296367 let mc := add (_postBytes, 0x20 )
297368 let end := add (mc, mlength)
298369
0 commit comments