This repository was archived by the owner on Aug 27, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 156
Expand file tree
/
Copy pathBytes.sol
More file actions
244 lines (221 loc) · 9.02 KB
/
Bytes.sol
File metadata and controls
244 lines (221 loc) · 9.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
pragma solidity ^0.4.16;
pragma experimental "v0.5.0";
pragma experimental "ABIEncoderV2";
import {Memory} from "../unsafe/Memory.sol";
library Bytes {
uint internal constant BYTES_HEADER_SIZE = 32;
// Checks if two `bytes memory` variables are equal. This is done using hashing,
// which is much more gas efficient then comparing each byte individually.
// Equality means that:
// - 'self.length == other.length'
// - For 'n' in '[0, self.length)', 'self[n] == other[n]'
function equals(bytes memory self, bytes memory other) internal pure returns (bool equal) {
if (self.length != other.length) {
return false;
}
uint addr;
uint addr2;
assembly {
addr := add(self, /*BYTES_HEADER_SIZE*/32)
addr2 := add(other, /*BYTES_HEADER_SIZE*/32)
}
equal = Memory.equals(addr, addr2, self.length);
}
// Checks if two 'bytes memory' variables points to the same bytes array.
// Technically this is done by de-referencing the two arrays in inline assembly,
// and checking if the values are the same.
function equalsRef(bytes memory self, bytes memory other) internal pure returns (bool equal) {
assembly {
equal := eq(self, other)
}
}
// Copies a byte array.
// Returns the copied bytes.
// The function works by creating a new bytes array in memory, with the
// same length as 'self', then copying all the bytes from 'self' into
// the new array.
function copy(bytes memory self) internal pure returns (bytes memory) {
if (self.length == 0) {
return;
}
var addr = Memory.dataPtr(self);
return Memory.toBytes(addr, self.length);
}
// Copies a section of 'self' into a new array, starting at the provided 'startIndex'.
// Returns the new copy.
// Requires that 'startIndex <= self.length'
// The length of the substring is: 'self.length - startIndex'
function substr(bytes memory self, uint startIndex) internal pure returns (bytes memory) {
require(startIndex <= self.length);
var len = self.length - startIndex;
var addr = Memory.dataPtr(self);
return Memory.toBytes(addr + startIndex, len);
}
// Copies 'len' bytes from 'self' into a new array, starting at the provided 'startIndex'.
// Returns the new copy.
// Requires that:
// - 'startIndex + len <= self.length'
// The length of the substring is: 'len'
function substr(bytes memory self, uint startIndex, uint len) internal pure returns (bytes memory) {
require(startIndex + len <= self.length);
if (len == 0) {
return;
}
var addr = Memory.dataPtr(self);
return Memory.toBytes(addr + startIndex, len);
}
// Combines 'self' and 'other' into a single array.
// Returns the concatenated arrays:
// [self[0], self[1], ... , self[self.length - 1], other[0], other[1], ... , other[other.length - 1]]
// The length of the new array is 'self.length + other.length'
function concat(bytes memory self, bytes memory other) internal pure returns (bytes memory) {
bytes memory ret = new bytes(self.length + other.length);
var (src, srcLen) = Memory.fromBytes(self);
var (src2, src2Len) = Memory.fromBytes(other);
var (dest,) = Memory.fromBytes(ret);
var dest2 = dest + srcLen;
Memory.copy(src, dest, srcLen);
Memory.copy(src2, dest2, src2Len);
return ret;
}
// Copies a section of a 'bytes32' starting at the provided 'startIndex'.
// Returns the copied bytes (padded to the right) as a new 'bytes32'.
// Requires that 'startIndex < 32'
function substr(bytes32 self, uint8 startIndex) internal pure returns (bytes32) {
require(startIndex < 32);
return bytes32(uint(self) << startIndex*8);
}
// Copies 'len' bytes from 'self' into a new array, starting at the provided 'startIndex'.
// Returns the copied bytes (padded to the right) as a new 'bytes32'.
// Requires that:
// - 'startIndex < 32'
// - 'startIndex + len <= 32'
function substr(bytes32 self, uint8 startIndex, uint8 len) internal pure returns (bytes32) {
require(startIndex < 32 && startIndex + len <= 32);
return bytes32(uint(self) << startIndex*8 & ~uint(0) << (32 - len)*8);
}
// Copies 'self' into a new 'bytes memory'.
// Returns the newly created 'bytes memory'
// The returned bytes will be of length '32'.
function toBytes(bytes32 self) internal pure returns (bytes memory bts) {
bts = new bytes(32);
assembly {
mstore(add(bts, /*BYTES_HEADER_SIZE*/32), self)
}
}
// Copies 'len' bytes from 'self' into a new 'bytes memory', starting at index '0'.
// Returns the newly created 'bytes memory'
// The returned bytes will be of length 'len'.
function toBytes(bytes32 self, uint8 len) internal pure returns (bytes memory bts) {
require(len <= 32);
bts = new bytes(len);
// Even though the bytes will allocate a full word, we don't want
// any potential garbage bytes in there.
uint data = uint(self) & ~uint(0) << (32 - len)*8;
assembly {
mstore(add(bts, /*BYTES_HEADER_SIZE*/32), data)
}
}
// Copies 'self' into a new 'bytes memory'.
// Returns the newly created 'bytes memory'
// The returned bytes will be of length '20'.
function toBytes(address self) internal pure returns (bytes memory bts) {
bts = toBytes(bytes32(uint(self) << 96), 20);
}
// Copies 'self' into a new 'bytes memory'.
// Returns the newly created 'bytes memory'
// The returned bytes will be of length '32'.
function toBytes(uint self) internal pure returns (bytes memory bts) {
bts = toBytes(bytes32(self), 32);
}
// Copies 'self' into a new 'bytes memory'.
// Returns the newly created 'bytes memory'
// Requires that:
// - '8 <= bitsize <= 256'
// - 'bitsize % 8 == 0'
// The returned bytes will be of length 'bitsize / 8'.
function toBytes(uint self, uint16 bitsize) internal pure returns (bytes memory bts) {
require(8 <= bitsize && bitsize <= 256 && bitsize % 8 == 0);
self <<= 256 - bitsize;
bts = toBytes(bytes32(self), uint8(bitsize / 8));
}
// Copies 'self' into a new 'bytes memory'.
// Returns the newly created 'bytes memory'
// The returned bytes will be of length '1', and:
// - 'bts[0] == 0 (if self == false)'
// - 'bts[0] == 1 (if self == true)'
function toBytes(bool self) internal pure returns (bytes memory bts) {
bts = new bytes(1);
bts[0] = self ? byte(1) : byte(0);
}
// Computes the index of the highest byte set in 'self'.
// Returns the index.
// Requires that 'self != 0'
// Uses big endian ordering (the most significant byte has index '0').
function highestByteSet(bytes32 self) internal pure returns (uint8 highest) {
highest = 31 - lowestByteSet(uint(self));
}
// Computes the index of the lowest byte set in 'self'.
// Returns the index.
// Requires that 'self != 0'
// Uses big endian ordering (the most significant byte has index '0').
function lowestByteSet(bytes32 self) internal pure returns (uint8 lowest) {
lowest = 31 - highestByteSet(uint(self));
}
// Computes the index of the highest byte set in 'self'.
// Returns the index.
// Requires that 'self != 0'
// Uses little endian ordering (the least significant byte has index '0').
function highestByteSet(uint self) internal pure returns (uint8 highest) {
require(self != 0);
uint ret;
if (self & 0xffffffffffffffffffffffffffffffff00000000000000000000000000000000 != 0) {
ret += 16;
self >>= 128;
}
if (self & 0xffffffffffffffff0000000000000000 != 0) {
ret += 8;
self >>= 64;
}
if (self & 0xffffffff00000000 != 0) {
ret += 4;
self >>= 32;
}
if (self & 0xffff0000 != 0) {
ret += 2;
self >>= 16;
}
if (self & 0xff00 != 0) {
ret += 1;
}
highest = uint8(ret);
}
// Computes the index of the lowest byte set in 'self'.
// Returns the index.
// Requires that 'self != 0'
// Uses little endian ordering (the least significant byte has index '0').
function lowestByteSet(uint self) internal pure returns (uint8 lowest) {
require(self != 0);
uint ret;
if (self & 0xffffffffffffffffffffffffffffffff == 0) {
ret += 16;
self >>= 128;
}
if (self & 0xffffffffffffffff == 0) {
ret += 8;
self >>= 64;
}
if (self & 0xffffffff == 0) {
ret += 4;
self >>= 32;
}
if (self & 0xffff == 0) {
ret += 2;
self >>= 16;
}
if (self & 0xff == 0) {
ret += 1;
}
lowest = uint8(ret);
}
}