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; |
33 import static java.lang.Math.max; | 36 import static java.lang.Math.max; |
34 | 37 |
35 import com.google.protobuf.Utf8.UnpairedSurrogateException; | 38 import com.google.protobuf.Utf8.UnpairedSurrogateException; |
36 | |
37 import java.io.IOException; | 39 import java.io.IOException; |
38 import java.io.OutputStream; | 40 import java.io.OutputStream; |
39 import java.lang.reflect.Field; | |
40 import java.nio.BufferOverflowException; | 41 import java.nio.BufferOverflowException; |
41 import java.nio.ByteBuffer; | 42 import java.nio.ByteBuffer; |
42 import java.nio.ByteOrder; | 43 import java.nio.ByteOrder; |
43 import java.security.AccessController; | |
44 import java.security.PrivilegedExceptionAction; | |
45 import java.util.logging.Level; | 44 import java.util.logging.Level; |
46 import java.util.logging.Logger; | 45 import java.util.logging.Logger; |
47 | 46 |
48 /** | 47 /** |
49 * Encodes and writes protocol message fields. | 48 * Encodes and writes protocol message fields. |
50 * | 49 * |
51 * <p>This class contains two kinds of methods: methods that write specific | 50 * <p>This class contains two kinds of methods: methods that write specific |
52 * protocol message constructs and field types (e.g. {@link #writeTag} and | 51 * protocol message constructs and field types (e.g. {@link #writeTag} and |
53 * {@link #writeInt32}) and methods that write low-level values (e.g. | 52 * {@link #writeInt32}) and methods that write low-level values (e.g. |
54 * {@link #writeRawVarint32} and {@link #writeRawBytes}). If you are | 53 * {@link #writeRawVarint32} and {@link #writeRawBytes}). If you are |
55 * writing encoded protocol messages, you should use the former methods, but if | 54 * writing encoded protocol messages, you should use the former methods, but if |
56 * you are writing some other format of your own design, use the latter. | 55 * you are writing some other format of your own design, use the latter. |
57 * | 56 * |
58 * <p>This class is totally unsynchronized. | 57 * <p>This class is totally unsynchronized. |
59 */ | 58 */ |
60 public abstract class CodedOutputStream extends ByteOutput { | 59 public abstract class CodedOutputStream extends ByteOutput { |
61 private static final Logger logger = Logger.getLogger(CodedOutputStream.class.
getName()); | 60 private static final Logger logger = Logger.getLogger(CodedOutputStream.class.
getName()); |
62 private static final sun.misc.Unsafe UNSAFE = getUnsafe(); | 61 private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = UnsafeUtil.hasUnsaf
eArrayOperations(); |
63 private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = supportsUnsafeArray
Operations(); | 62 private static final long ARRAY_BASE_OFFSET = UnsafeUtil.getArrayBaseOffset(); |
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; | |
69 | 63 |
70 /** | 64 /** |
71 * @deprecated Use {@link #computeFixed32SizeNoTag(int)} instead. | 65 * @deprecated Use {@link #computeFixed32SizeNoTag(int)} instead. |
72 */ | 66 */ |
73 @Deprecated | 67 @Deprecated |
74 public static final int LITTLE_ENDIAN_32_SIZE = FIXED_32_SIZE; | 68 public static final int LITTLE_ENDIAN_32_SIZE = FIXED_32_SIZE; |
75 | 69 |
76 /** | 70 /** |
77 * The buffer size used in {@link #newInstance(OutputStream)}. | 71 * The buffer size used in {@link #newInstance(OutputStream)}. |
78 */ | 72 */ |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
131 * byte array slice. If more bytes are written than fit in the slice, | 125 * byte array slice. If more bytes are written than fit in the slice, |
132 * {@link OutOfSpaceException} will be thrown. Writing directly to a flat | 126 * {@link OutOfSpaceException} will be thrown. Writing directly to a flat |
133 * array is faster than writing to an {@code OutputStream}. See also | 127 * array is faster than writing to an {@code OutputStream}. See also |
134 * {@link ByteString#newCodedBuilder}. | 128 * {@link ByteString#newCodedBuilder}. |
135 */ | 129 */ |
136 public static CodedOutputStream newInstance( | 130 public static CodedOutputStream newInstance( |
137 final byte[] flatArray, final int offset, final int length) { | 131 final byte[] flatArray, final int offset, final int length) { |
138 return new ArrayEncoder(flatArray, offset, length); | 132 return new ArrayEncoder(flatArray, offset, length); |
139 } | 133 } |
140 | 134 |
141 /** | 135 /** Create a new {@code CodedOutputStream} that writes to the given {@link Byt
eBuffer}. */ |
142 * Create a new {@code CodedOutputStream} that writes to the given {@link Byte
Buffer}. | 136 public static CodedOutputStream newInstance(ByteBuffer buffer) { |
143 */ | 137 if (buffer.hasArray()) { |
144 public static CodedOutputStream newInstance(ByteBuffer byteBuffer) { | 138 return new HeapNioEncoder(buffer); |
145 if (byteBuffer.hasArray()) { | |
146 return new NioHeapEncoder(byteBuffer); | |
147 } | 139 } |
148 return new NioEncoder(byteBuffer); | 140 if (buffer.isDirect() && !buffer.isReadOnly()) { |
| 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); |
149 } | 156 } |
150 | 157 |
151 /** | 158 /** |
| 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 /** |
152 * Create a new {@code CodedOutputStream} that writes to the given {@link Byte
Buffer}. | 197 * Create a new {@code CodedOutputStream} that writes to the given {@link Byte
Buffer}. |
153 * | 198 * |
154 * @deprecated the size parameter is no longer used since use of an internal b
uffer is useless | 199 * @deprecated the size parameter is no longer used since use of an internal b
uffer is useless |
155 * (and wasteful) when writing to a {@link ByteBuffer}. Use {@link #newInstanc
e(ByteBuffer)} | 200 * (and wasteful) when writing to a {@link ByteBuffer}. Use {@link #newInstanc
e(ByteBuffer)} |
156 * instead. | 201 * instead. |
157 */ | 202 */ |
158 @Deprecated | 203 @Deprecated |
159 public static CodedOutputStream newInstance(ByteBuffer byteBuffer, | 204 public static CodedOutputStream newInstance(ByteBuffer byteBuffer, |
160 @SuppressWarnings("unused") int unused) { | 205 @SuppressWarnings("unused") int unused) { |
161 return newInstance(byteBuffer); | 206 return newInstance(byteBuffer); |
(...skipping 700 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
862 } | 907 } |
863 | 908 |
864 /** | 909 /** |
865 * Compute the number of bytes that would be needed to encode an embedded | 910 * Compute the number of bytes that would be needed to encode an embedded |
866 * message field. | 911 * message field. |
867 */ | 912 */ |
868 public static int computeMessageSizeNoTag(final MessageLite value) { | 913 public static int computeMessageSizeNoTag(final MessageLite value) { |
869 return computeLengthDelimitedFieldSize(value.getSerializedSize()); | 914 return computeLengthDelimitedFieldSize(value.getSerializedSize()); |
870 } | 915 } |
871 | 916 |
872 private static int computeLengthDelimitedFieldSize(int fieldLength) { | 917 static int computeLengthDelimitedFieldSize(int fieldLength) { |
873 return computeUInt32SizeNoTag(fieldLength) + fieldLength; | 918 return computeUInt32SizeNoTag(fieldLength) + fieldLength; |
874 } | 919 } |
875 | 920 |
876 /** | 921 /** |
877 * Encode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers | 922 * Encode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers |
878 * into values that can be efficiently encoded with varint. (Otherwise, | 923 * into values that can be efficiently encoded with varint. (Otherwise, |
879 * negative values must be sign-extended to 64 bits to be varint encoded, | 924 * negative values must be sign-extended to 64 bits to be varint encoded, |
880 * thus always taking 10 bytes on the wire.) | 925 * thus always taking 10 bytes on the wire.) |
881 * | 926 * |
882 * @param n A signed 32-bit integer. | 927 * @param n A signed 32-bit integer. |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
938 public static class OutOfSpaceException extends IOException { | 983 public static class OutOfSpaceException extends IOException { |
939 private static final long serialVersionUID = -6947486886997889499L; | 984 private static final long serialVersionUID = -6947486886997889499L; |
940 | 985 |
941 private static final String MESSAGE = | 986 private static final String MESSAGE = |
942 "CodedOutputStream was writing to a flat byte array and ran out of space
."; | 987 "CodedOutputStream was writing to a flat byte array and ran out of space
."; |
943 | 988 |
944 OutOfSpaceException() { | 989 OutOfSpaceException() { |
945 super(MESSAGE); | 990 super(MESSAGE); |
946 } | 991 } |
947 | 992 |
| 993 OutOfSpaceException(String explanationMessage) { |
| 994 super(MESSAGE + ": " + explanationMessage); |
| 995 } |
| 996 |
948 OutOfSpaceException(Throwable cause) { | 997 OutOfSpaceException(Throwable cause) { |
949 super(MESSAGE, cause); | 998 super(MESSAGE, cause); |
950 } | 999 } |
| 1000 |
| 1001 OutOfSpaceException(String explanationMessage, Throwable cause) { |
| 1002 super(MESSAGE + ": " + explanationMessage, cause); |
| 1003 } |
951 } | 1004 } |
952 | 1005 |
953 /** | 1006 /** |
954 * Get the total number of bytes successfully written to this stream. The | 1007 * Get the total number of bytes successfully written to this stream. The |
955 * returned value is not guaranteed to be accurate if exceptions have been | 1008 * returned value is not guaranteed to be accurate if exceptions have been |
956 * found in the middle of writing. | 1009 * found in the middle of writing. |
957 */ | 1010 */ |
958 public abstract int getTotalBytesWritten(); | 1011 public abstract int getTotalBytesWritten(); |
959 | 1012 |
960 // ================================================================= | 1013 // ================================================================= |
(...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1243 public final void writeMessageNoTag(final MessageLite value) throws IOExcept
ion { | 1296 public final void writeMessageNoTag(final MessageLite value) throws IOExcept
ion { |
1244 writeUInt32NoTag(value.getSerializedSize()); | 1297 writeUInt32NoTag(value.getSerializedSize()); |
1245 value.writeTo(this); | 1298 value.writeTo(this); |
1246 } | 1299 } |
1247 | 1300 |
1248 @Override | 1301 @Override |
1249 public final void write(byte value) throws IOException { | 1302 public final void write(byte value) throws IOException { |
1250 try { | 1303 try { |
1251 buffer[position++] = value; | 1304 buffer[position++] = value; |
1252 } catch (IndexOutOfBoundsException e) { | 1305 } catch (IndexOutOfBoundsException e) { |
1253 throw new OutOfSpaceException(new IndexOutOfBoundsException( | 1306 throw new OutOfSpaceException( |
1254 String.format("Pos: %d, limit: %d, len: %d", position, limit, 1))); | 1307 String.format("Pos: %d, limit: %d, len: %d", position, limit, 1), e)
; |
1255 } | 1308 } |
1256 } | 1309 } |
1257 | 1310 |
1258 @Override | 1311 @Override |
1259 public final void writeInt32NoTag(int value) throws IOException { | 1312 public final void writeInt32NoTag(int value) throws IOException { |
1260 if (value >= 0) { | 1313 if (value >= 0) { |
1261 writeUInt32NoTag(value); | 1314 writeUInt32NoTag(value); |
1262 } else { | 1315 } else { |
1263 // Must sign-extend. | 1316 // Must sign-extend. |
1264 writeUInt64NoTag(value); | 1317 writeUInt64NoTag(value); |
1265 } | 1318 } |
1266 } | 1319 } |
1267 | 1320 |
1268 @Override | 1321 @Override |
1269 public final void writeUInt32NoTag(int value) throws IOException { | 1322 public final void writeUInt32NoTag(int value) throws IOException { |
1270 if (HAS_UNSAFE_ARRAY_OPERATIONS && spaceLeft() >= MAX_VARINT_SIZE) { | 1323 if (HAS_UNSAFE_ARRAY_OPERATIONS && spaceLeft() >= MAX_VARINT_SIZE) { |
1271 long pos = ARRAY_BASE_OFFSET + position; | 1324 long pos = ARRAY_BASE_OFFSET + position; |
1272 while (true) { | 1325 while (true) { |
1273 if ((value & ~0x7F) == 0) { | 1326 if ((value & ~0x7F) == 0) { |
1274 UNSAFE.putByte(buffer, pos++, (byte) value); | 1327 UnsafeUtil.putByte(buffer, pos++, (byte) value); |
1275 position++; | 1328 position++; |
1276 return; | 1329 return; |
1277 } else { | 1330 } else { |
1278 UNSAFE.putByte(buffer, pos++, (byte) ((value & 0x7F) | 0x80)); | 1331 UnsafeUtil.putByte(buffer, pos++, (byte) ((value & 0x7F) | 0x80)); |
1279 position++; | 1332 position++; |
1280 value >>>= 7; | 1333 value >>>= 7; |
1281 } | 1334 } |
1282 } | 1335 } |
1283 } else { | 1336 } else { |
1284 try { | 1337 try { |
1285 while (true) { | 1338 while (true) { |
1286 if ((value & ~0x7F) == 0) { | 1339 if ((value & ~0x7F) == 0) { |
1287 buffer[position++] = (byte) value; | 1340 buffer[position++] = (byte) value; |
1288 return; | 1341 return; |
1289 } else { | 1342 } else { |
1290 buffer[position++] = (byte) ((value & 0x7F) | 0x80); | 1343 buffer[position++] = (byte) ((value & 0x7F) | 0x80); |
1291 value >>>= 7; | 1344 value >>>= 7; |
1292 } | 1345 } |
1293 } | 1346 } |
1294 } catch (IndexOutOfBoundsException e) { | 1347 } catch (IndexOutOfBoundsException e) { |
1295 throw new OutOfSpaceException( | 1348 throw new OutOfSpaceException( |
1296 new IndexOutOfBoundsException( | 1349 String.format("Pos: %d, limit: %d, len: %d", position, limit, 1),
e); |
1297 String.format("Pos: %d, limit: %d, len: %d", position, limit,
1))); | |
1298 } | 1350 } |
1299 } | 1351 } |
1300 } | 1352 } |
1301 | 1353 |
1302 @Override | 1354 @Override |
1303 public final void writeFixed32NoTag(int value) throws IOException { | 1355 public final void writeFixed32NoTag(int value) throws IOException { |
1304 try { | 1356 try { |
1305 buffer[position++] = (byte) (value & 0xFF); | 1357 buffer[position++] = (byte) (value & 0xFF); |
1306 buffer[position++] = (byte) ((value >> 8) & 0xFF); | 1358 buffer[position++] = (byte) ((value >> 8) & 0xFF); |
1307 buffer[position++] = (byte) ((value >> 16) & 0xFF); | 1359 buffer[position++] = (byte) ((value >> 16) & 0xFF); |
1308 buffer[position++] = (byte) ((value >> 24) & 0xFF); | 1360 buffer[position++] = (byte) ((value >> 24) & 0xFF); |
1309 } catch (IndexOutOfBoundsException e) { | 1361 } catch (IndexOutOfBoundsException e) { |
1310 throw new OutOfSpaceException( | 1362 throw new OutOfSpaceException( |
1311 new IndexOutOfBoundsException( | 1363 String.format("Pos: %d, limit: %d, len: %d", position, limit, 1), e)
; |
1312 String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)
)); | |
1313 } | 1364 } |
1314 } | 1365 } |
1315 | 1366 |
1316 @Override | 1367 @Override |
1317 public final void writeUInt64NoTag(long value) throws IOException { | 1368 public final void writeUInt64NoTag(long value) throws IOException { |
1318 if (HAS_UNSAFE_ARRAY_OPERATIONS && spaceLeft() >= MAX_VARINT_SIZE) { | 1369 if (HAS_UNSAFE_ARRAY_OPERATIONS && spaceLeft() >= MAX_VARINT_SIZE) { |
1319 long pos = ARRAY_BASE_OFFSET + position; | 1370 long pos = ARRAY_BASE_OFFSET + position; |
1320 while (true) { | 1371 while (true) { |
1321 if ((value & ~0x7FL) == 0) { | 1372 if ((value & ~0x7FL) == 0) { |
1322 UNSAFE.putByte(buffer, pos++, (byte) value); | 1373 UnsafeUtil.putByte(buffer, pos++, (byte) value); |
1323 position++; | 1374 position++; |
1324 return; | 1375 return; |
1325 } else { | 1376 } else { |
1326 UNSAFE.putByte(buffer, pos++, (byte) (((int) value & 0x7F) | 0x80)); | 1377 UnsafeUtil.putByte(buffer, pos++, (byte) (((int) value & 0x7F) | 0x8
0)); |
1327 position++; | 1378 position++; |
1328 value >>>= 7; | 1379 value >>>= 7; |
1329 } | 1380 } |
1330 } | 1381 } |
1331 } else { | 1382 } else { |
1332 try { | 1383 try { |
1333 while (true) { | 1384 while (true) { |
1334 if ((value & ~0x7FL) == 0) { | 1385 if ((value & ~0x7FL) == 0) { |
1335 buffer[position++] = (byte) value; | 1386 buffer[position++] = (byte) value; |
1336 return; | 1387 return; |
1337 } else { | 1388 } else { |
1338 buffer[position++] = (byte) (((int) value & 0x7F) | 0x80); | 1389 buffer[position++] = (byte) (((int) value & 0x7F) | 0x80); |
1339 value >>>= 7; | 1390 value >>>= 7; |
1340 } | 1391 } |
1341 } | 1392 } |
1342 } catch (IndexOutOfBoundsException e) { | 1393 } catch (IndexOutOfBoundsException e) { |
1343 throw new OutOfSpaceException( | 1394 throw new OutOfSpaceException( |
1344 new IndexOutOfBoundsException( | 1395 String.format("Pos: %d, limit: %d, len: %d", position, limit, 1),
e); |
1345 String.format("Pos: %d, limit: %d, len: %d", position, limit,
1))); | |
1346 } | 1396 } |
1347 } | 1397 } |
1348 } | 1398 } |
1349 | 1399 |
1350 @Override | 1400 @Override |
1351 public final void writeFixed64NoTag(long value) throws IOException { | 1401 public final void writeFixed64NoTag(long value) throws IOException { |
1352 try { | 1402 try { |
1353 buffer[position++] = (byte) ((int) (value) & 0xFF); | 1403 buffer[position++] = (byte) ((int) (value) & 0xFF); |
1354 buffer[position++] = (byte) ((int) (value >> 8) & 0xFF); | 1404 buffer[position++] = (byte) ((int) (value >> 8) & 0xFF); |
1355 buffer[position++] = (byte) ((int) (value >> 16) & 0xFF); | 1405 buffer[position++] = (byte) ((int) (value >> 16) & 0xFF); |
1356 buffer[position++] = (byte) ((int) (value >> 24) & 0xFF); | 1406 buffer[position++] = (byte) ((int) (value >> 24) & 0xFF); |
1357 buffer[position++] = (byte) ((int) (value >> 32) & 0xFF); | 1407 buffer[position++] = (byte) ((int) (value >> 32) & 0xFF); |
1358 buffer[position++] = (byte) ((int) (value >> 40) & 0xFF); | 1408 buffer[position++] = (byte) ((int) (value >> 40) & 0xFF); |
1359 buffer[position++] = (byte) ((int) (value >> 48) & 0xFF); | 1409 buffer[position++] = (byte) ((int) (value >> 48) & 0xFF); |
1360 buffer[position++] = (byte) ((int) (value >> 56) & 0xFF); | 1410 buffer[position++] = (byte) ((int) (value >> 56) & 0xFF); |
1361 } catch (IndexOutOfBoundsException e) { | 1411 } catch (IndexOutOfBoundsException e) { |
1362 throw new OutOfSpaceException( | 1412 throw new OutOfSpaceException( |
1363 new IndexOutOfBoundsException( | 1413 String.format("Pos: %d, limit: %d, len: %d", position, limit, 1), e)
; |
1364 String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)
)); | |
1365 } | 1414 } |
1366 } | 1415 } |
1367 | 1416 |
1368 @Override | 1417 @Override |
1369 public final void write(byte[] value, int offset, int length) throws IOExcep
tion { | 1418 public final void write(byte[] value, int offset, int length) throws IOExcep
tion { |
1370 try { | 1419 try { |
1371 System.arraycopy(value, offset, buffer, position, length); | 1420 System.arraycopy(value, offset, buffer, position, length); |
1372 position += length; | 1421 position += length; |
1373 } catch (IndexOutOfBoundsException e) { | 1422 } catch (IndexOutOfBoundsException e) { |
1374 throw new OutOfSpaceException( | 1423 throw new OutOfSpaceException( |
1375 new IndexOutOfBoundsException( | 1424 String.format("Pos: %d, limit: %d, len: %d", position, limit, length
), e); |
1376 String.format("Pos: %d, limit: %d, len: %d", position, limit, le
ngth))); | |
1377 } | 1425 } |
1378 } | 1426 } |
1379 | 1427 |
1380 @Override | 1428 @Override |
1381 public final void writeLazy(byte[] value, int offset, int length) throws IOE
xception { | 1429 public final void writeLazy(byte[] value, int offset, int length) throws IOE
xception { |
1382 write(value, offset, length); | 1430 write(value, offset, length); |
1383 } | 1431 } |
1384 | 1432 |
1385 @Override | 1433 @Override |
1386 public final void write(ByteBuffer value) throws IOException { | 1434 public final void write(ByteBuffer value) throws IOException { |
1387 final int length = value.remaining(); | 1435 final int length = value.remaining(); |
1388 try { | 1436 try { |
1389 value.get(buffer, position, length); | 1437 value.get(buffer, position, length); |
1390 position += length; | 1438 position += length; |
1391 } catch (IndexOutOfBoundsException e) { | 1439 } catch (IndexOutOfBoundsException e) { |
1392 throw new OutOfSpaceException( | 1440 throw new OutOfSpaceException( |
1393 new IndexOutOfBoundsException( | 1441 String.format("Pos: %d, limit: %d, len: %d", position, limit, length
), e); |
1394 String.format("Pos: %d, limit: %d, len: %d", position, limit, le
ngth))); | |
1395 } | 1442 } |
1396 } | 1443 } |
1397 | 1444 |
1398 @Override | 1445 @Override |
1399 public final void writeLazy(ByteBuffer value) throws IOException { | 1446 public final void writeLazy(ByteBuffer value) throws IOException { |
1400 write(value); | 1447 write(value); |
1401 } | 1448 } |
1402 | 1449 |
1403 @Override | 1450 @Override |
1404 public final void writeStringNoTag(String value) throws IOException { | 1451 public final void writeStringNoTag(String value) throws IOException { |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1447 @Override | 1494 @Override |
1448 public final int getTotalBytesWritten() { | 1495 public final int getTotalBytesWritten() { |
1449 return position - offset; | 1496 return position - offset; |
1450 } | 1497 } |
1451 } | 1498 } |
1452 | 1499 |
1453 /** | 1500 /** |
1454 * A {@link CodedOutputStream} that writes directly to a heap {@link ByteBuffe
r}. Writes are | 1501 * A {@link CodedOutputStream} that writes directly to a heap {@link ByteBuffe
r}. Writes are |
1455 * done directly to the underlying array. The buffer position is only updated
after a flush. | 1502 * done directly to the underlying array. The buffer position is only updated
after a flush. |
1456 */ | 1503 */ |
1457 private static final class NioHeapEncoder extends ArrayEncoder { | 1504 private static final class HeapNioEncoder extends ArrayEncoder { |
1458 private final ByteBuffer byteBuffer; | 1505 private final ByteBuffer byteBuffer; |
1459 private int initialPosition; | 1506 private int initialPosition; |
1460 | 1507 |
1461 NioHeapEncoder(ByteBuffer byteBuffer) { | 1508 HeapNioEncoder(ByteBuffer byteBuffer) { |
1462 super(byteBuffer.array(), byteBuffer.arrayOffset() + byteBuffer.position()
, | 1509 super(byteBuffer.array(), byteBuffer.arrayOffset() + byteBuffer.position()
, |
1463 byteBuffer.remaining()); | 1510 byteBuffer.remaining()); |
1464 this.byteBuffer = byteBuffer; | 1511 this.byteBuffer = byteBuffer; |
1465 this.initialPosition = byteBuffer.position(); | 1512 this.initialPosition = byteBuffer.position(); |
1466 } | 1513 } |
1467 | 1514 |
1468 @Override | 1515 @Override |
1469 public void flush() { | 1516 public void flush() { |
1470 // Update the position on the buffer. | 1517 // Update the position on the buffer. |
1471 byteBuffer.position(initialPosition + getTotalBytesWritten()); | 1518 byteBuffer.position(initialPosition + getTotalBytesWritten()); |
1472 } | 1519 } |
1473 } | 1520 } |
1474 | 1521 |
1475 /** | 1522 /** |
1476 * A {@link CodedOutputStream} that writes directly to a {@link ByteBuffer}. | 1523 * A {@link CodedOutputStream} that writes directly to a direct {@link ByteBuf
fer}, using only |
| 1524 * safe operations.. |
1477 */ | 1525 */ |
1478 private static final class NioEncoder extends CodedOutputStream { | 1526 private static final class SafeDirectNioEncoder extends CodedOutputStream { |
1479 private final ByteBuffer originalBuffer; | 1527 private final ByteBuffer originalBuffer; |
1480 private final ByteBuffer buffer; | 1528 private final ByteBuffer buffer; |
1481 private final int initialPosition; | 1529 private final int initialPosition; |
1482 | 1530 |
1483 NioEncoder(ByteBuffer buffer) { | 1531 SafeDirectNioEncoder(ByteBuffer buffer) { |
1484 this.originalBuffer = buffer; | 1532 this.originalBuffer = buffer; |
1485 this.buffer = buffer.duplicate().order(ByteOrder.LITTLE_ENDIAN); | 1533 this.buffer = buffer.duplicate().order(ByteOrder.LITTLE_ENDIAN); |
1486 initialPosition = buffer.position(); | 1534 initialPosition = buffer.position(); |
1487 } | 1535 } |
1488 | 1536 |
1489 @Override | 1537 @Override |
1490 public void writeTag(final int fieldNumber, final int wireType) throws IOExc
eption { | 1538 public void writeTag(final int fieldNumber, final int wireType) throws IOExc
eption { |
1491 writeUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType)); | 1539 writeUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType)); |
1492 } | 1540 } |
1493 | 1541 |
(...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1776 private void encode(String value) throws IOException { | 1824 private void encode(String value) throws IOException { |
1777 try { | 1825 try { |
1778 Utf8.encodeUtf8(value, buffer); | 1826 Utf8.encodeUtf8(value, buffer); |
1779 } catch (IndexOutOfBoundsException e) { | 1827 } catch (IndexOutOfBoundsException e) { |
1780 throw new OutOfSpaceException(e); | 1828 throw new OutOfSpaceException(e); |
1781 } | 1829 } |
1782 } | 1830 } |
1783 } | 1831 } |
1784 | 1832 |
1785 /** | 1833 /** |
| 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 /** |
1786 * Abstract base class for buffered encoders. | 2184 * Abstract base class for buffered encoders. |
1787 */ | 2185 */ |
1788 private abstract static class AbstractBufferedEncoder extends CodedOutputStrea
m { | 2186 private abstract static class AbstractBufferedEncoder extends CodedOutputStrea
m { |
1789 final byte[] buffer; | 2187 final byte[] buffer; |
1790 final int limit; | 2188 final int limit; |
1791 int position; | 2189 int position; |
1792 int totalBytesWritten; | 2190 int totalBytesWritten; |
1793 | 2191 |
1794 AbstractBufferedEncoder(int bufferSize) { | 2192 AbstractBufferedEncoder(int bufferSize) { |
1795 if (bufferSize < 0) { | 2193 if (bufferSize < 0) { |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1848 /** | 2246 /** |
1849 * This method does not perform bounds checking on the array. Checking array
bounds is the | 2247 * This method does not perform bounds checking on the array. Checking array
bounds is the |
1850 * responsibility of the caller. | 2248 * responsibility of the caller. |
1851 */ | 2249 */ |
1852 final void bufferUInt32NoTag(int value) { | 2250 final void bufferUInt32NoTag(int value) { |
1853 if (HAS_UNSAFE_ARRAY_OPERATIONS) { | 2251 if (HAS_UNSAFE_ARRAY_OPERATIONS) { |
1854 final long originalPos = ARRAY_BASE_OFFSET + position; | 2252 final long originalPos = ARRAY_BASE_OFFSET + position; |
1855 long pos = originalPos; | 2253 long pos = originalPos; |
1856 while (true) { | 2254 while (true) { |
1857 if ((value & ~0x7F) == 0) { | 2255 if ((value & ~0x7F) == 0) { |
1858 UNSAFE.putByte(buffer, pos++, (byte) value); | 2256 UnsafeUtil.putByte(buffer, pos++, (byte) value); |
1859 break; | 2257 break; |
1860 } else { | 2258 } else { |
1861 UNSAFE.putByte(buffer, pos++, (byte) ((value & 0x7F) | 0x80)); | 2259 UnsafeUtil.putByte(buffer, pos++, (byte) ((value & 0x7F) | 0x80)); |
1862 value >>>= 7; | 2260 value >>>= 7; |
1863 } | 2261 } |
1864 } | 2262 } |
1865 int delta = (int) (pos - originalPos); | 2263 int delta = (int) (pos - originalPos); |
1866 position += delta; | 2264 position += delta; |
1867 totalBytesWritten += delta; | 2265 totalBytesWritten += delta; |
1868 } else { | 2266 } else { |
1869 while (true) { | 2267 while (true) { |
1870 if ((value & ~0x7F) == 0) { | 2268 if ((value & ~0x7F) == 0) { |
1871 buffer[position++] = (byte) value; | 2269 buffer[position++] = (byte) value; |
(...skipping 11 matching lines...) Expand all Loading... |
1883 /** | 2281 /** |
1884 * This method does not perform bounds checking on the array. Checking array
bounds is the | 2282 * This method does not perform bounds checking on the array. Checking array
bounds is the |
1885 * responsibility of the caller. | 2283 * responsibility of the caller. |
1886 */ | 2284 */ |
1887 final void bufferUInt64NoTag(long value) { | 2285 final void bufferUInt64NoTag(long value) { |
1888 if (HAS_UNSAFE_ARRAY_OPERATIONS) { | 2286 if (HAS_UNSAFE_ARRAY_OPERATIONS) { |
1889 final long originalPos = ARRAY_BASE_OFFSET + position; | 2287 final long originalPos = ARRAY_BASE_OFFSET + position; |
1890 long pos = originalPos; | 2288 long pos = originalPos; |
1891 while (true) { | 2289 while (true) { |
1892 if ((value & ~0x7FL) == 0) { | 2290 if ((value & ~0x7FL) == 0) { |
1893 UNSAFE.putByte(buffer, pos++, (byte) value); | 2291 UnsafeUtil.putByte(buffer, pos++, (byte) value); |
1894 break; | 2292 break; |
1895 } else { | 2293 } else { |
1896 UNSAFE.putByte(buffer, pos++, (byte) (((int) value & 0x7F) | 0x80)); | 2294 UnsafeUtil.putByte(buffer, pos++, (byte) (((int) value & 0x7F) | 0x8
0)); |
1897 value >>>= 7; | 2295 value >>>= 7; |
1898 } | 2296 } |
1899 } | 2297 } |
1900 int delta = (int) (pos - originalPos); | 2298 int delta = (int) (pos - originalPos); |
1901 position += delta; | 2299 position += delta; |
1902 totalBytesWritten += delta; | 2300 totalBytesWritten += delta; |
1903 } else { | 2301 } else { |
1904 while (true) { | 2302 while (true) { |
1905 if ((value & ~0x7FL) == 0) { | 2303 if ((value & ~0x7FL) == 0) { |
1906 buffer[position++] = (byte) value; | 2304 buffer[position++] = (byte) value; |
(...skipping 686 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2593 if (limit - position < requiredSize) { | 2991 if (limit - position < requiredSize) { |
2594 doFlush(); | 2992 doFlush(); |
2595 } | 2993 } |
2596 } | 2994 } |
2597 | 2995 |
2598 private void doFlush() throws IOException { | 2996 private void doFlush() throws IOException { |
2599 out.write(buffer, 0, position); | 2997 out.write(buffer, 0, position); |
2600 position = 0; | 2998 position = 0; |
2601 } | 2999 } |
2602 } | 3000 } |
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 } | |
2664 } | 3001 } |
OLD | NEW |