Skip to content

Commit 08f2a00

Browse files
authored
Merge pull request #8 from GNSPS/revert-5-docs
Revert "Code comments from reviewing"
2 parents 4397ece + 1463ef9 commit 08f2a00

File tree

2 files changed

+44
-115
lines changed

2 files changed

+44
-115
lines changed

README.md

-9
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,6 @@ TODOs:
4949
* Slicing directly from storage
5050
* Implement inline assembly functions for better readability
5151

52-
### Testing
53-
54-
This project uses Truffle for tests. Truffle's version of `solc` needs to be at least 0.4.19 for the contracts to compile. If you encounter compilation errors, try:
55-
56-
$ cd /usr/local/lib/node_modules/truffle
57-
$ npm install solc@latest
58-
59-
To run the tests, start a `testrpc` instance, then run `truffle test`.
60-
6152
## API
6253

6354
* `function concat(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bytes)`

contracts/BytesLib.sol

+44-106
Original file line numberDiff line numberDiff line change
@@ -4,52 +4,31 @@ pragma solidity 0.4.19;
44
library 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.
119
tempBytes := mload(0x40)
1210

13-
// Store the length of the first bytes array at the beginning of
14-
// the memory for tempBytes.
1511
let length := mload(_preBytes)
1612
mstore(tempBytes, length)
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.
13+
2114
let mc := add(tempBytes, 0x20)
22-
// Stop copying when the memory counter reaches the length of the
23-
// first bytes array.
2415
let end := add(mc, length)
25-
16+
2617
for {
27-
// Initialize a copy counter to the start of the _preBytes data,
28-
// 32 bytes into its memory.
2918
let cc := add(_preBytes, 0x20)
3019
} lt(mc, end) {
31-
// Increase both counters by 32 bytes each iteration.
3220
mc := add(mc, 0x20)
3321
cc := add(cc, 0x20)
3422
} {
35-
// Write the _preBytes data into the tempBytes memory 32 bytes
36-
// at a time.
3723
mstore(mc, mload(cc))
3824
}
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.
25+
4326
length := mload(_postBytes)
4427
mstore(tempBytes, add(length, mload(tempBytes)))
45-
46-
// Move the memory counter back from a multiple of 0x20 to the
47-
// actual end of the _preBytes data.
28+
4829
mc := end
49-
// Stop copying when the memory counter reaches the new combined
50-
// length of the arrays.
5130
end := add(mc, length)
52-
31+
5332
for {
5433
let cc := add(_postBytes, 0x20)
5534
} lt(mc, end) {
@@ -58,35 +37,21 @@ library BytesLib {
5837
} {
5938
mstore(mc, mload(cc))
6039
}
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 second array's length is a multiple of 32, mc will equal
66-
// end after it's been copied. Add one before rounding down
67-
// to leave a blank 32 bytes.
68-
mstore(0x40, and(
69-
add(add(end, iszero(sub(mc, end))), 31),
70-
not(31) // Round down to the nearest 32 bytes.
71-
))
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)))
7246
}
73-
47+
7448
return tempBytes;
7549
}
76-
50+
7751
function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal {
7852
assembly {
79-
// Read the first 32 bytes of _preBytes storage, which is the length
80-
// of the array. (We don't need to use the offset into the slot
81-
// because arrays use the entire slot.)
53+
// we know _preBytes_offset is 0
8254
let fslot := sload(_preBytes_slot)
83-
// Arrays of 31 bytes or less have an even value in their slot,
84-
// while longer arrays have an odd value. The actual length is
85-
// the slot divided by two for odd values, and the lowest order
86-
// byte divided by two for even values.
87-
// If the slot is even, bitwise and the slot with 255 and divide by
88-
// two to get the length. If the slot is odd, bitwise and the slot
89-
// with -1 and divide by two.
9055
let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
9156
let mlength := mload(_postBytes)
9257
let newlength := add(slength, mlength)
@@ -95,15 +60,13 @@ library BytesLib {
9560
// v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
9661
switch add(lt(slength, 32), lt(newlength, 32))
9762
case 2 {
98-
// Since the new array still fits in the slot, we just need to
99-
// update the contents of the slot.
10063
// uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length
10164
sstore(
10265
_preBytes_slot,
10366
// all the modifications to the slot are inside this
10467
// next block
10568
add(
106-
// we can just add to the slot contents because the
69+
// we can just add to the slot contents because the
10770
// bytes we want to change are the LSBs
10871
fslot,
10972
add(
@@ -126,29 +89,18 @@ library BytesLib {
12689
)
12790
}
12891
case 1 {
129-
// The stored value fits in the slot, but the combined value
130-
// will exceed it.
13192
// get the keccak hash to get the contents of the array
13293
mstore(0x0, _preBytes_slot)
13394
let sc := add(keccak256(0x0, 0x20), div(slength, 32))
134-
95+
13596
// save new length
13697
sstore(_preBytes_slot, add(mul(newlength, 2), 1))
137-
138-
// The contents of the _postBytes array start 32 bytes into
139-
// the structure. Our first read should obtain the `submod`
140-
// bytes that can fit into the unused space in the last word
141-
// of the stored array. To get this, we read 32 bytes starting
142-
// from `submod`, so the data we read overlaps with the array
143-
// contents by `submod` bytes. Masking the lowest-order
144-
// `submod` bytes allows us to add that value directly to the
145-
// stored value.
146-
98+
14799
let submod := sub(32, slength)
148100
let mc := add(_postBytes, submod)
149101
let end := add(add(_postBytes, 0x20), mlength)
150102
let mask := sub(exp(0x100, submod), 1)
151-
103+
152104
sstore(
153105
sc,
154106
add(
@@ -159,8 +111,8 @@ library BytesLib {
159111
and(mload(mc), mask)
160112
)
161113
)
162-
163-
for {
114+
115+
for {
164116
mc := add(mc, 0x20)
165117
sc := add(sc, 1)
166118
} lt(mc, end) {
@@ -173,23 +125,20 @@ library BytesLib {
173125
default {
174126
// get the keccak hash to get the contents of the array
175127
mstore(0x0, _preBytes_slot)
176-
// Start copying to the last used word of the stored array.
177128
let sc := add(keccak256(0x0, 0x20), div(slength, 32))
178-
129+
179130
// save new length
180131
sstore(_preBytes_slot, add(mul(newlength, 2), 1))
181-
182-
// Copy over the first `submod` bytes of the new data as in
183-
// case 1 above.
132+
184133
let slengthmod := mod(slength, 32)
185134
let submod := sub(32, slengthmod)
186135
let mc := add(_postBytes, submod)
187136
let end := add(mc, mlength)
188137
let mask := sub(exp(0x100, submod), 1)
189-
138+
190139
sstore(sc, add(sload(sc), and(mload(mc), mask)))
191-
192-
for {
140+
141+
for {
193142
mc := add(mc, 0x20)
194143
} lt(mc, end) {
195144
sc := add(sc, 1)
@@ -200,32 +149,22 @@ library BytesLib {
200149
}
201150
}
202151
}
203-
152+
204153
function slice(bytes _bytes, uint _start, uint _length) internal pure returns (bytes) {
205154
require(_bytes.length >= (_start + _length));
206-
155+
207156
bytes memory tempBytes;
208-
157+
209158
assembly {
210159
switch iszero(_length)
211160
case 0 {
212-
// Get a location of some free memory and store it in tempBytes as
213-
// Solidity does for memory variables.
214161
tempBytes := mload(0x40)
215-
216-
// The first word of the slice result is potentially a partial
217-
// word read from the original array. To read it, we calculate
218-
// the length of that partial word and start copying that many
219-
// bytes into the array. The first word we copy will start with
220-
// data we don't care about, but the last `lengthmod` bytes will
221-
// land at the beginning of the contents of the new array. When
222-
// we're done copying, we overwrite the full first word with
223-
// the actual length of the slice.
162+
224163
let lengthmod := and(_length, 31)
225-
164+
226165
let mc := add(tempBytes, lengthmod)
227166
let end := add(mc, _length)
228-
167+
229168
for {
230169
let cc := add(add(_bytes, lengthmod), _start)
231170
} lt(mc, end) {
@@ -234,9 +173,9 @@ library BytesLib {
234173
} {
235174
mstore(mc, mload(cc))
236175
}
237-
176+
238177
mstore(tempBytes, _length)
239-
178+
240179
//update free-memory pointer
241180
//allocating the array padded to 32 bytes like the compiler does now
242181
mstore(0x40, and(add(mc, 31), not(31)))
@@ -248,29 +187,29 @@ library BytesLib {
248187
mstore(0x40, add(tempBytes, 0x20))
249188
}
250189
}
251-
190+
252191
return tempBytes;
253192
}
254-
193+
255194
function toAddress(bytes _bytes, uint _start) internal pure returns (address) {
256195
require(_bytes.length >= (_start + 20));
257196
address tempAddress;
258-
197+
259198
assembly {
260199
tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
261200
}
262-
201+
263202
return tempAddress;
264203
}
265-
204+
266205
function toUint(bytes _bytes, uint _start) internal pure returns (uint256) {
267206
require(_bytes.length >= (_start + 32));
268207
uint256 tempUint;
269-
208+
270209
assembly {
271210
tempUint := mload(add(add(_bytes, 0x20), _start))
272211
}
273-
212+
274213
return tempUint;
275214
}
276215

@@ -283,7 +222,7 @@ library BytesLib {
283222
// if lengths don't match the arrays are not equal
284223
switch eq(length, mload(_postBytes))
285224
case 1 {
286-
// cb is a circuit breaker in the for loop since there's
225+
// cb is a circuit breaker in the for loop since there's
287226
// no said feature for inline assembly loops
288227
// cb = 1 - don't breaker
289228
// cb = 0 - break
@@ -323,7 +262,6 @@ library BytesLib {
323262
assembly {
324263
// we know _preBytes_offset is 0
325264
let fslot := sload(_preBytes_slot)
326-
// Decode the length of the stored array like in concatStorage().
327265
let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
328266
let mlength := mload(_postBytes)
329267

@@ -345,7 +283,7 @@ library BytesLib {
345283
}
346284
}
347285
default {
348-
// cb is a circuit breaker in the for loop since there's
286+
// cb is a circuit breaker in the for loop since there's
349287
// no said feature for inline assembly loops
350288
// cb = 1 - don't breaker
351289
// cb = 0 - break
@@ -354,7 +292,7 @@ library BytesLib {
354292
// get the keccak hash to get the contents of the array
355293
mstore(0x0, _preBytes_slot)
356294
let sc := keccak256(0x0, 0x20)
357-
295+
358296
let mc := add(_postBytes, 0x20)
359297
let end := add(mc, mlength)
360298

0 commit comments

Comments
 (0)