OLD | NEW |
1 // Protocol Buffers - Google's data interchange format | 1 // Protocol Buffers - Google's data interchange format |
2 // Copyright 2008 Google Inc. All rights reserved. | 2 // Copyright 2008 Google Inc. All rights reserved. |
3 // https://developers.google.com/protocol-buffers/ | 3 // https://developers.google.com/protocol-buffers/ |
4 // | 4 // |
5 // Redistribution and use in source and binary forms, with or without | 5 // Redistribution and use in source and binary forms, with or without |
6 // modification, are permitted provided that the following conditions are | 6 // modification, are permitted provided that the following conditions are |
7 // met: | 7 // met: |
8 // | 8 // |
9 // * Redistributions of source code must retain the above copyright | 9 // * Redistributions of source code must retain the above copyright |
10 // notice, this list of conditions and the following disclaimer. | 10 // notice, this list of conditions and the following disclaimer. |
(...skipping 12 matching lines...) Expand all Loading... |
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
30 | 30 |
31 package com.google.protobuf; | 31 package com.google.protobuf; |
32 | 32 |
33 import static com.google.protobuf.WireFormat.FIXED_32_SIZE; | |
34 import static com.google.protobuf.WireFormat.FIXED_64_SIZE; | |
35 import static com.google.protobuf.WireFormat.MAX_VARINT_SIZE; | |
36 import static java.lang.Math.max; | 33 import static java.lang.Math.max; |
37 | 34 |
38 import com.google.protobuf.Utf8.UnpairedSurrogateException; | 35 import com.google.protobuf.Utf8.UnpairedSurrogateException; |
| 36 |
39 import java.io.IOException; | 37 import java.io.IOException; |
40 import java.io.OutputStream; | 38 import java.io.OutputStream; |
| 39 import java.lang.reflect.Field; |
41 import java.nio.BufferOverflowException; | 40 import java.nio.BufferOverflowException; |
42 import java.nio.ByteBuffer; | 41 import java.nio.ByteBuffer; |
43 import java.nio.ByteOrder; | 42 import java.nio.ByteOrder; |
| 43 import java.security.AccessController; |
| 44 import java.security.PrivilegedExceptionAction; |
44 import java.util.logging.Level; | 45 import java.util.logging.Level; |
45 import java.util.logging.Logger; | 46 import java.util.logging.Logger; |
46 | 47 |
47 /** | 48 /** |
48 * Encodes and writes protocol message fields. | 49 * Encodes and writes protocol message fields. |
49 * | 50 * |
50 * <p>This class contains two kinds of methods: methods that write specific | 51 * <p>This class contains two kinds of methods: methods that write specific |
51 * protocol message constructs and field types (e.g. {@link #writeTag} and | 52 * protocol message constructs and field types (e.g. {@link #writeTag} and |
52 * {@link #writeInt32}) and methods that write low-level values (e.g. | 53 * {@link #writeInt32}) and methods that write low-level values (e.g. |
53 * {@link #writeRawVarint32} and {@link #writeRawBytes}). If you are | 54 * {@link #writeRawVarint32} and {@link #writeRawBytes}). If you are |
54 * writing encoded protocol messages, you should use the former methods, but if | 55 * writing encoded protocol messages, you should use the former methods, but if |
55 * you are writing some other format of your own design, use the latter. | 56 * you are writing some other format of your own design, use the latter. |
56 * | 57 * |
57 * <p>This class is totally unsynchronized. | 58 * <p>This class is totally unsynchronized. |
58 */ | 59 */ |
59 public abstract class CodedOutputStream extends ByteOutput { | 60 public abstract class CodedOutputStream extends ByteOutput { |
60 private static final Logger logger = Logger.getLogger(CodedOutputStream.class.
getName()); | 61 private static final Logger logger = Logger.getLogger(CodedOutputStream.class.
getName()); |
61 private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = UnsafeUtil.hasUnsaf
eArrayOperations(); | 62 private static final sun.misc.Unsafe UNSAFE = getUnsafe(); |
62 private static final long ARRAY_BASE_OFFSET = UnsafeUtil.getArrayBaseOffset(); | 63 private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = supportsUnsafeArray
Operations(); |
| 64 private static final long ARRAY_BASE_OFFSET = byteArrayBaseOffset(); |
| 65 |
| 66 private static final int FIXED_32_SIZE = 4; |
| 67 private static final int FIXED_64_SIZE = 8; |
| 68 private static final int MAX_VARINT_SIZE = 10; |
63 | 69 |
64 /** | 70 /** |
65 * @deprecated Use {@link #computeFixed32SizeNoTag(int)} instead. | 71 * @deprecated Use {@link #computeFixed32SizeNoTag(int)} instead. |
66 */ | 72 */ |
67 @Deprecated | 73 @Deprecated |
68 public static final int LITTLE_ENDIAN_32_SIZE = FIXED_32_SIZE; | 74 public static final int LITTLE_ENDIAN_32_SIZE = FIXED_32_SIZE; |
69 | 75 |
70 /** | 76 /** |
71 * The buffer size used in {@link #newInstance(OutputStream)}. | 77 * The buffer size used in {@link #newInstance(OutputStream)}. |
72 */ | 78 */ |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
125 * byte array slice. If more bytes are written than fit in the slice, | 131 * byte array slice. If more bytes are written than fit in the slice, |
126 * {@link OutOfSpaceException} will be thrown. Writing directly to a flat | 132 * {@link OutOfSpaceException} will be thrown. Writing directly to a flat |
127 * array is faster than writing to an {@code OutputStream}. See also | 133 * array is faster than writing to an {@code OutputStream}. See also |
128 * {@link ByteString#newCodedBuilder}. | 134 * {@link ByteString#newCodedBuilder}. |
129 */ | 135 */ |
130 public static CodedOutputStream newInstance( | 136 public static CodedOutputStream newInstance( |
131 final byte[] flatArray, final int offset, final int length) { | 137 final byte[] flatArray, final int offset, final int length) { |
132 return new ArrayEncoder(flatArray, offset, length); | 138 return new ArrayEncoder(flatArray, offset, length); |
133 } | 139 } |
134 | 140 |
135 /** Create a new {@code CodedOutputStream} that writes to the given {@link Byt
eBuffer}. */ | 141 /** |
136 public static CodedOutputStream newInstance(ByteBuffer buffer) { | 142 * Create a new {@code CodedOutputStream} that writes to the given {@link Byte
Buffer}. |
137 if (buffer.hasArray()) { | 143 */ |
138 return new HeapNioEncoder(buffer); | 144 public static CodedOutputStream newInstance(ByteBuffer byteBuffer) { |
| 145 if (byteBuffer.hasArray()) { |
| 146 return new NioHeapEncoder(byteBuffer); |
139 } | 147 } |
140 if (buffer.isDirect() && !buffer.isReadOnly()) { | 148 return new NioEncoder(byteBuffer); |
141 return UnsafeDirectNioEncoder.isSupported() | |
142 ? newUnsafeInstance(buffer) | |
143 : newSafeInstance(buffer); | |
144 } | |
145 throw new IllegalArgumentException("ByteBuffer is read-only"); | |
146 } | |
147 | |
148 /** For testing purposes only. */ | |
149 static CodedOutputStream newUnsafeInstance(ByteBuffer buffer) { | |
150 return new UnsafeDirectNioEncoder(buffer); | |
151 } | |
152 | |
153 /** For testing purposes only. */ | |
154 static CodedOutputStream newSafeInstance(ByteBuffer buffer) { | |
155 return new SafeDirectNioEncoder(buffer); | |
156 } | 149 } |
157 | 150 |
158 /** | 151 /** |
159 * Configures serialization to be deterministic. | |
160 * | |
161 * <p>The deterministic serialization guarantees that for a given binary, equa
l (defined by the | |
162 * {@code equals()} methods in protos) messages will always be serialized to t
he same bytes. This | |
163 * implies: | |
164 * | |
165 * <ul> | |
166 * <li>repeated serialization of a message will return the same bytes | |
167 * <li>different processes of the same binary (which may be executing on diffe
rent machines) will | |
168 * serialize equal messages to the same bytes. | |
169 * </ul> | |
170 * | |
171 * <p>Note the deterministic serialization is NOT canonical across languages;
it is also unstable | |
172 * across different builds with schema changes due to unknown fields. Users wh
o need canonical | |
173 * serialization, e.g. persistent storage in a canonical form, fingerprinting,
etc, should define | |
174 * their own canonicalization specification and implement the serializer using
reflection APIs | |
175 * rather than relying on this API. | |
176 * | |
177 * <p> Once set, the serializer will: (Note this is an implementation detail
and may subject to | |
178 * change in the future) | |
179 * | |
180 * <ul> | |
181 * <li> sort map entries by keys in lexicographical order or numerical order.
Note: For string | |
182 * keys, the order is based on comparing the Unicode value of each charact
er in the strings. | |
183 * The order may be different from the deterministic serialization in othe
r languages where | |
184 * maps are sorted on the lexicographical order of the UTF8 encoded keys. | |
185 * </ul> | |
186 */ | |
187 void useDeterministicSerialization() { | |
188 serializationDeterministic = true; | |
189 } | |
190 | |
191 boolean isSerializationDeterministic() { | |
192 return serializationDeterministic; | |
193 } | |
194 private boolean serializationDeterministic; | |
195 | |
196 /** | |
197 * Create a new {@code CodedOutputStream} that writes to the given {@link Byte
Buffer}. | 152 * Create a new {@code CodedOutputStream} that writes to the given {@link Byte
Buffer}. |
198 * | 153 * |
199 * @deprecated the size parameter is no longer used since use of an internal b
uffer is useless | 154 * @deprecated the size parameter is no longer used since use of an internal b
uffer is useless |
200 * (and wasteful) when writing to a {@link ByteBuffer}. Use {@link #newInstanc
e(ByteBuffer)} | 155 * (and wasteful) when writing to a {@link ByteBuffer}. Use {@link #newInstanc
e(ByteBuffer)} |
201 * instead. | 156 * instead. |
202 */ | 157 */ |
203 @Deprecated | 158 @Deprecated |
204 public static CodedOutputStream newInstance(ByteBuffer byteBuffer, | 159 public static CodedOutputStream newInstance(ByteBuffer byteBuffer, |
205 @SuppressWarnings("unused") int unused) { | 160 @SuppressWarnings("unused") int unused) { |
206 return newInstance(byteBuffer); | 161 return newInstance(byteBuffer); |
(...skipping 700 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
907 } | 862 } |
908 | 863 |
909 /** | 864 /** |
910 * Compute the number of bytes that would be needed to encode an embedded | 865 * Compute the number of bytes that would be needed to encode an embedded |
911 * message field. | 866 * message field. |
912 */ | 867 */ |
913 public static int computeMessageSizeNoTag(final MessageLite value) { | 868 public static int computeMessageSizeNoTag(final MessageLite value) { |
914 return computeLengthDelimitedFieldSize(value.getSerializedSize()); | 869 return computeLengthDelimitedFieldSize(value.getSerializedSize()); |
915 } | 870 } |
916 | 871 |
917 static int computeLengthDelimitedFieldSize(int fieldLength) { | 872 private static int computeLengthDelimitedFieldSize(int fieldLength) { |
918 return computeUInt32SizeNoTag(fieldLength) + fieldLength; | 873 return computeUInt32SizeNoTag(fieldLength) + fieldLength; |
919 } | 874 } |
920 | 875 |
921 /** | 876 /** |
922 * Encode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers | 877 * Encode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers |
923 * into values that can be efficiently encoded with varint. (Otherwise, | 878 * into values that can be efficiently encoded with varint. (Otherwise, |
924 * negative values must be sign-extended to 64 bits to be varint encoded, | 879 * negative values must be sign-extended to 64 bits to be varint encoded, |
925 * thus always taking 10 bytes on the wire.) | 880 * thus always taking 10 bytes on the wire.) |
926 * | 881 * |
927 * @param n A signed 32-bit integer. | 882 * @param n A signed 32-bit integer. |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
983 public static class OutOfSpaceException extends IOException { | 938 public static class OutOfSpaceException extends IOException { |
984 private static final long serialVersionUID = -6947486886997889499L; | 939 private static final long serialVersionUID = -6947486886997889499L; |
985 | 940 |
986 private static final String MESSAGE = | 941 private static final String MESSAGE = |
987 "CodedOutputStream was writing to a flat byte array and ran out of space
."; | 942 "CodedOutputStream was writing to a flat byte array and ran out of space
."; |
988 | 943 |
989 OutOfSpaceException() { | 944 OutOfSpaceException() { |
990 super(MESSAGE); | 945 super(MESSAGE); |
991 } | 946 } |
992 | 947 |
993 OutOfSpaceException(String explanationMessage) { | |
994 super(MESSAGE + ": " + explanationMessage); | |
995 } | |
996 | |
997 OutOfSpaceException(Throwable cause) { | 948 OutOfSpaceException(Throwable cause) { |
998 super(MESSAGE, cause); | 949 super(MESSAGE, cause); |
999 } | 950 } |
1000 | |
1001 OutOfSpaceException(String explanationMessage, Throwable cause) { | |
1002 super(MESSAGE + ": " + explanationMessage, cause); | |
1003 } | |
1004 } | 951 } |
1005 | 952 |
1006 /** | 953 /** |
1007 * Get the total number of bytes successfully written to this stream. The | 954 * Get the total number of bytes successfully written to this stream. The |
1008 * returned value is not guaranteed to be accurate if exceptions have been | 955 * returned value is not guaranteed to be accurate if exceptions have been |
1009 * found in the middle of writing. | 956 * found in the middle of writing. |
1010 */ | 957 */ |
1011 public abstract int getTotalBytesWritten(); | 958 public abstract int getTotalBytesWritten(); |
1012 | 959 |
1013 // ================================================================= | 960 // ================================================================= |
(...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1296 public final void writeMessageNoTag(final MessageLite value) throws IOExcept
ion { | 1243 public final void writeMessageNoTag(final MessageLite value) throws IOExcept
ion { |
1297 writeUInt32NoTag(value.getSerializedSize()); | 1244 writeUInt32NoTag(value.getSerializedSize()); |
1298 value.writeTo(this); | 1245 value.writeTo(this); |
1299 } | 1246 } |
1300 | 1247 |
1301 @Override | 1248 @Override |
1302 public final void write(byte value) throws IOException { | 1249 public final void write(byte value) throws IOException { |
1303 try { | 1250 try { |
1304 buffer[position++] = value; | 1251 buffer[position++] = value; |
1305 } catch (IndexOutOfBoundsException e) { | 1252 } catch (IndexOutOfBoundsException e) { |
1306 throw new OutOfSpaceException( | 1253 throw new OutOfSpaceException(new IndexOutOfBoundsException( |
1307 String.format("Pos: %d, limit: %d, len: %d", position, limit, 1), e)
; | 1254 String.format("Pos: %d, limit: %d, len: %d", position, limit, 1))); |
1308 } | 1255 } |
1309 } | 1256 } |
1310 | 1257 |
1311 @Override | 1258 @Override |
1312 public final void writeInt32NoTag(int value) throws IOException { | 1259 public final void writeInt32NoTag(int value) throws IOException { |
1313 if (value >= 0) { | 1260 if (value >= 0) { |
1314 writeUInt32NoTag(value); | 1261 writeUInt32NoTag(value); |
1315 } else { | 1262 } else { |
1316 // Must sign-extend. | 1263 // Must sign-extend. |
1317 writeUInt64NoTag(value); | 1264 writeUInt64NoTag(value); |
1318 } | 1265 } |
1319 } | 1266 } |
1320 | 1267 |
1321 @Override | 1268 @Override |
1322 public final void writeUInt32NoTag(int value) throws IOException { | 1269 public final void writeUInt32NoTag(int value) throws IOException { |
1323 if (HAS_UNSAFE_ARRAY_OPERATIONS && spaceLeft() >= MAX_VARINT_SIZE) { | 1270 if (HAS_UNSAFE_ARRAY_OPERATIONS && spaceLeft() >= MAX_VARINT_SIZE) { |
1324 long pos = ARRAY_BASE_OFFSET + position; | 1271 long pos = ARRAY_BASE_OFFSET + position; |
1325 while (true) { | 1272 while (true) { |
1326 if ((value & ~0x7F) == 0) { | 1273 if ((value & ~0x7F) == 0) { |
1327 UnsafeUtil.putByte(buffer, pos++, (byte) value); | 1274 UNSAFE.putByte(buffer, pos++, (byte) value); |
1328 position++; | 1275 position++; |
1329 return; | 1276 return; |
1330 } else { | 1277 } else { |
1331 UnsafeUtil.putByte(buffer, pos++, (byte) ((value & 0x7F) | 0x80)); | 1278 UNSAFE.putByte(buffer, pos++, (byte) ((value & 0x7F) | 0x80)); |
1332 position++; | 1279 position++; |
1333 value >>>= 7; | 1280 value >>>= 7; |
1334 } | 1281 } |
1335 } | 1282 } |
1336 } else { | 1283 } else { |
1337 try { | 1284 try { |
1338 while (true) { | 1285 while (true) { |
1339 if ((value & ~0x7F) == 0) { | 1286 if ((value & ~0x7F) == 0) { |
1340 buffer[position++] = (byte) value; | 1287 buffer[position++] = (byte) value; |
1341 return; | 1288 return; |
1342 } else { | 1289 } else { |
1343 buffer[position++] = (byte) ((value & 0x7F) | 0x80); | 1290 buffer[position++] = (byte) ((value & 0x7F) | 0x80); |
1344 value >>>= 7; | 1291 value >>>= 7; |
1345 } | 1292 } |
1346 } | 1293 } |
1347 } catch (IndexOutOfBoundsException e) { | 1294 } catch (IndexOutOfBoundsException e) { |
1348 throw new OutOfSpaceException( | 1295 throw new OutOfSpaceException( |
1349 String.format("Pos: %d, limit: %d, len: %d", position, limit, 1),
e); | 1296 new IndexOutOfBoundsException( |
| 1297 String.format("Pos: %d, limit: %d, len: %d", position, limit,
1))); |
1350 } | 1298 } |
1351 } | 1299 } |
1352 } | 1300 } |
1353 | 1301 |
1354 @Override | 1302 @Override |
1355 public final void writeFixed32NoTag(int value) throws IOException { | 1303 public final void writeFixed32NoTag(int value) throws IOException { |
1356 try { | 1304 try { |
1357 buffer[position++] = (byte) (value & 0xFF); | 1305 buffer[position++] = (byte) (value & 0xFF); |
1358 buffer[position++] = (byte) ((value >> 8) & 0xFF); | 1306 buffer[position++] = (byte) ((value >> 8) & 0xFF); |
1359 buffer[position++] = (byte) ((value >> 16) & 0xFF); | 1307 buffer[position++] = (byte) ((value >> 16) & 0xFF); |
1360 buffer[position++] = (byte) ((value >> 24) & 0xFF); | 1308 buffer[position++] = (byte) ((value >> 24) & 0xFF); |
1361 } catch (IndexOutOfBoundsException e) { | 1309 } catch (IndexOutOfBoundsException e) { |
1362 throw new OutOfSpaceException( | 1310 throw new OutOfSpaceException( |
1363 String.format("Pos: %d, limit: %d, len: %d", position, limit, 1), e)
; | 1311 new IndexOutOfBoundsException( |
| 1312 String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)
)); |
1364 } | 1313 } |
1365 } | 1314 } |
1366 | 1315 |
1367 @Override | 1316 @Override |
1368 public final void writeUInt64NoTag(long value) throws IOException { | 1317 public final void writeUInt64NoTag(long value) throws IOException { |
1369 if (HAS_UNSAFE_ARRAY_OPERATIONS && spaceLeft() >= MAX_VARINT_SIZE) { | 1318 if (HAS_UNSAFE_ARRAY_OPERATIONS && spaceLeft() >= MAX_VARINT_SIZE) { |
1370 long pos = ARRAY_BASE_OFFSET + position; | 1319 long pos = ARRAY_BASE_OFFSET + position; |
1371 while (true) { | 1320 while (true) { |
1372 if ((value & ~0x7FL) == 0) { | 1321 if ((value & ~0x7FL) == 0) { |
1373 UnsafeUtil.putByte(buffer, pos++, (byte) value); | 1322 UNSAFE.putByte(buffer, pos++, (byte) value); |
1374 position++; | 1323 position++; |
1375 return; | 1324 return; |
1376 } else { | 1325 } else { |
1377 UnsafeUtil.putByte(buffer, pos++, (byte) (((int) value & 0x7F) | 0x8
0)); | 1326 UNSAFE.putByte(buffer, pos++, (byte) (((int) value & 0x7F) | 0x80)); |
1378 position++; | 1327 position++; |
1379 value >>>= 7; | 1328 value >>>= 7; |
1380 } | 1329 } |
1381 } | 1330 } |
1382 } else { | 1331 } else { |
1383 try { | 1332 try { |
1384 while (true) { | 1333 while (true) { |
1385 if ((value & ~0x7FL) == 0) { | 1334 if ((value & ~0x7FL) == 0) { |
1386 buffer[position++] = (byte) value; | 1335 buffer[position++] = (byte) value; |
1387 return; | 1336 return; |
1388 } else { | 1337 } else { |
1389 buffer[position++] = (byte) (((int) value & 0x7F) | 0x80); | 1338 buffer[position++] = (byte) (((int) value & 0x7F) | 0x80); |
1390 value >>>= 7; | 1339 value >>>= 7; |
1391 } | 1340 } |
1392 } | 1341 } |
1393 } catch (IndexOutOfBoundsException e) { | 1342 } catch (IndexOutOfBoundsException e) { |
1394 throw new OutOfSpaceException( | 1343 throw new OutOfSpaceException( |
1395 String.format("Pos: %d, limit: %d, len: %d", position, limit, 1),
e); | 1344 new IndexOutOfBoundsException( |
| 1345 String.format("Pos: %d, limit: %d, len: %d", position, limit,
1))); |
1396 } | 1346 } |
1397 } | 1347 } |
1398 } | 1348 } |
1399 | 1349 |
1400 @Override | 1350 @Override |
1401 public final void writeFixed64NoTag(long value) throws IOException { | 1351 public final void writeFixed64NoTag(long value) throws IOException { |
1402 try { | 1352 try { |
1403 buffer[position++] = (byte) ((int) (value) & 0xFF); | 1353 buffer[position++] = (byte) ((int) (value) & 0xFF); |
1404 buffer[position++] = (byte) ((int) (value >> 8) & 0xFF); | 1354 buffer[position++] = (byte) ((int) (value >> 8) & 0xFF); |
1405 buffer[position++] = (byte) ((int) (value >> 16) & 0xFF); | 1355 buffer[position++] = (byte) ((int) (value >> 16) & 0xFF); |
1406 buffer[position++] = (byte) ((int) (value >> 24) & 0xFF); | 1356 buffer[position++] = (byte) ((int) (value >> 24) & 0xFF); |
1407 buffer[position++] = (byte) ((int) (value >> 32) & 0xFF); | 1357 buffer[position++] = (byte) ((int) (value >> 32) & 0xFF); |
1408 buffer[position++] = (byte) ((int) (value >> 40) & 0xFF); | 1358 buffer[position++] = (byte) ((int) (value >> 40) & 0xFF); |
1409 buffer[position++] = (byte) ((int) (value >> 48) & 0xFF); | 1359 buffer[position++] = (byte) ((int) (value >> 48) & 0xFF); |
1410 buffer[position++] = (byte) ((int) (value >> 56) & 0xFF); | 1360 buffer[position++] = (byte) ((int) (value >> 56) & 0xFF); |
1411 } catch (IndexOutOfBoundsException e) { | 1361 } catch (IndexOutOfBoundsException e) { |
1412 throw new OutOfSpaceException( | 1362 throw new OutOfSpaceException( |
1413 String.format("Pos: %d, limit: %d, len: %d", position, limit, 1), e)
; | 1363 new IndexOutOfBoundsException( |
| 1364 String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)
)); |
1414 } | 1365 } |
1415 } | 1366 } |
1416 | 1367 |
1417 @Override | 1368 @Override |
1418 public final void write(byte[] value, int offset, int length) throws IOExcep
tion { | 1369 public final void write(byte[] value, int offset, int length) throws IOExcep
tion { |
1419 try { | 1370 try { |
1420 System.arraycopy(value, offset, buffer, position, length); | 1371 System.arraycopy(value, offset, buffer, position, length); |
1421 position += length; | 1372 position += length; |
1422 } catch (IndexOutOfBoundsException e) { | 1373 } catch (IndexOutOfBoundsException e) { |
1423 throw new OutOfSpaceException( | 1374 throw new OutOfSpaceException( |
1424 String.format("Pos: %d, limit: %d, len: %d", position, limit, length
), e); | 1375 new IndexOutOfBoundsException( |
| 1376 String.format("Pos: %d, limit: %d, len: %d", position, limit, le
ngth))); |
1425 } | 1377 } |
1426 } | 1378 } |
1427 | 1379 |
1428 @Override | 1380 @Override |
1429 public final void writeLazy(byte[] value, int offset, int length) throws IOE
xception { | 1381 public final void writeLazy(byte[] value, int offset, int length) throws IOE
xception { |
1430 write(value, offset, length); | 1382 write(value, offset, length); |
1431 } | 1383 } |
1432 | 1384 |
1433 @Override | 1385 @Override |
1434 public final void write(ByteBuffer value) throws IOException { | 1386 public final void write(ByteBuffer value) throws IOException { |
1435 final int length = value.remaining(); | 1387 final int length = value.remaining(); |
1436 try { | 1388 try { |
1437 value.get(buffer, position, length); | 1389 value.get(buffer, position, length); |
1438 position += length; | 1390 position += length; |
1439 } catch (IndexOutOfBoundsException e) { | 1391 } catch (IndexOutOfBoundsException e) { |
1440 throw new OutOfSpaceException( | 1392 throw new OutOfSpaceException( |
1441 String.format("Pos: %d, limit: %d, len: %d", position, limit, length
), e); | 1393 new IndexOutOfBoundsException( |
| 1394 String.format("Pos: %d, limit: %d, len: %d", position, limit, le
ngth))); |
1442 } | 1395 } |
1443 } | 1396 } |
1444 | 1397 |
1445 @Override | 1398 @Override |
1446 public final void writeLazy(ByteBuffer value) throws IOException { | 1399 public final void writeLazy(ByteBuffer value) throws IOException { |
1447 write(value); | 1400 write(value); |
1448 } | 1401 } |
1449 | 1402 |
1450 @Override | 1403 @Override |
1451 public final void writeStringNoTag(String value) throws IOException { | 1404 public final void writeStringNoTag(String value) throws IOException { |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1494 @Override | 1447 @Override |
1495 public final int getTotalBytesWritten() { | 1448 public final int getTotalBytesWritten() { |
1496 return position - offset; | 1449 return position - offset; |
1497 } | 1450 } |
1498 } | 1451 } |
1499 | 1452 |
1500 /** | 1453 /** |
1501 * A {@link CodedOutputStream} that writes directly to a heap {@link ByteBuffe
r}. Writes are | 1454 * A {@link CodedOutputStream} that writes directly to a heap {@link ByteBuffe
r}. Writes are |
1502 * done directly to the underlying array. The buffer position is only updated
after a flush. | 1455 * done directly to the underlying array. The buffer position is only updated
after a flush. |
1503 */ | 1456 */ |
1504 private static final class HeapNioEncoder extends ArrayEncoder { | 1457 private static final class NioHeapEncoder extends ArrayEncoder { |
1505 private final ByteBuffer byteBuffer; | 1458 private final ByteBuffer byteBuffer; |
1506 private int initialPosition; | 1459 private int initialPosition; |
1507 | 1460 |
1508 HeapNioEncoder(ByteBuffer byteBuffer) { | 1461 NioHeapEncoder(ByteBuffer byteBuffer) { |
1509 super(byteBuffer.array(), byteBuffer.arrayOffset() + byteBuffer.position()
, | 1462 super(byteBuffer.array(), byteBuffer.arrayOffset() + byteBuffer.position()
, |
1510 byteBuffer.remaining()); | 1463 byteBuffer.remaining()); |
1511 this.byteBuffer = byteBuffer; | 1464 this.byteBuffer = byteBuffer; |
1512 this.initialPosition = byteBuffer.position(); | 1465 this.initialPosition = byteBuffer.position(); |
1513 } | 1466 } |
1514 | 1467 |
1515 @Override | 1468 @Override |
1516 public void flush() { | 1469 public void flush() { |
1517 // Update the position on the buffer. | 1470 // Update the position on the buffer. |
1518 byteBuffer.position(initialPosition + getTotalBytesWritten()); | 1471 byteBuffer.position(initialPosition + getTotalBytesWritten()); |
1519 } | 1472 } |
1520 } | 1473 } |
1521 | 1474 |
1522 /** | 1475 /** |
1523 * A {@link CodedOutputStream} that writes directly to a direct {@link ByteBuf
fer}, using only | 1476 * A {@link CodedOutputStream} that writes directly to a {@link ByteBuffer}. |
1524 * safe operations.. | |
1525 */ | 1477 */ |
1526 private static final class SafeDirectNioEncoder extends CodedOutputStream { | 1478 private static final class NioEncoder extends CodedOutputStream { |
1527 private final ByteBuffer originalBuffer; | 1479 private final ByteBuffer originalBuffer; |
1528 private final ByteBuffer buffer; | 1480 private final ByteBuffer buffer; |
1529 private final int initialPosition; | 1481 private final int initialPosition; |
1530 | 1482 |
1531 SafeDirectNioEncoder(ByteBuffer buffer) { | 1483 NioEncoder(ByteBuffer buffer) { |
1532 this.originalBuffer = buffer; | 1484 this.originalBuffer = buffer; |
1533 this.buffer = buffer.duplicate().order(ByteOrder.LITTLE_ENDIAN); | 1485 this.buffer = buffer.duplicate().order(ByteOrder.LITTLE_ENDIAN); |
1534 initialPosition = buffer.position(); | 1486 initialPosition = buffer.position(); |
1535 } | 1487 } |
1536 | 1488 |
1537 @Override | 1489 @Override |
1538 public void writeTag(final int fieldNumber, final int wireType) throws IOExc
eption { | 1490 public void writeTag(final int fieldNumber, final int wireType) throws IOExc
eption { |
1539 writeUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType)); | 1491 writeUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType)); |
1540 } | 1492 } |
1541 | 1493 |
(...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1824 private void encode(String value) throws IOException { | 1776 private void encode(String value) throws IOException { |
1825 try { | 1777 try { |
1826 Utf8.encodeUtf8(value, buffer); | 1778 Utf8.encodeUtf8(value, buffer); |
1827 } catch (IndexOutOfBoundsException e) { | 1779 } catch (IndexOutOfBoundsException e) { |
1828 throw new OutOfSpaceException(e); | 1780 throw new OutOfSpaceException(e); |
1829 } | 1781 } |
1830 } | 1782 } |
1831 } | 1783 } |
1832 | 1784 |
1833 /** | 1785 /** |
1834 * A {@link CodedOutputStream} that writes directly to a direct {@link ByteBuf
fer} using {@code | |
1835 * sun.misc.Unsafe}. | |
1836 */ | |
1837 private static final class UnsafeDirectNioEncoder extends CodedOutputStream { | |
1838 private final ByteBuffer originalBuffer; | |
1839 private final ByteBuffer buffer; | |
1840 private final long address; | |
1841 private final long initialPosition; | |
1842 private final long limit; | |
1843 private final long oneVarintLimit; | |
1844 private long position; | |
1845 | |
1846 UnsafeDirectNioEncoder(ByteBuffer buffer) { | |
1847 this.originalBuffer = buffer; | |
1848 this.buffer = buffer.duplicate().order(ByteOrder.LITTLE_ENDIAN); | |
1849 address = UnsafeUtil.addressOffset(buffer); | |
1850 initialPosition = address + buffer.position(); | |
1851 limit = address + buffer.limit(); | |
1852 oneVarintLimit = limit - MAX_VARINT_SIZE; | |
1853 position = initialPosition; | |
1854 } | |
1855 | |
1856 static boolean isSupported() { | |
1857 return UnsafeUtil.hasUnsafeByteBufferOperations(); | |
1858 } | |
1859 | |
1860 @Override | |
1861 public void writeTag(int fieldNumber, int wireType) throws IOException { | |
1862 writeUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType)); | |
1863 } | |
1864 | |
1865 @Override | |
1866 public void writeInt32(int fieldNumber, int value) throws IOException { | |
1867 writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); | |
1868 writeInt32NoTag(value); | |
1869 } | |
1870 | |
1871 @Override | |
1872 public void writeUInt32(int fieldNumber, int value) throws IOException { | |
1873 writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); | |
1874 writeUInt32NoTag(value); | |
1875 } | |
1876 | |
1877 @Override | |
1878 public void writeFixed32(int fieldNumber, int value) throws IOException { | |
1879 writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32); | |
1880 writeFixed32NoTag(value); | |
1881 } | |
1882 | |
1883 @Override | |
1884 public void writeUInt64(int fieldNumber, long value) throws IOException { | |
1885 writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); | |
1886 writeUInt64NoTag(value); | |
1887 } | |
1888 | |
1889 @Override | |
1890 public void writeFixed64(int fieldNumber, long value) throws IOException { | |
1891 writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64); | |
1892 writeFixed64NoTag(value); | |
1893 } | |
1894 | |
1895 @Override | |
1896 public void writeBool(int fieldNumber, boolean value) throws IOException { | |
1897 writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); | |
1898 write((byte) (value ? 1 : 0)); | |
1899 } | |
1900 | |
1901 @Override | |
1902 public void writeString(int fieldNumber, String value) throws IOException { | |
1903 writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); | |
1904 writeStringNoTag(value); | |
1905 } | |
1906 | |
1907 @Override | |
1908 public void writeBytes(int fieldNumber, ByteString value) throws IOException
{ | |
1909 writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); | |
1910 writeBytesNoTag(value); | |
1911 } | |
1912 | |
1913 @Override | |
1914 public void writeByteArray(int fieldNumber, byte[] value) throws IOException
{ | |
1915 writeByteArray(fieldNumber, value, 0, value.length); | |
1916 } | |
1917 | |
1918 @Override | |
1919 public void writeByteArray(int fieldNumber, byte[] value, int offset, int le
ngth) | |
1920 throws IOException { | |
1921 writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); | |
1922 writeByteArrayNoTag(value, offset, length); | |
1923 } | |
1924 | |
1925 @Override | |
1926 public void writeByteBuffer(int fieldNumber, ByteBuffer value) throws IOExce
ption { | |
1927 writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); | |
1928 writeUInt32NoTag(value.capacity()); | |
1929 writeRawBytes(value); | |
1930 } | |
1931 | |
1932 @Override | |
1933 public void writeMessage(int fieldNumber, MessageLite value) throws IOExcept
ion { | |
1934 writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); | |
1935 writeMessageNoTag(value); | |
1936 } | |
1937 | |
1938 @Override | |
1939 public void writeMessageSetExtension(int fieldNumber, MessageLite value) thr
ows IOException { | |
1940 writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP); | |
1941 writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber); | |
1942 writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value); | |
1943 writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP); | |
1944 } | |
1945 | |
1946 @Override | |
1947 public void writeRawMessageSetExtension(int fieldNumber, ByteString value) t
hrows IOException { | |
1948 writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP); | |
1949 writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber); | |
1950 writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value); | |
1951 writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP); | |
1952 } | |
1953 | |
1954 @Override | |
1955 public void writeMessageNoTag(MessageLite value) throws IOException { | |
1956 writeUInt32NoTag(value.getSerializedSize()); | |
1957 value.writeTo(this); | |
1958 } | |
1959 | |
1960 @Override | |
1961 public void write(byte value) throws IOException { | |
1962 if (position >= limit) { | |
1963 throw new OutOfSpaceException( | |
1964 String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)); | |
1965 } | |
1966 UnsafeUtil.putByte(position++, value); | |
1967 } | |
1968 | |
1969 @Override | |
1970 public void writeBytesNoTag(ByteString value) throws IOException { | |
1971 writeUInt32NoTag(value.size()); | |
1972 value.writeTo(this); | |
1973 } | |
1974 | |
1975 @Override | |
1976 public void writeByteArrayNoTag(byte[] value, int offset, int length) throws
IOException { | |
1977 writeUInt32NoTag(length); | |
1978 write(value, offset, length); | |
1979 } | |
1980 | |
1981 @Override | |
1982 public void writeRawBytes(ByteBuffer value) throws IOException { | |
1983 if (value.hasArray()) { | |
1984 write(value.array(), value.arrayOffset(), value.capacity()); | |
1985 } else { | |
1986 ByteBuffer duplicated = value.duplicate(); | |
1987 duplicated.clear(); | |
1988 write(duplicated); | |
1989 } | |
1990 } | |
1991 | |
1992 @Override | |
1993 public void writeInt32NoTag(int value) throws IOException { | |
1994 if (value >= 0) { | |
1995 writeUInt32NoTag(value); | |
1996 } else { | |
1997 // Must sign-extend. | |
1998 writeUInt64NoTag(value); | |
1999 } | |
2000 } | |
2001 | |
2002 @Override | |
2003 public void writeUInt32NoTag(int value) throws IOException { | |
2004 if (position <= oneVarintLimit) { | |
2005 // Optimization to avoid bounds checks on each iteration. | |
2006 while (true) { | |
2007 if ((value & ~0x7F) == 0) { | |
2008 UnsafeUtil.putByte(position++, (byte) value); | |
2009 return; | |
2010 } else { | |
2011 UnsafeUtil.putByte(position++, (byte) ((value & 0x7F) | 0x80)); | |
2012 value >>>= 7; | |
2013 } | |
2014 } | |
2015 } else { | |
2016 while (position < limit) { | |
2017 if ((value & ~0x7F) == 0) { | |
2018 UnsafeUtil.putByte(position++, (byte) value); | |
2019 return; | |
2020 } else { | |
2021 UnsafeUtil.putByte(position++, (byte) ((value & 0x7F) | 0x80)); | |
2022 value >>>= 7; | |
2023 } | |
2024 } | |
2025 throw new OutOfSpaceException( | |
2026 String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)); | |
2027 } | |
2028 } | |
2029 | |
2030 @Override | |
2031 public void writeFixed32NoTag(int value) throws IOException { | |
2032 buffer.putInt(bufferPos(position), value); | |
2033 position += FIXED_32_SIZE; | |
2034 } | |
2035 | |
2036 @Override | |
2037 public void writeUInt64NoTag(long value) throws IOException { | |
2038 if (position <= oneVarintLimit) { | |
2039 // Optimization to avoid bounds checks on each iteration. | |
2040 while (true) { | |
2041 if ((value & ~0x7FL) == 0) { | |
2042 UnsafeUtil.putByte(position++, (byte) value); | |
2043 return; | |
2044 } else { | |
2045 UnsafeUtil.putByte(position++, (byte) (((int) value & 0x7F) | 0x80))
; | |
2046 value >>>= 7; | |
2047 } | |
2048 } | |
2049 } else { | |
2050 while (position < limit) { | |
2051 if ((value & ~0x7FL) == 0) { | |
2052 UnsafeUtil.putByte(position++, (byte) value); | |
2053 return; | |
2054 } else { | |
2055 UnsafeUtil.putByte(position++, (byte) (((int) value & 0x7F) | 0x80))
; | |
2056 value >>>= 7; | |
2057 } | |
2058 } | |
2059 throw new OutOfSpaceException( | |
2060 String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)); | |
2061 } | |
2062 } | |
2063 | |
2064 @Override | |
2065 public void writeFixed64NoTag(long value) throws IOException { | |
2066 buffer.putLong(bufferPos(position), value); | |
2067 position += FIXED_64_SIZE; | |
2068 } | |
2069 | |
2070 @Override | |
2071 public void write(byte[] value, int offset, int length) throws IOException { | |
2072 if (value == null | |
2073 || offset < 0 | |
2074 || length < 0 | |
2075 || (value.length - length) < offset | |
2076 || (limit - length) < position) { | |
2077 if (value == null) { | |
2078 throw new NullPointerException("value"); | |
2079 } | |
2080 throw new OutOfSpaceException( | |
2081 String.format("Pos: %d, limit: %d, len: %d", position, limit, length
)); | |
2082 } | |
2083 | |
2084 UnsafeUtil.copyMemory( | |
2085 value, UnsafeUtil.getArrayBaseOffset() + offset, null, position, lengt
h); | |
2086 position += length; | |
2087 } | |
2088 | |
2089 @Override | |
2090 public void writeLazy(byte[] value, int offset, int length) throws IOExcepti
on { | |
2091 write(value, offset, length); | |
2092 } | |
2093 | |
2094 @Override | |
2095 public void write(ByteBuffer value) throws IOException { | |
2096 try { | |
2097 int length = value.remaining(); | |
2098 repositionBuffer(position); | |
2099 buffer.put(value); | |
2100 position += length; | |
2101 } catch (BufferOverflowException e) { | |
2102 throw new OutOfSpaceException(e); | |
2103 } | |
2104 } | |
2105 | |
2106 @Override | |
2107 public void writeLazy(ByteBuffer value) throws IOException { | |
2108 write(value); | |
2109 } | |
2110 | |
2111 @Override | |
2112 public void writeStringNoTag(String value) throws IOException { | |
2113 long prevPos = position; | |
2114 try { | |
2115 // UTF-8 byte length of the string is at least its UTF-16 code unit leng
th (value.length()), | |
2116 // and at most 3 times of it. We take advantage of this in both branches
below. | |
2117 int maxEncodedSize = value.length() * Utf8.MAX_BYTES_PER_CHAR; | |
2118 int maxLengthVarIntSize = computeUInt32SizeNoTag(maxEncodedSize); | |
2119 int minLengthVarIntSize = computeUInt32SizeNoTag(value.length()); | |
2120 if (minLengthVarIntSize == maxLengthVarIntSize) { | |
2121 // Save the current position and increment past the length field. We'l
l come back | |
2122 // and write the length field after the encoding is complete. | |
2123 int stringStart = bufferPos(position) + minLengthVarIntSize; | |
2124 buffer.position(stringStart); | |
2125 | |
2126 // Encode the string. | |
2127 Utf8.encodeUtf8(value, buffer); | |
2128 | |
2129 // Write the length and advance the position. | |
2130 int length = buffer.position() - stringStart; | |
2131 writeUInt32NoTag(length); | |
2132 position += length; | |
2133 } else { | |
2134 // Calculate and write the encoded length. | |
2135 int length = Utf8.encodedLength(value); | |
2136 writeUInt32NoTag(length); | |
2137 | |
2138 // Write the string and advance the position. | |
2139 repositionBuffer(position); | |
2140 Utf8.encodeUtf8(value, buffer); | |
2141 position += length; | |
2142 } | |
2143 } catch (UnpairedSurrogateException e) { | |
2144 // Roll back the change and convert to an IOException. | |
2145 position = prevPos; | |
2146 repositionBuffer(position); | |
2147 | |
2148 // TODO(nathanmittler): We should throw an IOException here instead. | |
2149 inefficientWriteStringNoTag(value, e); | |
2150 } catch (IllegalArgumentException e) { | |
2151 // Thrown by buffer.position() if out of range. | |
2152 throw new OutOfSpaceException(e); | |
2153 } catch (IndexOutOfBoundsException e) { | |
2154 throw new OutOfSpaceException(e); | |
2155 } | |
2156 } | |
2157 | |
2158 @Override | |
2159 public void flush() { | |
2160 // Update the position of the original buffer. | |
2161 originalBuffer.position(bufferPos(position)); | |
2162 } | |
2163 | |
2164 @Override | |
2165 public int spaceLeft() { | |
2166 return (int) (limit - position); | |
2167 } | |
2168 | |
2169 @Override | |
2170 public int getTotalBytesWritten() { | |
2171 return (int) (position - initialPosition); | |
2172 } | |
2173 | |
2174 private void repositionBuffer(long pos) { | |
2175 buffer.position(bufferPos(pos)); | |
2176 } | |
2177 | |
2178 private int bufferPos(long pos) { | |
2179 return (int) (pos - address); | |
2180 } | |
2181 } | |
2182 | |
2183 /** | |
2184 * Abstract base class for buffered encoders. | 1786 * Abstract base class for buffered encoders. |
2185 */ | 1787 */ |
2186 private abstract static class AbstractBufferedEncoder extends CodedOutputStrea
m { | 1788 private abstract static class AbstractBufferedEncoder extends CodedOutputStrea
m { |
2187 final byte[] buffer; | 1789 final byte[] buffer; |
2188 final int limit; | 1790 final int limit; |
2189 int position; | 1791 int position; |
2190 int totalBytesWritten; | 1792 int totalBytesWritten; |
2191 | 1793 |
2192 AbstractBufferedEncoder(int bufferSize) { | 1794 AbstractBufferedEncoder(int bufferSize) { |
2193 if (bufferSize < 0) { | 1795 if (bufferSize < 0) { |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2246 /** | 1848 /** |
2247 * This method does not perform bounds checking on the array. Checking array
bounds is the | 1849 * This method does not perform bounds checking on the array. Checking array
bounds is the |
2248 * responsibility of the caller. | 1850 * responsibility of the caller. |
2249 */ | 1851 */ |
2250 final void bufferUInt32NoTag(int value) { | 1852 final void bufferUInt32NoTag(int value) { |
2251 if (HAS_UNSAFE_ARRAY_OPERATIONS) { | 1853 if (HAS_UNSAFE_ARRAY_OPERATIONS) { |
2252 final long originalPos = ARRAY_BASE_OFFSET + position; | 1854 final long originalPos = ARRAY_BASE_OFFSET + position; |
2253 long pos = originalPos; | 1855 long pos = originalPos; |
2254 while (true) { | 1856 while (true) { |
2255 if ((value & ~0x7F) == 0) { | 1857 if ((value & ~0x7F) == 0) { |
2256 UnsafeUtil.putByte(buffer, pos++, (byte) value); | 1858 UNSAFE.putByte(buffer, pos++, (byte) value); |
2257 break; | 1859 break; |
2258 } else { | 1860 } else { |
2259 UnsafeUtil.putByte(buffer, pos++, (byte) ((value & 0x7F) | 0x80)); | 1861 UNSAFE.putByte(buffer, pos++, (byte) ((value & 0x7F) | 0x80)); |
2260 value >>>= 7; | 1862 value >>>= 7; |
2261 } | 1863 } |
2262 } | 1864 } |
2263 int delta = (int) (pos - originalPos); | 1865 int delta = (int) (pos - originalPos); |
2264 position += delta; | 1866 position += delta; |
2265 totalBytesWritten += delta; | 1867 totalBytesWritten += delta; |
2266 } else { | 1868 } else { |
2267 while (true) { | 1869 while (true) { |
2268 if ((value & ~0x7F) == 0) { | 1870 if ((value & ~0x7F) == 0) { |
2269 buffer[position++] = (byte) value; | 1871 buffer[position++] = (byte) value; |
(...skipping 11 matching lines...) Expand all Loading... |
2281 /** | 1883 /** |
2282 * This method does not perform bounds checking on the array. Checking array
bounds is the | 1884 * This method does not perform bounds checking on the array. Checking array
bounds is the |
2283 * responsibility of the caller. | 1885 * responsibility of the caller. |
2284 */ | 1886 */ |
2285 final void bufferUInt64NoTag(long value) { | 1887 final void bufferUInt64NoTag(long value) { |
2286 if (HAS_UNSAFE_ARRAY_OPERATIONS) { | 1888 if (HAS_UNSAFE_ARRAY_OPERATIONS) { |
2287 final long originalPos = ARRAY_BASE_OFFSET + position; | 1889 final long originalPos = ARRAY_BASE_OFFSET + position; |
2288 long pos = originalPos; | 1890 long pos = originalPos; |
2289 while (true) { | 1891 while (true) { |
2290 if ((value & ~0x7FL) == 0) { | 1892 if ((value & ~0x7FL) == 0) { |
2291 UnsafeUtil.putByte(buffer, pos++, (byte) value); | 1893 UNSAFE.putByte(buffer, pos++, (byte) value); |
2292 break; | 1894 break; |
2293 } else { | 1895 } else { |
2294 UnsafeUtil.putByte(buffer, pos++, (byte) (((int) value & 0x7F) | 0x8
0)); | 1896 UNSAFE.putByte(buffer, pos++, (byte) (((int) value & 0x7F) | 0x80)); |
2295 value >>>= 7; | 1897 value >>>= 7; |
2296 } | 1898 } |
2297 } | 1899 } |
2298 int delta = (int) (pos - originalPos); | 1900 int delta = (int) (pos - originalPos); |
2299 position += delta; | 1901 position += delta; |
2300 totalBytesWritten += delta; | 1902 totalBytesWritten += delta; |
2301 } else { | 1903 } else { |
2302 while (true) { | 1904 while (true) { |
2303 if ((value & ~0x7FL) == 0) { | 1905 if ((value & ~0x7FL) == 0) { |
2304 buffer[position++] = (byte) value; | 1906 buffer[position++] = (byte) value; |
(...skipping 686 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2991 if (limit - position < requiredSize) { | 2593 if (limit - position < requiredSize) { |
2992 doFlush(); | 2594 doFlush(); |
2993 } | 2595 } |
2994 } | 2596 } |
2995 | 2597 |
2996 private void doFlush() throws IOException { | 2598 private void doFlush() throws IOException { |
2997 out.write(buffer, 0, position); | 2599 out.write(buffer, 0, position); |
2998 position = 0; | 2600 position = 0; |
2999 } | 2601 } |
3000 } | 2602 } |
| 2603 |
| 2604 /** |
| 2605 * Gets the {@code sun.misc.Unsafe} instance, or {@code null} if not available
on this |
| 2606 * platform. |
| 2607 */ |
| 2608 private static sun.misc.Unsafe getUnsafe() { |
| 2609 sun.misc.Unsafe unsafe = null; |
| 2610 try { |
| 2611 unsafe = AccessController.doPrivileged(new PrivilegedExceptionAction<sun.m
isc.Unsafe>() { |
| 2612 @Override |
| 2613 public sun.misc.Unsafe run() throws Exception { |
| 2614 Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class; |
| 2615 |
| 2616 for (Field f : k.getDeclaredFields()) { |
| 2617 f.setAccessible(true); |
| 2618 Object x = f.get(null); |
| 2619 if (k.isInstance(x)) { |
| 2620 return k.cast(x); |
| 2621 } |
| 2622 } |
| 2623 // The sun.misc.Unsafe field does not exist. |
| 2624 return null; |
| 2625 } |
| 2626 }); |
| 2627 } catch (Throwable e) { |
| 2628 // Catching Throwable here due to the fact that Google AppEngine raises No
ClassDefFoundError |
| 2629 // for Unsafe. |
| 2630 } |
| 2631 |
| 2632 logger.log(Level.FINEST, "sun.misc.Unsafe: {}", |
| 2633 unsafe != null ? "available" : "unavailable"); |
| 2634 return unsafe; |
| 2635 } |
| 2636 |
| 2637 /** |
| 2638 * Indicates whether or not unsafe array operations are supported on this plat
form. |
| 2639 */ |
| 2640 // TODO(nathanmittler): Add support for Android's MemoryBlock. |
| 2641 private static boolean supportsUnsafeArrayOperations() { |
| 2642 boolean supported = false; |
| 2643 if (UNSAFE != null) { |
| 2644 try { |
| 2645 UNSAFE.getClass().getMethod("arrayBaseOffset", Class.class); |
| 2646 UNSAFE.getClass().getMethod("putByte", Object.class, long.class, byte.cl
ass); |
| 2647 supported = true; |
| 2648 } catch (Throwable e) { |
| 2649 // Do nothing. |
| 2650 } |
| 2651 } |
| 2652 logger.log(Level.FINEST, "Unsafe array operations: {}", |
| 2653 supported ? "available" : "unavailable"); |
| 2654 return supported; |
| 2655 } |
| 2656 |
| 2657 /** |
| 2658 * Get the base offset for byte arrays, or {@code -1} if {@code sun.misc.Unsaf
e} is not |
| 2659 * available. |
| 2660 */ |
| 2661 private static <T> int byteArrayBaseOffset() { |
| 2662 return HAS_UNSAFE_ARRAY_OPERATIONS ? UNSAFE.arrayBaseOffset(byte[].class) :
-1; |
| 2663 } |
3001 } | 2664 } |
OLD | NEW |