Skip to content

Commit afb34d7

Browse files
committed
assembly for more string stuff
1 parent 8a5765b commit afb34d7

File tree

5 files changed

+92
-10
lines changed

5 files changed

+92
-10
lines changed

src/CborDecode.sol

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,37 @@ library CBORDecoder {
111111
return (slice, byteIdx + len);
112112
}
113113

114-
function readStringBytes1(bytes memory cborData, uint byteIdx) internal pure returns (bytes1, uint) {
114+
function readStringBytes9(bytes memory cborData, uint byteIdx) internal pure returns (bytes9, uint) {
115+
uint8 major;
116+
uint64 len;
117+
118+
(major, len, byteIdx) = parseCborHeader(cborData, byteIdx);
119+
require(major == MajorText && len <= 9, "expected string length of 9 or less");
120+
121+
bytes9 slice;
122+
assembly {
123+
slice := and(mload(add(cborData, add(0x20, byteIdx))), not(shr(mul(len, 8), not(0))))
124+
}
125+
126+
return (slice, byteIdx + len);
127+
}
128+
129+
function readStringBytes7(bytes memory cborData, uint byteIdx) internal pure returns (bytes7, uint) {
130+
uint8 major;
131+
uint64 len;
132+
133+
(major, len, byteIdx) = parseCborHeader(cborData, byteIdx);
134+
require(major == MajorText && len <= 7, "expected string length of 7 or less");
135+
136+
bytes7 slice;
137+
assembly {
138+
slice := and(mload(add(cborData, add(0x20, byteIdx))), not(shr(mul(len, 8), not(0))))
139+
}
140+
141+
return (slice, byteIdx + len);
142+
}
143+
144+
function readStringBytes1_normal(bytes memory cborData, uint byteIdx) internal pure returns (bytes1, uint) {
115145
uint8 major;
116146
uint64 len;
117147

@@ -122,6 +152,24 @@ library CBORDecoder {
122152
return (cborData[byteIdx], byteIdx + len);
123153
}
124154

155+
function readStringBytes1(bytes memory cborData, uint byteIdx) internal pure returns (bytes1, uint) {
156+
return readStringBytes1_normal(cborData, byteIdx);
157+
}
158+
159+
function readStringBytes1_assembly(bytes memory cborData, uint byteIdx) internal pure returns (bytes1, uint) {
160+
uint8 head;
161+
assembly {
162+
head := mload(add(cborData, add(0x20, byteIdx)))
163+
}
164+
require(head == MajorText << shiftMajor | 0x01, "expected string length of 1");
165+
bytes1 slice;
166+
byteIdx += 1;
167+
assembly {
168+
slice := mload(add(cborData, add(0x20, byteIdx)))
169+
}
170+
return (slice, byteIdx + 2);
171+
}
172+
125173
function skipString(bytes memory cborData, uint byteIdx) internal pure returns (uint) {
126174
uint8 major;
127175
uint64 len;

src/CommitCbor.sol

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ library CommitCbor {
2323
require(mapLen == 5, "expected 5 fields in commit");
2424

2525
for (uint i = 0; i < mapLen; i++) {
26-
bytes memory mapKey;
27-
(mapKey, byteIdx) = cborData.readStringBytes(byteIdx);
28-
if (bytes8(mapKey) == "version") {
26+
bytes7 mapKey;
27+
(mapKey, byteIdx) = cborData.readStringBytes7(byteIdx);
28+
if (bytes7(mapKey) == "version") {
2929
(ret.version, byteIdx) = cborData.readUInt8(byteIdx);
3030
require(ret.version == COMMIT_VERSION, "commit version number must be 3");
3131
} else if (bytes5(mapKey) == "data") {

src/RecordCbor.sol

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ library RecordCbor {
1818
require(mapLen == 4, "expected 4 fields in record");
1919

2020
for (uint i = 0; i < mapLen; i++) {
21-
bytes memory mapKey;
22-
(mapKey, byteIdx) = cborData.readStringBytes(byteIdx);
21+
bytes9 mapKey;
22+
(mapKey, byteIdx) = cborData.readStringBytes9(byteIdx);
2323
if (bytes5(mapKey) == "text") {
2424
(ret.text, byteIdx) = cborData.readString(byteIdx);
2525
} else if (bytes6(mapKey) == "$type") {
@@ -31,7 +31,7 @@ library RecordCbor {
3131
// langs string unused.
3232
byteIdx = cborData.skipString(byteIdx);
3333
}
34-
} else if (bytes10(mapKey) == "createdAt") {
34+
} else if (bytes9(mapKey) == "createdAt") {
3535
// createdAt string unused.
3636
// this field is arbitrary user-defined data. the useful and
3737
// verifiable timestamp is the signed commit repo revision field

src/TreeNodeCbor.sol

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,40 @@ library TreeNodeCbor {
6565
}
6666

6767
function buildEntryKeys(TreeNodeE[] memory e) internal pure returns (TreeNodeEntry[] memory) {
68+
return buildEntryKeys_assembly(e);
69+
}
70+
71+
function buildEntryKeys_assembly(TreeNodeE[] memory e) internal pure returns (TreeNodeEntry[] memory) {
72+
TreeNodeEntry[] memory entries = new TreeNodeEntry[](e.length);
73+
bytes memory previousKey = new bytes(0);
74+
for (uint i = 0; i < e.length; i++) {
75+
uint8 p = e[i].p;
76+
bytes memory k = e[i].k;
77+
bytes memory key = new bytes(p + k.length);
78+
//console.log("i=%s", i);
79+
//console.log("before assembly p=%s k.length=%s key.length=%s", p, k.length, key.length);
80+
// Calculate number of words needed
81+
uint pWords = (p + 31) / 32; // ceil(p/32)
82+
uint kWords = (k.length + 31) / 32; // ceil(k.length/32)
83+
uint j;
84+
85+
assembly {
86+
for { j := 0 } lt(j, pWords) { j := add(j, 1) } {
87+
mstore(add(key, add(0x20, mul(j, 32))), mload(add(previousKey, add(0x20, mul(j, 32)))))
88+
}
89+
90+
for { j := 0 } lt(j, kWords) { j := add(j, 1) } {
91+
mstore(add(add(key, 0x20), add(p, mul(j, 32))), mload(add(k, add(0x20, mul(j, 32)))))
92+
}
93+
}
94+
//console.log("after assembly key=%s key.length=%s", string(key), key.length);
95+
entries[i] = TreeNodeEntry(string(key), e[i].v, e[i].t);
96+
previousKey = key;
97+
}
98+
return entries;
99+
}
100+
101+
function buildEntryKeys_loop(TreeNodeE[] memory e) internal pure returns (TreeNodeEntry[] memory) {
68102
TreeNodeEntry[] memory entries = new TreeNodeEntry[](e.length);
69103
bytes memory previousKey = new bytes(0);
70104
for (uint i = 0; i < e.length; i++) {

test/CborDecode.t.sol

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,19 +169,19 @@ contract CborDecodeTest {
169169
bytes1 mapKey;
170170
uint8 mapValue;
171171
(mapKey, index) = input.readStringBytes1(index);
172-
require(mapKey == bytes1("a"), "map key is not 'a'");
172+
require(mapKey == "a", "map key is not 'a'");
173173

174174
(mapValue, index) = input.readUInt8(index);
175175
require(mapValue == 1, "map value is not 1");
176176

177177
(mapKey, index) = input.readStringBytes1(index);
178-
require(mapKey == bytes1("b"), "map key is not 'b'");
178+
require(mapKey == "b", "map key is not 'b'");
179179

180180
(mapValue, index) = input.readUInt8(index);
181181
require(mapValue == 2, "map value is not 2");
182182

183183
(mapKey, index) = input.readStringBytes1(index);
184-
require(mapKey == bytes1("c"), "map key is not 'c'");
184+
require(mapKey == "c", "map key is not 'c'");
185185

186186
(mapValue, index) = input.readUInt8(index);
187187
require(mapValue == 3, "map value is not 3");

0 commit comments

Comments
 (0)